Androidでホームボタンの押下を検出する


94

これはしばらくの間私に気が狂っています。

Androidアプリケーションでホームボタンが押されたかどうかを確実に検出する方法はありますか?

それが失敗した場合、何が原因でアクティビティがonPauseになったかを確認する強力な方法はありますか?つまり、それが新しいアクティビティの起動によるものか、back / homeによるものかを検出できますか。

onPause()をオーバーライドしてisFinishing()を呼び出すことが提案されていますが、ホームボタンを押すとfalseが返され、新しいアクティビティが開始する場合と同じように、2つのアクティビティを区別できません。

どんな助けも大歓迎です。

**更新**:このリンクを@ android-hungryに感謝:https : //nishandroid.blogspot.com/

次のメソッドをオーバーライドします。

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
    this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);           
}

次に、次のイベントがホームボタンを押すと発生します。

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {     

    if(keyCode == KeyEvent.KEYCODE_HOME)
    {
       //The Code Want to Perform. 
    }
});

この行に副作用があるかどうかはわかりません:

this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);   

そのため、一般的な考えに反して、実際にはホームキーを聞くことができます。心配なことに、falseを返し、ホームキーに何もさせないことができます。

更新:予想通り、これにはいくつかの副作用があります-このモードを有効にすると、埋め込みビデオとGoogleマップが表示されないようです。

更新:このハッキングはAndroid 4.0以降では機能しないと思われます


私の問題は、BackキーとHomeキーを偽装することではありませんでしたが、両方のケースでアプリケーションを終了したいと思いました。どちらを使用したかActivity.onUserLeaveHint()
ハリズム2012年

唯一の問題は、onUserLeaveHint()が上記のアクティビティからアクティビティを開始したときにも起動することです。戻るまたはホームが押されたかどうかを知りたいだけです。提案をありがとう
Dean Wild

それは事実ですが、残念ながら、私の知る限り、ホームキーの使用に関する情報を受け取ることができるのはここだけです。多くの中から偽陽性を発見することをより問題にすることは容易に認識できますが、それでも簡単なサウンドタスクをかなり複雑にします。
ハリズム2012年

2
@DeanWild:これを読んだか:nisha113a5.blogspot.com
Pratik Bhat

2
TYPE_KEYGUARD定数は、Android 5.0のWindowManager.LayoutParamsから削除されました
theb1uro

回答:


136

次のコードは私にとってはうまくいきます:)

HomeWatcher mHomeWatcher = new HomeWatcher(this);
mHomeWatcher.setOnHomePressedListener(new OnHomePressedListener() {
    @Override
    public void onHomePressed() {
        // do something here...
    }
    @Override
    public void onHomeLongPressed() {
    }
});
mHomeWatcher.startWatch();
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;

public class HomeWatcher {

    static final String TAG = "hg";
    private Context mContext;
    private IntentFilter mFilter;
    private OnHomePressedListener mListener;
    private InnerReceiver mReceiver;

    public HomeWatcher(Context context) {
        mContext = context;
        mFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
    }

    public void setOnHomePressedListener(OnHomePressedListener listener) {
        mListener = listener;
        mReceiver = new InnerReceiver();
    }

    public void startWatch() {
        if (mReceiver != null) {
            mContext.registerReceiver(mReceiver, mFilter);
        }
    }

    public void stopWatch() {
        if (mReceiver != null) {
            mContext.unregisterReceiver(mReceiver);
        }
    }

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

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
                String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
                if (reason != null) {
                    Log.e(TAG, "action:" + action + ",reason:" + reason);
                    if (mListener != null) {
                        if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {
                            mListener.onHomePressed();
                        } else if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
                            mListener.onHomeLongPressed();
                        }
                    }
                }
            }
        }
    }
}
public interface OnHomePressedListener {
    void onHomePressed();
    void onHomeLongPressed();
}

3
あなたはonHomeLongPressed実際に「最近」システム活動の開始に対応しているようです。私の電話では、ホームボタンの横にある[最近]ボタンを押すことでトリガーされるため、ホームの長押しであるというコードの仮定は常に正しいとは限りません。
Sam

なぜそれが私にとってうまくいかないのか、マニフェストを通じてブロードキャストを登録したことを除いて、私はまったく同じことをしました。
ファルハン

