Rileva la pressione del pulsante home in Android


94

Questo mi sta facendo impazzire da un po 'di tempo.

Esiste un modo per rilevare in modo affidabile se il pulsante Home è stato premuto in un'applicazione Android?

In caso contrario, c'è un modo efficace per dire cosa ha causato un'attività in pausa? cioè Possiamo rilevare se è stato causato dal lancio di una nuova attività o premendo back / home.

Un suggerimento che ho visto è di sovrascrivere onPause () e chiamare isFinishing (), ma questo restituirà false quando si preme il pulsante home proprio come farebbe se una nuova attività sta iniziando, quindi questo non riesce a distinguere tra i due.

Qualsiasi aiuto molto apprezzato.

** Aggiornamento **: Grazie a @ android-hungry per questo link: https://nishandroid.blogspot.com/

Ignorando il seguente metodo:

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

Quindi il seguente evento verrà attivato per la pressione del pulsante home:

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

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

Non sono sicuro che ci siano effetti collaterali con questa linea:

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

Quindi sembrerebbe che contrariamente alla credenza popolare, puoi effettivamente ascoltare la chiave di casa. È preoccupante che tu possa restituire false e che la chiave home non faccia nulla.

Aggiornamento : come previsto, ci sono alcuni effetti collaterali con questo: sembra che i video incorporati e le mappe di Google non siano visibili con questa modalità abilitata.

Aggiornamento : presumibilmente questo hack non funziona più da Android 4.0 in poi


Il mio problema non era quello di camuffare tra back e home -key, ma volevo finire l'applicazione in entrambi i casi. Che ho fatto usando Activity.onUserLeaveHint().
harism

L'unico problema è che onUserLeaveHint () si attiva anche quando avvio un'attività da detta attività, voglio solo sapere se è stato premuto back o home. Grazie per il suggerimento però
Dean Wild

È vero, ma sfortunatamente, per quanto ne so, è l'unico posto in cui ricevere informazioni sull'uso della chiave Home. Rendere più un problema raccogliere i falsi positivi, tra molti può essere riconosciuto facilmente, ma comunque rendendo il compito facile da suonare piuttosto complicato.
harism

2
@DeanWild: hai letto questo: nisha113a5.blogspot.com
Bhat

2
La costante TYPE_KEYGUARD è stata rimossa da WindowManager.LayoutParams in Android 5.0
theb1uro

Risposte:


136

Il codice seguente funziona per 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();
}

3
La tua onHomeLongPressedeffettivamente sembra corrispondere all'apertura dell'attività di sistema "Recenti". Sul mio telefono, viene attivato premendo il pulsante Recenti accanto al pulsante Home, quindi l'ipotesi del tuo codice che sia una pressione prolungata a casa non è sempre corretta.
Sam

perché non funziona per me, ho fatto esattamente lo stesso tranne che ho registrato la trasmissione tramite manifest.
Farhan

Registrato in classe di applicazione, lavoro fino ad ora .. +1, mi chiedo qual è il trucco? Voglio dire, quale custodia originale ci mancherebbe ..: ^)
Farhan

1
a volte intent.getStringExtra (SYSTEM_DIALOG_REASON_KEY); restituire null. Vorrei sapere cosa sta succedendo ??
Fakher

1
Il motivo della lunga pressione è ora chiamatofinal String SYSTEM_DIALOG_REASON_LONG_PRESS = "assist"
JWqvist

49

Questa è una vecchia domanda ma potrebbe aiutare qualcuno.

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

Secondo la documentazione, il metodo onUserLeaveHint () viene chiamato quando l'utente fa clic sul pulsante home OPPURE quando qualcosa interrompe la tua applicazione (come una telefonata in arrivo).

Questo funziona per me .. :)


26
Non corretto !!! Funziona quando viene premuto il pulsante Home, ma funziona anche quando si cambia attività con intento !!
Nikunj Paradva

Questo verrà eseguito sempre prima di onStop (), anche se altre attività vengono in alto o l'utente abbandona con forza l'attività o fa clic sul pulsante Home ...
Navas pk

7

È impossibile rilevare e / o intercettare il pulsante HOME da un'app Android. Questo è integrato nel sistema per prevenire app dannose che non possono essere chiuse.


controlla la risposta accettata, è possibile. Non ancora testato su molti dispositivi però.
Dean Wild

