Android'de ev düğmesine basmayı algıla


94

Bu beni bir süredir deli ediyor.

Android uygulamasında ana sayfa düğmesine basılıp basılmadığını güvenilir bir şekilde tespit etmenin herhangi bir yolu var mı?

Başarısız olursa, bir etkinliğin Duraklatmaya girmesine neyin sebep olduğunu söylemenin sağlam bir yolu var mı? Örneğin, yeni bir etkinliğin başlatılmasından mı yoksa geri / eve düğmesine basarak mı oluştuğunu tespit edebilir miyiz?

Gördüğüm bir öneri, onPause () 'u geçersiz kılmak ve isFinishing ()' yi çağırmaktı, ancak bu, ana düğmeye basıldığında, tıpkı yeni bir faaliyetin başlaması durumunda olduğu gibi, bu ikisini ayırt etmekte başarısız olacaktır.

Herhangi bir yardım çok takdir edilir.

** Güncelleme **: Bu bağlantı için @ android-aç'a teşekkürler: https://nishandroid.blogspot.com/

Aşağıdaki yöntemi geçersiz kılmak:

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

Ardından, ana sayfa düğmesine basıldığında aşağıdaki olay TUTUŞTURULACAKTIR:

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

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

Bu satırın herhangi bir yan etkisi olup olmadığından emin değilim:

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

Görünüşe göre popüler inancın aksine, aslında ev anahtarını dinleyebilirsiniz. Endişe verici bir şekilde, yanlış dönebilir ve ana anahtarın hiçbir şey yapmamasını sağlayabilirsiniz.

Güncelleme : Beklendiği gibi, bunun bazı yan etkileri vardır - bu mod etkinleştirildiğinde gömülü videoların ve Google haritalarının görünmediği görülüyor.

Güncelleme : Sözde bu hack artık Android 4.0'dan itibaren çalışmıyor


Benim sorunum arka ve ev tuşu arasında gizlenmek değildi, ancak her iki durumda da uygulamayı bitirmek istedim. Kullanarak yaptım Activity.onUserLeaveHint().
harism

Tek sorun, onUserLeaveHint (), söz konusu etkinlikten bir etkinlik başlattığımda da ateşlenecek, yalnızca geri mi yoksa eve mi basıldığını bilmek istiyorum. Yine de öneriniz için teşekkürler
Dean Wild

Bu doğru, ancak ne yazık ki, bildiğim kadarıyla, Ev-anahtar kullanımı hakkında herhangi bir bilgi alabileceğim tek yer burası. Yanlış pozitifleri ortaya çıkarmayı daha büyük bir sorun haline getirerek, birçoğundan kolaylıkla fark edilebilir, ancak yine de kulağa kolay gelen işi oldukça karmaşık hale getirir.
harism

2
@DeanWild: Bunu okudun mu: nisha113a5.blogspot.com
Pratik Bhat

2
TYPE_KEYGUARD sabiti, Android
5.0'da

Yanıtlar:


136

Aşağıdaki kod benim için çalışıyor :)

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
Sizin onHomeLongPressedgerçekte "Son Kullanılanlar" sistem etkinliğinin açılışına karşılık geliyor gibi görünüyor. Telefonumda bu, ana sayfa düğmesinin yanındaki son aramalar düğmesine basılarak tetiklendiğinden, kodunuzun evde uzun süre basılmasıyla ilgili varsayımı her zaman doğru değildir.
Sam

neden benim için çalışmıyor, yayını manifest yoluyla kaydettirmek dışında tamamen aynısını yaptım.
Farhan

Uygulama sınıfına kayıtlı, Şimdiye kadar çalışıyor .. +1, merak ediyorum ne oluyor? Demek istediğim, hangi orijinal vakayı
kaçırırdık

1
bazen intent.getStringExtra (SYSTEM_DIALOG_REASON_KEY); boş döndür. Ne olduğunu bilmek ister miyim?
Fakher

1
Uzun basma nedeni artık deniyorfinal String SYSTEM_DIALOG_REASON_LONG_PRESS = "assist"
JWqvist

49

Bu eski bir soru ama birine yardımcı olabilir.

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

Belgelere göre, onUserLeaveHint () yöntemi, kullanıcı ana sayfa düğmesini tıkladığında VEYA bir şey uygulamanızı kesintiye uğrattığında (gelen bir telefon araması gibi) çağrılır.

Bu benim için çalışıyor .. :)


26
Doğru değil !!! Bu, ev düğmesine basıldığında çalışılır, ancak aynı zamanda Niyetle Etkinlik Değiştirme yapıldığında da çalışır !!
Nikunj Paradva

Bu, her zaman onStop () 'dan önce yürütülür, üste başka bir etkinlik gelse veya kullanıcı etkinliği zorla terk etse veya ana sayfa düğmesini tıklasa bile ...
Navas pk

7

Bir Android uygulamasından HOME düğmesini algılamak ve / veya kesmek imkansızdır. Bu, çıkılamayan kötü amaçlı uygulamaları önlemek için sisteme yerleştirilmiştir.


