在Android上启用Kiosk模式
我们的云帆机器人(上面运行的安卓程序)有一个线下场景是商场,由于商场人多,总会遇到一些用户在我们的app里乱点,然后会跳出程序进入到系统设置的一些界面,这样很不友好。
比如程序中有一些需要输入文字的地方,弹出了输入法,有的用户就去故意点输入法的设置,结果就能进入到安卓的系统设置,商场的用户用的是我们机器人程序而不是手机,并且机器人上本来就屏蔽了多任务和返回等虚拟按键,结果无法返回原来的程序。
一种解决方式是自己在程序里去实现一个中文的输入法,但这代价也太大了。
另外一种方式就是使用安卓的Kiosk模式。这个模式直译的话是贩售亭,但实际上的意思是屏幕固定功能,也就是我们想要将用户看到的屏幕固定到我们的app中的意思。
介绍url https://www.sureshjoshi.com/mobile/android-kiosk-mode-without-root/
源码展示区:https://github.com/sureshjoshi/android-kiosk-example
中文介绍 https://juejin.im/entry/578f873dd342d30058e99c51
只看代码可能不太明白,于是我对着代码自己重新写了一个demo。其中遇到的问题如下:
1.写好了后运行代码,并不能锁住,主要原因是没有admin的权限,这个需要到设置--系统安全--设备管理 中找到这个程序并选中才可以。
2.另外就是有了admin权限后还是不能锁定,debug后发现是判断isDeviceOwnerApp的时候为false,这个是因为一个系统只能有一个OwnerApp,需要使用adb命令设置对应的recevier。命令是:
adb shell dpm set-device-owner com.honghe.screenlocktest/.AdminReceiver
3.注意这个功能只能安卓5.1之后可用
代码如下
MainActivity
package com.honghe.screenlocktest; import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View; import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader; @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getName();
private DevicePolicyManager dpm;
private boolean inKioskMode;
private ComponentName deviceAdmin;
private Process process = null;
private DataOutputStream os = null; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
lockScreen();
}
});
findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dislockScreen();
}
});
} private boolean doLockScreen() {
if (dpm.isLockTaskPermitted(this.getPackageName())) {
Log.i("yunji.HotelAPP", "start lock screen");
startLockTask();
inKioskMode = true;
Log.i("yunji.HotelAPP", "lock screen success");
return true;
}
Log.w("yunji.HotelAPP", "cannot lock screen");
return false;
} private void lockScreen() {
try {
if (!inKioskMode) {
dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
deviceAdmin = new ComponentName(this, AdminReceiver.class);
Log.e(TAG, "isAdminActive: " + dpm.isAdminActive(deviceAdmin) + "\tisDeviceOwnerApp: " + dpm.isDeviceOwnerApp(getPackageName()));
if (dpm.isDeviceOwnerApp(getPackageName())) {
//如果这里失效,请使用adb shell命令设置deviceOwnerAPP为当前app $ adb shell dpm set-device-owner com.honghe.screenlocktest/.AdminReceiver
//参考 https://juejin.im/entry/578f873dd342d30058e99c51
dpm.setLockTaskPackages(deviceAdmin,
new String[]{getPackageName()});
Log.e(TAG, "setLockTaskPackages: ");
}
doLockScreen();
}
} catch (Exception e) {
Log.e("yunji.HotelAPP", "Exception: " + e);
}
} private void dislockScreen() { try {
if (inKioskMode) {
stopLockTask();
inKioskMode = false;
}
} catch (Exception e) {
Log.e("yunji.HotelAPP", "Exception: " + e);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" /> <Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="锁定" /> <Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="解锁" /> <EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:text="Name" /> </LinearLayout>
AdminReceiver.java
package com.honghe.screenlocktest;
import android.app.admin.DeviceAdminReceiver;
import android.content.Context;
import android.content.Intent; /**
* Created by zkzhou on 7/15/16.
*/
public class AdminReceiver extends DeviceAdminReceiver {
@Override
public void onEnabled(Context context, Intent intent) {
} @Override
public CharSequence onDisableRequested(Context context, Intent intent) {
return "Warning: Device Admin is going to be disabled.";
} @Override
public void onDisabled(Context context, Intent intent) {
} @Override
public void onLockTaskModeEntering(Context context, Intent intent,
String pkg) {
} @Override
public void onLockTaskModeExiting(Context context, Intent intent) {
}
}
androidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.honghe.screenlocktest"> <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".AdminReceiver"
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>
</application> </manifest>
xml/device_admin.xml
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<force-lock/>
<watch-login/>
<disable-camera/>
<disable-keyguard-features/>
<encrypted-storage/>
<expire-password/>
<limit-password/>
<reset-password/>
<set-global-proxy/>
<wipe-data/>
</uses-policies>
</device-admin>
在Android上启用Kiosk模式的更多相关文章
- Android上实现MVP模式的途径
今天我想分享我在Android上实现MVP(Model-View-Presenter)模式的方法.如果你对MVP模式还不熟悉,或者不了解为什么要在Android应用中使用MVP模式,推荐你先阅读这篇维 ...
- [手机取证] 绕过屏幕锁定启用调试模式-For Android 4.4.2
Google在Android 4.x中引入了调试信任机制,类似于iOS,在设备有屏幕密码的情况下首次连接(或未记住计算机)的情况下, 需要首先打开屏幕锁定后才可进行调试启用操作. 在Android 4 ...
- Android真机测试、乐视手机启用开发者模式
一.乐视手机启用开发者模式 1.进入 设置>关于手机,连续按5次,进入开发者模式 显示结果如下: 2.启用开发者模式,并且要启用USB调试 3.在VS中部署或调试Android引用,使用真机测试 ...
- 如何调试 Android 上 HTTP(S) 流量
http://greenrobot.me/devpost/how-to-debug-http-and-https-traffic-on-android/ 如何调试 Android 上 HTTP(S) ...
- 在Android上使用qemu-user运行可执行文件
在Android上使用qemu-user运行可执行文件 作者:寻禹@阿里聚安全 前言 QEMU简要介绍: QEMU可以解释执行可执行程序.既然QEMU可以解释执行可执行程序,那么QEMU就能够知道执行 ...
- 《C#微信开发系列(1)-启用开发者模式》
1.0启用开发者模式 ①填写服务器配置 启用开发模式需要先成为开发者,而且编辑模式和开发模式只能选择一个(进入微信公众平台=>开发=>基本配置)就可以看到以下的界面: 点击修改配置,会出现 ...
- Android上的MVP:如何组织显示层的内容
MVP(Model View Presenter)模式是著名的MVC(Model View Controller)模式的一个演化版本,目前它在Android应用开发中越来越重要了,大家也都在讨论关于M ...
- ZT 理解 Android 上的安全性
理解 Android 上的安全性 http://www.ibm.com/developerworks/cn/xml/x-androidsecurity/ 利用沙箱.应用程序签名和权限增强应用程序安全性 ...
- 【转】Android 当打开“开发者模式”中的“不保留活动”后,程序应当怎么保持正常运行
当打开这个设置以后,程序的Activity会自动销毁,每次返回的时候就会不断重oncreate,此时伴随的问题多多. 参考文档:http://www.bubuko.com/infodetail-960 ...
随机推荐
- 在django中使用FormView,success_url死活不能生效的问题
真的不知道是怎么回事, 以前都是手动的, form使用modelform. view使用createview. 今天写新系统时,为了更灵活. form使用form,(这样一来,可以在form是随便按数 ...
- webpack 使用环境变量
要在开发和生产构建之间,消除 webpack.config.js 的差异.你可能需要环境变量. 可以使用 Node.js 模块的标准方式:在运行 webpack 时设置环境变量,并且使用 Node.j ...
- requirejs模块路径配置问题
三种情况:一.设置data-main,没配置baseUrl,以data-main的文件为基准:二.设置data-main,配置baseUrl,baseUrl以值以引用require.js的HTML为基 ...
- PDA智能程序访问WebService,报告“未能建立与网络的连接”
其实就是你没又连接上网络.首先下个第三方软件关于vs模拟器连接的.然后根据以下说明操作就可以连接了在确保主机已连上互联网的情况下,按以下步骤设置: 1.打开ActiveSync ,点击“文件”——&g ...
- 自适应阈值二值化之最大类间方差法(大津法,OTSU)
最大类间方差法是由日本学者大津(Nobuyuki Otsu)于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU.它是按图像的灰度特性,将图像分成背景和目标2部分.背景和目标之间 ...
- linux 重要笔记
nginx 服务器重启命令,关闭 nginx -s reload :修改配置后重新加载生效 nginx -s reopen :重新打开日志文件nginx -t -c /path/to/ngin ...
- update date and keep time
select TO_CHAR((date '2010-01-02' + (sysdate-trunc(sysdate))),'YYYY-MM-DD HH:mi:ss') from dual;
- 为什么要使用getter/setter
变量私有化的好处 1. 在setter中可以加入合法性检查,比如设置颜色的函数中,对于RGB颜色要判断其值在0~255之间. 2. 更新与被设置变量相关的其它变量的值,比如在一个潜水艇模拟系统中,改变 ...
- es6的解构赋值用途
(1)交换变量的值 let x = 1; let y = 2; [x, y] = [y, x]; 上面代码交换变量x和y的值,这样的写法不仅简洁,而且易读,语义非常清晰. (2)从函数返回多个值 函数 ...
- loj#2054. 「TJOI / HEOI2016」树
题目链接 loj#2054. 「TJOI / HEOI2016」树 题解 每次标记覆盖整棵字数,子树维护对于标记深度取max dfs序+线段树维护一下 代码 #include<cstdio> ...