1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.apis.app;
18 
19 import com.example.android.apis.R;
20 
21 import android.app.ActivityManager;
22 import android.app.AlertDialog;
23 import android.app.admin.DeviceAdminReceiver;
24 import android.app.admin.DevicePolicyManager;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.DialogInterface;
28 import android.content.Intent;
29 import android.content.SharedPreferences;
30 import android.os.Bundle;
31 import android.os.PersistableBundle;
32 import android.preference.CheckBoxPreference;
33 import android.preference.EditTextPreference;
34 import android.preference.ListPreference;
35 import android.preference.Preference;
36 import android.preference.Preference.OnPreferenceChangeListener;
37 import android.preference.Preference.OnPreferenceClickListener;
38 import android.preference.PreferenceActivity;
39 import android.preference.PreferenceCategory;
40 import android.preference.PreferenceFragment;
41 import android.preference.PreferenceScreen;
42 import android.text.TextUtils;
43 import android.util.Log;
44 import android.widget.Toast;
45 
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.List;
49 
50 /**
51  * This activity provides a comprehensive UI for exploring and operating the DevicePolicyManager
52  * api.  It consists of two primary modules:
53  *
54  * 1:  A device policy controller, implemented here as a series of preference fragments.  Each
55  *     one contains code to monitor and control a particular subset of device policies.
56  *
57  * 2:  A DeviceAdminReceiver, to receive updates from the DevicePolicyManager when certain aspects
58  *     of the device security status have changed.
59  */
60 public class DeviceAdminSample extends PreferenceActivity {
61 
62     // Miscellaneous utilities and definitions
63     private static final String TAG = "DeviceAdminSample";
64 
65     private static final int REQUEST_CODE_ENABLE_ADMIN = 1;
66     private static final int REQUEST_CODE_START_ENCRYPTION = 2;
67 
68     private static final long MS_PER_MINUTE = 60 * 1000;
69     private static final long MS_PER_HOUR = 60 * MS_PER_MINUTE;
70     private static final long MS_PER_DAY = 24 * MS_PER_HOUR;
71 
72     // The following keys are used to find each preference item
73     private static final String KEY_ENABLE_ADMIN = "key_enable_admin";
74     private static final String KEY_DISABLE_CAMERA = "key_disable_camera";
75     private static final String KEY_DISABLE_NOTIFICATIONS = "key_disable_notifications";
76     private static final String KEY_DISABLE_UNREDACTED = "key_disable_unredacted";
77     private static final String KEY_DISABLE_TRUST_AGENTS = "key_disable_trust_agents";
78     private static final String KEY_TRUST_AGENT_COMPONENT = "key_trust_agent_component";
79     private static final String KEY_TRUST_AGENT_FEATURES = "key_trust_agent_features";
80     private static final String KEY_DISABLE_KEYGUARD_WIDGETS = "key_disable_keyguard_widgets";
81     private static final String KEY_DISABLE_KEYGUARD_SECURE_CAMERA
82             = "key_disable_keyguard_secure_camera";
83     private static final String KEY_DISABLE_FINGERPRINT = "key_disable_fingerprint";
84     private static final String KEY_DISABLE_REMOTE_INPUT = "key_disable_remote_input";
85 
86     private static final String KEY_CATEGORY_QUALITY = "key_category_quality";
87     private static final String KEY_SET_PASSWORD = "key_set_password";
88     private static final String KEY_RESET_PASSWORD = "key_reset_password";
89     private static final String KEY_QUALITY = "key_quality";
90     private static final String KEY_MIN_LENGTH = "key_minimum_length";
91     private static final String KEY_MIN_LETTERS = "key_minimum_letters";
92     private static final String KEY_MIN_NUMERIC = "key_minimum_numeric";
93     private static final String KEY_MIN_LOWER_CASE = "key_minimum_lower_case";
94     private static final String KEY_MIN_UPPER_CASE = "key_minimum_upper_case";
95     private static final String KEY_MIN_SYMBOLS = "key_minimum_symbols";
96     private static final String KEY_MIN_NON_LETTER = "key_minimum_non_letter";
97 
98     private static final String KEY_CATEGORY_EXPIRATION = "key_category_expiration";
99     private static final String KEY_HISTORY = "key_history";
100     private static final String KEY_EXPIRATION_TIMEOUT = "key_expiration_timeout";
101     private static final String KEY_EXPIRATION_STATUS = "key_expiration_status";
102 
103     private static final String KEY_CATEGORY_LOCK_WIPE = "key_category_lock_wipe";
104     private static final String KEY_MAX_TIME_SCREEN_LOCK = "key_max_time_screen_lock";
105     private static final String KEY_MAX_FAILS_BEFORE_WIPE = "key_max_fails_before_wipe";
106     private static final String KEY_LOCK_SCREEN = "key_lock_screen";
107     private static final String KEY_WIPE_DATA = "key_wipe_data";
108     private static final String KEY_WIP_DATA_ALL = "key_wipe_data_all";
109 
110     private static final String KEY_CATEGORY_ENCRYPTION = "key_category_encryption";
111     private static final String KEY_REQUIRE_ENCRYPTION = "key_require_encryption";
112     private static final String KEY_ACTIVATE_ENCRYPTION = "key_activate_encryption";
113 
114     // Interaction with the DevicePolicyManager
115     DevicePolicyManager mDPM;
116     ComponentName mDeviceAdminSample;
117 
118     @Override
onCreate(Bundle savedInstanceState)119     protected void onCreate(Bundle savedInstanceState) {
120         super.onCreate(savedInstanceState);
121 
122         // Prepare to work with the DPM
123         mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
124         mDeviceAdminSample = new ComponentName(this, DeviceAdminSampleReceiver.class);
125     }
126 
127     /**
128      * We override this method to provide PreferenceActivity with the top-level preference headers.
129      */
130     @Override
onBuildHeaders(List<Header> target)131     public void onBuildHeaders(List<Header> target) {
132         loadHeadersFromResource(R.xml.device_admin_headers, target);
133     }
134 
135     /**
136      * Helper to determine if we are an active admin
137      */
isActiveAdmin()138     private boolean isActiveAdmin() {
139         return mDPM.isAdminActive(mDeviceAdminSample);
140     }
141 
142     @Override
isValidFragment(String fragmentName)143     protected boolean isValidFragment(String fragmentName) {
144         return GeneralFragment.class.getName().equals(fragmentName)
145                 || QualityFragment.class.getName().equals(fragmentName)
146                 || ExpirationFragment.class.getName().equals(fragmentName)
147                 || LockWipeFragment.class.getName().equals(fragmentName)
148                 || EncryptionFragment.class.getName().equals(fragmentName);
149     }
150 
151     /**
152      * Common fragment code for DevicePolicyManager access.  Provides two shared elements:
153      *
154      *   1.  Provides instance variables to access activity/context, DevicePolicyManager, etc.
155      *   2.  Provides support for the "set password" button(s) shared by multiple fragments.
156      */
157     public static class AdminSampleFragment extends PreferenceFragment
158             implements OnPreferenceChangeListener, OnPreferenceClickListener{
159 
160         // Useful instance variables
161         protected DeviceAdminSample mActivity;
162         protected DevicePolicyManager mDPM;
163         protected ComponentName mDeviceAdminSample;
164         protected boolean mAdminActive;
165 
166         // Optional shared UI
167         private PreferenceScreen mSetPassword;
168         private EditTextPreference mResetPassword;
169 
170         @Override
onActivityCreated(Bundle savedInstanceState)171         public void onActivityCreated(Bundle savedInstanceState) {
172             super.onActivityCreated(savedInstanceState);
173 
174             // Retrieve the useful instance variables
175             mActivity = (DeviceAdminSample) getActivity();
176             mDPM = mActivity.mDPM;
177             mDeviceAdminSample = mActivity.mDeviceAdminSample;
178             mAdminActive = mActivity.isActiveAdmin();
179 
180             // Configure the shared UI elements (if they exist)
181             mResetPassword = (EditTextPreference) findPreference(KEY_RESET_PASSWORD);
182             mSetPassword = (PreferenceScreen) findPreference(KEY_SET_PASSWORD);
183 
184             if (mResetPassword != null) {
185                 mResetPassword.setOnPreferenceChangeListener(this);
186             }
187             if (mSetPassword != null) {
188                 mSetPassword.setOnPreferenceClickListener(this);
189             }
190         }
191 
192         @Override
onResume()193         public void onResume() {
194             super.onResume();
195             mAdminActive = mActivity.isActiveAdmin();
196             reloadSummaries();
197             // Resetting the password via API is available only to active admins
198             if (mResetPassword != null) {
199                 mResetPassword.setEnabled(mAdminActive);
200             }
201         }
202 
203         /**
204          * Called automatically at every onResume.  Should also call explicitly any time a
205          * policy changes that may affect other policy values.
206          */
reloadSummaries()207         protected void reloadSummaries() {
208             if (mSetPassword != null) {
209                 if (mAdminActive) {
210                     // Show password-sufficient status under Set Password button
211                     boolean sufficient = mDPM.isActivePasswordSufficient();
212                     mSetPassword.setSummary(sufficient ?
213                             R.string.password_sufficient : R.string.password_insufficient);
214                 } else {
215                     mSetPassword.setSummary(null);
216                 }
217             }
218         }
219 
postReloadSummaries()220         protected void postReloadSummaries() {
221             getView().post(new Runnable() {
222                 @Override
223                 public void run() {
224                     reloadSummaries();
225                 }
226             });
227         }
228 
229         @Override
onPreferenceClick(Preference preference)230         public boolean onPreferenceClick(Preference preference) {
231             if (mSetPassword != null && preference == mSetPassword) {
232                 Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
233                 startActivity(intent);
234                 return true;
235             }
236             return false;
237         }
238 
239         @Override
onPreferenceChange(Preference preference, Object newValue)240         public boolean onPreferenceChange(Preference preference, Object newValue) {
241             if (mResetPassword != null && preference == mResetPassword) {
242                 doResetPassword((String)newValue);
243                 return true;
244             }
245             return false;
246         }
247 
248         /**
249          * This is dangerous, so we prevent automated tests from doing it, and we
250          * remind the user after we do it.
251          */
doResetPassword(String newPassword)252         private void doResetPassword(String newPassword) {
253             if (alertIfMonkey(mActivity, R.string.monkey_reset_password)) {
254                 return;
255             }
256             mDPM.resetPassword(newPassword, DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY);
257             AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
258             String message = mActivity.getString(R.string.reset_password_warning, newPassword);
259             builder.setMessage(message);
260             builder.setPositiveButton(R.string.reset_password_ok, null);
261             builder.show();
262         }
263 
264         /**
265          * Simple helper for summaries showing local & global (aggregate) policy settings
266          */
localGlobalSummary(Object local, Object global)267         protected String localGlobalSummary(Object local, Object global) {
268             return getString(R.string.status_local_global, local, global);
269         }
270     }
271 
272     /**
273      * PreferenceFragment for "general" preferences.
274      */
275     public static class GeneralFragment extends AdminSampleFragment
276             implements OnPreferenceChangeListener {
277         // UI elements
278         private CheckBoxPreference mEnableCheckbox;
279         private CheckBoxPreference mDisableCameraCheckbox;
280         private CheckBoxPreference mDisableKeyguardWidgetsCheckbox;
281         private CheckBoxPreference mDisableKeyguardSecureCameraCheckbox;
282         private CheckBoxPreference mDisableKeyguardNotificationCheckbox;
283         private CheckBoxPreference mDisableKeyguardTrustAgentCheckbox;
284         private CheckBoxPreference mDisableKeyguardUnredactedCheckbox;
285         private EditTextPreference mTrustAgentComponent;
286         private EditTextPreference mTrustAgentFeatures;
287         private CheckBoxPreference mDisableKeyguardFingerprintCheckbox;
288         private CheckBoxPreference mDisableKeyguardRemoteInputCheckbox;
289 
290         @Override
onCreate(Bundle savedInstanceState)291         public void onCreate(Bundle savedInstanceState) {
292             super.onCreate(savedInstanceState);
293             addPreferencesFromResource(R.xml.device_admin_general);
294             mEnableCheckbox = (CheckBoxPreference) findPreference(KEY_ENABLE_ADMIN);
295             mEnableCheckbox.setOnPreferenceChangeListener(this);
296 
297             mDisableCameraCheckbox = (CheckBoxPreference) findPreference(KEY_DISABLE_CAMERA);
298             mDisableCameraCheckbox.setOnPreferenceChangeListener(this);
299 
300             mDisableKeyguardWidgetsCheckbox =
301                 (CheckBoxPreference) findPreference(KEY_DISABLE_KEYGUARD_WIDGETS);
302             mDisableKeyguardWidgetsCheckbox.setOnPreferenceChangeListener(this);
303 
304             mDisableKeyguardSecureCameraCheckbox =
305                 (CheckBoxPreference) findPreference(KEY_DISABLE_KEYGUARD_SECURE_CAMERA);
306             mDisableKeyguardSecureCameraCheckbox.setOnPreferenceChangeListener(this);
307 
308             mDisableKeyguardNotificationCheckbox =
309                     (CheckBoxPreference) findPreference(KEY_DISABLE_NOTIFICATIONS);
310             mDisableKeyguardNotificationCheckbox.setOnPreferenceChangeListener(this);
311 
312             mDisableKeyguardUnredactedCheckbox =
313                     (CheckBoxPreference) findPreference(KEY_DISABLE_UNREDACTED);
314             mDisableKeyguardUnredactedCheckbox.setOnPreferenceChangeListener(this);
315 
316             mDisableKeyguardFingerprintCheckbox =
317                     (CheckBoxPreference) findPreference(KEY_DISABLE_FINGERPRINT);
318             mDisableKeyguardFingerprintCheckbox.setOnPreferenceChangeListener(this);
319 
320             mDisableKeyguardRemoteInputCheckbox =
321                     (CheckBoxPreference) findPreference(KEY_DISABLE_REMOTE_INPUT);
322             mDisableKeyguardRemoteInputCheckbox.setOnPreferenceChangeListener(this);
323 
324             mDisableKeyguardTrustAgentCheckbox =
325                     (CheckBoxPreference) findPreference(KEY_DISABLE_TRUST_AGENTS);
326             mDisableKeyguardTrustAgentCheckbox.setOnPreferenceChangeListener(this);
327 
328             mTrustAgentComponent =
329                     (EditTextPreference) findPreference(KEY_TRUST_AGENT_COMPONENT);
330             mTrustAgentComponent.setOnPreferenceChangeListener(this);
331 
332             mTrustAgentFeatures =
333                     (EditTextPreference) findPreference(KEY_TRUST_AGENT_FEATURES);
334             mTrustAgentFeatures.setOnPreferenceChangeListener(this);
335         }
336 
337         // At onResume time, reload UI with current values as required
338         @Override
onResume()339         public void onResume() {
340             super.onResume();
341             mEnableCheckbox.setChecked(mAdminActive);
342             enableDeviceCapabilitiesArea(mAdminActive);
343 
344             if (mAdminActive) {
345                 mDPM.setCameraDisabled(mDeviceAdminSample, mDisableCameraCheckbox.isChecked());
346                 mDPM.setKeyguardDisabledFeatures(mDeviceAdminSample, createKeyguardDisabledFlag());
347                 reloadSummaries();
348             }
349         }
350 
createKeyguardDisabledFlag()351         int createKeyguardDisabledFlag() {
352             int flags = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
353             flags |= mDisableKeyguardWidgetsCheckbox.isChecked() ?
354                     DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL : 0;
355             flags |= mDisableKeyguardSecureCameraCheckbox.isChecked() ?
356                     DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA : 0;
357             flags |= mDisableKeyguardNotificationCheckbox.isChecked() ?
358                     DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS : 0;
359             flags |= mDisableKeyguardUnredactedCheckbox.isChecked() ?
360                     DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS : 0;
361             flags |= mDisableKeyguardTrustAgentCheckbox.isChecked() ?
362                     DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS : 0;
363             flags |= mDisableKeyguardFingerprintCheckbox.isChecked() ?
364                     DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT : 0;
365             flags |= mDisableKeyguardRemoteInputCheckbox.isChecked() ?
366                     DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT : 0;
367             return flags;
368         }
369 
370         @Override
onPreferenceChange(Preference preference, Object newValue)371         public boolean onPreferenceChange(Preference preference, Object newValue) {
372             if (super.onPreferenceChange(preference, newValue)) {
373                 return true;
374             }
375             if (preference == mEnableCheckbox) {
376                 boolean value = (Boolean) newValue;
377                 if (value != mAdminActive) {
378                     if (value) {
379                         // Launch the activity to have the user enable our admin.
380                         Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
381                         intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdminSample);
382                         intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
383                                 mActivity.getString(R.string.add_admin_extra_app_text));
384                         startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
385                         // return false - don't update checkbox until we're really active
386                         return false;
387                     } else {
388                         mDPM.removeActiveAdmin(mDeviceAdminSample);
389                         enableDeviceCapabilitiesArea(false);
390                         mAdminActive = false;
391                     }
392                 }
393             } else if (preference == mDisableCameraCheckbox) {
394                 boolean value = (Boolean) newValue;
395                 mDPM.setCameraDisabled(mDeviceAdminSample, value);
396                 // Delay update because the change is only applied after exiting this method.
397                 postReloadSummaries();
398             } else if (preference == mDisableKeyguardWidgetsCheckbox
399                     || preference == mDisableKeyguardSecureCameraCheckbox
400                     || preference == mDisableKeyguardNotificationCheckbox
401                     || preference == mDisableKeyguardUnredactedCheckbox
402                     || preference == mDisableKeyguardTrustAgentCheckbox
403                     || preference == mDisableKeyguardFingerprintCheckbox
404                     || preference == mDisableKeyguardRemoteInputCheckbox
405                     || preference == mTrustAgentComponent
406                     || preference == mTrustAgentFeatures) {
407                 postUpdateDpmDisableFeatures();
408                 postReloadSummaries();
409             }
410             return true;
411         }
412 
postUpdateDpmDisableFeatures()413         private void postUpdateDpmDisableFeatures() {
414             getView().post(new Runnable() {
415                 @Override
416                 public void run() {
417                     mDPM.setKeyguardDisabledFeatures(mDeviceAdminSample,
418                             createKeyguardDisabledFlag());
419                     String component = mTrustAgentComponent.getText();
420                     if (component != null) {
421                         ComponentName agent = ComponentName.unflattenFromString(component);
422                         if (agent != null) {
423                             String featureString = mTrustAgentFeatures.getText();
424                             if (featureString != null) {
425                                 PersistableBundle bundle = new PersistableBundle();
426                                 bundle.putStringArray("features", featureString.split(","));
427                                 mDPM.setTrustAgentConfiguration(mDeviceAdminSample, agent, bundle);
428                             }
429                         } else {
430                             Log.w(TAG, "Invalid component: " + component);
431                         }
432                     }
433                 }
434             });
435         }
436 
437         @Override
reloadSummaries()438         protected void reloadSummaries() {
439             super.reloadSummaries();
440             String cameraSummary = getString(mDPM.getCameraDisabled(mDeviceAdminSample)
441                     ? R.string.camera_disabled : R.string.camera_enabled);
442             mDisableCameraCheckbox.setSummary(cameraSummary);
443 
444             int disabled = mDPM.getKeyguardDisabledFeatures(mDeviceAdminSample);
445 
446             String keyguardWidgetSummary = getString(
447                     (disabled & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0 ?
448                             R.string.keyguard_widgets_disabled : R.string.keyguard_widgets_enabled);
449             mDisableKeyguardWidgetsCheckbox.setSummary(keyguardWidgetSummary);
450 
451             String keyguardSecureCameraSummary = getString(
452                 (disabled & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0 ?
453                 R.string.keyguard_secure_camera_disabled : R.string.keyguard_secure_camera_enabled);
454             mDisableKeyguardSecureCameraCheckbox.setSummary(keyguardSecureCameraSummary);
455 
456             String keyguardSecureNotificationsSummary = getString(
457                     (disabled & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS) != 0 ?
458                         R.string.keyguard_secure_notifications_disabled
459                         : R.string.keyguard_secure_notifications_enabled);
460             mDisableKeyguardNotificationCheckbox.setSummary(keyguardSecureNotificationsSummary);
461 
462             String keyguardUnredactedSummary = getString(
463                     (disabled & DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS) != 0
464                         ? R.string.keyguard_unredacted_notifications_disabled
465                         : R.string.keyguard_unredacted_notifications_enabled);
466             mDisableKeyguardUnredactedCheckbox.setSummary(keyguardUnredactedSummary);
467 
468             String keyguardEnableTrustAgentSummary = getString(
469                     (disabled & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0 ?
470                         R.string.keyguard_trust_agents_disabled
471                         : R.string.keyguard_trust_agents_enabled);
472             mDisableKeyguardTrustAgentCheckbox.setSummary(keyguardEnableTrustAgentSummary);
473 
474             String keyguardEnableFingerprintSummary = getString(
475                     (disabled & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0 ?
476                         R.string.keyguard_fingerprint_disabled
477                         : R.string.keyguard_fingerprint_enabled);
478             mDisableKeyguardFingerprintCheckbox.setSummary(keyguardEnableFingerprintSummary);
479 
480             String keyguardEnableRemoteInputSummary = getString(
481                     (disabled & DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT) != 0 ?
482                         R.string.keyguard_remote_input_disabled
483                         : R.string.keyguard_remote_input_enabled);
484             mDisableKeyguardRemoteInputCheckbox.setSummary(keyguardEnableRemoteInputSummary);
485 
486             final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
487             final boolean trustDisabled =
488                     (disabled & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
489             String component = prefs.getString(mTrustAgentComponent.getKey(), null);
490             mTrustAgentComponent.setSummary(component);
491             mTrustAgentComponent.setEnabled(trustDisabled);
492 
493             String features = prefs.getString(mTrustAgentFeatures.getKey(), null);
494             mTrustAgentFeatures.setSummary(features);
495             mTrustAgentFeatures.setEnabled(trustDisabled);
496         }
497 
498         /** Updates the device capabilities area (dis/enabling) as the admin is (de)activated */
enableDeviceCapabilitiesArea(boolean enabled)499         private void enableDeviceCapabilitiesArea(boolean enabled) {
500             mDisableCameraCheckbox.setEnabled(enabled);
501             mDisableKeyguardWidgetsCheckbox.setEnabled(enabled);
502             mDisableKeyguardSecureCameraCheckbox.setEnabled(enabled);
503             mDisableKeyguardNotificationCheckbox.setEnabled(enabled);
504             mDisableKeyguardUnredactedCheckbox.setEnabled(enabled);
505             mDisableKeyguardTrustAgentCheckbox.setEnabled(enabled);
506             mTrustAgentComponent.setEnabled(enabled);
507             mTrustAgentFeatures.setEnabled(enabled);
508         }
509     }
510 
511     /**
512      * PreferenceFragment for "password quality" preferences.
513      */
514     public static class QualityFragment extends AdminSampleFragment
515             implements OnPreferenceChangeListener {
516 
517         // Password quality values
518         // This list must match the list found in samples/ApiDemos/res/values/arrays.xml
519         final static int[] mPasswordQualityValues = new int[] {
520             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
521             DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
522             DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
523             DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX,
524             DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
525             DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
526             DevicePolicyManager.PASSWORD_QUALITY_COMPLEX
527         };
528 
529         // Password quality values (as strings, for the ListPreference entryValues)
530         // This list must match the list found in samples/ApiDemos/res/values/arrays.xml
531         final static String[] mPasswordQualityValueStrings = new String[] {
532             String.valueOf(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED),
533             String.valueOf(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING),
534             String.valueOf(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC),
535             String.valueOf(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX),
536             String.valueOf(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC),
537             String.valueOf(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC),
538             String.valueOf(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX)
539         };
540 
541         // UI elements
542         private PreferenceCategory mQualityCategory;
543         private ListPreference mPasswordQuality;
544         private EditTextPreference mMinLength;
545         private EditTextPreference mMinLetters;
546         private EditTextPreference mMinNumeric;
547         private EditTextPreference mMinLowerCase;
548         private EditTextPreference mMinUpperCase;
549         private EditTextPreference mMinSymbols;
550         private EditTextPreference mMinNonLetter;
551 
552         @Override
onCreate(Bundle savedInstanceState)553         public void onCreate(Bundle savedInstanceState) {
554             super.onCreate(savedInstanceState);
555             addPreferencesFromResource(R.xml.device_admin_quality);
556 
557             mQualityCategory = (PreferenceCategory) findPreference(KEY_CATEGORY_QUALITY);
558             mPasswordQuality = (ListPreference) findPreference(KEY_QUALITY);
559             mMinLength = (EditTextPreference) findPreference(KEY_MIN_LENGTH);
560             mMinLetters = (EditTextPreference) findPreference(KEY_MIN_LETTERS);
561             mMinNumeric = (EditTextPreference) findPreference(KEY_MIN_NUMERIC);
562             mMinLowerCase = (EditTextPreference) findPreference(KEY_MIN_LOWER_CASE);
563             mMinUpperCase = (EditTextPreference) findPreference(KEY_MIN_UPPER_CASE);
564             mMinSymbols = (EditTextPreference) findPreference(KEY_MIN_SYMBOLS);
565             mMinNonLetter = (EditTextPreference) findPreference(KEY_MIN_NON_LETTER);
566 
567             mPasswordQuality.setOnPreferenceChangeListener(this);
568             mMinLength.setOnPreferenceChangeListener(this);
569             mMinLetters.setOnPreferenceChangeListener(this);
570             mMinNumeric.setOnPreferenceChangeListener(this);
571             mMinLowerCase.setOnPreferenceChangeListener(this);
572             mMinUpperCase.setOnPreferenceChangeListener(this);
573             mMinSymbols.setOnPreferenceChangeListener(this);
574             mMinNonLetter.setOnPreferenceChangeListener(this);
575 
576             // Finish setup of the quality dropdown
577             mPasswordQuality.setEntryValues(mPasswordQualityValueStrings);
578         }
579 
580         @Override
onResume()581         public void onResume() {
582             super.onResume();
583             mQualityCategory.setEnabled(mAdminActive);
584         }
585 
586         /**
587          * Update the summaries of each item to show the local setting and the global setting.
588          */
589         @Override
reloadSummaries()590         protected void reloadSummaries() {
591             super.reloadSummaries();
592             // Show numeric settings for each policy API
593             int local, global;
594             local = mDPM.getPasswordQuality(mDeviceAdminSample);
595             global = mDPM.getPasswordQuality(null);
596             mPasswordQuality.setSummary(
597                     localGlobalSummary(qualityValueToString(local), qualityValueToString(global)));
598             local = mDPM.getPasswordMinimumLength(mDeviceAdminSample);
599             global = mDPM.getPasswordMinimumLength(null);
600             mMinLength.setSummary(localGlobalSummary(local, global));
601             local = mDPM.getPasswordMinimumLetters(mDeviceAdminSample);
602             global = mDPM.getPasswordMinimumLetters(null);
603             mMinLetters.setSummary(localGlobalSummary(local, global));
604             local = mDPM.getPasswordMinimumNumeric(mDeviceAdminSample);
605             global = mDPM.getPasswordMinimumNumeric(null);
606             mMinNumeric.setSummary(localGlobalSummary(local, global));
607             local = mDPM.getPasswordMinimumLowerCase(mDeviceAdminSample);
608             global = mDPM.getPasswordMinimumLowerCase(null);
609             mMinLowerCase.setSummary(localGlobalSummary(local, global));
610             local = mDPM.getPasswordMinimumUpperCase(mDeviceAdminSample);
611             global = mDPM.getPasswordMinimumUpperCase(null);
612             mMinUpperCase.setSummary(localGlobalSummary(local, global));
613             local = mDPM.getPasswordMinimumSymbols(mDeviceAdminSample);
614             global = mDPM.getPasswordMinimumSymbols(null);
615             mMinSymbols.setSummary(localGlobalSummary(local, global));
616             local = mDPM.getPasswordMinimumNonLetter(mDeviceAdminSample);
617             global = mDPM.getPasswordMinimumNonLetter(null);
618             mMinNonLetter.setSummary(localGlobalSummary(local, global));
619         }
620 
621         @Override
onPreferenceChange(Preference preference, Object newValue)622         public boolean onPreferenceChange(Preference preference, Object newValue) {
623             if (super.onPreferenceChange(preference, newValue)) {
624                 return true;
625             }
626             String valueString = (String)newValue;
627             if (TextUtils.isEmpty(valueString)) {
628                 return false;
629             }
630             int value = 0;
631             try {
632                 value = Integer.parseInt(valueString);
633             } catch (NumberFormatException nfe) {
634                 String warning = mActivity.getString(R.string.number_format_warning, valueString);
635                 Toast.makeText(mActivity, warning, Toast.LENGTH_SHORT).show();
636             }
637             if (preference == mPasswordQuality) {
638                 mDPM.setPasswordQuality(mDeviceAdminSample, value);
639             } else if (preference == mMinLength) {
640                 mDPM.setPasswordMinimumLength(mDeviceAdminSample, value);
641             } else if (preference == mMinLetters) {
642                 mDPM.setPasswordMinimumLetters(mDeviceAdminSample, value);
643             } else if (preference == mMinNumeric) {
644                 mDPM.setPasswordMinimumNumeric(mDeviceAdminSample, value);
645             } else if (preference == mMinLowerCase) {
646                 mDPM.setPasswordMinimumLowerCase(mDeviceAdminSample, value);
647             } else if (preference == mMinUpperCase) {
648                 mDPM.setPasswordMinimumUpperCase(mDeviceAdminSample, value);
649             } else if (preference == mMinSymbols) {
650                 mDPM.setPasswordMinimumSymbols(mDeviceAdminSample, value);
651             } else if (preference == mMinNonLetter) {
652                 mDPM.setPasswordMinimumNonLetter(mDeviceAdminSample, value);
653             }
654             // Delay update because the change is only applied after exiting this method.
655             postReloadSummaries();
656             return true;
657         }
658 
qualityValueToString(int quality)659         private String qualityValueToString(int quality) {
660             for (int i=  0; i < mPasswordQualityValues.length; i++) {
661                 if (mPasswordQualityValues[i] == quality) {
662                     String[] qualities =
663                         mActivity.getResources().getStringArray(R.array.password_qualities);
664                     return qualities[i];
665                 }
666             }
667             return "(0x" + Integer.toString(quality, 16) + ")";
668         }
669     }
670 
671     /**
672      * PreferenceFragment for "password expiration" preferences.
673      */
674     public static class ExpirationFragment extends AdminSampleFragment
675             implements OnPreferenceChangeListener, OnPreferenceClickListener {
676         private PreferenceCategory mExpirationCategory;
677         private EditTextPreference mHistory;
678         private EditTextPreference mExpirationTimeout;
679         private PreferenceScreen mExpirationStatus;
680 
681         @Override
onCreate(Bundle savedInstanceState)682         public void onCreate(Bundle savedInstanceState) {
683             super.onCreate(savedInstanceState);
684             addPreferencesFromResource(R.xml.device_admin_expiration);
685 
686             mExpirationCategory = (PreferenceCategory) findPreference(KEY_CATEGORY_EXPIRATION);
687             mHistory = (EditTextPreference) findPreference(KEY_HISTORY);
688             mExpirationTimeout = (EditTextPreference) findPreference(KEY_EXPIRATION_TIMEOUT);
689             mExpirationStatus = (PreferenceScreen) findPreference(KEY_EXPIRATION_STATUS);
690 
691             mHistory.setOnPreferenceChangeListener(this);
692             mExpirationTimeout.setOnPreferenceChangeListener(this);
693             mExpirationStatus.setOnPreferenceClickListener(this);
694         }
695 
696         @Override
onResume()697         public void onResume() {
698             super.onResume();
699             mExpirationCategory.setEnabled(mAdminActive);
700         }
701 
702         /**
703          * Update the summaries of each item to show the local setting and the global setting.
704          */
705         @Override
reloadSummaries()706         protected void reloadSummaries() {
707             super.reloadSummaries();
708 
709             int local, global;
710             local = mDPM.getPasswordHistoryLength(mDeviceAdminSample);
711             global = mDPM.getPasswordHistoryLength(null);
712             mHistory.setSummary(localGlobalSummary(local, global));
713 
714             long localLong, globalLong;
715             localLong = mDPM.getPasswordExpirationTimeout(mDeviceAdminSample);
716             globalLong = mDPM.getPasswordExpirationTimeout(null);
717             mExpirationTimeout.setSummary(localGlobalSummary(
718                     localLong / MS_PER_MINUTE, globalLong / MS_PER_MINUTE));
719 
720             String expirationStatus = getExpirationStatus();
721             mExpirationStatus.setSummary(expirationStatus);
722         }
723 
724         @Override
onPreferenceChange(Preference preference, Object newValue)725         public boolean onPreferenceChange(Preference preference, Object newValue) {
726             if (super.onPreferenceChange(preference, newValue)) {
727                 return true;
728             }
729             String valueString = (String)newValue;
730             if (TextUtils.isEmpty(valueString)) {
731                 return false;
732             }
733             int value = 0;
734             try {
735                 value = Integer.parseInt(valueString);
736             } catch (NumberFormatException nfe) {
737                 String warning = mActivity.getString(R.string.number_format_warning, valueString);
738                 Toast.makeText(mActivity, warning, Toast.LENGTH_SHORT).show();
739             }
740             if (preference == mHistory) {
741                 mDPM.setPasswordHistoryLength(mDeviceAdminSample, value);
742             } else if (preference == mExpirationTimeout) {
743                 mDPM.setPasswordExpirationTimeout(mDeviceAdminSample, value * MS_PER_MINUTE);
744             }
745             // Delay update because the change is only applied after exiting this method.
746             postReloadSummaries();
747             return true;
748         }
749 
750         @Override
onPreferenceClick(Preference preference)751         public boolean onPreferenceClick(Preference preference) {
752             if (super.onPreferenceClick(preference)) {
753                 return true;
754             }
755             if (preference == mExpirationStatus) {
756                 String expirationStatus = getExpirationStatus();
757                 mExpirationStatus.setSummary(expirationStatus);
758                 return true;
759             }
760             return false;
761         }
762 
763         /**
764          * Create a summary string describing the expiration status for the sample app,
765          * as well as the global (aggregate) status.
766          */
getExpirationStatus()767         private String getExpirationStatus() {
768             // expirations are absolute;  convert to relative for display
769             long localExpiration = mDPM.getPasswordExpiration(mDeviceAdminSample);
770             long globalExpiration = mDPM.getPasswordExpiration(null);
771             long now = System.currentTimeMillis();
772 
773             // local expiration
774             String local;
775             if (localExpiration == 0) {
776                 local = mActivity.getString(R.string.expiration_status_none);
777             } else {
778                 localExpiration -= now;
779                 String dms = timeToDaysMinutesSeconds(mActivity, Math.abs(localExpiration));
780                 if (localExpiration >= 0) {
781                     local = mActivity.getString(R.string.expiration_status_future, dms);
782                 } else {
783                     local = mActivity.getString(R.string.expiration_status_past, dms);
784                 }
785             }
786 
787             // global expiration
788             String global;
789             if (globalExpiration == 0) {
790                 global = mActivity.getString(R.string.expiration_status_none);
791             } else {
792                 globalExpiration -= now;
793                 String dms = timeToDaysMinutesSeconds(mActivity, Math.abs(globalExpiration));
794                 if (globalExpiration >= 0) {
795                     global = mActivity.getString(R.string.expiration_status_future, dms);
796                 } else {
797                     global = mActivity.getString(R.string.expiration_status_past, dms);
798                 }
799             }
800             return mActivity.getString(R.string.status_local_global, local, global);
801         }
802     }
803 
804     /**
805      * PreferenceFragment for "lock screen & wipe" preferences.
806      */
807     public static class LockWipeFragment extends AdminSampleFragment
808             implements OnPreferenceChangeListener, OnPreferenceClickListener {
809         private PreferenceCategory mLockWipeCategory;
810         private EditTextPreference mMaxTimeScreenLock;
811         private EditTextPreference mMaxFailures;
812         private PreferenceScreen mLockScreen;
813         private PreferenceScreen mWipeData;
814         private PreferenceScreen mWipeAppData;
815 
816         @Override
onCreate(Bundle savedInstanceState)817         public void onCreate(Bundle savedInstanceState) {
818             super.onCreate(savedInstanceState);
819             addPreferencesFromResource(R.xml.device_admin_lock_wipe);
820 
821             mLockWipeCategory = (PreferenceCategory) findPreference(KEY_CATEGORY_LOCK_WIPE);
822             mMaxTimeScreenLock = (EditTextPreference) findPreference(KEY_MAX_TIME_SCREEN_LOCK);
823             mMaxFailures = (EditTextPreference) findPreference(KEY_MAX_FAILS_BEFORE_WIPE);
824             mLockScreen = (PreferenceScreen) findPreference(KEY_LOCK_SCREEN);
825             mWipeData = (PreferenceScreen) findPreference(KEY_WIPE_DATA);
826             mWipeAppData = (PreferenceScreen) findPreference(KEY_WIP_DATA_ALL);
827 
828             mMaxTimeScreenLock.setOnPreferenceChangeListener(this);
829             mMaxFailures.setOnPreferenceChangeListener(this);
830             mLockScreen.setOnPreferenceClickListener(this);
831             mWipeData.setOnPreferenceClickListener(this);
832             mWipeAppData.setOnPreferenceClickListener(this);
833         }
834 
835         @Override
onResume()836         public void onResume() {
837             super.onResume();
838             mLockWipeCategory.setEnabled(mAdminActive);
839         }
840 
841         /**
842          * Update the summaries of each item to show the local setting and the global setting.
843          */
844         @Override
reloadSummaries()845         protected void reloadSummaries() {
846             super.reloadSummaries();
847 
848             long localLong, globalLong;
849             localLong = mDPM.getMaximumTimeToLock(mDeviceAdminSample);
850             globalLong = mDPM.getMaximumTimeToLock(null);
851             mMaxTimeScreenLock.setSummary(localGlobalSummary(
852                     localLong / MS_PER_MINUTE, globalLong / MS_PER_MINUTE));
853 
854             int local, global;
855             local = mDPM.getMaximumFailedPasswordsForWipe(mDeviceAdminSample);
856             global = mDPM.getMaximumFailedPasswordsForWipe(null);
857             mMaxFailures.setSummary(localGlobalSummary(local, global));
858         }
859 
860         @Override
onPreferenceChange(Preference preference, Object newValue)861         public boolean onPreferenceChange(Preference preference, Object newValue) {
862             if (super.onPreferenceChange(preference, newValue)) {
863                 return true;
864             }
865             String valueString = (String)newValue;
866             if (TextUtils.isEmpty(valueString)) {
867                 return false;
868             }
869             int value = 0;
870             try {
871                 value = Integer.parseInt(valueString);
872             } catch (NumberFormatException nfe) {
873                 String warning = mActivity.getString(R.string.number_format_warning, valueString);
874                 Toast.makeText(mActivity, warning, Toast.LENGTH_SHORT).show();
875             }
876             if (preference == mMaxTimeScreenLock) {
877                 mDPM.setMaximumTimeToLock(mDeviceAdminSample, value * MS_PER_MINUTE);
878             } else if (preference == mMaxFailures) {
879                 if (alertIfMonkey(mActivity, R.string.monkey_wipe_data)) {
880                     return true;
881                 }
882                 mDPM.setMaximumFailedPasswordsForWipe(mDeviceAdminSample, value);
883             }
884             // Delay update because the change is only applied after exiting this method.
885             postReloadSummaries();
886             return true;
887         }
888 
889         @Override
onPreferenceClick(Preference preference)890         public boolean onPreferenceClick(Preference preference) {
891             if (super.onPreferenceClick(preference)) {
892                 return true;
893             }
894             if (preference == mLockScreen) {
895                 if (alertIfMonkey(mActivity, R.string.monkey_lock_screen)) {
896                     return true;
897                 }
898                 mDPM.lockNow();
899                 return true;
900             } else if (preference == mWipeData || preference == mWipeAppData) {
901                 if (alertIfMonkey(mActivity, R.string.monkey_wipe_data)) {
902                     return true;
903                 }
904                 promptForRealDeviceWipe(preference == mWipeAppData);
905                 return true;
906             }
907             return false;
908         }
909 
910         /**
911          * Wiping data is real, so we don't want it to be easy.  Show two alerts before wiping.
912          */
promptForRealDeviceWipe(final boolean wipeAllData)913         private void promptForRealDeviceWipe(final boolean wipeAllData) {
914             final DeviceAdminSample activity = mActivity;
915 
916             AlertDialog.Builder builder = new AlertDialog.Builder(activity);
917             builder.setMessage(R.string.wipe_warning_first);
918             builder.setPositiveButton(R.string.wipe_warning_first_ok,
919                     new DialogInterface.OnClickListener() {
920                 @Override
921                 public void onClick(DialogInterface dialog, int which) {
922                     AlertDialog.Builder builder = new AlertDialog.Builder(activity);
923                     if (wipeAllData) {
924                         builder.setMessage(R.string.wipe_warning_second_full);
925                     } else {
926                         builder.setMessage(R.string.wipe_warning_second);
927                     }
928                     builder.setPositiveButton(R.string.wipe_warning_second_ok,
929                             new DialogInterface.OnClickListener() {
930                         @Override
931                         public void onClick(DialogInterface dialog, int which) {
932                             boolean stillActive = mActivity.isActiveAdmin();
933                             if (stillActive) {
934                                 mDPM.wipeData(wipeAllData
935                                         ? DevicePolicyManager.WIPE_EXTERNAL_STORAGE : 0);
936                             }
937                         }
938                     });
939                     builder.setNegativeButton(R.string.wipe_warning_second_no, null);
940                     builder.show();
941                 }
942             });
943             builder.setNegativeButton(R.string.wipe_warning_first_no, null);
944             builder.show();
945         }
946     }
947 
948     /**
949      * PreferenceFragment for "encryption" preferences.
950      */
951     public static class EncryptionFragment extends AdminSampleFragment
952             implements OnPreferenceChangeListener, OnPreferenceClickListener {
953         private PreferenceCategory mEncryptionCategory;
954         private CheckBoxPreference mRequireEncryption;
955         private PreferenceScreen mActivateEncryption;
956 
957         @Override
onCreate(Bundle savedInstanceState)958         public void onCreate(Bundle savedInstanceState) {
959             super.onCreate(savedInstanceState);
960             addPreferencesFromResource(R.xml.device_admin_encryption);
961 
962             mEncryptionCategory = (PreferenceCategory) findPreference(KEY_CATEGORY_ENCRYPTION);
963             mRequireEncryption = (CheckBoxPreference) findPreference(KEY_REQUIRE_ENCRYPTION);
964             mActivateEncryption = (PreferenceScreen) findPreference(KEY_ACTIVATE_ENCRYPTION);
965 
966             mRequireEncryption.setOnPreferenceChangeListener(this);
967             mActivateEncryption.setOnPreferenceClickListener(this);
968         }
969 
970         @Override
onResume()971         public void onResume() {
972             super.onResume();
973             mEncryptionCategory.setEnabled(mAdminActive);
974             mRequireEncryption.setChecked(mDPM.getStorageEncryption(mDeviceAdminSample));
975         }
976 
977         /**
978          * Update the summaries of each item to show the local setting and the global setting.
979          */
980         @Override
reloadSummaries()981         protected void reloadSummaries() {
982             super.reloadSummaries();
983 
984             boolean local, global;
985             local = mDPM.getStorageEncryption(mDeviceAdminSample);
986             global = mDPM.getStorageEncryption(null);
987             mRequireEncryption.setSummary(localGlobalSummary(local, global));
988 
989             int deviceStatusCode = mDPM.getStorageEncryptionStatus();
990             String deviceStatus = statusCodeToString(deviceStatusCode);
991             String status = mActivity.getString(R.string.status_device_encryption, deviceStatus);
992             mActivateEncryption.setSummary(status);
993         }
994 
995         @Override
onPreferenceChange(Preference preference, Object newValue)996         public boolean onPreferenceChange(Preference preference, Object newValue) {
997             if (super.onPreferenceChange(preference, newValue)) {
998                 return true;
999             }
1000             if (preference == mRequireEncryption) {
1001                 boolean newActive = (Boolean) newValue;
1002                 mDPM.setStorageEncryption(mDeviceAdminSample, newActive);
1003                 // Delay update because the change is only applied after exiting this method.
1004                 postReloadSummaries();
1005                 return true;
1006             }
1007             return true;
1008         }
1009 
1010         @Override
onPreferenceClick(Preference preference)1011         public boolean onPreferenceClick(Preference preference) {
1012             if (super.onPreferenceClick(preference)) {
1013                 return true;
1014             }
1015             if (preference == mActivateEncryption) {
1016                 if (alertIfMonkey(mActivity, R.string.monkey_encryption)) {
1017                     return true;
1018                 }
1019                 // Check to see if encryption is even supported on this device (it's optional).
1020                 if (mDPM.getStorageEncryptionStatus() ==
1021                         DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) {
1022                     AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
1023                     builder.setMessage(R.string.encryption_not_supported);
1024                     builder.setPositiveButton(R.string.encryption_not_supported_ok, null);
1025                     builder.show();
1026                     return true;
1027                 }
1028                 // Launch the activity to activate encryption.  May or may not return!
1029                 Intent intent = new Intent(DevicePolicyManager.ACTION_START_ENCRYPTION);
1030                 startActivityForResult(intent, REQUEST_CODE_START_ENCRYPTION);
1031                 return true;
1032             }
1033             return false;
1034         }
1035 
statusCodeToString(int newStatusCode)1036         private String statusCodeToString(int newStatusCode) {
1037             int newStatus = R.string.encryption_status_unknown;
1038             switch (newStatusCode) {
1039                 case DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED:
1040                     newStatus = R.string.encryption_status_unsupported;
1041                     break;
1042                 case DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE:
1043                     newStatus = R.string.encryption_status_inactive;
1044                     break;
1045                 case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVATING:
1046                     newStatus = R.string.encryption_status_activating;
1047                     break;
1048                 case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE:
1049                     newStatus = R.string.encryption_status_active;
1050                     break;
1051             }
1052             return mActivity.getString(newStatus);
1053         }
1054     }
1055 
1056     /**
1057      * Simple converter used for long expiration times reported in mSec.
1058      */
timeToDaysMinutesSeconds(Context context, long time)1059     private static String timeToDaysMinutesSeconds(Context context, long time) {
1060         long days = time / MS_PER_DAY;
1061         long hours = (time / MS_PER_HOUR) % 24;
1062         long minutes = (time / MS_PER_MINUTE) % 60;
1063         return context.getString(R.string.status_days_hours_minutes, days, hours, minutes);
1064     }
1065 
1066     /**
1067      * If the "user" is a monkey, post an alert and notify the caller.  This prevents automated
1068      * test frameworks from stumbling into annoying or dangerous operations.
1069      */
alertIfMonkey(Context context, int stringId)1070     private static boolean alertIfMonkey(Context context, int stringId) {
1071         if (ActivityManager.isUserAMonkey()) {
1072             AlertDialog.Builder builder = new AlertDialog.Builder(context);
1073             builder.setMessage(stringId);
1074             builder.setPositiveButton(R.string.monkey_ok, null);
1075             builder.show();
1076             return true;
1077         } else {
1078             return false;
1079         }
1080     }
1081 
1082     /**
1083      * Sample implementation of a DeviceAdminReceiver.  Your controller must provide one,
1084      * although you may or may not implement all of the methods shown here.
1085      *
1086      * All callbacks are on the UI thread and your implementations should not engage in any
1087      * blocking operations, including disk I/O.
1088      */
1089     public static class DeviceAdminSampleReceiver extends DeviceAdminReceiver {
showToast(Context context, String msg)1090         void showToast(Context context, String msg) {
1091             String status = context.getString(R.string.admin_receiver_status, msg);
1092             Toast.makeText(context, status, Toast.LENGTH_SHORT).show();
1093         }
1094 
1095         @Override
onReceive(Context context, Intent intent)1096         public void onReceive(Context context, Intent intent) {
1097             if (intent.getAction() == ACTION_DEVICE_ADMIN_DISABLE_REQUESTED) {
1098                 abortBroadcast();
1099             }
1100             super.onReceive(context, intent);
1101         }
1102 
1103         @Override
onEnabled(Context context, Intent intent)1104         public void onEnabled(Context context, Intent intent) {
1105             showToast(context, context.getString(R.string.admin_receiver_status_enabled));
1106         }
1107 
1108         @Override
onDisableRequested(Context context, Intent intent)1109         public CharSequence onDisableRequested(Context context, Intent intent) {
1110             return context.getString(R.string.admin_receiver_status_disable_warning);
1111         }
1112 
1113         @Override
onDisabled(Context context, Intent intent)1114         public void onDisabled(Context context, Intent intent) {
1115             showToast(context, context.getString(R.string.admin_receiver_status_disabled));
1116         }
1117 
1118         @Override
onPasswordChanged(Context context, Intent intent)1119         public void onPasswordChanged(Context context, Intent intent) {
1120             showToast(context, context.getString(R.string.admin_receiver_status_pw_changed));
1121         }
1122 
1123         @Override
onPasswordFailed(Context context, Intent intent)1124         public void onPasswordFailed(Context context, Intent intent) {
1125             showToast(context, context.getString(R.string.admin_receiver_status_pw_failed));
1126         }
1127 
1128         @Override
onPasswordSucceeded(Context context, Intent intent)1129         public void onPasswordSucceeded(Context context, Intent intent) {
1130             showToast(context, context.getString(R.string.admin_receiver_status_pw_succeeded));
1131         }
1132 
1133         @Override
onPasswordExpiring(Context context, Intent intent)1134         public void onPasswordExpiring(Context context, Intent intent) {
1135             DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
1136                     Context.DEVICE_POLICY_SERVICE);
1137             long expr = dpm.getPasswordExpiration(
1138                     new ComponentName(context, DeviceAdminSampleReceiver.class));
1139             long delta = expr - System.currentTimeMillis();
1140             boolean expired = delta < 0L;
1141             String message = context.getString(expired ?
1142                     R.string.expiration_status_past : R.string.expiration_status_future);
1143             showToast(context, message);
1144             Log.v(TAG, message);
1145         }
1146     }
1147 
1148     public static class DeviceAdminSampleReceiver2 extends DeviceAdminReceiver {
1149     }
1150 }
1151