Where does the Android CallScreeningService place if I'm using BroadcastReceiver?

903 views Asked by At

I am using the Broadcast receiver to detect the incoming call and then call my custom incoming Screen as follow:

public class CallReceiver extends BroadcastReceiver {
  @Override
  public void onReceive(Context context, Intent intent) {

    if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) {
      String phoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
      String msg = phoneNumber + " Incoming Call";
      String name = "Gil Pires";
      //showToast(context, msg);


      Intent callerIntent = new Intent(context, CallerInfoActivity.class);
      callerIntent.putExtras(callerIntent);
      callerIntent.putExtra("EXTRA_PHONE_CALLER", phoneNumber);
      callerIntent.putExtra("EXTRA_NAME_CALLER", name);

      context.startActivity(callerIntent);
      //showToast(context,msg);
    }

  }

  void showToast(Context context,String message){
    Toast toast=Toast.makeText(context,message,Toast.LENGTH_LONG);
    toast.setGravity(Gravity.CENTER,0,0);
    toast.show();
  }
}

And this is the CallScreeningService:

@RequiresApi(api = Build.VERSION_CODES.N)
public class CallService extends CallScreeningService {
  @Override
  public void onScreenCall(@NonNull Call.Details callDetails) {
    CallResponse.Builder response = new CallResponse.Builder();
    Uri callerPhone = callDetails.getHandle();
    Log.e("CallBouncer", "Call screening service triggered " + callerPhone);
    respondToCall(callDetails, response.build() );
  }
}

So I'm not sure where is this CallScreeningService is beeing used as with the BroadcastReceiver I'm able to create and display my custom Screen on Incoming Calls?

1

There are 1 answers

0
Assad khan On

I used CallScreenService to show a small window with caller details on incoming calls. You have to follow some steps to implement CallScreenService: First Declaration in Manifest.xml

`<activity
        android:name=".calling_app.ui.navigation.HomeActivity"
        android:configChanges="orientation|keyboardHidden|screenSize"
        android:excludeFromRecents="false"
        android:exported="true"
        android:screenOrientation="portrait"
        android:windowSoftInputMode="adjustNothing">

        <intent-filter>
            <action android:name="android.intent.action.DIAL"/>
            <action android:name="android.intent.category.DEFAULT"/>
        </intent-filter>

        <intent-filter>
            <action android:name="android.intent.action.DIAL"/>
            <action android:name="android.intent.category.DEFAULT"/>
            <data android:scheme="tel"/>
        </intent-filter>

    </activity>`

Create a Class where you will implement CallScreenService and write your logic there myServiceClass:

class CallerAppService : CallScreeningService() {
@Inject
lateinit var applicationRepository: ApplicationRepository

@Inject
lateinit var telephonyManager: TelephonyManager
private val windowManagerForNumber by lazy {
    WindowManagerForNumber(this)
}
private var finalPhoneNumb: String? = ""
private val callerName: String?
    get() = finalPhoneNumb?.let {
        applicationRepository.fetchNameFromPhoneNumber(
            it
        )
    }
private val notificationManagerImpl = NotificationManagerImpl()

private val notification by lazy {
   com.example.truecaller.calling_app.utils.notification.Notification(this)
}

companion object {
    fun startService(context: Context) {
        Intent(context, TrueCallerAppService::class.java).apply {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startForegroundService(context, this)
            } else {
                context.startService(this)
            }
        }
    }
}


override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    super.onStartCommand(intent, flags, startId)
    startNotification()
    return START_STICKY
}

override fun onScreenCall(p0: Call.Details) {
    val number = getPhoneNumber(p0)
    var callResponse = CallResponse.Builder()
    callResponse = handlePhoneCall(callResponse, number)
    respondToCall(p0, callResponse.build())
}

private fun handlePhoneCall(                 //Here you will write your logic 
                                            //what you want to do on ScreenCall
    response: CallResponse.Builder,
    phoneNumber: String
): CallResponse.Builder {
    if (phoneNumber == FORBIDDEN_PHONE_CALL_NUMBER) {
        response.apply {
            setRejectCall(true)
            setDisallowCall(true)
            setSkipCallLog(false)

        }
    } else {
        if (Settings.canDrawOverlays(this)) {
            finalPhoneNumb = phoneNumber
            if (PhoneNumberValidCheck.checkValidPhoneNumber(phoneNumber)) {
                displayToast(phoneNumber)
                Log.e("phone", "handlePhoneCall: $phoneNumber")
            }
        }
    }
    return response
}

private fun startNotification() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForeground(notification.notificationId, notification.createNotification())
    } else {
        startForeground(
            notification.notificationId,
            android.app.Notification()
        )
    }
    isForeGroundService = true
}

private fun displayToast(message: String) {
    try {
        val countryCodeOfNumber = telephonyManager.simCountryIso.toString()
        val phoneNumberUtil = PhoneNumberUtil.getInstance()
        val phoneNumber: Phonenumber.PhoneNumber =
            phoneNumberUtil.parse(message, countryCodeOfNumber.uppercase(Locale.ENGLISH))
        val incomingNumber = phoneNumberUtil.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164)
        notificationManagerImpl.appRepo(applicationRepository, windowManagerForNumber, incomingNumber)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

private fun getPhoneNumber(callDetails: Call.Details): String {
    return callDetails.handle.toString().removeTelephonePrefix().parseNumberCountryCode()
}

}

You have to make your app default dialler app or default for caller id and spam

@RequiresApi(Build.VERSION_CODES.Q)
fun Activity.startCallScreeningPermissionScreen(onCall: (intent: Intent) -> Unit) {
    val roleManager = this.getSystemService(AppCompatActivity.ROLE_SERVICE) as RoleManager
    val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING)
    onCall.invoke(intent)
}
fun Activity.startSelectDialerScreen(onCall: (intent: Intent) -> Unit) {
    if (this.hasDialerCapability())
        return
        val intent = Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER)
            .putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName)
        onCall.invoke(intent)
}

Now in your mainActivity request to change the default dialer app

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
           activity.startCallScreeningPermissionScreen { intent->

              activityResultLauncher?.launch(intent)
                        }
                    } else {
                        activity.startSelectDialerScreen { intent ->
                            activityResultLauncher?.launch(intent)
                        }

activityResultLauncher:

activityResultLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            when (it.resultCode) {
                RESULT_OK -> {
                    //do something when the app selected as a default dialer
                    }
                }
        }