zoukankan      html  css  js  c++  java
  • 【起航计划 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中,当密码过期时,通过DevicePolicyManagergetPasswordExpiration方法获取过期的时间与当前时间对比。

    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管理策略:链接

  • 相关阅读:
    leetcode之String to Integer (atoi)
    初次思考
    leetcode之Reverse Words in a String
    Leetcode之Database篇
    在项目中添加类
    创建项目
    配置Eclipse

    递归
    多态
  • 原文地址:https://www.cnblogs.com/dongdong230/p/4317656.html
Copyright © 2011-2022 走看看