Android 中的自助服务终端模式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2068084/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Kiosk mode in Android
提问by Erik
I'm in the process of evaluating if and how a CF .NET enterprise application can be ported to run on Android devices. The application on Windows Mobile phones are run in kiosk mode where the application autostart in fullscreen-mode after booting and with the users unable to accidentally or willingly access any other parts of the phone.
我正在评估是否以及如何将 CF .NET 企业应用程序移植到 Android 设备上运行。Windows Mobile 手机上的应用程序在自助服务终端模式下运行,该应用程序在启动后以全屏模式自动启动,用户无法意外或自愿访问手机的任何其他部分。
Is it possible on Android to have only one application autostart after booting and prevent users from accidentally (or willingly) access any other parts of the Android device?
在 Android 上是否有可能在启动后只有一个应用程序自动启动并防止用户意外(或自愿)访问 Android 设备的任何其他部分?
采纳答案by Valentin
You can autostart applications on boot by listening to the android.intent.action.BOOT_COMPLETED
intent in a BroadcastReceiver and start your Activity from there. In the Activity you can register yourself as the new default homescreen[1] and handle the keys.
您可以通过侦听android.intent.action.BOOT_COMPLETED
BroadcastReceiver 中的意图在启动时自动启动应用程序,并从那里启动您的 Activity。在活动中,您可以将自己注册为新的默认主屏幕 [1] 并处理按键。
I think there are some instances that you can't handle without modifying the framework (like longpress on Home to show currently active Applications) - I could also be mistaken though.
我认为有些情况如果不修改框架就无法处理(例如在主页上长按以显示当前活动的应用程序) - 不过我也可能会误会。
But for a prototype that could be sufficient.
但是对于一个可能就足够了的原型。
Have fun tinkering!
玩得开心!
[1]:
[1]:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
回答by rbot
You could customise this (disable access to menu, limit application addition etc) to enable kiosk. http://code.google.com/p/android-launcher-plus/
您可以自定义此功能(禁用对菜单的访问、限制应用程序添加等)以启用信息亭。http://code.google.com/p/android-launcher-plus/
回答by nhaarman
In the new Android L Preview, Google has announced Task Locking, which does exactly that. It does seem to need root however.
在新的 Android L 预览版中,谷歌宣布了任务锁定,它正是这样做的。然而,它似乎确实需要root。
The L Developer Preview introduces a new task locking API that lets you temporarily restrict users from leaving your app or being interrupted by notifications. This could be used, for example, if you are developing an education app to support high stakes assessment requirements on Android. Once your app activates this mode, users will not be able to see notifications, access other apps, or return to the Home screen, until your app exits the mode.
To prevent unauthorized usage, only authorized apps can activate task locking. Furthermore, task locking authorization must be granted by a specially-configured device owner app, through the
android.app.admin.DevicePolicyManager.setLockTaskComponents()
method.To set up a device owner, follow these steps:
- Attach a device running an Android
userdebug
build to your development machine.- Install your device owner app.
- Create a
device_owner.xml
file and save it to the/data/system
directory on the device.
L Developer Preview 引入了一个新的任务锁定 API,可让您暂时限制用户离开您的应用程序或被通知中断。例如,如果您正在开发教育应用程序以支持 Android 上的高风险评估要求,则可以使用此方法。一旦您的应用激活此模式,用户将无法查看通知、访问其他应用或返回主屏幕,直到您的应用退出该模式。
为了防止未经授权的使用,只有授权的应用程序才能激活任务锁定。此外,任务锁定授权必须由专门配置的设备所有者应用程序通过该
android.app.admin.DevicePolicyManager.setLockTaskComponents()
方法授予 。要设置设备所有者,请按以下步骤操作:
- 将运行 Android
userdebug
版本的设备连接到您的开发机器。- 安装您的设备所有者应用程序。
- 创建一个
device_owner.xml
文件并将其保存到/data/system
设备上的目录中。
$ adb root
$ adb shell stop
$ rm /tmp/device_owner.xml
$ echo "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>" >> /tmp/device_owner.xml
$ echo "&device-owner package=\"<your_device_owner_package>\" name=\"*<your_organization_name>\" />" >> /tmp/device_owner.xml
$ adb push /tmp/device_owner.xml /data/system/device_owner.xml
$ adb reboot
Before using the task locking API in your app, verify that your activity is authorized by calling DevicePolicyManager.isLockTaskPermitted().
To activate task locking, call
android.app.Activity.startLockTask()
from your authorized activity.When task locking is active, the following behavior takes effect:
- The status bar is blank, and user notifications and status information is hidden.
- The Home and Recent Apps buttons are hidden.
- Other apps may not launch new activities.
- The current app may start new activities, as long as doing so does not create new tasks.
- The user remains locked on your app until an authorized activity calls
Activity.stopLockTask()
.
在您的应用程序中使用任务锁定 API 之前,请通过调用 DevicePolicyManager.isLockTaskPermitted() 验证您的活动是否已获得授权。
要激活任务锁定,请
android.app.Activity.startLockTask()
从您的授权活动中调用。当任务锁定处于活动状态时,以下行为生效:
- 状态栏为空白,隐藏用户通知和状态信息。
- “主页”和“最近使用的应用程序”按钮被隐藏。
- 其他应用可能不会启动新活动。
- 当前应用程序可能会启动新活动,只要这样做不会创建新任务。
- 用户在您的应用程序上保持锁定状态,直到授权活动调用
Activity.stopLockTask()
。
回答by matt_lethargic
After searching for this for a while I've come up with a good solution. This only works on rooted devices though, but I guess if it's just for this one app then rooting it shouldn't be a problem.
在搜索了一段时间后,我想出了一个很好的解决方案。虽然这只适用于有根的设备,但我想如果它只是为了这个应用程序,那么生根它应该不是问题。
Make your application the launcher by adding
<category android:name="android.intent.category.HOME" />
to your intent-filter
Make sure your app collapses the toolbar so you cannot reach the notification bar see How to disable status bar / notification bar on android programmatically?or http://blog.vogella.com/2011/02/28/android-hidding-the-status-and-title-bar/
Then to stop any other programs from opening by mistake use an Accessibility Service to check for Window State Changed, compare the package to a white or black list and use ActivityManager.killBackgroundProcesses to kill if it shouldn't run.
通过添加使您的应用程序成为启动器
<category android:name="android.intent.category.HOME" />
到你的意图过滤器
确保您的应用折叠工具栏,以便您无法到达通知栏,请参阅如何以编程方式禁用 android 上的状态栏/通知栏?或http://blog.vogella.com/2011/02/28/android-hidding-the-status-and-title-bar/
然后要阻止任何其他程序错误地打开,请使用辅助功能服务来检查窗口状态已更改,将包与白名单或黑名单进行比较,如果它不应该运行,则使用 ActivityManager.killBackgroundProcesses 将其杀死。
Also check out http://thebitplague.wordpress.com/2013/04/05/kiosk-mode-on-the-nexus-7/for another way
另请查看http://thebitplague.wordpress.com/2013/04/05/kiosk-mode-on-the-nexus-7/以获取另一种方式
回答by nonsensei
Starting your app on boot
在启动时启动您的应用程序
the BEST way to accomplish this is setting your app as the launcher
实现此目的的最佳方法是将您的应用设置为启动器
<activity ...
android:launchMode="singleInstance"
android:windowActionBar="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Locking your app
锁定您的应用
the most reliable way is to use a device with Lollipop or greater and make use of
最可靠的方法是使用 Lollipop 或更高版本的设备并利用
startLockTask
first you must set your app as the device owner. NB your device must be unprovisioned: if you registered it you should do a factory reset and skip the account registration.
首先,您必须将您的应用设置为设备所有者。注意你的设备必须是未配置的:如果你注册了它,你应该恢复出厂设置并跳过帐户注册。
to be able to register your app you must first setup a DeviceAdminReceiver component:
为了能够注册您的应用程序,您必须首先设置一个 DeviceAdminReceiver 组件:
package com.example.myapp;
public class MyDeviceAdminReceiver extends android.app.admin.DeviceAdminReceiver {
@Override
public void onEnabled(Context context, Intent intent) {
Toast.makeText(context, "Device admin permission received", Toast.LENGTH_SHORT).show();
}
@Override
public CharSequence onDisableRequested(Context context, Intent intent) {
return "are you sure?";
}
@Override
public void onDisabled(Context context, Intent intent) {
Toast.makeText(context, "Device admin permission revoked", Toast.LENGTH_SHORT).show();
}
@Override
public void onLockTaskModeExiting(Context context, Intent intent) {
// here you must re-lock your app. make your activity know of this event and make it call startLockTask again!
}
}
once you have an unprovisioned device you can launch the following command from adb (no root required)
一旦你有一个未配置的设备,你可以从 adb 启动以下命令(不需要 root)
adb shell dpm set-device-owner com.example.myapp/.MyDeviceAdminReceiver
to avoid android asking the user permissions to pin your app you must call setLockTaskPackages
为避免 android 要求用户权限来固定您的应用程序,您必须调用 setLockTaskPackages
finally!
最后!
@Override
public void onResume(){
super.onResume();
DevicePolicyManager mDevicePolicyManager = (DevicePolicyManager) getSystemService(
Context.DEVICE_POLICY_SERVICE);
ComponentName mAdminComponentName = new ComponentName(getApplicationContext(), MyDeviceAdminReceiver.class);
mDevicePolicyManager.setLockTaskPackages(mAdminComponentName, new String[]{getPackageName()});
startLockTask();
}
@Override
public void finish(){
stopLockTask();
super.finish();
}
回答by Fred
Google recently released the Android Management APIwhich allows to easily set up kiosk mode for any Android devices running Android 5.1 or above, and also to set various other policies.
Google 最近发布了Android Management API,它允许为运行 Android 5.1 或更高版本的任何 Android 设备轻松设置信息亭模式,并设置各种其他策略。
回答by Keyur
Set up Single-Purpose Devices Pageof android developer have described this things you can easily get to know more things from there.
设置单用途设备android 开发人员页面已经描述了这些事情,您可以从那里轻松了解更多信息。
Now it is easy to configure Android 6.0 Marshmallow and laterdevices as corporate-owned, single-use (COSU) devices.
现在可以轻松地将Android 6.0 Marshmallow 及更高版本的设备配置为企业拥有的一次性 (COSU) 设备。
回答by JohnyTex
Xposed frameworkcan do this. It needs root and there is a possibility that it won't work on every and all platforms. Look for disable()method in class android.app.StatusBarManager.
Xposed 框架可以做到这一点。它需要 root,并且可能无法在所有平台上运行。在android.app.StatusBarManager类中查找disable()方法。
Look here on how to write your own module: Xposed development tutorial
在这里查看如何编写自己的模块: Xposed 开发教程
It's much easier than you think at first glance. Good Luck!
乍一看,这比您想象的要容易得多。祝你好运!
回答by Big Rich
Found another possible technique in this forum post. Quoting that post:
在此论坛帖子中找到了另一种可能的技术。引用那个帖子:
Using the following methods you can build an application that will prevent "regular" users from playing with anything other than your application.
The application is made of two modules. The main activity and a service. The service is configured to start at boot. When the service is started it checks if the activity is running or not. If it is not running it uses a timer to start the main activity.
When the activity is paused it schedules the service to start in one second: Code:
使用以下方法,您可以构建一个应用程序,以防止“普通”用户玩您的应用程序以外的任何东西。
该应用程序由两个模块组成。主要活动和服务。该服务配置为在引导时启动。当服务启动时,它会检查活动是否正在运行。如果它没有运行,它使用一个计时器来启动主要活动。
当活动暂停时,它会安排服务在一秒钟内启动:代码:
Sub Activity_Pause (UserClosed As Boolean)
If kiosk Then StartServiceAt(KioskService, DateTime.Now + 1 * DateTime.TicksPerSecond, false)
End Sub
If the user presses on the home screen, the home screen will appear for several seconds. However your application will return to the front after a few seconds and the user will not be able to interact with any other applications or change the settings.
The service is set to be a foreground service. This prevents Android from killing our service. Press on the Stop button to deactivate kiosk mode.
如果用户按下主屏幕,主屏幕将出现几秒钟。但是,您的应用程序将在几秒钟后返回到前面,用户将无法与任何其他应用程序交互或更改设置。
该服务设置为前台服务。这可以防止 Android 终止我们的服务。按停止按钮可停用自助服务终端模式。
There appears to be an example kiosk-mode code ZIP file available for download, too.
似乎也有一个示例信息亭模式代码 ZIP 文件可供下载。
回答by Kristy Welsh
Along with setting up your application with a BOOT receiver, and this answerfor preventing status bar expansion, this solution works on 4.4 and above as a complete kiosk app :
除了使用 BOOT 接收器设置您的应用程序以及防止状态栏扩展的答案外,该解决方案还可以在 4.4 及更高版本上作为完整的信息亭应用程序运行:
Place in your onCreate():
放置在您的 onCreate() 中:
final View view = (View) findViewById(android.R.id.content);
if (view != null) {
//"hides" back, home and return button on screen.
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
View.SYSTEM_UI_FLAG_FULLSCREEN);
view.setOnSystemUiVisibilityChangeListener
(new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
// Note that system bars will only be "visible" if none of the
// LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_IMMERSIVE |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
View.SYSTEM_UI_FLAG_FULLSCREEN);
}
}
});
}
This will completely hide the back button, apps and home button.
这将完全隐藏后退按钮、应用程序和主页按钮。