web-dev-qa-db-fra.com

Détecter le bouton d'accueil, appuyez sur Android

Cela me rend fou depuis un moment. 

Existe-t-il un moyen de détecter de manière fiable si le bouton d'accueil a été activé dans une application Android?

À défaut, existe-t-il un moyen robuste de dire ce qui a motivé une activité à se mettre en pause? Autrement dit, pouvons-nous détecter si cela a été causé par le lancement d'une nouvelle activité ou en appuyant sur/retour à la maison.

Une suggestion que j'ai vue est de remplacer onPause () et d'appeler isFinishing (), mais cela retournera false lorsque vous appuierez sur le bouton d'accueil, comme si une nouvelle activité commençait et que la distinction entre les deux n'était pas possible.

Toute aide très appréciée.

** Mise à jour **: Merci à @ Android-faim pour ce lien: http://nisha113a5.blogspot.com/

Ignorant la méthode suivante:

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

Ensuite, l'événement suivant sera déclenché pour avoir appuyé sur le bouton d'accueil:

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

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

Je ne suis pas sûr s'il y a des effets secondaires avec cette ligne:

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

Donc, il semblerait que contrairement à la croyance populaire, vous puissiez écouter la clé home. De manière inquiétante, vous pouvez retourner false et laisser la clé home inactive.

Update: Comme prévu, il y a quelques effets secondaires: il semble que les vidéos intégrées et les cartes Google ne soient pas visibles avec ce mode activé.

Mise à jour: Soi-disant, ce hack ne fonctionne plus à partir d'Android 4.0

76
Dean Wild

Le code suivant fonctionne pour moi :)

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

C'est une vieille question, mais cela pourrait aider quelqu'un.

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

Selon la documentation, la méthode onUserLeaveHint () est appelée lorsque l'utilisateur clique sur le bouton d'accueil OR lorsque quelque chose interrompt votre application (comme un appel téléphonique entrant).

Cela fonctionne pour moi .. :)

42
AL̲̳I

Il est impossible de détecter et/ou d'intercepter le bouton HOME depuis une application Android. Ceci est intégré au système pour empêcher les applications malveillantes qui ne peuvent pas être quittées.

8
Jave

Je devais démarrer/arrêter la musique de fond dans mon application lorsque la première activité s'ouvre et se ferme ou lorsqu'une activité est suspendue par le bouton d'accueil puis reprise à partir du gestionnaire de tâches. La lecture pure arrêtée/reprise dans Activity.onPause() et Activity.onResume() a interrompu la musique pendant un moment, ce qui m'a obligé à écrire le code suivant: 

@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
  }
}

qui interrompt la lecture uniquement lorsque l’application (toutes ses activités) est fermée ou lorsque le bouton d’accueil est enfoncé. Malheureusement, je n’ai pas réussi à modifier l’ordre des appels de la méthode onPause() de l’activité de démarrage et de onResume() de l’activité démarrée lorsque Activity.startActivity() est appelé (ou de détecter dans onPause() que cette activité lance une autre activité d’une autre manière); : 

private boolean mIsStarting;

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

Un autre inconvénient est que cela nécessite l’autorisation GET_TASKS ajoutée à AndroidManifest.xml:

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

Modifier ce code pour qu’il ne réagisse que lorsque vous appuyez sur le bouton d’accueil est très simple.

7
Blackhex

Remplacer onUserLeaveHint() dans l'activité. Il n'y aura jamais de rappel de l'activité lorsqu'une nouvelle activité survient ou que l'utilisateur appuie en arrière sur la presse.

4
Napolean

J'ai eu ce problème, et comme le fait de surcharger la méthode onKeyDown () n'a rien donné parce que le système Android sous-jacent n'appelle pas cette méthode, j'ai résolu le problème en surchargeant onBackPressed (), et j'avais une valeur booléenne définie sur false. , parce que j'ai appuyé en arrière, laissez-moi vous montrer ce que je veux dire dans le code:

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

Donc, la raison pour laquelle cela a fonctionné est que le seul moyen de naviguer en dehors de cette activité est d'appuyer sur la touche back ou home. Si vous avez appuyé sur back, vous savez que la cause n'était pas à la maison, mais sinon, la cause était à la maison. valeur pour homePressed pour être vrai. Cependant, cela ne fonctionnera qu'avec une seule instance d'activité dans votre application, sinon vous aurez plus de possibilités de provoquer l'appel de la méthode onPause (). 

2
Moshe Rabaev

Essayez de créer un compteur pour chaque écran. Si l'utilisateur touche HOME, le compteur sera à zéro. 

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

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

Vous pouvez envisager une solution d'Andreas Shrade dans son article sur Comment créer un mode Kiosque de travail sous Android . C'est un peu hacky, mais étant donné les raisons pour lesquelles l'interception du bouton d'accueil est empêchée, il doit l'être;) 

2
Vito

onUserLeaveHint ();

substitue cette méthode de classe d'activité.Ceci détectera le clic sur la touche de base . Cette méthode est appelée juste avant le rappel onPause () de l'activité. , à part ces interruptions, il appellera lorsque l'utilisateur cliquera sur la touche d'accueil.

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

Depuis l'API 14, vous pouvez utiliser la fonction onTrimMemory() et rechercher l'indicateur TRIM_MEMORY_UI_HIDDEN. Cela vous dira que votre application va au fond.

Ainsi, dans votre classe d'application personnalisée, vous pouvez écrire quelque chose comme:

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

Pour une étude approfondie de ce sujet, je vous invite à lire cet article: http://www.developerphil.com/no-you-can-not-override-the-home-button-but-you-dont -devoir/

1
Renaud C.

Récemment, j’essayais de détecter le bouton d’accueil, car j’avais besoin de faire la même chose que la méthode " onBackPressed () ". Pour ce faire, j'ai dû remplacer la méthode " onSupportNavigateUp () " comme ceci:

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

Cela a fonctionné parfaitement. =)

C'est une mauvaise idée de changer le comportement de la touche home. C'est pourquoi Google ne vous permet pas de remplacer la clé de base. Je ne voudrais pas jouer avec la clé de la maison en général. Vous devez donner à l'utilisateur un moyen de sortir de votre application si elle se propage dans les mauvaises herbes pour une raison quelconque.

J'imagine que n'importe quel travail aura des effets secondaires indésirables.

0
Andi Jay

Une option pour votre application serait d'écrire un écran d'accueil de remplacement à l'aide de l'intention Android.intent.category.HOME. Je crois que ce type d'intention, vous pouvez voir le bouton d'accueil.

Plus de détails: 

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

0
ademar111190

Puisque vous souhaitez uniquement que l’activité racine soit réaffiche lors du lancement de l’application, vous pouvez peut-être obtenir ce comportement en modifiant les modes de lancement, etc., dans le manifeste?

Par exemple, avez-vous essayé d'appliquer l'attribut Android: clearTaskOnLaunch = "true" à votre activité de lancement, éventuellement en parallèle avec Android: launchMode = "singleInstance" ?

Tasks and Back Stack est une excellente ressource pour peaufiner ce type de comportement.

0
Josh

La réponse de Jack fonctionne parfaitement pour l'événement click alors que longClick considère que le bouton est menu.

À propos, si quelqu'un se demande comment faire via 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()
                }
            }
        }
    } 
}
0
Heisenberg

la méthode override onUserLeaveHint peut intercepter l'événement de presse à domicile, mais vous devez également tenir compte des événements de clic de l'utilisateur. les codes suivants fonctionnent pour moi.

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.
}
0
zyc zyc