【问题标题】:How to disable home button in Android like lock screen apps do?如何像锁屏应用一样禁用Android中的主页按钮?
【发布时间】:2016-07-22 20:32:09
【问题描述】:

我知道这个问题被问了很多次,但我发现没有一个解决方案有效。 我尝试了下面给出的代码......

   protected void onPause() {
   super.onPause();
    Intent intent = new Intent(this,LockActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT |Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
    }

它的作用是在启动 android 主屏幕时将当前 Activity 再次置于最前面,但在启动主屏幕时将 Activity 再次置于最前面需要将近 3-4 秒。

我使用了一些锁定屏幕应用程序,当单击主页按钮时它们甚至不启动主屏幕。我想实现这样的目标。

我也使用过 onUserLeavesHint 方法、onKeyDown 方法和 onKeyDispatch 方法,但它们都不适合我。

并且请不要回答或评论无法在 Android 中禁用主页按钮。对于这样的答案或 cmets,我建议您浏览 PlayStore 上的一些锁屏应用程序。我还沿着源代码在 github 上找到了一个工作应用程序。它在我的手机上运行,​​并且应用程序使用了 disableKeyguard,但是当我在我的应用程序中执行相同操作时它不起作用(disableKeyguard 已弃用,但我使用 @supress 警告(“deprecation”))。

【问题讨论】:

  • 那么在KIOSK模式旁边的坦率回答是你不能禁用主页按钮。
  • 我不介意你说什么,但我已经在第一行提到我已经阅读了与我的问题相关的所有问题,每篇文章都说你不能禁用 android 中的主页按钮,而且最后我说他们在 Playstore 上有很多屏幕储物柜应用程序可以禁用主页按钮,如果你有时间可以尝试其中一个。
  • @Ruag 我恳请您查看 PiLocker,一个开源锁屏,特别是:github.com/Pi-Developers/Pi-Locker/blob/master/pilocker/src/…,它将引导您查看 HomeKeyLocker,并最终查看 github.com/shaobin0604/Android-HomeKey-Locker
  • 感谢@JasonSec。我已经检查过一次(我已经浏览了 github 上每个涉及禁用 home key 的开源项目)并且它没有 100% 工作,但我认为我应该按照你的建议再次查看这个。 Shaobin0604 的 Home key locker 不是一个完美的解决方案,因为它不处理虚拟 Home 键。
  • @Ruag 啊,我明白了,还没有用 Pilocker 测试过虚拟主页键,但假设它确实有效,相关代码在这里:github.com/Pi-Developers/Pi-Locker/blob/…

标签: android homescreen android-homebutton screen-lock


【解决方案1】:

你可以做的是像这样覆盖主页键功能:

@Override public boolean onKeyDown(int keyCode, KeyEvent event)
{
    if(keyCode == KeyEvent.KEYCODE_HOME)
    {
        //The Code Want to Perform.
    }
});

然后您应该能够阻止用户使用此按钮返回主屏幕。 希望对你有用。

编辑: 覆盖主页按钮的问题是它被认为是 作为谷歌的一个安全漏洞,所以每次有人找到一种方法来覆盖它时,谷歌都会修补这个“漏洞”。

