10

I'd like to catch anything that causes the display of my Activity to get even partially hidden, e.g. power options, recent apps tray, low battery notification, etc... and I'm having a hard time to detect these system events.

I was pretty sure onPause() would be called when such events happen, but it seems to be wrong... or is it me?

Any other idea?... I'd preferably not hook on each system broadcast action individually, since I'd like to be as generic as possible (and react to ANYTHING that hides my Activity).

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Wouzz
  • 1,200
  • 1
  • 10
  • 12
  • 1
    Strange. As per the docs *onPause()* should be just the way to go: "Paused: Another activity is in the foreground and has focus, but this one is still visible. That is, another activity is visible on top of this one and that activity is partially transparent or doesn't cover the entire screen." – JimmyB Jan 20 '12 at 13:53
  • Yup, I would think onPause() should function how you want. Is it not working that way for you? If so what device are you on? and which system dialogs specifically have you seen that don't trigger your onPause()? – FoamyGuy Jan 20 '12 at 14:18
  • Just as incredulous as you guys, but I'm testing on a wide range of devices (HTC / Samsung / Sony Ericsson) none of which call onPause() when I long-click the power button or the home button. Yet onPause() is called if I just click them! Beats me... – Wouzz Jan 20 '12 at 14:35
  • I would like to have an answer to a similar case; when pairing with a BT device I would like to know if Android pops up the user confirmation or passkey dialog. Some times it does not. If it does not, I want to do it and if it does I want to let Android take over and do nothing. – Brian Reinhold Sep 26 '17 at 00:01

3 Answers3

7

On working on a kiosk style app I know that some Dialogs come to the foreground and can be detected by

    ActivityManager activityManager = (ActivityManager)getBaseContext()
       .getSystemService(Activity.ACTIVITY_SERVICE);
    String className = activityManager.getRunningTasks(1).get(0).topActivity.getClassName();

An example for that is the bluetooth-binding dialog that brings the com.android.settings to the foreground.

A counter-example is the power-button dialog (Turn off, Reboot etc) that does not come to the foreground.

Note that you can close system dialogs (even the power-button dialog) with this broadcast:

    Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        sendBroadcast(closeDialog);

But on most (all newer?) devices this Broadcast will even close the software keyboard, so it is not advisable to have a service running that frequently sends it as the user will then be unable to enter anything into a text field.

Note that such behaviour will definetly gratify your app a status as beeing malware, keeping it from beeing published on google play.

jox
  • 2,218
  • 22
  • 32
FrankKrumnow
  • 501
  • 5
  • 13
1

The best solution I have come to this so far is to implement in your activity onWindowFocusChanged

https://developer.android.com/reference/android/app/Activity#onWindowFocusChanged(boolean)

In Kotlin:

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (!hasFocus) {
            //todo your logic
        }
    }

Since this can be called a lot of times you can debounce this event when showing an animation

Ultimo_m
  • 4,724
  • 4
  • 38
  • 60
0

I was pretty sure onPause() would be called when such events happen, but it seems to be wrong... or is it me?

onPause() will be called if another activity takes over foreground input. So, if a third-party app came to the foreground, even with a dialog-themed activity, onPause() would be called.

There is no requirement for onPause() to be called from OS components, though.

I'd preferably not hook on each system broadcast action individually, since I'd like to be as generic as possible (and react to ANYTHING that hides my Activity).

What you want is not possible. Not all of the things you list have broadcast Intents, and there are other techniques that people can use (e.g., Toasts) that will obscure part of your activity of which you will have no knowledge.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Hi CommonsWare, thanks for your reply :) Good point, I actually don't have to care about Toasts. But it's strange to me that we can't react to events that display full-screen layers, like the "recent apps" tray or the "power options" one, which even blur and darken the background... Maybe I can explain my specific use-case: I work on a video player, and all I want to do is pause the playback when it's just not visible to the user. Is it too much to ask for ?... – Wouzz Jan 20 '12 at 17:25
  • 1
    @Wouzz: I imagine that it is in part a bit of a security measure, so malware doesn't detect these events and pop up their own thing over top of the other thing in an attempt to fool users. While your objective is noble, I'd simply focus on a nice convenient rewind-by-10-seconds option, so users who feel they missed something can easily go back in time. – CommonsWare Jan 20 '12 at 18:35