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