我们的云帆机器人(上面运行的安卓程序)有一个线下场景是商场,由于商场人多,总会遇到一些用户在我们的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 3259 Wormholes(bellman_ford,判断有没有负环回路)

    题意:John的农场里field块地,path条路连接两块地,hole个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts.我们的任务是知道会不会在从某块地出发后又回来,看到了离开之前 ...

  2. POJ 3280 Cheapest Palindrome【DP】

    题意:对一个字符串进行插入删除等操作使其变成一个回文串,但是对于每个字符的操作消耗是不同的.求最小消耗. 思路: 我们定义dp [ i ] [ j ] 为区间 i 到 j 变成回文的最小代价.那么对于 ...

  3. [转]ubuntu安装skype

    Skype 4.3 Released, How to Install it in Ubuntu 14.04/12.04 June 19, 2014 — 107 Comments   Skype for ...

  4. MySQL_join连接

    join连接 table1: table2: 笛卡尔积: 就是一个表里的记录要分别和另外一个表的记录匹配为一条记录,即如果表A有2条记录,表B也有2条记录,经过笛卡尔运算之后就应该有2*2即4条记录. ...

  5. GitHub安装教程

    第一步是安装两个软件 安装 git for windows这个是一个git的windows系统的命令行版本https://git-scm.com/downloads或者https://pan.baid ...

  6. 《Android进阶之光》--事件总线

    No1: EventBus三要素: 1)Event:事件 2)Subscriber:事件订阅者 3)Publisher:事件发布者 No2: EventBus的4种ThreadMode(线程模型): ...

  7. UVA 10976 分数拆分【暴力】

    题目链接:https://vjudge.net/contest/210334#problem/C 题目大意: It is easy to see that for every fraction in ...

  8. 001.Open-Falcon简介

    一 Open-Falcon简介 监控系统是整个运维环节,乃至整个产品生命周期中最重要的一环,事前及时预警发现故障,事后提供翔实的数据用于追查定位问题.监控系统作为一个成熟的运维产品,相对成熟的解决方案 ...

  9. C# JSON帮助类(可互转)

    public class JsonHelper { public JsonHelper() { // // TODO: Add constructor logic here // } /// < ...

  10. 在webpack中使用postcss之插件包precss

    precss是一个预处理css的插件包,集成了很多postcss插件的功能,比如嵌套,变量,继承,混合,循环,判断.下面来介绍如何在webpack中使用precss.一.新建项目1.新建package ...