1

I have implemented a CallService which I have in the manifest like this:

 <service
        android:name=".dialer.CallService"
        android:permission="android.permission.BIND_INCALL_SERVICE">
        <meta-data
            android:name="android.telecom.IN_CALL_SERVICE_UI"
            android:value="true"/>

        <intent-filter>
            <action android:name="android.telecom.InCallService"/>
        </intent-filter>
    </service>

And this is it:

@TargetApi(Build.VERSION_CODES.M)
class CallService : InCallService() {

companion object {
    private const val LOG_TAG = "CallService"
}

override fun onCallAdded(call: Call) {
    super.onCallAdded(call)
    App.GSMCALL = true;
    Log.i(LOG_TAG, "onCallAdded: $call")
    Log.i(LOG_TAG, "onCallAdded: ${call.details.handle.schemeSpecificPart}")
    call.registerCallback(callCallback)
    val intent = Intent(this, IncomingCallActivity::class.java)
    if (call.details.handle.schemeSpecificPart.contains("<INSERT PHONE NR HERE>")) { // something similar will be done, if I don't pass new_task it will go through default caller
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    }
    startActivity(intent)
    CallManager.updateCall(call)
}

override fun onCallRemoved(call: Call) {
    super.onCallRemoved(call)
    App.GSMCALL = false;
    Log.i(LOG_TAG, "onCallRemoved: $call")
    call.unregisterCallback(callCallback)
    CallManager.updateCall(null)
}

private val callCallback = object : Call.Callback() {
    override fun onStateChanged(call: Call, state: Int) {
        Log.i(LOG_TAG, "Call.Callback onStateChanged: $call, state: $state")
        CallManager.updateCall(call)
    }
}

}

Now this is what I want. If my phone call is then I want it to go through my Call Activity. But if it's a different phone number, I want it to fall back to the phones dialler. Is this possible? I've seen that If I do not add the FLAG_ACTIVITY_NEW_TASK it will crash which makes the phones main Dialler to appear. But this just works once, And I wouldn't use such a hack to make it work. So any other ideas?

EDIT:

I am using a Google Pixel with Android Pie

I tried to implement the logic that @marmor suggested but still doesn't work.

This is my activity on create:

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    wakeUpDeviceWhenWindowShown()
    setTheme(R.style.AppTheme)
    var params = WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            if (VERSION.SDK_INT >= VERSION_CODES.O) WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY else WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or FLAG_SHOW_WHEN_LOCKED or FLAG_DISMISS_KEYGUARD, ActivityInfo.COLOR_MODE_DEFAULT)
    setContentView(R.layout.activity_call)
    val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager
    wm.addView(window.decorView, params)
}

I added in AndroidManifest: <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> And also have the code for:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
    {
        if (!Settings.canDrawOverlays(this))
        {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, 0);
        }
    }

This is the error I get:

2019-07-23 13:13:06.600 18418-18418/com.xelion.android.debug E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.xelion.android.debug, PID: 18418
java.lang.IllegalStateException: View DecorView@53d8f92[IncomingCallActivity] has already been added to the window manager.
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:328)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3906)
    at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1816)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6718)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

I also tried just doing:

    window.setType(if (VERSION.SDK_INT >= VERSION_CODES.O) WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY else WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)
    window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or FLAG_SHOW_WHEN_LOCKED or FLAG_DISMISS_KEYGUARD)

Without doing wm.addView(window.decorView, params)

But I just get this: What Am I doing wrong? enter image description here

rosu alin
  • 5,674
  • 11
  • 69
  • 150
  • not sure i understand, which intent are you talking about? is it `ACTION_CALL`, `ACTION_DIAL` or something else? – marmor Jul 16 '19 at 17:30
  • Receiving a call, from another phone, I want it to show for a specific number(for specific list of numbers need custom UI). I implemented this: https://github.com/mbarrben/android_dialer_replacement This works. But For the rest of the numbers I want to NOT show my custom UI but simply revert to the initial default phone app (how I would get the calls if I don't change the default Caller app to my own). Now I saw that if I don't set the FLAG_ACTIVITY_NEW_TASK on my intent it will start the phones caller screen as a fallback. But I want something more clean – rosu alin Jul 17 '19 at 08:43
  • please don't do that... you're messing with people incoming calls, and might create a world of pain. if you want to show some UI for specific calls, I would suggest detecting such incoming calls via a Telephony state listener, and add an always-on-top UI view on top of the system call UI. let me know if you need references – marmor Jul 17 '19 at 10:57
  • So just make a telephony state receiver. And when I get the flags for receving a call, I force my own UI on top of the System Call UI? If so? you can you provide some references? – rosu alin Jul 17 '19 at 12:34
  • @marmor I edited my question, to include more data, if you have the chance to check – rosu alin Jul 23 '19 at 11:17

1 Answers1

1

Ok, so like in the comments, I would recommend to listen on incoming call events and if the specific call is getting in, force your UI on top of the system in-call UI.

Listening on incoming calls: https://developer.android.com/reference/android/telephony/PhoneStateListener Add PhoneStateListener

Displaying an always-on-top view: How to create always-top fullscreen overlay activity in Android

The WindowManager.LayoutParams to use:

WindowManager.LayoutParams(
    LayoutParams.WRAP_CONTENT,
    LayoutParams.WRAP_CONTENT,
    VERSION.SDK_INT >= VERSION_CODES.O ? LayoutParams.TYPE_APPLICATION_OVERLAY : LayoutParams.TYPE_SYSTEM_ERROR,
    LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_SHOW_WHEN_LOCKED | LayoutParams.FLAG_DISMISS_KEYGUARD);

EDIT:

The code you posted is trying to make an Activity show up on top of the incoming call screen, instead you should create a View and add it to the windowManager as an alert view. i.e. instead of:

setContentView(R.layout.activity_call)
val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager
wm.addView(window.decorView, params)

Try doing something like this (not tested code):

View view = LayoutInflater.from(this).inflate(R.layout.activity_call)
val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager
wm.addView(view, params)
marmor
  • 27,641
  • 11
  • 107
  • 150
  • I tried this but sadly it won't work. The default dialler has priority, so it will be overlayed over my activity :( – rosu alin Jul 23 '19 at 08:29
  • I have this working in a popular production app, check again. a common use-case for this pattern is caller-ID apps that show a popup on top of the incoming call screen, install any caller-ID app and you can verify it's working – marmor Jul 23 '19 at 08:36
  • can you tell me the name of the production app? so I can take a look, please, thanks in advance – rosu alin Jul 23 '19 at 08:39
  • just search Google Play for "Caller ID" and you'll find many apps that show a popup on top of the incoming call screen – marmor Jul 23 '19 at 08:50
  • Ok, thanks. Then from the "How To Create always-top fullscreen overlay" link, which answer did it work for you? The accepted one? PS: I want it without setting the app as the "default call app". I can also do that, in my app, if I set from settings to be default app.But I want just to intercept and show my activity, in case of special numbers – rosu alin Jul 23 '19 at 09:00
  • see the edit to my answer with a version of LayoutParams that's working – marmor Jul 23 '19 at 09:06