简体   繁体   English

在 android 中检测主页按钮按下

[英]Detect home button press in android

This has been driving me nuts for a while now.这让我发疯了一段时间。

Is there any way of reliably detecting if the home button has been pressed in an android application?有什么方法可以可靠地检测是否在 android 应用程序中按下了主页按钮?

Failing that, is there a robust way of telling what caused an activity to go into onPause?如果做不到这一点,是否有一种可靠的方法可以说明是什么导致 go 的活动进入 onPause? ie Can we detect if it was caused by a new activity launching or by pressing back/home.即我们可以检测它是由启动新活动还是按返回/主页引起的。

One suggestion I have seen is to override onPause() and call isFinishing() but this will return false when pressing the home button just as it would if a new activity is starting so this fails to distinguish between the two.我看到的一个建议是覆盖 onPause() 并调用 isFinishing() 但是当按下主页按钮时这将返回 false 就像新活动开始时一样,因此无法区分两者。

Any help much appreciated.非常感谢任何帮助。

** Update**: Thanks to @android-hungry for this link: https://nishandroid.blogspot.com/ ** 更新**:感谢@android-hungry 提供此链接: https://nishandroid.blogspot.com/

Overiding the following method:覆盖以下方法:

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

Then the following event WILL get fired for home button presses:然后按下主页按钮将触发以下事件:

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

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

I'm not sure if there are any side effects with this line:我不确定这条线是否有任何副作用:

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

So it would seem that contrary to popular belief, you can in fact listen out for the home key.因此,这似乎与普遍的看法相反,您实际上可以听出主页键。 Worryingly, you can return false and have the home key do nothing.令人担忧的是,您可以返回 false 并让主页键不执行任何操作。

Update : As expected, there are some side affects with this - it seems that embedded videos and google maps are not visible with this mode enabled.更新:正如预期的那样,这有一些副作用 - 启用此模式后,嵌入式视频和谷歌地图似乎不可见。

Update : Supposedly this hack no longer works as of Android 4.0 onwards更新:据说这个 hack 从 Android 4.0 开始不再有效

Following code works for me :)以下代码对我有用:)

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();
}

This is an old question but it might help someone.这是一个老问题,但它可能对某人有所帮助。

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

According to the documentation, the onUserLeaveHint() method is called when the user clicks the home button OR when something interrupts your application (like an incoming phone call).根据文档, onUserLeaveHint() 方法在用户单击主页按钮或某些事情中断您的应用程序(如来电)时调用。

This works for me.. :)这对我有用.. :)

I needed to start/stop background music in my application when first activity opens and closes or when any activity is paused by home button and then resumed from task manager.当第一个活动打开和关闭或任何活动被主页按钮暂停然后从任务管理器恢复时,我需要在我的应用程序中启动/停止背景音乐。 Pure playback stopping/resuming in Activity.onPause() and Activity.onResume() interrupted the music for a while, so I had to write the following code: 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
  }
}

which interrupts the playback only when application (all its activities) is closed or when home button is pressed.仅当应用程序(其所有活动)关闭或按下主页按钮时才会中断播放。 Unfortunatelly I didn't manage to change order of calls of onPause() method of the starting activity and onResume() of the started actvity when Activity.startActivity() is called (or detect in onPause() that activity is launching another activity other way) so this case have to be handled specially:不幸的是,当Activity.startActivity()被调用时,我没有设法改变启动活动的onPause()方法和启动活动的onResume()的调用顺序(或在onPause()中检测到该活动正在启动另一个活动方式)所以这种情况必须特别处理:

private boolean mIsStarting;

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

Another drawback is that this requires GET_TASKS permission added to AndroidManifest.xml :另一个缺点是这需要将GET_TASKS权限添加到AndroidManifest.xml

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

Modifying this code that it only reacts on home button press is straighforward.修改此代码使其仅对按下主页按钮作出反应是直接的。

It is impossible to detect and/or intercept the HOME button from within an Android app.从 Android 应用程序中检测和/或拦截 HOME 按钮是不可能的。 This is built into the system to prevent malicious apps that cannot be exited.这是系统内置的,以防止无法退出的恶意应用程序。