kabul edilen cevabı kontrol et, bu mümkün. Yine de birçok cihazda test edilmedi.
Dean Wild

Evet ... benimkine düşen uygulama.
Jeremy Logan

başlatıcılar / ev değiştirme uygulamaları ne olacak? Bir tane inşa ediyorum ve kullanıcılar ana sayfa
düğmesini

Başlatıcılar için şunu kullanın: @Override korumalı void onNewIntent (Amaç amacı) {super.onNewIntent (niyet); / * Eğer * /} istiyorsunuz neyi
Ton

@lisovaccaro başlatıcısı ve / veya ev değiştirmeleri hala google (src diane hackborn) tarafından desteklenmemektedir ve bu nedenle kullanıcının ana düğmeyi tıklamasını engelleyemezsiniz. Yine de, görünümünüzü her şeyi kaplayacak bir sistem uyarısı iletişim kutusu olarak ekleyebilirsiniz. Ancak ana sayfa düğmesi tıklamaları bundan geçecektir.
JacksOnF1re

7

İlk etkinlik açılıp kapandığında veya herhangi bir etkinlik ana sayfa düğmesi ile duraklatılıp ardından görev yöneticisinden devam ettirildiğinde uygulamamda arka plan müziğini başlatmam / durdurmam gerekiyordu. Tamamen çalmayı durdurma / devam ettirme Activity.onPause()ve Activity.onResume()müziği bir süre kesintiye uğrattı, bu yüzden aşağıdaki kodu yazmam gerekiyordu:

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

oynatmayı yalnızca uygulama (tüm etkinlikleri) kapatıldığında veya ana sayfa düğmesine basıldığında kesintiye uğratır. Maalesef ben aramaların değişim düzenine başaramadı onPause()başlangıç aktivitesinin ve yöntemin onResume()başladı aktiviteyle ait Activity.startActivity()adlandırılır (veya algılamak onPause()bu durumda özel olarak ele alınması var ki aktivitenin başka bir etkinliği başka bir yol başlatıyor):

private boolean mIsStarting;

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

Diğer bir dezavantaj, bunun GET_TASKSşuna eklenmiş izin gerektirmesidir AndroidManifest.xml:

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

Bu kodu, yalnızca ana sayfa düğmesine basıldığında tepki verecek şekilde değiştirmek basittir.


4

onUserLeaveHint()Aktivitede geçersiz kıl . Yeni bir etkinlik üzerine geldiğinde veya kullanıcı geri basmaya bastığında, etkinlik için hiçbir zaman geri arama olmayacaktır.


4
aynı zamanda uygulama içinde bir aktiviteden diğerine geçerken de çağrılır
Amir Uval

3

onUserLeaveHint ();

Bu aktivite sınıfı yöntemini geçersiz kılın. Bu, ana anahtar tıklamasını algılayacaktır. Bu yöntem, etkinliğin onPause () geri aramasından hemen önce çağrılır, ancak bir etkinlik kesintiye uğradığında, bir çağrı içi etkinlik ön plana çıktığında çağrılmaz, bu kesintilerin dışında kullanıcı ana tuşa tıkladığında çağırır.

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

2

Her ekran için bir sayaç oluşturmaya çalışın. Kullanıcı HOME'a dokunursa, sayaç sıfır olacaktır.

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

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

3
Küresel uygulama sayacını kastediyorsanız, bir etkinlik arka yığına taşındığında ve diğeri en üste taşındığında veya en üst etkinlik bittiğinde ve arka yığın etkinliği en üste taşındığında, bu normal bir yerde sıfır olacaktır. ev düğmesine basıldığında tepki vermek istiyorsanız. Aktivite çapında sayacı kastediyorsanız, aktivite görünür olmadığında sıfır olacaktır (ana sayfa düğmesine basılması gerekmez). Tek çözüm, bu geçişi atlamak için zamanlayıcı kullanarak reaksiyonunuzu ertelemek olabilir, ancak gerekli gecikme tahmin edilebilir veya istenmeyebilir.
Blackhex


1

Bu sorunu yaşadım ve onKeyDown () yöntemini geçersiz kılmak, temeldeki android sistemi bu yöntemi çağırmadığından hiçbir şey başaramadığından, bunu onBackPressed () geçersiz kılarak çözdüm ve orada yanlış olarak ayarlanmış bir boole değeri vardı , çünkü geri bastım, size kodda ne demek istediğimi göstereyim:

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

Bu yüzden bunun işe yaramasının nedeni, bu aktivitenin dışında gezinmenin tek yolunun geri veya eve basmaktır, böylece geri basıldığında, neden evde olmadığını biliyorum, ancak aksi takdirde neden evdi, bu nedenle varsayılan boole ayarladım home için değer doğru olması için bastırıldı Ancak bu, uygulamanızda yalnızca tek bir etkinlik örneğiyle çalışır, çünkü aksi takdirde onPause () yönteminin çağrılmasına neden olmak için daha fazla olasılığa sahip olursunuz.


