在启动时的安卓PIN活动

9
我有一个应用程序,它在启动时会自动将自己注册为默认启动器并固定在屏幕上。安装该应用程序时,所有功能都可以正常运行,应用程序也被成功固定,只能看到返回按钮。
然而,当设备首次启动时,应用程序无法正确固定。我会看到一系列的提示信息“屏幕已固定”和“屏幕未固定”,这些提示信息会多次出现。此外,“主页”和“最近任务”按钮仍然可见。
运行命令“adb shell dumpsys activity activities”后,最后几行显示应用程序未被固定。
mLockTaskModeState=NONE mLockTaskPackages (userId:packages)=
0:[com.example.myapp]
mLockTaskModeTasks[]

--

测试设备为华硕ZenPad,运行Android 6.0的Marshmallow系统,版本号为23。

我依赖于MainActivity清单文件中的"lockTaskMode"属性来锁定屏幕(而不是使用activity.startLockTask()方法):

<activity
    android:name=".MainActivity"
    android:configChanges="keyboardHidden|orientation|screenSize"
    android:label="@string/launcher_main"
    android:launchMode="singleTask"
    android:lockTaskMode="if_whitelisted"
    android:screenOrientation="landscape">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.HOME"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>

任何帮助或指导都将不胜感激。


如果您使用默认的lockTaskMode并调用startLockTask()会发生什么? - Kevin Krumwiede
似乎表现出相同的行为。 - Greg T
我想知道在启动启动器和建立任务固定权限之间是否存在竞争条件。我编写了一个应用程序,当启动时自动将自己固定,但它不是启动器,而是响应于“BOOT_COMPLETED”后几秒钟启动的。 - Kevin Krumwiede
1
你关于BOOT_COMPLETED广播被延迟的说法是正确的。它似乎先被传递给系统应用程序,然后才传递给用户应用程序。但我不确定这就是问题所在...在DeviceAdminReceiver中,我看到了onLockTaskModeEntering和onLockTaskModeExiting。我只是不知道是什么触发了它的退出。 - Greg T
3个回答

3

我也遇到了同样的问题,只找到了一个解决方案。不确定为什么,但安卓系统在启动时阻止任务锁定,这让我感到困惑,因为任务锁定是设计用来创建“信息亭”类型应用程序的。我找到的唯一解决方案是检测它未锁定的情况,然后重新启动应用程序。虽然有些“hacky”,但又能怎么办呢?

要检测它未锁定的情况,我创建了一个状态变量并分配状态(锁定、已锁定、解锁、已解锁)。然后在设备管理器接收器的onTaskModeExiting中,如果状态不是“解锁”状态,则我知道它自行解锁了。所以如果出现了这种失败的情况,我会使用以下方法重新启动应用程序(该方法将应用程序安排在报警管理器中,然后结束应用程序):

如何以编程方式“重新启动”安卓应用程序?

以下是一些示例代码:

DeviceAdminReceiver

@Override
public void onLockTaskModeEntering(Context context, Intent intent, String pkg) {
    super.onLockTaskModeEntering(context, intent, pkg);
    Lockdown.LockState = Lockdown.LOCK_STATE_LOCKED;
}

@Override
public void onLockTaskModeExiting(Context context, Intent intent) {
    super.onLockTaskModeExiting(context, intent);

    if (Lockdown.LockState != Lockdown.LOCK_STATE_UNLOCKING) {
        MainActivity.restartActivity(context);
    }
    Lockdown.LockState = Lockdown.LOCK_STATE_UNLOCKED;
}

主活动

public static void restartActivity(Context context) {
    if (context != null) {
        PackageManager pm = context.getPackageManager();
        if (pm != null) {
            Intent intent = pm.getLaunchIntentForPackage(context.getPackageName());
            if (intent != null) {
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                int pendingIntentId = 223344;
                PendingIntent pendingIntent = PendingIntent.getActivity(context, pendingIntentId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
                AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
                mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent);
                System.exit(0);
            }
        }
    }
}

private void lock() {
    Lockdown.LockState = Lockdown.LOCK_STATE_LOCKING;
    startLockTask();
}

private void unlock() {
    ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    if (am.getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_LOCKED) {
        Lockdown.LockState = Lockdown.LOCK_STATE_UNLOCKING;
        stopLockTask();
    }
}

实际上这只是我实现的简化版本。但它应该能帮助您指向一个解决方案。


不是理想的解决方案,但这确实可以防止用户退出 kiosk 模式。应用程序将被终止并重新启动(假设它是默认启动器)。 - Greg T
希望在未来的Android版本中能够解决这个问题。 - Greg T
对我来说它不起作用。我的活动像往常一样重新启动,进入无限循环 ;( 请问还有更多的解决方案吗? - LionisIAm

0
目前我找到的唯一解决方案是:创建另一个启动器应用程序,不使用locktask,每次启动器出现时都会触发主应用程序。这样可以避免用户在调用on BOOT_COMPLETED接收器时等待几秒钟,因此我们只有在lockTask应用程序在清单中具有某些活动的启动器属性时才会遇到此问题。

0

抱歉回复晚了,但是...
任何遇到这个问题的人都可以在第一个(启动器/主页)活动中(例如MainActivity)进行这个棘手的工作:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (mSharedPreferences.getBoolean(KEY_PREF_RECREATED, false)) {
        mSharedPreferences.edit().putBoolean(KEY_PREF_RECREATED, false).apply();

        // start LOCK TASK here
    } else {
        mSharedPreferences.edit().putBoolean(KEY_PREF_RECREATED, true).apply();

        finish(); // close the app
        startActivity(new Intent(this, MainActivity.class)); // reopen the app
        return;
    }

    setContentView(R.layout.activity_main);

    // other codes
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接