Android从API2.2开始提供了设备管理的API。可以实现以下功能:
一.密码管理
密码管理目前只用于屏幕解锁
密码管理提供的策略:
2.2API
1.最小密码长度
2.包含字母数字密码
3.至少包含字母
3.0 API
1.复杂密码(至少一个数字,一个字母,一个特殊符号 )
2.最少字母
3.最少小写
4.最少非字母字符
5.最少数字
6.最少符号
7.最少大写
8.密码过期时间
9.密码历史限制(防止用户重用过去的密码)
10.最大尝试次数
二.数据管理
2.2API:擦除数据
三.硬件管理
2.2API:锁屏
锁屏策略:
1. 立即锁屏
2. 最大间隔时间锁屏
4.0API:禁止使用摄像头
4.2API:禁止使用软键盘
注:一个手机可以安装多个设备管理程序,如果同时存在多个设备管理程序并且都处于启用状态的话,所有管理程序中最严格的策略被执行。
实现设备管理的步骤:
一.在代码中,写一个类实现DeviceAdminReceiver接口
public static class DeviceAdminTestReceiver extends DeviceAdminReceiver {
@Override
public void onEnabled(Context context, Intent intent) {
showToast(context, "启用了策略");
}
@Override
public CharSequence onDisableRequested(Context context, Intent intent) {
showToast(context, "试图停用策略");
return null;
}
@Override
public void onDisabled(Context context, Intent intent) {
showToast(context, "停用了策略");
}
@Override
public void onPasswordChanged(Context context, Intent intent) {
showToast(context, "改变了密码");
}
@Override
public void onPasswordFailed(Context context, Intent intent) {
showToast(context, "密码尝试失败");
}
@Override
public void onPasswordSucceeded(Context context, Intent intent) {
showToast(context, "密码尝试成功");
}
@Override
public void onPasswordExpiring(Context context, Intent intent) {
showToast(context, "密码过期");
}
void showToast(Context context, String msg) {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
每个回调方法中可以对事件做出相应的处理,这里只是简单做Toast处理
二.在清单文件中如下配置
<receiver android:name=".app.DeviceAdminSample$DeviceAdminTestReceiver"
android:label="@string/sample_device_admin"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data android:name="android.app.device_admin"
android:resource="@xml/device_admin_sample" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
android:name=".app.DeviceAdminSample$DeviceAdminTestReceiver"指出刚才在代码中新建的类
<meta-data>中,android:name="android.app.device_admin"是固定写法,
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />也是固定写法
android:resource="@xml/device_admin_sample"指向一个xml文件,文件中配置了设备管理需要用到的策略
device_admin_sample.xml:
<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<limit-password />
<watch-login />
<reset-password />
<force-lock />
<wipe-data />
<expire-password />
<encrypted-storage />
<disable-camera />
<disable-keyguard-features />
</uses-policies>
</device-admin>
三.在程序中启动设备管理。
DevicePolicyManager mDPM;
ComponentName mComponentName;
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mComponentName = new ComponentName(this, DeviceAdminTestReceiver.class);
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mComponentName);
startActivityForResult(intent, 1);
调用此段代码后,用户界面会弹出一个页面提示是否启动设备管理以及设备管理所使用的策略,列出来的策略是在刚才xml文件中配置的
用户选择了激活之后启用设备管理。
如果要禁止一个已经启用的策略,调用如下代码
DevicePolicyManager mDPM;
......
removeActiveAdmin(ComponentName who);
ComponentName是程序中DeviceAdminReceiver实例的ComponentName对象,可以通过如下方法得到
new ComponentName(this,DeviceAdminTestReceiver.class);
四.通过代码设置相应的策略和管理
(一).密码策略
在介绍密码策略前先介绍一下解锁:
在一般的手机上,按电源键后会关闭屏幕,再次按电源键时会点亮屏幕,一般的手机会显示一个滑动条,提示滑动解锁,拖动滑动条回到关闭屏幕前的页面。
滑动解锁只是所有屏幕解锁方式的一种。Android系统提供了以下5种解锁方式:
1.无 :没有解锁,点亮屏幕时直接返回关闭屏幕前的页面
2.滑动:通过拖动解锁按钮解锁,如上图
3.图案:通过点与点之间的连接产生图案解锁,如下图:
4.PIN:纯数字密码解锁
5.密码:混合密码解锁
通过API设置的密码策略会对PIN和密码这2种解锁方式起作用。
下面列出设置密码策略的API,这些方法都来自于DevicePolicyManager。每次设置解锁密码时,系统会检查设置的密码是否符合策略,如果符合,才能设置成功。如果当前已经设置了密码,则新设定的策略在下次设置密码时生效。
例如,通过
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
...
setPasswordMinimumLength(ComponentName, 4)
设置了最小长度为4,下次更改密码时,如果输入的新密码不符合长度,则界面显示:
setPasswordExpirationTimeout(ComponentName admin, long timeout) | 密码过期时间,第二个参数是时间,单位为毫秒 |
setPasswordHistoryLength(ComponentName admin, int length) | 密码历史长度,第二个参数是记录历史密码的次数,如果设置为2,则表示新密码和前2次设置的不能相同 |
setPasswordMinimumLength(ComponentName admin, int length) | 密码最小长度 |
setPasswordMinimumLetters(ComponentName admin, int length) | 密码最少需要的字母 |
setPasswordMinimumLowerCase(ComponentName admin, int length) | 密码最少需要的小写字母 |
setPasswordMinimumNonLetter(ComponentName admin, int length) | 对于数字和字符组成的密码,最少需要的数字 |
setPasswordMinimumNumeric(ComponentName admin, int length) | 密码最少需要的数字 |
setPasswordMinimumSymbols(ComponentName admin, int length) | 密码最少需要的符号 |
setPasswordMinimumUpperCase(ComponentName admin, int length) | 密码最少需要的大写字母 |
setPasswordQuality(ComponentName admin, int quality) | 设置密码质量,是比较粗糙的策略,在3.0以下的API中使用,第二个参数是对应策略的常量
|
setPasswordExpirationTimeout(ComponentName admin, long timeout) | 密码过期时间,单位毫秒 |
setMaximumFailedPasswordsForWipe(ComponentName admin, int num) | 尝试密码失败多少次后擦除数据 第二个参数为次数,不建议使用此方法,可以在实现DeviceAdminReceiver接口的类的 onPasswordFailed回调方法里面灵活处理 |
(二)设置密码
设置密码有2种方式
1.启动用户设置界面设置(通过系统指定的Intent启动设置Activity)
2.通过API设置
启动用户设置界面设置:
Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
startActivity(intent);
调用此段代码后用户界面显示如下,点击后2个选项可以人工设置屏幕解锁密码
点击最后一个选项“密码”后,跳出如下界面:
连续输入2次密码并且符合密码策略后设置成功
另外一种设置密码的方式是用DevicePolicyManager的API:
resetPassword (String newPsw, int flags)
调用此API时传入的新密码必须符合当前的密码策略,不然无法起作用。
第二个参数如果设置为DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY,则通过用户界面进入密码设置前需要输入通过此API重设的密码。
(三)锁屏
锁屏2种方式:
1.立刻锁屏
2.设置一定时间内无操作锁屏
立刻锁屏:
DevicePolicyManager mDPM;
………
mDPM.lockNow();
设置一定时间内无操作锁屏
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
...
long timeMs = 1000L*Long.parseLong(mTimeout.getText().toString());
mDPM.setMaximumTimeToLock(mDeviceAdminSample, timeMs);
(四)摄像头管理
启用/禁用:
setCameraDisabled (ComponentName admin, boolean disabled)
参数 disabled:true停用,false启用
停用后打开相机功能,如下图:
(五)擦除数据
擦除数据2种方式
1. 擦除应用数据
2. 擦除应用数据和擦除sd卡数据
擦除应用数据
DevicePolicyManager mDPM;
……
mDPM.wipeData(0);
擦除应用数据和擦除sd卡数据
DevicePolicyManager mDPM;
……
mDPM.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
设备管理实例
Java代码:
package com.example.devicemanagetest;
import java.util.List;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import android.widget.Toast;
public class MainActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mComponentName = new ComponentName(this, DeviceAdminTestReceiver.class);
}
@Override
public void onBuildHeaders(List<Header> target) {
super.onBuildHeaders(target);
loadHeadersFromResource(R.xml.device_admin_headers, target);
}
public static class BaseFragment extends PreferenceFragment {
MainActivity mMainActivity;
DevicePolicyManager mDPM;
ComponentName mComponentName;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mMainActivity = (MainActivity)getActivity();
mDPM = mMainActivity.mDPM;
mComponentName = mMainActivity.mComponentName;
}
}
/***
* 启动/停用
*/
public static class EnableFragment extends BaseFragment implements OnPreferenceChangeListener{
CheckBoxPreference mEnable;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.device_admin_enable);
mEnable = (CheckBoxPreference) findPreference("key_enable");
mEnable.setOnPreferenceChangeListener(this);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean ifEnable = (Boolean)newValue;
if (ifEnable != mDPM.isAdminActive(mComponentName)) {
if (ifEnable) {
enableAdmin();
} else {
mDPM.removeActiveAdmin(mComponentName);
}
}
return true;
}
private void enableAdmin() {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mComponentName);
startActivityForResult(intent, 1);
}
}
/**
* 密码策略
* */
public static class QualityFragment extends BaseFragment implements OnPreferenceChangeListener{
CheckBoxPreference alphabeticPreference;
CheckBoxPreference alphanumericPreference;
EditTextPreference minLetter;
EditTextPreference minTimeOut;
EditTextPreference maxWipe;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.device_admin_pswquality);
alphabeticPreference = (CheckBoxPreference) findPreference("key_alphabetic");
alphanumericPreference = (CheckBoxPreference) findPreference("key_alphanumeric");
alphabeticPreference.setOnPreferenceChangeListener(this);
alphanumericPreference.setOnPreferenceChangeListener(this);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == alphabeticPreference) {
boolean value = (Boolean)newValue;
if (value) {
//字母
mDPM.setPasswordQuality(mComponentName,
DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
}
} else if (preference == alphanumericPreference) {
boolean value = (Boolean)newValue;
if (value) {
//字母数字
mDPM.setPasswordQuality(mComponentName,
DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
}
} else if (preference == minLetter) {
int minLetter = (Integer)newValue;
mDPM.setPasswordMinimumLetters(mComponentName, minLetter);
} else if (preference == minTimeOut) {
int day = (Integer)newValue;
long minTimeOut = 86400 * 1000 * day;
mDPM.setPasswordExpirationTimeout(mComponentName, minTimeOut);
} else if (preference == maxWipe) {
int time = (Integer)newValue;
mDPM.setMaximumFailedPasswordsForWipe(mComponentName, time);
}
return true;
}
}
/**
* 设置密码
* */
public static class PswSettingFragment extends BaseFragment implements OnPreferenceClickListener, OnPreferenceChangeListener{
PreferenceScreen change;
EditTextPreference reset;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.device_admin_setpsw);
change = (PreferenceScreen) findPreference("key_set_password");
reset = (EditTextPreference) findPreference("key_reset_password");
change.setOnPreferenceClickListener(this);
reset.setOnPreferenceChangeListener(this);
}
@Override
public boolean onPreferenceClick(Preference preference) {
//点击了设置解密方式,如果选择的方式没有设置密码,则进行设置
if (preference == change) {
Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
startActivity(intent);
}
return false;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == reset) {
//立刻重设密码,重设前需要解密
String newPassword = String.valueOf(newValue);
mDPM.resetPassword(newPassword, DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY);
}
return true;
}
}
/**
* 屏幕锁/相机
* */
public static class LockFragment extends BaseFragment implements OnPreferenceChangeListener, OnPreferenceClickListener{
CheckBoxPreference camera;
PreferenceScreen lockNow;
EditTextPreference lockAtTime;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.device_admin_lock);
lockNow = (PreferenceScreen) findPreference("key_lock");
lockAtTime = (EditTextPreference) findPreference("key_lock_time");
camera = (CheckBoxPreference)findPreference("key_disable_camera");
lockNow.setOnPreferenceClickListener(this);
lockAtTime.setOnPreferenceChangeListener(this);
camera.setOnPreferenceChangeListener(this);
}
@Override
public boolean onPreferenceClick(Preference preference) {
//立刻锁屏
mDPM.lockNow();
return false;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == lockAtTime) {
// 多久以后锁屏,毫秒单位
long timeMs = 1000L * Long.parseLong(String.valueOf(newValue));
mDPM.setMaximumTimeToLock(mComponentName, timeMs);
} else if (preference == camera) {
boolean ifEnable = (Boolean)newValue;
if (ifEnable) {
mDPM.setCameraDisabled(mComponentName, true);
}
else {
mDPM.setCameraDisabled(mComponentName, false);
}
}
return true;
}
}
/**
* 擦除数据/数据加密
* */
public static class WipeFragment extends BaseFragment implements OnPreferenceClickListener{
PreferenceScreen wipeApp;
PreferenceScreen wipeSD;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.device_admin_wipe);
wipeApp = (PreferenceScreen) findPreference("wipe_ram");
wipeSD = (PreferenceScreen) findPreference("wipe_sdcard");
wipeApp.setOnPreferenceClickListener(this);
wipeSD.setOnPreferenceClickListener(this);
}
@Override
public boolean onPreferenceClick(Preference preference) {
if (preference == wipeApp) {
mDPM.wipeData(0);
} else if (preference == wipeSD) {
mDPM.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
}
return false;
}
}
/**
* 处理策略的receiver
* */
public static class DeviceAdminTestReceiver extends DeviceAdminReceiver {
@Override
public void onEnabled(Context context, Intent intent) {
showToast(context, "启用了策略");
}
@Override
public CharSequence onDisableRequested(Context context, Intent intent) {
showToast(context, "试图停用策略");
return null;
}
@Override
public void onDisabled(Context context, Intent intent) {
showToast(context, "停用了策略");
}
@Override
public void onPasswordChanged(Context context, Intent intent) {
showToast(context, "改变了密码");
}
@Override
public void onPasswordFailed(Context context, Intent intent) {
showToast(context, "密码尝试失败");
}
@Override
public void onPasswordSucceeded(Context context, Intent intent) {
showToast(context, "密码尝试成功");
}
@Override
public void onPasswordExpiring(Context context, Intent intent) {
showToast(context, "密码过期");
}
void showToast(Context context, String msg) {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
private DevicePolicyManager mDPM;
private ComponentName mComponentName;
}
清单文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.devicemanagetest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="16" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.devicemanagetest.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.example.devicemanagetest.MainActivity$DeviceAdminTestReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data android:name="android.app.device_admin"
android:resource="@xml/device_admin_list" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
</application>
</manifest>
xml文件:
device_admin_list.xml:
<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<limit-password />
<watch-login />
<reset-password />
<force-lock />
<wipe-data />
<expire-password />
<encrypted-storage />
<disable-camera />
<disable-keyguard-features />
</uses-policies>
</device-admin>
device_admin_headers.xml
<preference-headers
xmlns:android="http://schemas.android.com/apk/res/android" >
<header
android:fragment="com.example.devicemanagetest.MainActivity$EnableFragment"
android:title="启用/停用" />
<header
android:fragment="com.example.devicemanagetest.MainActivity$QualityFragment"
android:title="密码策略" />
<header
android:fragment="com.example.devicemanagetest.MainActivity$PswSettingFragment"
android:title="密码设置" />
<header
android:fragment="com.example.devicemanagetest.MainActivity$LockFragment"
android:title="屏幕锁/摄像头" />
<header
android:fragment="com.example.devicemanagetest.MainActivity$WipeFragment"
android:title="擦除数据/加密" />
</preference-headers>
device_admin_enable.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:title="启用停用"
>
<CheckBoxPreference
android:key="key_enable"
android:title="启用/停用"
android:summary="启用/停用策略"
/>
</PreferenceCategory>
</PreferenceScreen>
device_admin_lock.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="锁屏设置"
>
<PreferenceScreen
android:key="key_lock"
android:title="立刻锁屏"
></PreferenceScreen>
<EditTextPreference
android:key="key_lock_time"
android:title="锁屏时间(分钟)"
/>
<CheckBoxPreference
android:key="key_disable_camera"
android:title="禁止/启动摄像头"
/>
</PreferenceCategory>
</PreferenceScreen>
device_admin_pswquality.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:title="密码强度"
>
<CheckBoxPreference
android:key="key_alphabetic"
android:title="PASSWORD_QUALITY_ALPHABETIC"
android:summary="至少包含字母"
/>
<CheckBoxPreference
android:key="key_alphanumeric"
android:title="PASSWORD_QUALITY_ALPHANUMERIC"
android:summary="字母数字"
/>
</PreferenceCategory>
<PreferenceCategory
android:title="更详细的设置"
>
<EditTextPreference
android:key="key_min_letter"
android:title="setPasswordMinimumLetters()"
android:summary="最少需要的字母"
/>
<EditTextPreference
android:key="key_min_timeout"
android:title="setPasswordExpirationTimeout()"
android:summary="密码过期时间"
/>
<EditTextPreference
android:key="key_max_wipe"
android:title="setMaximumFailedPasswordsForWipe()"
android:summary="最大尝试次数后擦除"
/>
</PreferenceCategory>
</PreferenceScreen>
device_admin_setpsw.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:title="密码"
>
<PreferenceScreen
android:key="key_set_password"
android:title="解密方式"
/>
<EditTextPreference
android:key="key_reset_password"
android:title="重新设置密码"
android:dialogTitle="设置文字密码"
/>
</PreferenceCategory>
</PreferenceScreen>
device_admin_wipe.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:title="数据擦除/加密"
>
<PreferenceScreen
android:title="擦除应用数据"
android:key="wipe_ram"
></PreferenceScreen>
<PreferenceScreen
android:title="擦除sd卡数据"
android:key="wipe_sdcard"
></PreferenceScreen>
</PreferenceCategory>
</PreferenceScreen>