Override onUserLeaveHint() in the activity.覆盖活动中的onUserLeaveHint() There will never be any callback to the activity when a new activity comes over it or user presses back press.当新活动经过它或用户按下回按时,将永远不会对该活动进行任何回调。

onUserLeaveHint(); onUserLeaveHint();

override this activity class method.This will detect the home key click .覆盖此活动类方法。这将检测主页键单击。 This method is called right before the activity's onPause() callback.But it will not be called when an activity is interrupted like a in-call activity comes into foreground, apart from that interruptions it will call when user click home key.这个方法在活动的 onPause() 回调之前被调用。但是当活动被中断时它不会被调用,就像调用中的活动进入前台一样,除了当用户点击主页键时它会调用的中断。

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

Since API 14 you can use the function onTrimMemory() and check for the flag TRIM_MEMORY_UI_HIDDEN .从 API 14 开始,您可以使用函数onTrimMemory()并检查标志TRIM_MEMORY_UI_HIDDEN This will tell you that your Application is going to the background.这将告诉您您的应用程序将进入后台。

So in your custom Application class you can write something like:因此,在您的自定义 Application 类中,您可以编写如下内容:

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

For an in-depth study of this, I invite you to read this article: http://www.developerphil.com/no-you-can-not-override-the-home-button-but-you-dont-have-to/为了对此进行深入研究,我邀请您阅读这篇文章: http : //www.developerphil.com/no-you-can-not-override-the-home-button-but-you-dont-have -到/

Try to create a counter for each screen.尝试为每个屏幕创建一个计数器。 If the user touch HOME, then the counter will be zero.如果用户触摸 HOME,则计数器将为零。

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

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

You might consider a solution by Andreas Shrade in his post on How-To Create a Working Kiosk Mode in Android .您可能会考虑 Andreas Shrade 在他关于How-To Create a Working Kiosk Mode in Android 的帖子中提出的解决方案。 It's a bit hacky, but given the reasons that interception of the home button is prevented it has to be ;)这有点hacky,但考虑到阻止拦截主页按钮的原因,它必须是;)

I had this problem, and since overriding the onKeyDown() method didn't accomplish anything because of the underlying android system didn't call this method, I solved this with overriding onBackPressed(), and I had a boolean value set there to false, because I pressed back, let me show you what I mean in code:我遇到了这个问题,由于覆盖 onKeyDown() 方法没有完成任何事情,因为底层的 android 系统没有调用这个方法,我通过覆盖 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"); }
    }

So the reason why this worked is because the only way to navigate outside this activity is by pressing back or home so if back was pressed then i know the cause wasn't home, but otherwise the cause was home, therefore i set the default boolean value for homePressed to be true.所以这有效的原因是因为在此活动之外导航的唯一方法是按后退或回家,所以如果按后退,那么我知道原因不是家,但否则原因是家,因此我设置了默认布尔值homePressed 的值为 true。 However this will only work with a single activity instance in your application because otherwise you have more possibilities to cause the onPause() method to be called.但是,这仅适用于应用程序中的单个活动实例,否则您有更多可能导致 onPause() 方法被调用。

Recently I was trying to detect the home press button, because I needed it to do the same as the method " onBackPressed() ".最近我试图检测主页按钮,因为我需要它做与方法“ onBackPressed() ”相同的事情 In order to do this, I had to override the method " onSupportNavigateUp() " like this:为了做到这一点,我必须像这样覆盖方法“ onSupportNavigateUp() ”:

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

It worked perfectly.它工作得很好。 =) =)

在此处输入图片说明 Android Home Key handled by the framework layer you can't able to handle this in the application layer level. Android Home Key 由框架层处理,您无法在应用程序层级别处理此问题。 Because the home button action is already defined in the below level.因为主页按钮操作已经在下面的级别中定义。 But If you are developing your custom ROM, then It might be possible.但是如果您正在开发您的自定义 ROM,那么它可能是可能的。 Google restricted the HOME BUTTON override functions because of security reasons.出于安全原因,谷歌限制了主页按钮覆盖功能。

