16

我目前有一个周期性问题,IllegalArgumentException当我打电话时我得到一个Activity.startLockTask()。我的应用程序安装了一个设备所有者应用程序,它允许我的包自动固定自己。

下面的代码正在检查以确保我的包裹可以自行锁定。如果可以,那么它会自行固定。

代码:

if (dpm.isLockTaskPermitted(getPackageName())) {
    super.startLockTask();
}

日志猫:

java.lang.IllegalArgumentException: Invalid task, not in foreground
    at android.os.Parcel.readException(Parcel.java:1544)
    at android.os.Parcel.readException(Parcel.java:1493)
    at android.app.ActivityManagerProxy.startLockTaskMode(ActivityManagerNative.java:5223)
    at android.app.Activity.startLockTask(Activity.java:6163)

问题是我的应用程序需要偶尔重新启动。所以我们取消固定,完成活动并使用新任务重新启动它,然后退出我们的流程。当活动恢复时,它会尝试固定自己 - 有时它会起作用 - 有时它不会。我相信我们如何重新启动可能是引发异常的原因,但这并不重要,因为新活动在前台并且集中在。

一旦活动无法固定,只要它尝试,它就会继续失败:如果我坐在那里,每 5 秒尝试固定任务,它每次都会继续失败。我试过固定在onCreate, onWindowFocusChanged,onResumeonStart.

有谁知道问题可能是什么?

供参考:
第 8853 行:https ://android.googlesource.com/platform/frameworks/base/+/android-5.0.2_r1/services/core/java/com/android/server/am/ActivityManagerService.java

4

6 回答 6

8

我有同样的问题,我还没有找到合适的解决方案。但这就是我目前所做的。

Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        try {
            if (dpm.isLockTaskPermitted(getPackageName())) {
                super.startLockTask();
            }
        }catch (Exception exception) {
            Log.v("KioskActivity","startLockTask - Invalid task, not in foreground");
        }
    }
},1500);

即使 onWindowFocusChanged 被触发,请求锁定的应用程序似乎还没有收到焦点。通过延迟调用 startLocktask 一段时间,它会起作用。如何有一小段时间应用程序不会被固定/锁定。我已经通过一些额外的安全措施解决了这个问题(我在后台有一个长时间运行的服务,它可以防止通知阴影下拉,如果打开会关闭设置窗口)。

顺便说一句,你有没有设法以适当的方式解决这个问题?

于 2016-07-27T07:25:57.763 回答
3

我遇到了这个问题,并使用从这篇文章中的答案中获取的逻辑解决了这个问题: 你怎么知道何时绘制了布局?

基本上,它只是确保首先绘制 UI,然后尝试固定。

示例代码(把它放在你的 onCreate 方法中):

> findViewById(R.id.your_view).post( new Runnable() {
>             @Override
>             public void run() {
> 
>                 // Run pinning code here
>             }
>         });
于 2018-03-08T03:51:15.287 回答
1

我知道这是一个相当古老的问题,但我也遇到了它,这就是我解决它的方法。关键是文档中的这句话startLockTask()(同样适用stopLockTask()

注意:该方法只能在 Activity 处于前台时调用。也就是在 onResume() 和 onPause() 之间

我有一些代码路径最终试图调用startLockTask()之前onResume()。我通过确保正确的活动状态来修复它(使用 AndroidX 生命周期)

if(lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
    startLockTask()
}

这对我的情况来说已经足够了。您可能需要执行一些类似这样的附加逻辑(伪代码):

if(not yet resumed) {
    doWhenResumed { // Implement this as a helper function that executes when your Activity is resumed
        startLockTask()
    }
}
于 2019-08-28T04:08:16.773 回答
0

这类似于@Schtibb 的答案,但是我对硬编码只有一个 1500 毫秒的延迟而没有任何重试逻辑感到不舒服。它仍然可能偶尔失败。

但是我发现这样做的诀窍是try在调用时使用 a startLockTask(),如果它失败了,只需捕获错误并在短暂延迟后重试,直到它成功:

void startLockTaskDelayed () {
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            // start lock task mode if its not already active
            try {
                ActivityManager am = (ActivityManager) getSystemService(
                        Context.ACTIVITY_SERVICE);

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if (am.getLockTaskModeState() ==
                            ActivityManager.LOCK_TASK_MODE_NONE) {
                        startLockTask();
                    }
                }

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (!am.isInLockTaskMode()) {
                        startLockTask();
                    }
                }
            } catch(IllegalArgumentException e) {
                Log.d("SVC0", "Was not in foreground yet, try again..");
                startLockTaskDelayed();
            }
        }
    }, 10);
}

