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