アプリケーションクラスに登録されています。これまでのところ作業中です。+ 1、何が問題でしょうか。つまり、どのような元のケースが見当たらないでしょうか..:^)
Farhan

1
時々intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY); nullを返します。何が起こっているのか知りたいのですが?
Fakher、2016

1
長押しの理由が今呼び出されますfinal String SYSTEM_DIALOG_REASON_LONG_PRESS = "assist"
JWqvist 2016

49

これは古い質問ですが、誰かを助けるかもしれません。

@Override
protected void onUserLeaveHint()
{
    Log.d("onUserLeaveHint","Home button pressed");
    super.onUserLeaveHint();
}

ドキュメントによると、onUserLeaveHint()メソッドは、ユーザーがホームボタンをクリックしたとき、または何かがアプリケーションに割り込んだとき(電話の着信など)に呼び出されます。

これは私のために働く.. :)


26
正しくありません !!!それはホームボタンが押されたときに機能しますが、意図を持ってアクティビティを切り替えるときにも機能します!!
Nikunj Paradva 2016

これは、他のアクティビティが上に来たり、ユーザーがアクティビティを強制的に離れたり、ホームボタンをクリックしたりした場合でも、onStop()の前に常に実行されます...
Navas pk

7

Androidアプリ内からHOMEボタンを検出またはインターセプトすることはできません。これは、終了できない悪意のあるアプリを防ぐためにシステムに組み込まれています。


受け入れられた答えをチェックして、それは可能です。ただし、まだ多くのデバイスでテストされていません。
Dean Wild

うん...私のアプリがクラッシュした。
ジェレミーローガン

ランチャー/ホーム交換アプリはどうですか?私は1つを構築していて、ユーザーがホームをクリックしたときに最初の画面に移動したい
lisovaccaro

ランチャーの場合、これを使用します。@Override protected void onNewIntent(Intent intent){super.onNewIntent(intent); / *やりたいことをする* /}
Ton

@lisovaccaroランチャーやホームの交換は、まだgoogle(src diane hackborn)でサポートされていないため、ユーザーがホームボタンをクリックするのを防ぐことはできません。それでも、ビューをシステムアラートダイアログとして追加して、すべてをオーバーレイすることができます。しかし、ホームボタンのクリックはそれを通過します。
JacksOnF1re 2015年

7

最初のアクティビティが開いたり閉じたりしたとき、またはホームボタンでアクティビティを一時停止してからタスクマネージャーから再開したときに、アプリケーションでバックグラウンドミュージックを開始/停止する必要がありました。ピュア再生に再開/停止Activity.onPause()し、Activity.onResume()私は次のコードを記述しなければならなかったので、しばらくの間、音楽を中断:

@Override
public void onResume() {
  super.onResume();

  // start playback here (if not playing already)
}

@Override
public void onPause() {
  super.onPause();

  ActivityManager manager = (ActivityManager) this.getSystemService(Activity.ACTIVITY_SERVICE);
  List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(Integer.MAX_VALUE);
  boolean is_finishing = this.isFinishing();
  boolean is_last = false;
  boolean is_topmost = false;
  for (ActivityManager.RunningTaskInfo task : tasks) {
    if (task.topActivity.getPackageName().startsWith("cz.matelier.skolasmyku")) {
      is_last = task.numRunning == 1;
      is_topmost = task.topActivity.equals(this.getComponentName());
      break;
    }
  }

  if ((is_finishing && is_last) || (!is_finishing && is_topmost && !mIsStarting)) {
    mIsStarting = false;
    // stop playback here
  }
}

これは、アプリケーション(そのすべてのアクティビティ)が閉じているとき、またはホームボタンが押されたときにのみ再生を中断します。生憎、私はの呼び出しの変更命令に管理していなかったonPause()開始活動及び方法onResume()開始actvityのActivity.startActivity()と呼ばれている(またはに検出しonPause()、この場合は、特別に処理する必要があるので、そのアクティビティ別のアクティビティ、他の方法で起動しています):

private boolean mIsStarting;

@Override
public void startActivity(Intent intent) {
  mIsStarting = true;
  super.startActivity(intent);
}

もう1つの欠点は、これにGET_TASKS許可を追加する必要があることAndroidManifest.xmlです。

<uses-permission
  android:name="android.permission.GET_TASKS"/>

ホームボタンを押したときにのみ反応するようにこのコードを変更するのは簡単です。


