又是用户的需求,实现Kiosk模式,让设备只运行他想要的程序。之前做过一种是自动隐藏底部所有按键,可以看我之前的博客隐藏底部按键
但是这种方式还是有缺陷,虽然也能实现想要的模式,总感觉,很不满意。这次想要实现Android原本就有的Kiosk模式。
在Android中有两种模式对我们非常有用
DeviceAdmin设备管理
当然还有一种模式ProfileOwner(配置文件所有者),这种模式看了一下资料说国内不好用,暂时不管,因为今天讲的也用不上。
先说设备管理模式
Android 2.2通过提供Android设备管理API引入了对企业应用程序的支持。设备管理API提供了系统级的设备管理功能。这些api允许您创建安全感知的应用程序,这些应用程序在企业设置中非常有用,在企业设置中,IT专业人员需要对员工设备进行丰富的控制。例如,内置的Android电子邮件应用程序利用了新的api来改进Exchange支持。通过电子邮件应用程序,Exchange管理员可以跨设备强制执行密码策略——包括字母数字密码或数字pin。管理员还可以远程擦除(即恢复出厂默认值)丢失或被盗的手机。Exchange用户可以同步他们的电子邮件和日历数据。 ——来自有道翻译官方Android文档。哈哈哈哈哈哈哈
代码实现如下
在AndroidManifest.xml文件中添加
上面的receiver的name就是我们要创建的类名
public class AdminReceiver extends DeviceAdminReceiver {
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
LogUtil.d("设备管理=onReceive");
}
@Override
public CharSequence onDisableRequested(Context context, Intent intent) {
LogUtil.d("设备管理=onDisableRequested");
return super.onDisableRequested(context, intent);
}
@Override
public void onDisabled(Context context, Intent intent) {
super.onDisabled(context, intent);
LogUtil.d("设备管理=onDisabled");
}
@Override
public void onEnabled(Context context, Intent intent) {
super.onEnabled(context, intent);
LogUtil.d("设备管理=onEnabled");
//可以在此处进行跳转,但是不好处理其他的逻辑,暂时保留,后面会说其他跳转
Intent itn = new Intent(context,
MainActivity.class);
itn.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(itn);
}
}
其中还有一个xml文件,声明元数据中使用的安全策略。元数据提供特定于设备管理员的附加信息,由DeviceAdminInfo类解析
device_admin示例:
当然你也可以创建一个空的
好了,需要的文件已经准备好了,现在是开始触发该模式的方式了
先通过代码判断我们的包名app是否已经处在设备管理者模式状态下
private DevicePolicyManager dpm;
private ComponentName componentName;
dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
componentName = new ComponentName(context, AdminReceiver.class);
dpm.isAdminActive(componentName);//判断是否已经是设备管理者模式了,返回boolean。
当我们进入闪屏页时,进行判断。
if(isAdminActive()){ startMain();//跳转主页面的逻辑 }else { satrtOpenDevicer();//主动询问设备管理者权限的逻辑 }
public void satrtOpenDevicer() {
ComponentName componentName = new ComponentName(this, AdminReceiver.class);
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "请求设备管理权限...");
/*
* 不能直接startActivity 因为可能在激活的时候用户点击了取消,这时候CheckBox状态是勾选的,但是实际是没激活的,
*/
startActivityForResult(intent, DEVICECOMPONENTCODE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.e("jsb_kiosk","结果"+requestCode);
if(requestCode == DEVICECOMPONENTCODE){
startMain();
}
}
这个时候当我们处于没有设备管理权限时进入app都会进行询问权限,界面如下:
好了处于设备模式后,就该处理DeviceOwner设备所有者
在这里查看大神写的比较完整的介绍
Android 提供了比较完善的设备所有者api,但是我发现调用的那些api效果完全没有作用,
ComponentName deviceAdmin = new ComponentName(this, AdminReceiver.class);
mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
if (!mDpm.isAdminActive(deviceAdmin)) {
Toast.makeText(this, "没有设备管理权限", Toast.LENGTH_SHORT).show();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mDpm.isDeviceOwnerApp(getPackageName())) {
mDpm.setLockTaskPackages(deviceAdmin, new String[]{getPackageName()});
} else {
Log.i("jsb_","没有专属模式");
}
}
上面代码没有效果。我们通过mDpm.isDeviceOwnerApp去判断当前是否处于设备所有者的是没有效果的。
但是通过adb shell处理设备确实可以进入Kiosk模式,
命令adb shell dpm set-device-owner 包名/包名.
AdminReceiver (跟你创建的AdminReceiver地址一样)设置DeviceOwner;
命令adb shell dpm remove-active-admin 包名/包名.
AdminReceiver 退出DeviceOwner;
那么我们只要通过代码实现该操作命令就可以了
private void execShell(String cmd){
try{
java.lang.Process p = Runtime.getRuntime().exec("sh");
OutputStream outputStream = p.getOutputStream();
DataOutputStream dataOutputStream=new DataOutputStream(outputStream);
dataOutputStream.writeBytes(cmd);
dataOutputStream.flush();
dataOutputStream.close();
outputStream.close();
} catch(Throwable t) {
t.printStackTrace();
}
}
调用:
execShell("adb shell dpm set-device-owner "+getPackageName()+"/"+AdminReceiver.class.getName());
至于在什么时候调用该命令,就看个人需要,我是在闪屏页获取设备管理者后直接调用的
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.e("jsb_kiosk","结果"+requestCode);
if(requestCode == DEVICECOMPONENTCODE){
execShell("adb shell dpm set-device-owner "+getPackageName()+"/"+AdminReceiver.class.getName());
startMain();
}
}
好了通过上面的操作,我们已经完全进入DeviceOwner设备所有者模式了
但是并没有完事,还差最后一步,真正的完成Kiosk模式
调用下面方法
private void enableKioskMode(boolean enabled) {
try {
if (enabled) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mDpm.isLockTaskPermitted(this.getPackageName())) {
startLockTask();
mIsKioskEnabled = true;
} else {
//没有进入该模式,没有权限
}
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
stopLockTask();
}
mIsKioskEnabled = false;
}
} catch (Exception e) {
// TODO: Log and handle appropriately
}
}
最后看效果吧
点击进入改模式
ok,感觉很不错~~今天就到这里了,有空我上传一下demo,下班了。