it-swarm.com.ru

Как обнаружить нажатия кнопки "Недавние приложения" (Honeycomb +)

Мне интересно, какой метод вызывает эта кнопка.

enter image description here

Моя игра всегда правильно ставится на паузу/возобновляется, за исключением случаев, когда я использую эту кнопку. Кажется, эта кнопка не вызывает методы onPause() и onResume() для Activity . Она работает, если я выхожу из игры. другое окно (как на картинке), а затем используйте эту кнопку для возобновления. Но если я просто нажму эту кнопку во время игры, игра остановится, но поток не возобновится, как это происходит в любой другой момент, игра просто останавливается на экране и немного мигает. 

Трудно объяснить, но я надеюсь, что я проясню, если нет, спросите!

24
Green_qaue

Ни один из стандартных Activity Lifecycle методов не вызывается при нажатии кнопки «Последние приложения». Активность останется активной после появления списка последних приложений. Через полупрозрачную левую часть этого списка вы можете даже наблюдать, как анимация приложения все еще работает, если вы запускаете игру с некоторой анимацией, которая не справилась с этой ситуацией должным образом. На самом деле многие игры в Google Play не справились с этой ситуацией должным образом, даже хорошие, например, Angry Birds.

Единственный метод Activity вызывается, когда пользователь открывает список «Недавние приложения» (или возвращается из него), это onWindowFocusChanged с логическим параметром hasFocus. Когда пользователь открывает список Недавнего приложения, метод onWindowFocusChanged(), вызванный с hasFocus, равен false, а тот же метод, вызванный с hasFocus, равен true, когда пользователь нажимает кнопку Назад в этом списке.

22
HitOdessit

Чтобы определить, когда была нажата кнопка «Недавние приложения», вы можете использовать Accessibility Service. Вам нужно будет запустить собственную службу специальных возможностей и получать события с типом «TYPE_WINDOW_STATE_CHANGED» и проверять имя класса события.

  1. Читайте о Служба специальных возможностей в Android Developer. Настройте свою собственную службу специальных возможностей, запросите разрешение у пользователя.
  2. В вашем методе переопределения Accessibility Service onAccessibilityEvent()
  3. В этом методе вы получите объект AccessibilityEvent event, который содержит всю необходимую информацию о событии, которое только что произошло на вашем устройстве.
  4. Мы заинтересованы в ClassName. Иногда ClassName может иметь значение null, поэтому не забывайте о проверке! = Null. Имена пакетов окна недавних приложений могут отличаться в зависимости от версии Android:

    • Android 4.1: "com.Android.internal.policy.impl.RecentApplicationsDialog"
    • Android 4.2 - 4.4: «com.Android.systemui.recent.RecentsActivity»
    • Android 5.0 - 7.1: "com.Android.systemui.recents.RecentsActivity" (добавлено письмо "s")

Не знаю название класса для старых устройств, но я не думаю, что кто-то поддерживает их в 2017 году;) 

Таким образом, у вас будет что-то вроде этого:

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || event.getClassName() == null) 
        return;

    String className = String.valueOf(event.getClassName());

    if (className.equals("com.Android.internal.policy.impl.RecentApplicationsDialog")
            || className.equals("com.Android.systemui.recent.RecentsActivity")
            || className.equals("com.Android.systemui.recents.RecentsActivity")){
        //Recent button was pressed. Do something.
    }
}

Я тестировал его на следующих реальных устройствах: LG, Nexus, Sony и виртуальных устройствах: Motorola, Samsung.

Если кто-то знает исключение для этих имен классов, пожалуйста, пингуйте меня.

5
Kirill Karmazin

У меня та же проблема, я решил эту проблему, как показано ниже. 

Регистрация трансляции по нажатию кнопки для Home и RecentApp

InnerReceiver mReceiver = new InnerReceiver();
IntentFilter mFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
registerReceiver(mReceiver, mFilter);

Теперь код BroadcastReceiver

class InnerReceiver extends BroadcastReceiver {
    final String SYSTEM_DIALOG_REASON_KEY = "reason";
    final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
    final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";

    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
            String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
            if (reason != null) {
                if (mListener != null) {
                    if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {
                        // Home Button click
                    } else if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
                        // RecentApp or Overview Button click
                    }
                }
            }
        }
    }
}