4

onUserLeaveHint()アクティビティをオーバーライドします。新しいアクティビティが発生したり、ユーザーがバックプレスを押したりしても、アクティビティへのコールバックはありません。


4
アプリ内のあるアクティビティから別のアクティビティに移動するときにも呼び出されます
Amir Uval

3

onUserLeaveHint();

このアクティビティクラスメソッドをオーバーライドします。これにより、ホームキーのクリックが検出されます。このメソッドは、アクティビティのonPause()コールバックの直前に呼び出されます。ただし、コール中のアクティビティがフォアグラウンドになったようにアクティビティが中断された場合は、ユーザーがホームキーをクリックしたときに呼び出される中断を除いて、このメソッドは呼び出されません。

@Override
protected void onUserLeaveHint() {
    super.onUserLeaveHint();
    Log.d(TAG, "home key clicked");
}

2

各画面のカウンターを作成してみてください。ユーザーが[ホーム]をタッチすると、カウンターはゼロになります。

public void onStart() {
  super.onStart();
  counter++;
}

public void onStop() {
  super.onStop();
  counter--;    
  if (counter == 0) {
      // Do..
  }
}

3
グローバルアプリケーションカウンターを意味する場合、1つのアクティビティがバックスタックに移動され、別のアクティビティがトップに移動されているとき、またはトップアクティビティが終了してバックスタックアクティビティが通常の場所であるトップに移動されているときにゼロになります。あなたはホームボタンを押したときに反応したい。アクティビティ全体のカウンタを意味する場合、アクティビティが表示されないときは常にゼロになります(ホームボタンを押したことが原因であるとは限りません)。唯一の解決策は、この移行をスキップするためにタイマーを使用して反応を延期することですが、必要な遅延は予測できないか望ましくない場合があります。
Blackhex 2013年


1

私はこの問題を抱えていて、基礎となるAndroidシステムがこのメソッドを呼び出さなかったため、onKeyDown()メソッドをオーバーライドしても何も実行されなかったため、onBackPressed()をオーバーライドしてこれを解決し、ブール値をfalseに設定しました、私は押し戻したので、コードで私が何を意味するかをお見せしましょう:

import android.util.Log;
public class HomeButtonActivity extends Activity {
    boolean homePressed = false;
    // override onCreate() here.

    @Override
    public void onBackPressed() {
        homePressed = false; // simply set homePressed to false
    }

    @Overide
    public void onResume() {
        super.onResume();
        homePressed = true; // default: other wise onBackPressed will set it to false
    }

