web-dev-qa-db-ja.com

「最近のアプリ」のシステムボタンクリックを検出する方法(Honeycomb +)

このボタンがどのメソッドを呼び出すのかと思います。

enter image description here

私のゲームは、このボタンを使用する場合を除いて、常に正しく一時停止/再開します。このボタンが ActivityonPause()およびonResume()メソッドを呼び出さないようです=。ゲームを終了し、別のウィンドウ(図のようなウィンドウ)に移動して、このボタンを使用して再開すると機能します。しかし、このボタンを押すだけの場合、ゲーム内でゲームが一時停止しますが、スレッドは1回おきのように再開しません。ゲームは、画面上に静止し、ちらつきます。

説明するのは難しいですが、はっきりしていると思いますが、そうでない場合は質問してください!

28
Green_qaue

「最近のアプリ」ボタンが押されたときに、標準の Activity Lifecycle メソッドは呼び出されません。最近のアプリポップアップのリストが表示された後も、アクティビティはアクティブのままです。この状況を適切に処理しなかったアニメーションでゲームを実行している場合は、このリストの半透明の左側を通して、アプリケーションアニメーションがまだ実行されていることを確認することもできます。実際、Google Playのゲームの多くはこの状況を適切に処理しませんでした。AngryBirdsのような良い状況でもそうです。

ユーザーが「最近のアプリ」リストを開いたとき(またはリストから戻ったとき)に呼び出される唯一のActivityメソッドは、ブールパラメータhasFocusを指定した onWindowFocusChanged です。 hasFocusで呼び出された最近のアプリメソッドonWindowFocusChanged()のリストを開くとfalseと等しくなり、hasFocusで呼び出された同じメソッドはtrueと等しくなります。ユーザーはこのリストで[戻る]を押します。

23
HitOdessit

「最近のアプリ」ボタンが押されたことを検出するには、ユーザー補助サービスを使用できます。独自のユーザー補助サービスを実行し、タイプ「TYPE_WINDOW_STATE_CHANGED」のイベントを受信して​​、イベントのクラス名を確認する必要があります。

  1. Accessibility Service について読むAndroid developer。独自のAccessibility Serviceをセットアップし、ユーザーの許可を求めます。
  2. ユーザー補助サービスのオーバーライドメソッド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。

誰かがこれらのクラス名の例外を知っている場合は、私にpingしてください。

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()を呼び出すのに時間がかかることがわかったので、応答時間に関連するこれらの2つのボタンを区別し、2つのメソッドをオーバーライドする方法を考えます。

@オーバーライド

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

@オーバーライド

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()メソッドが呼び出されたが、onUserLeaveHint()が呼び出されなかった場合。
3
khaled_alokby

私が見つけた最良の方法は、「ACTION_CLOSE_SYSTEM_DIALOGS」と呼ばれるブロードキャストアクションをリストすることです。Googleドキュメントから:

ブロードキャストアクション:これは、ユーザーアクションが一時的なシステムダイアログを閉じるよう要求する必要があるときにブロードキャストされます。一時的なシステムダイアログのいくつかの例は、通知ウィンドウシェードと最近のタスクダイアログです。

作業コード:

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

これはこの特定のゲームの問題だけですか?それとも、あなたがプレイするすべてのゲームでそれはありますか?

onPause()onResume()のほかに、onStop()と呼ばれる別のサイクルがあります。多分ここで行われているいくつかの基本的なことがあります。その「windows-open」ボタンを押すと、ゲームは「ホーム」ボタンを押すのとは異なり、おそらくonStop- stateに入りません。

0
DroidBender

アクティビティとフラグメントの両方に関して、recent-apps/recents keyの動作を明確に示すアプリを作成しました。

(通常のライフサイクルイベントがこのキーによってトリガーされないという主張はすべて、明らかに誤りです。)

onCreate()のメインActivityは、すべての既知のActivityライフサイクルイベントのログを記録するための配列を初期化し、メインフラグメントをそれ自体と一緒に起動します2番目のFrameLayout。

onAttach()のメインFragmentは、既知のすべてのFragmentライフサイクルイベントのログを記録するための個別の配列を初期化します。

ロギングの目的で、ActivityFragmentはどちらもonWindowFocusChanged()を別のライフサイクルイベントとして扱います。

ログに記録されたイベントにはタイムスタンプが付けられるため、レンダリング時にユーザーの「一時停止」を示すことができます(そして、レンダリングはonWindowFocusChanged()内で発生し、hasFocus==true)。

以下は、テストアプリが起動したときにユーザーに表示されるものです。

enter image description here

数秒後、ユーザーはrecent-appsを押し、数秒待ってからもう一度押して、真実を確認します。

enter image description here

注:[最近のアプリ]ボタンを使用する代わりに、(a)タブレットのオフ/オンボタンを押す(b)[2番目のアクティビティを開始]ボタンを押す(c)などで実験を繰り返すと、同じ結果が得られます。

OPへの回答:
どうやら、recent-appsキーが実際に押されたことを検出できるコードはありません。

ただし、アプリは関連するライフサイクルイベントを正しく処理する必要があるため、問題ではありません。

0
Bad Loser