我们的云帆机器人(上面运行的安卓程序)有一个线下场景是商场,由于商场人多,总会遇到一些用户在我们的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模式的更多相关文章

  1. Android上实现MVP模式的途径

    今天我想分享我在Android上实现MVP(Model-View-Presenter)模式的方法.如果你对MVP模式还不熟悉,或者不了解为什么要在Android应用中使用MVP模式,推荐你先阅读这篇维 ...

  2. [手机取证] 绕过屏幕锁定启用调试模式-For Android 4.4.2

    Google在Android 4.x中引入了调试信任机制,类似于iOS,在设备有屏幕密码的情况下首次连接(或未记住计算机)的情况下, 需要首先打开屏幕锁定后才可进行调试启用操作. 在Android 4 ...

  3. Android真机测试、乐视手机启用开发者模式

    一.乐视手机启用开发者模式 1.进入 设置>关于手机,连续按5次,进入开发者模式 显示结果如下: 2.启用开发者模式,并且要启用USB调试 3.在VS中部署或调试Android引用,使用真机测试 ...

  4. 如何调试 Android 上 HTTP(S) 流量

    http://greenrobot.me/devpost/how-to-debug-http-and-https-traffic-on-android/ 如何调试 Android 上 HTTP(S) ...

  5. 在Android上使用qemu-user运行可执行文件

    在Android上使用qemu-user运行可执行文件 作者:寻禹@阿里聚安全 前言 QEMU简要介绍: QEMU可以解释执行可执行程序.既然QEMU可以解释执行可执行程序,那么QEMU就能够知道执行 ...

  6. 《C#微信开发系列(1)-启用开发者模式》

    1.0启用开发者模式 ①填写服务器配置 启用开发模式需要先成为开发者,而且编辑模式和开发模式只能选择一个(进入微信公众平台=>开发=>基本配置)就可以看到以下的界面: 点击修改配置,会出现 ...

  7. Android上的MVP:如何组织显示层的内容

    MVP(Model View Presenter)模式是著名的MVC(Model View Controller)模式的一个演化版本,目前它在Android应用开发中越来越重要了,大家也都在讨论关于M ...

  8. ZT 理解 Android 上的安全性

    理解 Android 上的安全性 http://www.ibm.com/developerworks/cn/xml/x-androidsecurity/ 利用沙箱.应用程序签名和权限增强应用程序安全性 ...

  9. 【转】Android 当打开“开发者模式”中的“不保留活动”后,程序应当怎么保持正常运行

    当打开这个设置以后,程序的Activity会自动销毁,每次返回的时候就会不断重oncreate,此时伴随的问题多多. 参考文档:http://www.bubuko.com/infodetail-960 ...

随机推荐

  1. POJ 1631 Bridging signals (LIS:最长上升子序列)

    题意:给你一个长为n(n<=40000)的整数序列, 要你求出该序列的最长上升子序列LIS. 思路:要求(nlogn)解法 令g[i]==x表示当前遍历到的长度为i的所有最长上升子序列中的最小序 ...

  2. hihocoder 1341 Constraint Checker【string】

    hihocoder 1341 解释:这道题题目还是比较容易理解,就是根据输入的若干个不等式,校验后面输入的数据是否都满足前面的不等式,满足就输出Yes,只要有一个不满足就输出No.如“A<B&l ...

  3. 6-8 树 uva548

    read 的方式值得学习 当不知道每一行有多少个输入的时候 getline  在弄成stringstream!一个一个处理 用built递归的方式化大为小进行建立树 dfs 遍历整个树来求最值 变量的 ...

  4. 用户设置与virtual host配置

    1.进入localhost:15672yemian 然后选择Admin菜单. 2.添加用户 caojun/123456 3.效果 4.virtual hosts添加 相当于db. /cjhost,一般 ...

  5. 汇编之 eax, ebx, ecx, edx, esi, edi, ebp, esp??

    一般寄存器:AX.BX.CX.DXAX:累积暂存器,BX:基底暂存器,CX:计数暂存器,DX:资料暂存器 索引暂存器:SI.DISI:来源索引暂存器,DI:目的索引暂存器 堆叠.基底暂存器:SP.BP ...

  6. ModuleNotFoundError: No module named 'win32api'

    原因:缺少了win32解决: pip install pypiwin32

  7. python连接mysql、sqlserver、oracle、postgresql数据库的一些封装

    包括python连接数据库,以及django下配置连接数据库 # -*- coding:utf-8 -*- import psycopg2 import pymysql import pymssql ...

  8. angular中使用代理

    使用代理 1.在跟目录创建proxy.config.json文件 { "/api": { "target": "http://localhost:30 ...

  9. codeforces-1114F-线段树练习

    https://www.cnblogs.com/31415926535x/p/10391639.html 概述 这是一道用线段树维区间值的一道题,,题意很简单,,就是对于给定的一个序列,,初始时每个数 ...

  10. TFT LCD显示原理详解

    <什么是液晶> 我们一般认为物体有三态:固态.液态.气态,其实这只是针对水而言,有一些有机化和物 还有介于固态和液态中间的状态 就是液晶态,如下图(一):                 ...