    @Override
    public void onPause() {
        super.onPause();
        if(homePressed) { Log.i("homePressed", "yay"); }
    }

したがって、これが機能した理由は、このアクティビティの外に移動する唯一の方法は、戻るまたは家を押すことであるため、戻るが押された場合、原因は家ではなかったことがわかりますが、それ以外の場合、原因は家だったため、デフォルトのブール値を設定しましたtrueになるhomePressedの値。ただし、これはアプリケーションの単一のアクティビティインスタンスでのみ機能します。そうしないと、onPause()メソッドが呼び出される可能性が高くなるためです。


実際、別のアクティビティに移動すると、onpauseメソッドが呼び出されます
Fakher

これが、アプリケーションが単一のアクティビティのみを組み込んでいる場合にのみ機能することを明示的に述べた理由です!
Moshe Rabaev

また、無関係な複数のアクティビティが同時に実行されていて、ユーザーがそれらを切り替えるだけの場合はどうなりますか?最新のAndroidデバイスはマルチタスクをサポートしています。このコードを使用すると、アプリに戻るとhomePressedtrueに設定され、別のアプリに切り替えるとHomeが実際には押されていなかったときに押されたように見えます。
レミールボー

1

API 14以降では、関数onTrimMemory()を使用してフラグを確認できますTRIM_MEMORY_UI_HIDDEN。これにより、アプリケーションがバックグラウンドで実行されることがわかります。

したがって、カスタムApplicationクラスでは、次のように記述できます。

override fun onTrimMemory(level: Int) {
    if (level == TRIM_MEMORY_UI_HIDDEN) {
        // Application going to background, do something
    }
}

これについての詳細な調査については、この記事を読むことをお勧めします。http//www.developerphil.com/no-you-can-not-override-the-home-button-but-you-dont-have -に/


1
良い記事-おそらくほとんどの人が必要とするものを実行する便利な代替案
Dean Wild

素晴らしい解決策。アプリケーションがバックグラウンドから戻ったときにフラグをリセットする方法を知っていますか?たとえば、ブールのisInBackgroundを作成した場合、バックグラウンドから戻ったらそれをリセットしたいと思います。
MikeOscarEcho

0

アプリケーションのオプションは、android.intent.category.HOMEインテントを使用して、代わりのホーム画面を作成することです。私はあなたがホームボタンを見ることができるこのタイプの意図を信じています。

詳細:

http://developer.android.com/guide/topics/intents/intents-filters.html#imatch


1
面白いアイデアが、私が望んでいるだろうと少し長い息切れしていないエレガントなど
ディーン・ワイルド

0

アプリの起動時にルートアクティビティのみが再表示されることを望んでいるので、マニフェストで起動モードなどを変更することでこの動作を取得できますか?

たとえば、あなたは、適用しようとしているclearTaskOnLaunch =「true」を:アンドロイドおそらくと並行して、あなたの発射活動に属性をアンドロイド:launchMode =「singleInstance」

タスクとバックスタックは、この種の動作を微調整するための優れたリソースです。


これは最もエレガントなソリューションのように思われますが、信頼性が非常に低いことがわかりました。数回のオープン/クローズ/一時停止サイクルの後、アプリは完全に再起動するのではなく、単に再開し始めます
Dean Wild

0

ホームキーの動作を変更することは悪い考えです。これが、Googleがホームキーの上書きを許可しない理由です。一般的に言えば、ホームキーをいじる必要はありません。なんらかの理由でアプリが雑草に入った場合、アプリから抜け出す方法をユーザーに提供する必要があります。

回避策はありますが、望ましくない副作用があります。


1
あなたは絶対に満足していますが、一部のクライアントは回答を受け入れず、ガイドラインに違反してはならない理由を理解していません。
ディーンワイルド

問題は、ホームボタンの動作を変更したくない場合でも、ホームボタンを押したためにアプリケーションが後ろに移動する状況に対して、現在のアクティビティがwatheverで一時停止している状況とは異なる反応をする必要がある場合があることです。理由。同じ問題は、Application.onDestroy()をポダクションビルドに使用できないという事実にも当てはまります。このような例はなど、バックグラウンドミュージックを停止し、ユーザーがappicationを隠し、ゲームを一時停止している
Blackhex

0

最近、「onBackPressed()」メソッドと同じことをする必要があるため、ホームプレスボタンを検出しようとしました。これを行うには、次のようにメソッド " onSupportNavigateUp() " をオーバーライドする必要がありました。

override fun onSupportNavigateUp(): Boolean {
    onBackPressed()
    return true
}

それは完全に機能しました。=)


0

ジャックの答えは、ボタンのクリックとして考えているclick間、イベントに完全に機能します。longClickmenu

ちなみにコトリン経由でどうしたらいいのか迷っているなら

class HomeButtonReceiver(private var context: Context,private var listener: OnHomeButtonClickListener) {
    private val mFilter: IntentFilter = IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
    private var mReceiver: InnerReceiver = InnerReceiver()

    fun startWatch() {
        context.registerReceiver(mReceiver, mFilter)
    }

    fun stopWatch() {
        context.unregisterReceiver(mReceiver)
    }

    inner class InnerReceiver: BroadcastReceiver() {
        private val systemDialogReasonKey = "reason"
        private val systemDialogReasonHomeKey = "homekey"
        override fun onReceive(context: Context?, intent: Intent?) {
            val action = intent?.action
            if (action == Intent.ACTION_CLOSE_SYSTEM_DIALOGS) {
                val reason = intent.getStringExtra(systemDialogReasonKey)
                if (reason != null && reason == systemDialogReasonHomeKey) {
                    listener.onHomeButtonClick()
                }
            }
        }
    } 
}

0

ここに画像の説明を入力してください フレームワークレイヤーで処理されるAndroid Home Keyでは、アプリケーションレイヤーレベルではこれを処理できません。ホームボタンのアクションはすでに下のレベルで定義されているためです。しかし、カスタムROMを開発している場合、それは可能かもしれません。Googleは、セキュリティ上の理由から、ホームボタンのオーバーライド機能を制限しました。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.