aslında başka bir aktiviteye gittiğinizde, tekrar duraklatma yöntemine
Fakher

Bu nedenle, bunun yalnızca uygulamanız yalnızca tek bir aktivite içeriyorsa işe yarayacağını açıkça belirttim!
Moshe Rabaev

Ya aynı anda birden fazla alakasız aktivite çalışıyorsa ve kullanıcı sadece bunlar arasında geçiş yapıyorsa? Modern Android cihazlar, çoklu görevi destekler. Bu kodla, uygulamanıza geri dönmenin homePresseddoğru olarak ayarlanacağı ve başka bir uygulamaya geçilmesi, gerçekten olmadığı halde Ana Ekran'a basıldığını düşünecek gibi görünüyor .
Remy Lebeau

1

API 14'ten bu yana işlevi kullanabilir onTrimMemory()ve bayrağı kontrol edebilirsiniz TRIM_MEMORY_UI_HIDDEN. Bu size Uygulamanızın arka plana gideceğini söyleyecektir.

Böylece, özel Uygulama sınıfınızda aşağıdaki gibi bir şey yazabilirsiniz:

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

Bunu derinlemesine incelemek için sizi bu makaleyi okumaya davet ediyorum: http://www.developerphil.com/no-you-can-not-override-the-home-button-but-you-dont-have -to /


1
İyi makale - muhtemelen çoğu insanın ihtiyaç duyduğu şeyi yapan yararlı bir alternatif
Dean Wild

Güzel çözüm. Uygulama arka plandan döndüğünde bayrağı nasıl sıfırlayacağınızı biliyor musunuz? Örneğin, bir boole isInBackground oluşturursam, arka plandan döndüğümüzde onu sıfırlamak isterim.
MikeOscarEcho


0

Uygulama başlatıldığında yalnızca kök etkinliğinin yeniden gösterilmesini istediğiniz için, bu davranışı manifestteki başlatma modlarını vb. Değiştirerek elde edebilirsiniz.

Örneğin, başlatma etkinliğinize android: clearTaskOnLaunch = "true" özelliğini, belki de android: launchMode = "singleInstance" ile birlikte uygulamayı denediniz mi?

Görevler ve Arka Yığın , bu tür davranışlarda ince ayar yapmak için harika bir kaynaktır.


Bu en zarif çözüm gibi görünebilir, ancak oldukça güvenilmez buldum. Birkaç açma / kapama / duraklatma döngüsünden sonra uygulama tamamen yeniden başlatmak yerine devam etmeye başlayacak
Dean Wild

0

Giriş anahtarının davranışını değiştirmek kötü bir fikirdir. Bu nedenle Google, ana anahtarınızı geçersiz kılmanıza izin vermez. Genel olarak konuşursak ev anahtarını karıştırmazdım. Hangi nedenle olursa olsun yabani otlara karışırsa, kullanıcıya uygulamanızdan çıkması için bir yol vermeniz gerekir.

Herhangi bir çalışmanın istenmeyen yan etkileri olacağını hayal ediyorum.


1
Kesinlikle farkındasınız, ancak bazı müşteriler hayır cevabını kabul etmiyor ve neden kuralları ihlal etmemeleri gerektiğini anlamıyor.
Dean Wild

Sorun şu ki, ana sayfa düğmesi davranışını değiştirmek istemeseniz bile, ana sayfa düğmesine basılması nedeniyle uygulamanın geri taşınması durumunda, mevcut etkinliğinizin herhangi bir nedenle duraklatıldığı durumdan farklı şekilde zaman zaman farklı tepki vermeniz gerekmesidir. sebep. Aynı sorun, Application.onDestroy () uygulamasının üretim yapıları için kullanılamamasıdır. Bu tür örnekler, kullanıcı uygulamayı gizlediğinde oyunu duraklatmak, arka plan müziğini durdurmak vb.
Blackhex

0

Son zamanlarda, " onBackPressed () " yöntemiyle aynı şeyi yapması gerektiğinden, evdeki basma düğmesini algılamaya çalışıyordum . Bunu yapmak için, " onSupportNavigateUp () " yöntemini şu şekilde geçersiz kılmam gerekiyordu :

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

Mükemmel çalıştı. =)


0

Jack'in cevabı clickolay için mükemmel bir şekilde işe yarıyor longClick, düşünülürken bir menudüğme tıklamak gibi.

Bu arada, kotlin üzerinden nasıl yapılacağını merak eden varsa,

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

görüntü açıklamasını buraya girin Android Ana Anahtar, çerçeve katmanı tarafından yönetilir, bunu uygulama katmanı düzeyinde işleyemezsiniz. Çünkü ana sayfa düğmesi eylemi zaten aşağıdaki düzeyde tanımlanmıştır. Ancak özel ROM'unuzu geliştiriyorsanız, o zaman mümkün olabilir. Google, güvenlik nedeniyle HOME BUTTON geçersiz kılma işlevlerini kısıtladı.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.