需求

接上回,还是那台小米平板4,终于拿到了root权限。并且实现了开机启动某app,现在的需求是:要求只能运行这个app,不能退出,不能回退到主屏幕,不能Home键,重启之后还是我的app,你不能退出,除非你输入万能密码。。。

背景

然而之前用的是ScreenPin功能(也有翻译成报刊亭模式),这是Android自5.0开始系统内置的一个功能,主要用作商场演示等的场景,就是设定好之后,手机只能运行这个app(比如这个app是介绍手机的一个广告app,或者某工厂内的一个办公app,比如扫码,只能扫码用,别的干不了,因为你不能回到主屏幕,只能操作这一个)。这个系统内置功能长这个样子

可以看到有两个可操作项:“知道了”和”不用了“,那么这个时候如果点击”不用了“是不会激活ScreenPin的,跟操作普通app一样,想退出就退出,想结束任务就结束,没有任何限制。那么这一定不是我想要的。
PS. 如果进入了固定屏幕模式,除了重启手机之外另外一种方法是adb执行命令:
adb shell am force-stop xx.xx.xx 后面是你的包名。

步骤一

如果不想让用户看到上面的固定屏幕提示而直接固定了屏幕的话,你的应用必须要成为设备拥有者
来自StackoverFlow大神的解答:https://stackoverflow.com/questions/28437529/how-to-pin-an-app-without-a-dialog-android
这让我想起早年间用安卓机装某60安全卫士的时候提示绑定设备的场景,应该就是这里了。

那么问题来,如何将我的app注册为设备拥有者,直接搞之。

AndroidManifest.xml注册一个继承自android.app.admin.DeviceAdminReceiver的receiver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<receiver
android:name=".DeviceAdminReceiver"
android:description="@string/device_admin_desc"
android:label="@string/device_admin"
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" />
<action android:name="android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED"/>
<action android:name="android.app.action.DEVICE_ADMIN_DISABLED"/>
</intent-filter>
</receiver>

/rex/xml/device_admin内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<device-admin>
<uses-policies>
<limit-password />
<watch-login />
<reset-password />
<force-lock />
<wipe-data />
<expire-password />
<encrypted-storage />
<disable-camera />
<disable-keyguard-features />
</uses-policies>
</device-admin>

DeviceAdminReceiver里毛都不用写

1
2
3
4
5
6
7
8
9
10
11
12
public class DeviceAdminReceiver extends android.app.admin.DeviceAdminReceiver{

void showToast(Context context, String msg) {
String status = context.getString(R.string.admin_receiver_status, msg);
Toast.makeText(context, status, Toast.LENGTH_SHORT).show();
}

@Override
public void onEnabled(Context context, Intent intent) {
showToast(context, context.getString(R.string.admin_receiver_status_enabled));
}
}

ok代码部分到这里,然后adb shell进入到设备,切换su执行命令

1
dpm set-device-owner cc.lison.qis_shell/.DeviceAdminReceiver

然而我却得到了这样的提示

set-device-owner异常

也是,都MIUI了,设备拥有者肯定不会空闲出来,但是打开设置却怎么也找不到绑定设备拥有者的地方,一定是雷总故意隐藏起来了。

其他注册设备拥有者的方法,既然已经获取了root权限,那么系统目录简直我是畅行无阻,/data/system/device_owner.xml,创建这个文件,写入如下内容:

1
2
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<device-owner package="your.owner.app.package.id" name="Your app name" />

然后reboot。挖槽还是不好死,而新建的device_owner.xml也不翼而飞,看来是遇到了鬼,于是便把目光投向了/system/app里的其他文件/夹,其中有一个叫XiaoMiFramework之类的名字,我居然删除了它,然后程序各种报错,然后reboot,然后再次执行

1
dpm set-device-owner cc.lison.qis_shell/.DeviceAdminReceiver

居然出现了下面的提示:

dpm-set-device-owner

后来的故事大家都知道了,白雪公主和七个小矮人从此过上了幸福快乐的生阿活。。。

参考链接:
1.How to pin an app without a dialog android
2.HOW TO TURN YOUR ANDROID APPLICATION INTO A KIOSK
3.Android Kiosk Mode Without Root
4.DeviceAdmin简单实践

#文章做折腾过程记录,不对任何变砖与异常负责