【讨论】:

    【解决方案2】:

    对您的问题的简单回答是您不能这样做。

    你提到的解决方案是我大约四年前提出的 [Link]

    onUserLeavesHint、onKeyDown 和 onKeyDispatch 永远不会“禁用”硬件键。

    如果您真的想“处理”主页按钮,则必须将您的应用程序设置为主屏幕。请参阅thisthis

    如果您真的想在不创建主屏幕应用程序的情况下禁用硬件密钥,您应该根您的设备并从内核模块中删除相应的设备文件。 (请自行承担风险!)

    【讨论】:

    • 感谢@PC。但你的观点对我没有任何帮助。我认为你没有尝试过任何来自 Google Play 的锁屏应用程序,否则你不会这样回答,请通过其中任何一个,它会在应用程序的某个时间点真正帮助你发展。顺便说一句,我探索了一些锁定屏幕应用程序的开源项目,他们所做的就像他们使用了一个警报对话框,他们的锁定活动使其尺寸为 0,颜色透明,并将其重力设置为底部。但我不明白实现,也不知道它是如何工作的?你能帮我多一点吗?
    【解决方案3】:

    您可以使用shaobin0604 library 来执行此操作。它也会禁用后退按钮。您的活动将如下所示:

    
    public class MainActivity extends Activity {
    
    
    HomeKeyLocker homeKeyLocker;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        homeKeyLocker = new HomeKeyLocker();
        homeKeyLocker.lock(this);
    }
    

    }

    【讨论】:

    • 很好的参考,我不知道这种解决方法存在。除了列出的 shaobin 之外,如果能获得一份可以使用(和不使用)的手机的完整列表会很好。还想知道是否可以绕过它(这对于锁屏至关重要)。
    • @Jordan 在这里提出问题之前,我探索了这个网站上的所有问题以及 github 上与我的问题相关的所有开源项目。我也尝试过 shaobin0604 的库,但是使用该代码的应用程序崩溃了。
    • 在 UT880 设备上根本不会闪烁。
    【解决方案4】:

    提供完美无瑕的非根锁屏功能的可靠方法是将您的“储物柜”应用创意与启动器应用相结合。

    清单中的一个简单更改将允许您的应用注册为主屏幕/启动器,这将使您的 .apk 完全控制主页按钮:

    <application
        android:launchMode="singleTask"
        android:clearTaskOnLaunch="true"
        android:stateNotNeeded="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="ch.arnab.simplelauncher.HomeScreen"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:excludeFromRecents="true"
            android:screenOrientation="nosensor">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
    
                <!-- These 2 intent-filters identify a launcher: -->
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
    

    来自this tutorial

    然后您将有两项活动,一项用于主屏幕,一项用于锁定屏幕。

    您必须检测屏幕何时关闭/打开,以显示您的锁屏活动:

    public class MainActivity extends Activity {
    
        //Create a receiver for screen-on/screen-off
        BroadcastReceiver mybroadcast = new BroadcastReceiver() {   
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
                    //Show lock-screen
                }
                else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                    //Also show lock-screen, to remove flicker/delay when screen on?
                }
    
            }
        };
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            registerReceiver(mybroadcast, new IntentFilter(Intent.ACTION_SCREEN_ON));
            registerReceiver(mybroadcast, new IntentFilter(Intent.ACTION_SCREEN_OFF));
        }
    }
    

    来自this answer

    仅供参考:由于此时您的“锁定屏幕”仍将被视为您的启动器的一部分,因此应用程序将能够在您的锁定屏幕上启动,这很糟糕:用户有权访问通知抽屉可以点击消息/推文等,但也可以用于:无需解锁手机即可接听来电。

    无论哪种方式,您的锁屏活动都应该覆盖onPause,检查用户是否“经过身份验证”,如果不是,则假定用户打开了某些东西并应该返回锁屏:

    @Override
    public void onPause() {
        super.onPause();
        if(password!=storedPassword) {
          //Lockscreen activity shouldn't ever be escaped without the right password!
          //Return to launcher without root!
          Intent homeIntent = new Intent(Intent.ACTION_MAIN);
          homeIntent.addCategory(Intent.CATEGORY_HOME);
          homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
          startActivity(homeIntent);
        }
    }
    

    为了获得更好的用户体验,您应该为用户提供允许一些应用绕过锁屏的选项(例如 Spotify),您可以将其包含在上面的 if 语句中(例如 if(password!=storedPassword||isForegroundAppSpotify))。

    至于在您的主屏幕上加载应用程序,您可以参考tutorials on Google 创建您自己的启动器活动。

    结合启动器+锁屏是避免root访问的最简单方法。您可能会发现使用 root 更容易,但您会限制您的客户群。

    希望这会有所帮助!

    【讨论】:

    • 感谢@Aaron Gillion。我也已经尝试过这个并且它可以工作,但问题是它在我不想要的家庭新闻期间要求启动器。有什么方法可以让我以编程方式为我的应用设置主页启动器。
    • 这个问题是关于主页按钮而不是主屏幕锁定
    【解决方案5】:

    来源 - https://github.com/shaobin0604/Android-HomeKey-Locker

    //Copy this class
    public class HomeKeyLocker {
        private OverlayDialog mOverlayDialog;
        public void lock(Activity activity) {
            if (mOverlayDialog == null) {
                mOverlayDialog = new OverlayDialog(activity);
                mOverlayDialog.show();
            }
        }
        public void unlock() {
            if (mOverlayDialog != null) {
                mOverlayDialog.dismiss();
                mOverlayDialog = null;
            }
        }
        private static class OverlayDialog extends AlertDialog {
    
            public OverlayDialog(Activity activity) {
                super(activity, R.style.OverlayDialog);
                WindowManager.LayoutParams params = getWindow().getAttributes();
                params.type =  WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
                params.dimAmount = 0.0F; // transparent
                params.width = 0;
                params.height = 0;
                params.gravity = Gravity.BOTTOM;
                getWindow().setAttributes(params);
                getWindow().setFlags( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |  WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, 0xffffff);
                setOwnerActivity(activity);
                setCancelable(false);
            }
    
            public final boolean dispatchTouchEvent(MotionEvent motionevent) {
                return true;
            }
    
            protected final void onCreate(Bundle bundle) {
                super.onCreate(bundle);
                FrameLayout framelayout = new FrameLayout(getContext());
                framelayout.setBackgroundColor(0);
                setContentView(framelayout);
            }
        }
    }
    
    //Paste this in your activity
    mHomeKeyLocker = new HomeKeyLocker();
    mHomeKeyLocker.lock(this);
    

    【讨论】:

    • 来源:This Github project 始终引用您的来源。问题:可以在锁屏情况下使用硬件按钮(或打开通知)绕过此方法吗?这仅适用于此 hack 适用的选定 Android 手机/版本(2.3 - 一些 4.x 版本)。
    • @Nitin 我已经尝试过了,但是当我在我的活动中使用那两行代码(mHomeKeyLocker = new HomeKeyLocker(); mHomeKeyLocker.lock(this);) 时,应用程序崩溃了。
    • @Raug : 你能粘贴崩溃日志吗?
    • 很好,库工作正常!但我有一个问题,在我的情况下,键盘也被阻止了......这是库的行为吗?
    • @freakAR 是的,这个库会阻止键盘和后退按钮。
    【解决方案6】:

    我为设计锁屏做了很多研究,终于找到了解决方案。 Android 禁用了覆盖除后退按钮之外的系统栏的功能。但是有一些工作可以完成这项工作:

    耐心地理解和实施屏幕固定,你就会成功。

    您可以创建一个应用来控制要在哪些应用中实现屏幕固定,或者您可以直接在要固定的同一应用中实现屏幕固定。

    我将在本文中向您展示后面的实现:

    1.首先,您的应用应该是设备所有者。

    您可以通过多种方式进行操作,最简单的是执行命令:

    adb shell dpm set-device-owner [yourPackageName]/.[MyDeviceAdminReceiver]

    创建一个扩展 DeviceAdminReceiver 的接收器(MyDeviceAdminReceiver)。你不需要在这里有任何代码。有关设备所有者实施的更多信息,请参阅此链接
    http://florent-dupont.blogspot.com/2015/02/10-things-to-know-about-device-owner.html

    以这种方式在 AndroidManifest.xml 文件中注册接收器:

    <receiver
           android:name=".MyDeviceAdminReceiver"
           android:label="@string/app_name"
           android:permission="android.permission.BIND_DEVICE_ADMIN">
         <meta-data
           android:name="android.app.device_admin"
           android:resource="@xml/device_admin" />
    
           <intent-filter>
             <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
           </intent-filter>
      </receiver>
    

    2。您的 onCreate 方法应如下所示:

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lock_screen);
    
        ComponentName deviceAdmin = new ComponentName(this, MyDeviceAdminReceiver.class);
        DevicePolicyManager mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
    
    
        if (mDpm.isDeviceOwnerApp(getPackageName())) {
            mDpm.setLockTaskPackages(deviceAdmin, new String[]{getPackageName()});
        }
    
        if (mDpm.isLockTaskPermitted(this.getPackageName()))
            startLockTask();
    

    3.取消固定屏幕并使导航栏发挥作用

    在代码中要取消固定的位置调用函数 stopLockTask()。例如在我的应用程序中,一旦我验证用户输入了正确的密码,我就会调用这个函数:

     if (userInput.length() == 4) {
    
                        if (userInput.equals(passcode)) {
                            userInput = "";
                            etxtPasscodeDisplay.setText("");
                            stopLockTask(); // this is what you need
                            unlockHomeButton(); // A method to show home screen when 
                             passcode is correct
                            finishAffinity(); //kill other activities
                        }
    

    锁屏通常需要的额外信息:

    1.如果您的应用是启动后出现的第一件事

    为此,您需要一个服务 (StartAtBootService) 和一个接收器 (BootCompletedReceiver)。

    2。如果您希望您的应用在屏幕锁定和解锁后显示 (按电源键锁定和解锁):

    创建扩展 service 的 AEScreenOnOffService 和扩展 BroadcastReceiver 的 AEScreenOnOffReceiver 以在屏幕打开时启动您的活动。

    有关我在这里提到的所有内容的详细信息,请参阅http://www.sureshjoshi.com/mobile/android-kiosk-mode-without-root/
    这是一篇很棒的文章,对我帮助很大。特别感谢作者。

    我需要至少 10 个声望才能发布两个以上的链接。由于我是 stackoverflow 的新手,我没有足够的声誉,所以很抱歉无法分享我提到的所有链接。一旦我获得访问权限,肯定会更新帖子。

    【讨论】:

    • 在android studio中,这将是一个广播接收器,对吧?此外,当我尝试在 AndroidManifest.xml 中注册接收器时出现此错误。 Cannot resolve symbol '@xml/device_admin'。任何线索为什么?
    • 是的,myDeviceAdminReceiver 扩展了广播接收器。 wrt xml 错误,我认为您要么在 xml 中没有 xml 文件夹或 device_admin。在 xml 文件夹中创建 device_admin 文件,它会正常工作
    猜你喜欢
    • 2020-09-04
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多