It's a bad idea to change the behavior of the home key.改变主页键的行为是一个坏主意。 This is why Google doesn't allow you to override the home key.这就是 Google 不允许您覆盖主页键的原因。 I wouldn't mess with the home key generally speaking.一般来说,我不会弄乱home键。 You need to give the user a way to get out of your app if it goes off into the weeds for whatever reason.如果您的应用因任何原因陷入困境,您需要为用户提供一种退出应用的方法。

I'd image any work around will have unwanted side effects.我认为任何解决方法都会产生不必要的副作用。

override onUserLeaveHint method can catch the home press event, but you need also consider user click events. override onUserLeaveHint方法可以捕获主页按下事件,但您还需要考虑用户单击事件。 following codes works for me. 以下代码适合我。

private boolean isUserClickToLeave = false;
private Handler mHandler = new Handler();

 Runnable resetUserClickFlagRunnable = new Runnable() {
    @Override
    public void run() {
        isUserClickToLeave = false;
    }
};

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP) {
        isUserClickToLeave = true;
        mHandler.removeCallbacks(resetUserClickFlagRunnable);
        mHandler.postDelayed(resetUserClickFlagRunnable, 1000);
    }
    return super.dispatchTouchEvent(ev);
}

@Override
protected void onUserLeaveHint() {
    super.onUserLeaveHint();
    if (!isUserClickToLeave ) {
        //user press home button case.
       onHomePressed();
    }
    isUserClickToLeave = false;
}

private onHomePressed() {
    //do something here.
}

Jack's answer is perfectly working for click event while longClick is considering is as menu button click.杰克的答案非常适用于click事件,而longClick正在考虑作为menu按钮点击。

By the way, if anyone is wondering how to do via kotlin,顺便说一句,如果有人想知道如何通过 kotlin,

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()
                }
            }
        }
    } 
}

SOLVED: This works for BACK, HOME and TASK OVERVIEW已解决:这适用于 BACK、HOME 和 TASK OVERVIEW

@Override
public void onBackPressed() {
}

@Override
public void onPause() {
    if (isApplicationSentToBackground(MainActivity.this)){
        // Do what you want to do on detecting Home Key being Pressed
        Toast.makeText(this, "You pressed the task button!", Toast.LENGTH_LONG).show();
    }
    super.onPause();
    ActivityManager activityManager = (ActivityManager) getApplicationContext()
            .getSystemService(Context.ACTIVITY_SERVICE);

    activityManager.moveTaskToFront(getTaskId(), 0);
}

@SuppressWarnings("deprecation")
public boolean isApplicationSentToBackground(final Context context) {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(context.getPackageName())) {
            return true;
        }
    }
    return false;
}

And add to manifest: android.permission.REORDER_TASKS并添加到清单:android.permission.REORDER_TASKS

An option for your application would be to write a replacement Home Screen using the android.intent.category.HOME Intent.您的应用程序的一个选项是使用 android.intent.category.HOME Intent 编写替换主屏幕。 I believe this type of Intent you can see the home button.我相信这种类型的 Intent 你可以看到主页按钮。

More details:更多细节:

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

Since you only wish for the root activity to be reshown when the app is launched, maybe you can get this behavior by changing launch modes, etc. in the manifest?由于您只希望在启动应用程序时重新显示根活动,也许您可​​以通过更改清单中的启动模式等来获得此行为?

For instance, have you tried applying the android:clearTaskOnLaunch="true" attribute to your launch activity, perhaps in tandem with android:launchMode="singleInstance" ?例如,您是否尝试将android:clearTaskOnLaunch="true"属性应用于您的启动活动,也许与android:launchMode="singleInstance" 一起使用

Tasks and Back Stack is a great resource for fine-tuning this sort of behavior. Tasks 和 Back Stack是微调此类行为的重要资源。

This works for me.这对我有用。 You can override onUserLeaveHint method https://www.tutorialspoint.com/detect-home-button-press-in-android您可以覆盖 onUserLeaveHint 方法https://www.tutorialspoint.com/detect-home-button-press-in-android

@Override
    protected void onUserLeaveHint() {
        //
        super.onUserLeaveHint();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM