【起航计划 019】2015 起航计划 Android APIDemo的魔鬼步伐 18 App->Device Admin 设备管理器 DeviceAdminReceiver DevicePolicyManager PreferenceActivity的使用

Device Admin示例介绍了类DeviceAdminReceiverDevicePolicyManagerActivityManager

使用DevicePolicyManager这个类,这个类可以接管手机的应用权限,对手机做出很多大胆的操作,比如锁屏、恢复出厂设置、设置密码、强制清除密码,修改密码、设置屏幕灯光渐暗时间间隔等操作。

当它Publish在AndroidManifest.xml作为BroadcastReceiver定义时,必须处理 android.app.action.DEVICE_ADMIN_ENABLED和设置 android.permission.BIND_DEVICE_ADMIN权限,来监听权限的变化:

        <receiver android:name=".app.DeviceAdminSample$DeviceAdminSampleReceiver"
                android:label="@string/sample_device_admin"
                android:description="@string/sample_device_admin_description"
                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:permission 表示此功能需要的权限。

Android:name="android.app.action.DEVICE_ADMIN_ENABLED"表示此动作的跳转界面。

<meta-data android:name="android.app.device_admin" android:resource="@xml/device_admin_sample" />表示这个应用可以管理的权限清单,对应的device_admin_sample如下:

<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>

在你设计你的设备管理程序时,并不需要包括所有的安全策略,按需定制即可。

更多WIKI见:链接

完成DeviceAdminReceiver的子类

要创建一个设备管理程序,就要实现一个继承DeviceAdminReceiver的类。DeviceAdminReceiver包含了一系列的回调函数,这些回调函数会在具体的事件发生时被调用。

在例子程序里,我们只是简单地显示了一个Toast,来做为对相应事件的应答。例如:

    /**
     * Sample implementation of a DeviceAdminReceiver.  Your controller must provide one,
     * although you may or may not implement all of the methods shown here.
     *
     * All callbacks are on the UI thread and your implementations should not engage in any
     * blocking operations, including disk I/O.
     */
    public static class DeviceAdminSampleReceiver extends DeviceAdminReceiver {
        void showToast(Context context, String msg) {
            String status = context.getString(R.string.admin_receiver_status, msg);
            Toast.makeText(context, status, Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction() == ACTION_DEVICE_ADMIN_DISABLE_REQUESTED) {
                abortBroadcast();
            }
            super.onReceive(context, intent);
        }

        @Override
        public void onEnabled(Context context, Intent intent) {
            showToast(context, context.getString(R.string.admin_receiver_status_enabled));
        }

        @Override
        public CharSequence onDisableRequested(Context context, Intent intent) {
            return context.getString(R.string.admin_receiver_status_disable_warning);
        }

        @Override
        public void onDisabled(Context context, Intent intent) {
            showToast(context, context.getString(R.string.admin_receiver_status_disabled));
        }

        @Override
        public void onPasswordChanged(Context context, Intent intent) {
            showToast(context, context.getString(R.string.admin_receiver_status_pw_changed));
        }

        @Override
        public void onPasswordFailed(Context context, Intent intent) {
            showToast(context, context.getString(R.string.admin_receiver_status_pw_failed));
        }

        @Override
        public void onPasswordSucceeded(Context context, Intent intent) {
            showToast(context, context.getString(R.string.admin_receiver_status_pw_succeeded));
        }

        @Override
        public void onPasswordExpiring(Context context, Intent intent) {
            DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
                    Context.DEVICE_POLICY_SERVICE);
            long expr = dpm.getPasswordExpiration(
                    new ComponentName(context, DeviceAdminSampleReceiver.class));
            long delta = expr - System.currentTimeMillis();
            boolean expired = delta < 0L;
            String message = context.getString(expired ?
                    R.string.expiration_status_past : R.string.expiration_status_future);
            showToast(context, message);
            Log.v(TAG, message);
        }
    }

比如onPasswordExpiring中,当密码过期时,通过DevicePolicyManager的getPasswordExpiration方法获取过期的时间与当前时间对比。

DeviceAdminSample.java这个类继承自PreferenceActivity。

PreferenceActivity 继承自ListActivity 它是以一个列表的形式在展现内容,它最主要的特点是添加Preference可以让控件的状态持久化储存,举个例子 比如用户选中checkbox后 退出应用然后在进入应用,这时用户希望看到的是checkbox被选中,所以软件须要记录用户每次操作的过程并且持久储存,在进入应用的时候须要判断这些 久储存的数据然后将系统控件的状态呈现在UI中。

需要重写onBuilderHeaders来展示列表,loadHeadersFromResource是PreferenceActivity的方法,用来读取headers:

   /**
     * We override this method to provide PreferenceActivity with the top-level preference headers.
     */
    @Override
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.device_admin_headers, target);
    }

其中R.xml.device_admin_headers如下:

<!-- Headers for a set of preferences used to exercise the DevicePolicyManager API. -->
<preference-headers
    xmlns:android="http://schemas.android.com/apk/res/android" >

    <header
        android:fragment="com.example.android.apis.app.DeviceAdminSample$GeneralFragment"
        android:title="@string/header_general" />

    <header
        android:fragment="com.example.android.apis.app.DeviceAdminSample$QualityFragment"
        android:title="@string/header_quality" />

    <header
        android:fragment="com.example.android.apis.app.DeviceAdminSample$ExpirationFragment"
        android:title="@string/header_expiration" />

    <header
        android:fragment="com.example.android.apis.app.DeviceAdminSample$LockWipeFragment"
        android:title="@string/header_lock_wipe" />

    <header
        android:fragment="com.example.android.apis.app.DeviceAdminSample$EncryptionFragment"
        android:title="@string/header_encryption" />

</preference-headers>

点击各个条目会进入到对应的PreferenceFragment中:

这里先定义了一个基类AdminSampleFragment,它做了两件事:

1.提供context实例变量和DevicePolicyManager对象

2.针对多个fragment中存在的set password按钮的点击事件进行处理

    /**
     * Common fragment code for DevicePolicyManager access.  Provides two shared elements:
     *
     *   1.  Provides instance variables to access activity/context, DevicePolicyManager, etc.
     *   2.  Provides support for the "set password" button(s) shared by multiple fragments.
     */
    public static class AdminSampleFragment extends PreferenceFragment
            implements OnPreferenceChangeListener, OnPreferenceClickListener

接下来就是各个子PreferenceFragment了。

GeneralFragment

调用addPreferencesFromResource展示列表,findPreference获取各个列表对象并设置监听:

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.device_admin_general);
            mEnableCheckbox = (CheckBoxPreference) findPreference(KEY_ENABLE_ADMIN);
            mEnableCheckbox.setOnPreferenceChangeListener(this);

            mDisableCameraCheckbox = (CheckBoxPreference) findPreference(KEY_DISABLE_CAMERA);
            mDisableCameraCheckbox.setOnPreferenceChangeListener(this);

            mDisableKeyguardWidgetsCheckbox =
                (CheckBoxPreference) findPreference(KEY_DISABLE_KEYGUARD_WIDGETS);
            mDisableKeyguardWidgetsCheckbox.setOnPreferenceChangeListener(this);

            mDisableKeyguardSecureCameraCheckbox =
                (CheckBoxPreference) findPreference(KEY_DISABLE_KEYGUARD_SECURE_CAMERA);
            mDisableKeyguardSecureCameraCheckbox.setOnPreferenceChangeListener(this);

            mDisableKeyguardNotificationCheckbox =
                    (CheckBoxPreference) findPreference(KEY_DISABLE_NOTIFICATIONS);
            mDisableKeyguardNotificationCheckbox.setOnPreferenceChangeListener(this);

            mDisableKeyguardUnredactedCheckbox =
                    (CheckBoxPreference) findPreference(KEY_DISABLE_UNREDACTED);
            mDisableKeyguardUnredactedCheckbox.setOnPreferenceChangeListener(this);

            mDisableKeyguardTrustAgentCheckbox =
                    (CheckBoxPreference) findPreference(KEY_DISABLE_TRUST_AGENTS);
            mDisableKeyguardTrustAgentCheckbox.setOnPreferenceChangeListener(this);
        }

对应的PreferenceScreen布局如下:

<!-- A set of preferences used to exercise the DevicePolicyManager API. -->
<!-- This screen is shown for the "General" header. -->
<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android" >

    <PreferenceCategory
        android:title="@string/enable_admin" >

        <CheckBoxPreference
            android:key="key_enable_admin"
            android:title="@string/enable_admin" />

    </PreferenceCategory>

    <PreferenceCategory
        android:title="@string/device_capabilities_category" >

        <CheckBoxPreference
            android:key="key_disable_camera"
            android:title="@string/disable_camera" />

        <CheckBoxPreference
            android:key="key_disable_keyguard_widgets"
            android:title="@string/disable_keyguard_widgets" />

        <CheckBoxPreference
            android:key="key_disable_keyguard_secure_camera"
            android:title="@string/disable_keyguard_secure_camera" />

        <CheckBoxPreference
            android:key="key_disable_notifications"
            android:title="@string/disable_keyguard_notifications" />

        <CheckBoxPreference
            android:key="key_disable_unredacted"
            android:title="@string/disable_keyguard_unredacted_notifications" />

        <CheckBoxPreference
            android:key="key_disable_trust_agents"
            android:title="@string/disable_keyguard_trust_agents" />

    </PreferenceCategory>

</PreferenceScreen>
PreferenceScreen:代表显示一整个屏幕
PreferenceCategory:内部嵌套PreferenceCategory标签,表示偏好类别,在PreferenceCategory标签内部可以随便存放复选框CheckBoxPreference,输入框EditTextPreference,列表ListPreference等显示控件
CheckBoxPreference:复选框控件

其他组件见:链接

当用户点击了Enable Admin 选择框,设备就会提示用户已经启用了设备管理程序,

下面就是当用户点击了 Enable Admin 选择框要执行的代码。效果是触发了onPreferenceChange()回调函数。当用户改变Preference的值时,就会调用这个回调函数。如果用户启用程序,界面就会提示用户正在启用程序,否则就是禁止程序:

     @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            if (super.onPreferenceChange(preference, newValue)) {
                return true;
            }
            boolean value = (Boolean) newValue;
            if (preference == mEnableCheckbox) {
                if (value != mAdminActive) {
                    if (value) {
                        // Launch the activity to have the user enable our admin.
                        Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
                        intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdminSample);
                        intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
                                mActivity.getString(R.string.add_admin_extra_app_text));
                        startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
                        // return false - don‘t update checkbox until we‘re really active
                        return false;
                    } else {
                        mDPM.removeActiveAdmin(mDeviceAdminSample);
                        enableDeviceCapabilitiesArea(false);
                        mAdminActive = false;
                    }
                }
            } else if (preference == mDisableCameraCheckbox) {
                mDPM.setCameraDisabled(mDeviceAdminSample, value);
                ...
            }
            return true;
        }

当程序要执行一个操作,它要确定管理程序是否已经被启用了。实现的方法就是使用DevicePolicyManagerisAdminActive()方法。要注意的是,DevicePolicyManagerisAdminActive()方法需要一个DeviceAdminReceiver类型的参数。

DevicePolicyManager mDPM;
...
private boolean isActiveAdmin() {
    return mDPM.isAdminActive(mDeviceAdminSample);
}

其他管理策略的代码请见链接的4.2.3管理策略:链接

时间: 2024-11-06 10:15:20

【起航计划 019】2015 起航计划 Android APIDemo的魔鬼步伐 18 App->Device Admin 设备管理器 DeviceAdminReceiver DevicePolicyManager PreferenceActivity的使用的相关文章

【起航计划 002】2015 起航计划 Android APIDemo的魔鬼步伐 01

本文链接:[起航计划 002]2015 起航计划 Android APIDemo的魔鬼步伐 01 参考链接:http://blog.csdn.net/column/details/mapdigitapidemos.html?&page=12

【起航计划 031】2015 起航计划 Android APIDemo的魔鬼步伐 30 App-&gt;Preferences-&gt;Advanced preferences 自定义preference OnPreferenceChangeListener

前篇文章Android ApiDemo示例解析(31):App->Preferences->Launching preferences 中用到了Advanced preferences 中定义的AdvancedPreferences. 本篇具体介绍AdvancedPreferences, 这个例子称为Advanced ,是因为它涉及到了自定义Preference, 并在一个工作线程中刷新某个Preference的值. Preference 为显示在PreferenceActivity (一般以

【起航计划 020】2015 起航计划 Android APIDemo的魔鬼步伐 19 App-&gt;Dialog Dialog样式

这个例子的主Activity定义在AlertDialogSamples.java 主要用来介绍类AlertDialog的用法,AlertDialog提供的功能是多样的: 显示消息给用户,并可提供一到三个按钮(OK, Cancel ,Yes ,No)用于选择或是显示警告. 显示一个列表以供用户选择,列表中可以是Radio Button  (单选),Check button (多选) 显示文本框来接受用户输入等. 创建AlertDialog一般是通过AlertDialog.Builder来构造: A

【起航计划 012】2015 起航计划 Android APIDemo的魔鬼步伐 11 App-&gt;Activity-&gt;Save &amp; Restore State onSaveInstanceState onRestoreInstanceState

Save & Restore State与之前的例子Android ApiDemo示例解析(9):App->Activity->Persistent State 实现的UI类似,但功能和实现方法稍有不同. (9)是通过Shared Preferences 和 Activity 的onPause() ,和onResume()来保持UI中 EditText 的值. 本例是通过onSaveInstanceState(Bundle savedBundle) 来实现保持UI状态. 和onPaus

【起航计划 003】2015 起航计划 Android APIDemo的魔鬼步伐 02

01 API Demos ApiDemos 详细介绍了Android平台主要的 API,android 5.0主要包括下图几个大类,涵盖了数百api示例: 02 入口类 ApiDemos采用分类层次显示,ApiDemo是ApiDemos的入口类,继承自ListActivity,该类的主要功能是分类列出大类,进而更进一步显示示例. ListActivity可以看做为一个含有ListView的Activity,可以不用setContentView设置布局,除非你想定制自己的List布局,这样的话,你

【起航计划 007】2015 起航计划 Android APIDemo的魔鬼步伐 06 App-&gt;Activity-&gt;Forwarding Activity启动另外一个Activity finish()方法

Android应用可以包含多个Activity,某个Activity可以启动另外的Activity. 这些Activity采用栈结构来管理,新打开的Activity叠放在当前的Activity之上,当前的Activity停止运行. 当一个Activity停止运行时,Android系统保留其停止前的状态,当用户按下“Back”按键时,栈最上的Activity从栈顶退栈,之前的Activity移到栈顶,显示在屏幕上: 有些时候,当一个Activity启动新的Activity后,不希望把当前Activ

【起航计划 005】2015 起航计划 Android APIDemo的魔鬼步伐 04 App-&gt;Activity-&gt;Custom Dialog Dialog形式的Activity,Theme的使用,Shape的使用

App->Activity->Custom Dialog 例子使用Activity 来实现自定义对话框 类CustomDialogActivity本身无任何特别之处.关键的一点是其在AndroidManifest.xml中的定义: <activity android:name=".app.CustomDialogActivity" android:label="@string/activity_custom_dialog" android:them

【起航计划 006】2015 起航计划 Android APIDemo的魔鬼步伐 05 App-&gt;Activity-&gt;Custom Title 自定义标题栏

Android UI缺省的标题栏由android:label 定义,显示在屏幕左上角,Android允许Activity自定义标题栏,使用自定义Layout重新设置标题栏,比如实现Windows Mobile 风格的标题栏. App->Activity->Custom Title 重新将Activity标题栏定义为左右两个文本框,类CustomTitle,其Layout定义R.layout.custom_title_1如下,为一左一右两个文本框: <!-- Demonstrates ho

【起航计划 016】2015 起航计划 Android APIDemo的魔鬼步伐 15 App-&gt;Activity-&gt;Wallpaper 系统壁纸作为当前Activity的背景

Wallpaper介绍一个Activity如何通过Style把系统Wallpaper作为当前Activity的背景. 这是WallpaperActivity在AndroidManifest.xml中的定义: <activity android:name=".app.WallpaperActivity" android:label="@string/activity_wallpaper" android:theme="@style/Theme.Wall