Sì ... app bloccata sulla mia.
Jeremy Logan

che dire dei lanciatori / app sostitutive della casa? Ne sto costruendo uno e voglio andare alla prima schermata quando gli utenti
cliccano su

Per i lanciatori usa questo: @Override protected void onNewIntent (Intent intent) {super.onNewIntent (intent); / * Fai quello che vuoi * /}
Ton

Il programma di avvio di @lisovaccaro e / o le sostituzioni di casa non sono ancora supportati da Google (src diane hackborn) e quindi non puoi impedire all'utente di fare clic sul pulsante home. Puoi ancora aggiungere la tua vista come una finestra di dialogo di avviso di sistema, che si sovrapporrà a tutto. Ma i clic del pulsante home lo attraverseranno.
JacksOnF1re

7

Avevo bisogno di avviare / interrompere la musica di sottofondo nella mia applicazione quando la prima attività si apre e si chiude o quando qualsiasi attività viene messa in pausa dal pulsante Home e quindi ripresa dal task manager. Riproduzione pura interrompendo / riprendendo Activity.onPause()e Activity.onResume()interrompendo la musica per un po ', quindi ho dovuto scrivere il seguente codice:

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

che interrompe la riproduzione solo quando l'applicazione (tutte le sue attività) viene chiusa o quando viene premuto il tasto home. Sfortunatamente non sono riuscito a cambiare l'ordine delle chiamate del onPause()metodo dell'attività iniziale e dell'attività onResume()avviata quando Activity.startActivity()viene chiamato (o rilevare in onPause()quell'attività che sta avviando un'altra attività in altro modo) quindi questo caso deve essere gestito in modo speciale:

private boolean mIsStarting;

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

Un altro svantaggio è che ciò richiede l' GET_TASKSautorizzazione aggiunta a AndroidManifest.xml:

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

Modificare questo codice in modo che reagisca solo alla pressione del pulsante home è immediato.


4

Ignora onUserLeaveHint()l'attività. Non ci sarà mai alcuna richiamata all'attività quando viene rilevata una nuova attività o l'utente preme indietro.


4
viene anche chiamato anche quando si passa da un'attività all'altra all'interno dell'app
Amir Uval

3

onUserLeaveHint ();

sovrascrivere questo metodo della classe di attività. Questo rileverà il clic del tasto home. Questo metodo viene chiamato subito prima del callback onPause () dell'attività, ma non verrà chiamato quando un'attività viene interrotta come un'attività in chiamata viene in primo piano, a parte le interruzioni che chiamerà quando l'utente fa clic sul tasto home.

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

2

Prova a creare un contatore per ogni schermata. Se l'utente tocca HOME, il contatore sarà zero.

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

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

3
Se intendi il contatore globale dell'applicazione sarà zero in un momento in cui un'attività viene spostata nello stack precedente e un'altra viene spostata all'inizio o quando l'attività superiore è terminata e l'attività dello stack posteriore viene spostata in alto che è il solito posto in cui si desidera reagire alla pressione del pulsante home. Se intendi il contatore a livello di attività, sarà zero ogni volta che l'attività non è visibile (non necessariamente causato dalla pressione del pulsante home). L'unica soluzione sarebbe posticipare la tua reazione usando il timer per saltare questa transizione, ma il ritardo necessario potrebbe non essere prevedibile o desiderabile.
Blackhex

2

Potresti prendere in considerazione una soluzione di Andreas Shrade nel suo post su How-To Create a Kiosk Mode in Android . È un po 'hacky, ma visti i motivi per cui l'intercettazione del pulsante home è impedita, deve esserlo;)


1

Ho avuto questo problema e poiché l'override del metodo onKeyDown () non ha ottenuto nulla perché il sistema Android sottostante non ha chiamato questo metodo, l'ho risolto sovrascrivendo onBackPressed () e avevo un valore booleano impostato su false , perché ho premuto indietro, lascia che ti mostri cosa intendo in codice:

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

Quindi il motivo per cui ha funzionato è perché l'unico modo per navigare al di fuori di questa attività è premendo back o home quindi se back è stato premuto allora so che la causa non era home, ma altrimenti la causa era home, quindi ho impostato il booleano predefinito valore per home Premuto per essere vero. Tuttavia questo funzionerà solo con una singola istanza di attività nella tua applicazione perché altrimenti hai più possibilità di far chiamare il metodo onPause ().


