一、Home键的监听

public class HomeWatcherReceiver extends BroadcastReceiver {
    private static final String TAG = "HomeReceiver";
    private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
    private static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
    private static 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);
            Log.d(TAG, "reason: " + reason);

            if (SYSTEM_DIALOG_REASON_HOME_KEY.equals(reason)) {
                // 短按Home键
                Log.d(TAG, "homekey");

            }
        }
    }
}

注册这个Receiver只能动态注册

private static void registerHomeKeyReceiver(Context context) {
    Log.d(TAG, "registerHomeKeyReceiver");
    mHomeKeyReceiver = new HomeWatcherReceiver();
    final IntentFilter homeFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
    context.registerReceiver(mHomeKeyReceiver, homeFilter);
}

private static void unregisterHomeKeyReceiver(Context context) {
    Log.i(TAG, "unregisterHomeKeyReceiver");
    if (null != mHomeKeyReceiver) {
        context.unregisterReceiver(mHomeKeyReceiver);
    }
}

二、代码操作程序Home键退出
我们经常看到QQ程序虽然我们点击back退出了,但实际上它并没有退出,只是将该Activity置到了后台,跟操作了Home键一样。

方法一:其实我们的Home主界面也是一个Activity,所以,我们只需要在应用执行back操作之后,启动一下这个Home主界面,这样我们的程序就被置于后台,被这个Home主界面Activity覆盖。

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

    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.addCategory(Intent.CATEGORY_HOME);
    startActivity(intent);
}

这种方法会出现一个问题,如果手机上有多个桌面,那么当你启动这个Activity的时候,可能系统不会直接跳转到该Home桌面而是让你选你你要启动哪个桌面,所以使用这种方法会有一些问题。

方法二:我们的Activity有一个moveTasktoBack()方法,moveTasktoBack()就是说让进程activity栈在后台去运行,类似最小化。可以使用这个方法,不让我们的应用退出。

@Override
public void onBackPressed() {
    super.onBackPressed();
    moveTasktoBack(true);
}

三、Activity#onUserLeaveHint()和Activity#onUserInteraction()

/**  
  * Called as part of the activity lifecycle when an activity is about to go into the background as the result of user choice.  
  * For example, when the user presses the Home key, {@link #onUserLeaveHint} will be called, but 
  * when an incoming phone call causes the in-call Activity to be automatically brought to the foreground,  
  *{@link #onUserLeaveHint} will not be called on the activity being interrupted.  
  * 
  * 当用户的操作使一个activity准备进入后台时,此方法会像activity的生命周期的一部分被调用。例如,当用户按下Home键, 
  * Activity#onUserLeaveHint()将会被回调。但是当来电导致来电activity自动占据前台,Activity#onUserLeaveHint()将不会被回调。 
  */

Activity#onUserLeaveHint()
用户手动离开当前activity,会调用该方法,比如用户主动切换任务,短按home进入桌面等。系统自动切换activity不会调用此方法,如来电,灭屏等。

onUserLeaveHint()作为activity周期的一部分,它在activity因为用户要跳转到别的activity而要退到background时使用。比如,在用户按下Home键,它将被调用。比如有电话进来(不属于用户的选择),它就不会被调用。
那么系统如何区分让当前activity退到background时使用是用户的选择?

它是根据促使当前activity退到background的那个新启动的Activity的Intent里是否有FLAG_ACTIVITY_NO_USER_ACTION来确定的。

注意:调用finish()使该activity销毁时不会调用该函数

/** 
  * Called whenever a key, touch, or trackball event is dispatched to the 
  * activity.  Implement this method if you wish to know that the user has 
  * interacted with the device in some way while your activity is running. 
  * 
  * <p>All calls to your activity's {@link #onUserLeaveHint} callback will 
  * be accompanied by calls to {@link #onUserInteraction}. 
  * 
  * activity无论分发按键事件、触摸事件或者轨迹球事件都会调用Activity#onUserInteraction()。 
  * 如果你想知道用户用某种方式和你正在运行的activity交互,可以重写Activity#onUserInteraction()。 
  * 所有调用Activity#onUserLeaveHint()的回调都会首先回调Activity#onUserInteraction()。 
  */

Activity#onUserInteraction()
activity在分发各种事件的时候会调用该方法,注意:启动另一个activity,Activity#onUserInteraction()会被调用两次,一次是activity捕获到事件,另一次是调用Activity#onUserLeaveHint()之前会调用Activity#onUserInteraction()。

参考文章:
Activity#onUserLeaveHint()和Activity#onUserInteraction()

Activity启动模式 及 Intent Flags 与 栈 的关联分析