Как определить, отображается ли какой-либо системный диалог?

Как проверить, отображается ли какая-либо система dialog (например, приведенная ниже или USSD) на Android?

диалог переключения режима полета

Программный путь или корневой путь cmd? Любые варианты.

Ответ 1

Теоретически вы можете это сделать с помощью AccessibilityService, но он довольно сложный и может работать или не работать на разных устройствах. Пользователям необходимо будет вручную включить функции доступности для вашего приложения. Вы можете получать обратные вызовы от Android всякий раз, когда открыто какое-либо окно, и затем вы можете опросить окно, чтобы определить, имеет ли он в нем определенный текст или принадлежит к определенному пакету и т.д. Это подход "грубой силы", но он может быть полезен в некоторых ситуациях.

Ответ 2

Системный диалог - это действие. Вы можете определить его с помощью имени класса активности, используя ActivityManager.

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

В устройствах с уровнем API менее 23 (М):

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
}

В новых устройствах:

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
}

Или в этом случае вы можете проверить, находится ли устройство в режиме полета перед запуском:

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
}

Ответ 3

Ваш вопрос заставлял меня думать о решении, которое используется в управлении разрешениями в Android 6+. Вы когда-нибудь видели сообщение об ошибке, если при попытке установить разрешения открывается диалоговое окно "Toast" или "системное предупреждение"? Android "Screen Overlay Detected" если пользователь пытается предоставить разрешение при показе уведомления

То, как они это сделали, - это переопределить метод dispatchTouchEvent в Activity. Это может проверить, нет ли чего-то "в пути" для перехвата событий касания. Вы можете использовать свою специальную активность в качестве базового класса для любого Activity в своем приложении, которое вы хотите обнаружить на нем.

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

Добавить публичный метод для проверки в любой момент времени, если ваша активность закрыта

public boolean isObscured() {
    return mObscured;
}

Вы должны быть осторожны - поскольку это не ясно из вопроса - если второе действие из системного или привилегированного приложения находится в передней части стека, тогда ваша собственная деятельность больше не будет получать события касания. Это делается для захвата фрагментов, тостов, плавающих виджетов и других элементов, которые могут совместно использовать иерархию представлений.