infatti, quando si va a un'altra attività, viene chiamato il metodo in pausa
Fakher

Ecco perché ho dichiarato esplicitamente che funzionerà solo se la tua applicazione include solo una singola attività!
Moshe Rabaev

E se più attività non correlate sono in esecuzione contemporaneamente e l'utente passa semplicemente dall'una all'altra? I moderni dispositivi Android supportano il multi-tasking. Con questo codice, sembra che tornare alla tua app sarebbe impostato homePressedsu true, e quindi passare a un'altra app penserebbe che sia stato premuto Home quando in realtà non lo era.
Remy Lebeau,

1

Dall'API 14 è possibile utilizzare la funzione onTrimMemory()e verificare la presenza del flagTRIM_MEMORY_UI_HIDDEN . Questo ti dirà che la tua applicazione sta andando in background.

Quindi nella tua classe Application personalizzata puoi scrivere qualcosa come:

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

Per uno studio approfondito di questo, ti invito a leggere questo articolo: http://www.developerphil.com/no-you-can-not-override-the-home-button-but-you-dont-have -per/


1
Buon articolo - alternativa utile che probabilmente fa ciò di cui la maggior parte delle persone ha bisogno
Dean Wild

Bella soluzione. Sai come resettare il flag quando l'applicazione ritorna dallo sfondo? Ad esempio, se creo un booleano isInBackground, vorrei ripristinarlo una volta tornati dallo sfondo.
MikeOscarEcho


0

Poiché desideri che l'attività di root venga mostrata nuovamente all'avvio dell'app, forse puoi ottenere questo comportamento cambiando le modalità di avvio, ecc. Nel manifest?

Ad esempio, hai provato ad applicare l' attributo android: clearTaskOnLaunch = "true" alla tua attività di lancio, magari in tandem con android: launchMode = "singleInstance" ?

Tasks and Back Stack è un'ottima risorsa per mettere a punto questo tipo di comportamento.


Questa sembrerebbe la soluzione più elegante ma l'ho trovata abbastanza inaffidabile. Dopo alcuni cicli di apertura / chiusura / pausa, l'app inizierà a riprendere semplicemente anziché riavviarsi completamente
Dean Wild

0

È una cattiva idea cambiare il comportamento della chiave home. Questo è il motivo per cui Google non ti consente di sovrascrivere la chiave home. Non scherzerei con la chiave di casa in generale. Devi dare all'utente un modo per uscire dalla tua app se si spegne tra le erbacce per qualsiasi motivo.

Immagino che qualsiasi soluzione abbia effetti collaterali indesiderati.


1
Sei assolutamente perfetto, ma alcuni clienti non accettano un no come risposta e non capiscono perché non dovrebbero infrangere le linee guida.
Dean Wild

Il problema è che anche se non si desidera modificare il comportamento del pulsante home, occasionalmente è necessario reagire in modo diverso alla situazione in cui l'applicazione viene spostata indietro a causa della pressione del pulsante home in modo diverso rispetto alla situazione in cui l'attività corrente è sospesa per qualsiasi cosa Motivo. Lo stesso problema è con il fatto che Application.onDestroy () non può essere utilizzato per build di poduction. Tali esempi sono mettere in pausa un gioco quando l'utente nasconde l'appication, interrompendo la musica di sottofondo, ecc.
Blackhex

0

Recentemente stavo cercando di rilevare il pulsante home press, perché avevo bisogno che facesse lo stesso del metodo " onBackPressed () ". Per fare ciò, ho dovuto sovrascrivere il metodo " onSupportNavigateUp () " in questo modo:

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

Ha funzionato perfettamente. =)


0

La risposta di Jack funziona perfettamente per l' clickevento mentre longClicksta prendendo in considerazione il menuclic del pulsante.

A proposito, se qualcuno si sta chiedendo come fare tramite 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

inserisci qui la descrizione dell'immagine Chiave Home Android gestita dal livello del framework non è possibile gestirla a livello del livello dell'applicazione. Perché l'azione del pulsante home è già definita nel livello inferiore. Ma se stai sviluppando la tua ROM personalizzata, potrebbe essere possibile. Google ha limitato le funzioni di override del PULSANTE HOME per motivi di sicurezza.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.