2

I have an app which runs on a watch and where there is an incoming call it displays a translucent overlay activity on top of the OS's incoming call screen.

95% of the time this works great, but for the other 5% of the time my activity isn't visible on an incoming call. The difference is that when it doesn't work my activity's onPause() and onStop() get called right after its onCreate() i.e.

Log when it displays successfully:

03-27 10:04:41.958 onCreate() 
03-27 10:04:41.981 onStart()
03-27 10:04:41.981 onResume()

Log when it doesn't display:

03-27 09:54:53.346     onCreate() 
03-27 09:54:53.367     onStart()
03-27 09:54:53.367     onResume()
03-27 09:54:53.373     onPause()
03-27 09:54:53.437     onStop()

See how it jumps directly from onResume() to onPause(). My speculation for it doing this is that maybe its a timing issue and that in these 5% of failures my activity is being launched a fraction of a second before the incoming call screen's activity and that is causing it to move to the onPause() state. Though there's only microseconds between onResume() and onPause()

Question 1) Could there be any other reason why its going to onPause() 5% of the time?

I tried adding this code to rectify when this happens:

protected  void onStop()
{
    Log.i(TAG, "  ACTIVITY onStop()");
    super.onStop();
    if (/*activity isn't being stopped because I am dismissing it*/)
    {
        moveToFront();
    }
}

private void moveToFront()
{
    final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    final List<ActivityManager.AppTask> tasks = activityManager.getAppTasks();
    Integer count = tasks.size();
    // There should only ever be one task as a launchMode of singleInstance is used
    ActivityManager.AppTask task = tasks.get(0);
    task.moveToFront();
}

However this does not work as my activity isn't visible after moveToFront() is called.

Question 2) Does anybody have any suggestions for solutions for my problem? How I can always get my activity to display on top of the incoming call screen at all times?

Gruntcakes
  • 37,738
  • 44
  • 184
  • 378
  • Well, it's being stopped and paused because something is taking precedence. In my experience, when things happen "only XX % of times" that means there's a threading issue. In this case, it may not be under your control, but the execution sequence fails under some cases (hard/impossible to debug). How about you use a service and send an Intent to your activity? (Just thinking out loud) – Martin Marconcini Mar 30 '15 at 16:11
  • 1
    I'm curious. Once the phone call is done and it is stopped. Does your app pick up where it left off? – Andy Mar 30 '15 at 16:20
  • Interesting question, I would also love to know what does the app do to require such a deep integration with the OS. – Martin Marconcini Mar 30 '15 at 17:07
  • @MartínMarconcini I can think in apps like Facebook messenger or MusicXMatch that overlaps activity in order to display lyrics/conversations. – Guilherme Torres Castro Mar 30 '15 at 17:58
  • @Martin - I am already using a service. The app has a class derived from WearableListenerService, when my handheld app detects an incoming call it sends a message to the watch app which goes via the WearableListenerService, which creates an intent and starts the activity. I've tried keeping the activity permanently and the service just resurrecting it as opposed to it being created/destroyed but its the same 5% or so failure scenario. – Gruntcakes Mar 30 '15 at 17:59
  • For the moment I seem to have solved this problem by adding a small delay (about 0.8 seconds) before launching the activity. But that is a sticking plaster solution and may not always be guaranteed to succeed and its a bit hacky and unsatisfactory. So I would prefer to find a more deterministic solution. – Gruntcakes Mar 30 '15 at 18:03
  • @Andy The app displays some additional information about the person making the call for the duration while the incoming call is ringing. Once the call is answered/rejected/times out them my activity gets removed. – Gruntcakes Mar 30 '15 at 18:04
  • Hmm have you tried using the permission to "Draw on top of other apps" so you can actually draw an overlay that is not tied to your activity? (Much like `Pocket` does) – Martin Marconcini Mar 30 '15 at 19:50
  • Do you mean SYSTEM_ALERT_WINDOW? I haven't experimented with it yet as for various reasons adding additional permission is to be avoided if at all possible. – Gruntcakes Mar 30 '15 at 20:37

3 Answers3

1

Question 1) Could there be any other reason why its going to onPause() 5% of the time?

It is a timing issue, Call app also listening to some intent to start and your app as well. Your activity is displayed first and then call screen. Check the activity manager logs?

Question 2) Does anybody have any suggestions for solutions for my problem? How I can always get my activity to display on top of the incoming call screen at all times?

After getting the call intent, go through the running applications and make sure call app is displayed and then launch your activity.

An example to check if another app is running is here

Or after getting the intent add a little delay and display your activity?

Community
  • 1
  • 1
Deepu
  • 598
  • 6
  • 12
0

you can try launching your activity with some delay so that your Activity is always launched after system Calling-Screen. But this may fail on slow devices or may take much longer time to show up your activity. The better way is to show a view on screen using SYSTEM_ALERT_WINDOW etc. flags from a service.

Arnav M.
  • 2,590
  • 1
  • 27
  • 44
0

TL; DR: you want to either detect precise moment, when the phone window comes up, or give your view a priority higher than WindowManager.LayoutParams.TYPE_PHONE. Former is hard and shunned on new Android versions, but still possible to accomplish. Later requires the permission, but... see below.

Using SYSTEM_ALERT_WINDOW is easy, and there are lots of apps, that require this permission for mundane reasons. Are you really more constrained than Facebook? You do not have to put your view in Activity to show it in such fashion, just create a window, set it's type high enough and attach it to WindowManager. See this app's source code for example of such approach.

Detailed research, concerning detecting current foreground Activity, can be found in responses to these questions:

It is rather ugly and ad-hoc, but still possible on all Android versions.

But do you really need an Activity to your this trick? A Toast has high view priority and can contain whatever status blabber you want.

Community
  • 1
  • 1
user1643723
  • 4,109
  • 1
  • 24
  • 48