Но не забыл unregisterReceiver BroadcastReceiver 

4
Lokesh

Я столкнулся с подобной проблемой, поэтому мне нужно было знать, когда пользователь нажимает кнопку недавних приложений (кнопка меню в старых версиях Android). после нескольких часов исследований я не нашел ни одного события, которое можно поймать, когда нажата кнопка «Домой» или кнопка меню. я обнаружил, что вызов onStop () занимает больше времени, когда пользователь нажимает кнопку «домой», поэтому я придумываю хитрость, чтобы различать эти кнопки буксировки, касающиеся времени ответа и переопределения двух методов:

@Override

public void onUserLeaveHint() {
    // do stuff
    super.onUserLeaveHint();
    userLeaveTime = System.currentTimeMillis() ;
    isNotPower = true;
}

@Override

public void onStop() {
    super.onStop();
    if (isNotPower) {
        defStop = System.currentTimeMillis() - userLeaveTime;
        if (defStop > 200 ) {
            //home button
        }
        if (defStop < 200) {
            //recent apps button
        }
    }
    isNotPower = false;
}
  • параметр isNotPower предназначен для проверки того, что кнопка питания не нажата - при нажатии кнопки питания вызывается метод onStop (), но не th onUserLeaveHint ().
3
khaled_alokby

Лучший способ, который я нашел, - это использовать Broadcast Action под названием «ACTION_CLOSE_SYSTEM_DIALOGS». Из документов Google:

Broadcast Action: Это вещание, когда пользовательское действие должно запросить временное системное диалоговое окно , Чтобы закрыть его. Некоторыми примерами временных системных диалогов Являются тень окна уведомлений и диалог недавних задач .

Рабочий код:

IntentFilter intentFilterACSD = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);

    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
                    //do what you want here
            }
        }
    };
    this.registerReceiver(broadcastReceiver, intentFilterACSD);
2
Mihuilk

попробуй это:

public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

    Log.d("Focus debug", "Focus changed !");

    if (!hasFocus) {
        Log.d("Focus debug", "Lost focus !");

    }
}
0
androidBoomer

Это только проблема с этой конкретной игрой? Или это с каждой игрой, в которую вы играете? 

Помимо onPause() и onResume(), существует еще один цикл, называемый onStop(). Может быть, есть некоторые фундаментальные вещи, которые здесь делают. С нажатием этой кнопки «windows-open» игра, вероятно, не перейдет в состояние onStop-, тогда как при нажатии кнопки «home» это произойдет. 

0
DroidBender

Я написал приложение, которое однозначно демонстрирует поведение ключа latest-apps/recents в отношении действий и фрагментов.

(Любое утверждение, что этот ключ не инициирует нормальные события жизненного цикла, явно ложно.) 

В onCreate() main Activity инициализирует массив для регистрации всех известных событий жизненного цикла Activity, а также запускает основной фрагмент вместе с самим собой во втором FrameLayout.

В onAttach() основной Fragment инициализирует отдельный массив для регистрации всех известных событий жизненного цикла Fragment.

В целях ведения журнала и Activity, и Fragment обрабатывают onWindowFocusChanged() как еще одно событие жизненного цикла. 

Зарегистрированные события имеют временную метку, поэтому при рендеринге может быть дано указание пользователю «пауза» (и рендеринг происходит внутри onWindowFocusChanged(), когда hasFocus==true). 

Вот что видит пользователь при запуске тестового приложения: 

 enter image description here

Через несколько секунд пользователь нажимает latest-apps, ждет несколько секунд, а затем нажимает снова, чтобы увидеть правду: 

 enter image description here

NB. Если вместо использования кнопки недавних приложений эксперимент повторяется путем (a) нажатия кнопки выключения/включения планшета (b) нажатия кнопки «Запустить 2-е действие» (c) и т.д., Получаются идентичные результаты.

Ответ ОП:
По-видимому, нет кода, который мог бы обнаружить фактическое нажатие клавиши недавних приложений! 

Но это не имеет значения, потому что приложение должно правильно обрабатывать связанные события жизненного цикла.

0
Bad Loser