在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

 1 package com.honghe.screenlocktest;
 2 
 3 import android.app.admin.DevicePolicyManager;
 4 import android.content.ComponentName;
 5 import android.content.Context;
 6 import android.os.Build;
 7 import android.support.annotation.RequiresApi;
 8 import android.support.v7.app.AppCompatActivity;
 9 import android.os.Bundle;
10 import android.util.Log;
11 import android.view.View;
12 
13 import java.io.BufferedReader;
14 import java.io.DataOutputStream;
15 import java.io.InputStream;
16 import java.io.InputStreamReader;
17 
18 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
19 public class MainActivity extends AppCompatActivity {
20     private static final String TAG = MainActivity.class.getName();
21     private DevicePolicyManager dpm;
22     private boolean inKioskMode;
23     private ComponentName deviceAdmin;
24     private Process process = null;
25     private DataOutputStream os = null;
26 
27     @Override
28     protected void onCreate(Bundle savedInstanceState) {
29         super.onCreate(savedInstanceState);
30         setContentView(R.layout.activity_main);
31         findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
32             @Override
33             public void onClick(View v) {
34                 lockScreen();
35             }
36         });
37         findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
38             @Override
39             public void onClick(View v) {
40                 dislockScreen();
41             }
42         });
43     }
44 
45 
46     private boolean doLockScreen() {
47         if (dpm.isLockTaskPermitted(this.getPackageName())) {
48             Log.i("yunji.HotelAPP", "start lock screen");
49             startLockTask();
50             inKioskMode = true;
51             Log.i("yunji.HotelAPP", "lock screen success");
52             return true;
53         }
54         Log.w("yunji.HotelAPP", "cannot lock screen");
55         return false;
56     }
57 
58     private void lockScreen() {
59         try {
60             if (!inKioskMode) {
61                 dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
62                 deviceAdmin = new ComponentName(this, AdminReceiver.class);
63                 Log.e(TAG, "isAdminActive: " + dpm.isAdminActive(deviceAdmin) + "\tisDeviceOwnerApp: " + dpm.isDeviceOwnerApp(getPackageName()));
64                 if (dpm.isDeviceOwnerApp(getPackageName())) {
65                     //如果這里失效,請使用adb shell命令設置deviceOwnerAPP為當前app $ adb shell dpm set-device-owner com.honghe.screenlocktest/.AdminReceiver
66                     //參考 https://juejin.im/entry/578f873dd342d30058e99c51
67                     dpm.setLockTaskPackages(deviceAdmin,
68                             new String[]{getPackageName()});
69                     Log.e(TAG, "setLockTaskPackages: ");
70                 }
71                 doLockScreen();
72             }
73         } catch (Exception e) {
74             Log.e("yunji.HotelAPP", "Exception: " + e);
75         }
76     }
77 
78     private void dislockScreen() {
79 
80         try {
81             if (inKioskMode) {
82                 stopLockTask();
83                 inKioskMode = false;
84             }
85         } catch (Exception e) {
86             Log.e("yunji.HotelAPP", "Exception: " + e);
87         }
88     }
89 }

activity_main.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     android:orientation="vertical"
 8     tools:context=".MainActivity">
 9 
10     <TextView
11         android:layout_width="wrap_content"
12         android:layout_height="wrap_content"
13         android:text="Hello World!"
14         app:layout_constraintBottom_toBottomOf="parent"
15         app:layout_constraintLeft_toLeftOf="parent"
16         app:layout_constraintRight_toRightOf="parent"
17         app:layout_constraintTop_toTopOf="parent" />
18 
19     <Button
20         android:id="@+id/button"
21         android:layout_width="wrap_content"
22         android:layout_height="wrap_content"
23         android:text="鎖定" />
24 
25     <Button
26         android:id="@+id/button2"
27         android:layout_width="wrap_content"
28         android:layout_height="wrap_content"
29         android:text="解鎖" />
30 
31     <EditText
32         android:id="@+id/editText"
33         android:layout_width="match_parent"
34         android:layout_height="wrap_content"
35         android:ems="10"
36         android:inputType="textPersonName"
37         android:text="Name" />
38 
39 </LinearLayout>

 

 

AdminReceiver.java

 1 package com.honghe.screenlocktest;
 2 import android.app.admin.DeviceAdminReceiver;
 3 import android.content.Context;
 4 import android.content.Intent;
 5 
 6 
 7 /**
 8  * Created by zkzhou on 7/15/16.
 9  */
10 public class AdminReceiver extends DeviceAdminReceiver {
11     @Override
12     public void onEnabled(Context context, Intent intent) {
13     }
14 
15     @Override
16     public CharSequence onDisableRequested(Context context, Intent intent) {
17         return "Warning: Device Admin is going to be disabled.";
18     }
19 
20     @Override
21     public void onDisabled(Context context, Intent intent) {
22     }
23 
24     @Override
25     public void onLockTaskModeEntering(Context context, Intent intent,
26                                        String pkg) {
27     }
28 
29     @Override
30     public void onLockTaskModeExiting(Context context, Intent intent) {
31     }
32 }

androidManifest.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3     package="com.honghe.screenlocktest">
 4 
 5     <application
 6         android:allowBackup="true"
 7         android:icon="@mipmap/ic_launcher"
 8         android:label="@string/app_name"
 9         android:roundIcon="@mipmap/ic_launcher_round"
10         android:supportsRtl="true"
11         android:theme="@style/AppTheme">
12         <activity android:name=".MainActivity">
13             <intent-filter>
14                 <action android:name="android.intent.action.MAIN" />
15 
16                 <category android:name="android.intent.category.LAUNCHER" />
17             </intent-filter>
18         </activity>
19         <receiver
20             android:name=".AdminReceiver"
21             android:label="@string/app_name"
22             android:permission="android.permission.BIND_DEVICE_ADMIN">
23             <meta-data
24                 android:name="android.app.device_admin"
25                 android:resource="@xml/device_admin" />
26 
27             <intent-filter>
28                 <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
29             </intent-filter>
30         </receiver>
31     </application>
32 
33 
34 </manifest>

xml/device_admin.xml

 1 <device-admin xmlns:android="http://schemas.android.com/apk/res/android">
 2     <uses-policies>
 3         <force-lock/>
 4         <watch-login/>
 5         <disable-camera/>
 6         <disable-keyguard-features/>
 7         <encrypted-storage/>
 8         <expire-password/>
 9         <limit-password/>
10         <reset-password/>
11         <set-global-proxy/>
12         <wipe-data/>
13     </uses-policies>
14 </device-admin>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM