12

How to check if any system dialog (like the one below or USSD) is displayed in Android ?

airplane mode switching dialog

Programmatic way or cmd root way? Any variants.

shadygoneinsane
  • 2,226
  • 1
  • 24
  • 47
ilw
  • 2,499
  • 5
  • 30
  • 54
  • 2
    A "system dialog" is just an activity, like any other. There is nothing magic that makes one activity a "system dialog" and another not a "system dialog". So, you first need to decide for yourself what is the distinguishing characteristic between a "system dialog" and some other dialog-themed activity. – CommonsWare May 05 '17 at 22:36
  • I mean dialog like message about "Airplane mode on or off" , or ussd mesage or something... – ilw May 06 '17 at 09:51

3 Answers3

5

You can theoretically do this using the AccessibilityService, but it is rather complicated and may or may not work on different devices. Users will need to manually enable accessibility features for your application. You can get callbacks from Android whenever any window is opened and you can then interrogate the window to determine if it has specific text in it or belongs to a specific package, etc. This is a "brute force" approach, but it can be useful in some situations.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
3

A system dialog is an activity. You can detect it by the top activity class name using ActivityManager.

final ActivityManager manager = (ActivityManager) context
    .getSystemService(Activity.ACTIVITY_SERVICE);

In devices with API Level less than 23 (M):

final List<ActivityManager.RunningTaskInfo> runningTasks = manager.getRunningTasks(1);
final ComponentName componentName = runningTasks.get(0).topActivity;
final String className = componentName.getClassName();

if (className.equals("YOUR_EXPECTED_ACTIVITY_CLASS_NAME")) {
    // do something
}

In newer devices:

final List<ActivityManager.AppTask> appTasks = manager.getAppTasks();
final ComponentName componentName = appTasks.get(0).getTaskInfo().topActivity;
final String className = componentName.getClassName();

if (className.equals("YOUR_EXPECTED_ACTIVITY_CLASS_NAME")) {
    // do something
}

Or in this case, you can check if the device is in airplane mode before starting the activity:

private boolean isAirplaneModeOn(final Context context) {
    final int airplaneMode = Settings.System.getInt(
        context.getContentResolver(),
        Settings.System.AIRPLANE_MODE_ON,
        0
    );

    return airplaneMode != 0;
}

...

if (!isAirplaneModeOn(this)) {
    // do something
}
Pedro Rodrigues
  • 1,662
  • 15
  • 19
  • Thank you for your efforts. But unfortunately your options do not work for me. In my case, className is always equal to my main activity class name. I checked your methods before, and they did not even work for me. That's why I asked this question. Also, your isAirplaneModeOn method is not what I need. I just need to track the appearance of the AirplaneMode dialog. I will vote for your answer, but I can not accept it. Sorry. – ilw May 10 '17 at 07:09
  • My codes for testing: https://gist.github.com/goodandrewsoft/b961c2b6cfc6666bcbbb2a617f6f8d9e – ilw May 10 '17 at 07:23
  • Sorry, I misinterpreted. – Pedro Rodrigues May 10 '17 at 11:36
2

Your question made me think of a solution in use by the permissions management in Android 6+. Have you ever seen the error message if a Toast or system alert dialog opens up when trying to set permissions? Android "Screen Overlay Detected" message if user is trying to grant a permission when a notification is showing

The way they did it is by overriding the dispatchTouchEvent method in Activity. This can check if anything is 'in the way' intercepting touch events. You can use your special Activity as a base class for any Activity in your app that you wish to detect any overlays on it.

   @Override
   public boolean dispatchTouchEvent(MotionEvent event) {
       mObscured = (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0;
    return super.dispatchTouchEvent(event);
}

Add a public method to check at any given time if your activity is obscured

public boolean isObscured() {
    return mObscured;
}

You should be careful - as it's not clear from the question - if a second Activity from a system or privileged app is at the front of the stack then your own activity will no longer be receiving touch events. This is to capture the fragments, toasts, floating widgets and other items that may share the view hierarchy.

Community
  • 1
  • 1
dr_g
  • 1,179
  • 7
  • 10
  • this won't work as even if you dispatched the touches from activity to your custom dispatcher, the system dialog has another dispatcher and you will have to override its dispatcher to delegate it to the activity then to yours. – Hanaa Mohamed May 28 '19 at 13:01
  • As mentioned, if your activity is at front of activity stack, then this works, tried and tested. – dr_g Jun 04 '19 at 11:34