我觉得这种方法稍微更有活力,并且(几乎)尽快固定屏幕。

于 2019-07-17T08:20:13.587 回答
0

错误说应用程序不在前台,所以我在 onStart 方法中创建了一个循环来检查应用程序是否在前台

 boolean completed = false;
                while (!completed)
                    if (isAppInForeground(this)) {
                        startLockTask();
                        completed = true;
                    }

函数是AppInForeground

  private boolean isAppInForeground(Context context) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
        ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
        String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();

        return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase());
    } else {
        ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
        ActivityManager.getMyMemoryState(appProcessInfo);
        if (appProcessInfo.importance == IMPORTANCE_FOREGROUND 
                || appProcessInfo.importance == IMPORTANCE_VISIBLE) {
            return true;
        }

        KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
        // App is foreground, but screen is locked, so show notification
        return km.inKeyguardRestrictedInputMode();
    }
}
于 2018-07-06T15:14:19.177 回答
0

我为信息亭模式创建了一个单独的活动

主要思想是将此任务从其他活动中传递出来,并将锁定任务始终保持在堆栈的根目录中

View.post(...)魔术延迟类似对我不起作用

onResume()检查方法isFinishing()工作正常,但要小心清除任务标志

<style name="AppTheme.Transparent" parent="android:style/Theme.Translucent.NoTitleBar.Fullscreen">
    <item name="android:colorPrimary">@color/colorPrimary</item>
    <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="android:colorAccent">@color/colorAccent</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:backgroundDimEnabled">false</item>
</style>
class LockActivity : Activity() {

    private lateinit var adminManager: AdminManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        adminManager = AdminManager(applicationContext)
    }

    override fun onStart() {
        super.onStart()
        when (activityManager.lockTaskModeState) {
            ActivityManager.LOCK_TASK_MODE_NONE -> {
                if (true/*IT IS NEEDED*/) {
                    if (adminManager.setKioskMode(true)) {
                        // need startLockTask on resume
                        return
                    } else {
                        //toast("HAVE NO OWNER RIGHTS")
                    }
                }
                launchActivity()
                finish()
            }
            ActivityManager.LOCK_TASK_MODE_LOCKED -> {
                if (false/*IT IS NOT NEEDED*/) {
                    if (adminManager.setKioskMode(false)) {
                        stopLockTask()
                        launchActivity()
                        finish()
                        return
                    } else {
                        //toast("HAVE NO OWNER RIGHTS")
                    }
                }
                launchActivity()
            }
            else -> finishAffinity()
        }
    }

    override fun onResume() {
        super.onResume()
        if (!isFinishing) {
            if (activityManager.lockTaskModeState == ActivityManager.LOCK_TASK_MODE_NONE) {
                startLockTask()
                launchActivity()
            }
        }
    }

    private fun launchActivity() {
        // todo startActivity depending on business logic
    }

    override fun onBackPressed() {}
}
class AdminManager(context: Context) {

    private val adminComponent = ComponentName(context, AdminReceiver::class.java)

    private val deviceManager = context.devicePolicyManager

    private val packageName = context.packageName

    @Suppress("unused")
    val isAdmin: Boolean
        get() = deviceManager.isAdminActive(adminComponent)

    val isDeviceOwner: Boolean
        get() = deviceManager.isDeviceOwnerApp(packageName)

    fun setKioskMode(enable: Boolean): Boolean {
        if (isDeviceOwner) {
            setRestrictions(enable)
            deviceManager.setKeyguardDisabled(adminComponent, enable)
            setLockTask(enable)
            return true
        }
        return false
    }

    /**
     * @throws SecurityException if {@code admin} is not a device or profile owner.
     */
    private fun setRestrictions(enable: Boolean) {
        arrayOf(
            UserManager.DISALLOW_FACTORY_RESET,
            UserManager.DISALLOW_SAFE_BOOT,
            UserManager.DISALLOW_ADD_USER
        ).forEach {
            if (enable) {
                deviceManager.addUserRestriction(adminComponent, it)
            } else {
                deviceManager.clearUserRestriction(adminComponent, it)
            }
        }
    }

    /**
     * @throws SecurityException if {@code admin} is not the device owner, the profile owner of an
     * affiliated user or profile, or the profile owner when no device owner is set.
     */
    private fun setLockTask(enable: Boolean) {
        if (enable) {
            deviceManager.setLockTaskPackages(adminComponent, arrayOf(packageName))
        } else {
            deviceManager.setLockTaskPackages(adminComponent, arrayOf())
        }
    }
}
于 2019-10-08T08:56:18.650 回答