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.android.email.activity.setup; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.app.Dialog; 22 import android.app.DialogFragment; 23 import android.app.FragmentManager; 24 import android.app.LoaderManager; 25 import android.app.admin.DevicePolicyManager; 26 import android.content.Context; 27 import android.content.DialogInterface; 28 import android.content.Intent; 29 import android.content.Loader; 30 import android.content.res.Resources; 31 import android.net.Uri; 32 import android.os.AsyncTask; 33 import android.os.Bundle; 34 import android.os.Handler; 35 import android.text.TextUtils; 36 37 import com.android.email.DebugUtils; 38 import com.android.email.R; 39 import com.android.email.SecurityPolicy; 40 import com.android.emailcommon.provider.Account; 41 import com.android.emailcommon.provider.EmailContent; 42 import com.android.emailcommon.provider.HostAuth; 43 import com.android.emailcommon.provider.Policy; 44 import com.android.emailcommon.utility.IntentUtilities; 45 import com.android.mail.ui.MailAsyncTaskLoader; 46 import com.android.mail.utils.LogUtils; 47 48 /** 49 * Psuedo-activity (no UI) to bootstrap the user up to a higher desired security level. This 50 * bootstrap requires the following steps. 51 * 52 * 1. Confirm the account of interest has any security policies defined - exit early if not 53 * 2. If not actively administrating the device, ask Device Policy Manager to start that 54 * 3. When we are actively administrating, check current policies and see if they're sufficient 55 * 4. If not, set policies 56 * 5. If necessary, request for user to update device password 57 * 6. If necessary, request for user to activate device encryption 58 */ 59 public class AccountSecurity extends Activity { 60 private static final String TAG = "Email/AccountSecurity"; 61 62 private static final boolean DEBUG = false; // Don't ship with this set to true 63 64 private static final String EXTRA_ACCOUNT_ID = "ACCOUNT_ID"; 65 private static final String EXTRA_SHOW_DIALOG = "SHOW_DIALOG"; 66 private static final String EXTRA_PASSWORD_EXPIRING = "EXPIRING"; 67 private static final String EXTRA_PASSWORD_EXPIRED = "EXPIRED"; 68 69 private static final String SAVESTATE_INITIALIZED_TAG = "initialized"; 70 private static final String SAVESTATE_TRIED_ADD_ADMINISTRATOR_TAG = "triedAddAdministrator"; 71 private static final String SAVESTATE_TRIED_SET_PASSWORD_TAG = "triedSetpassword"; 72 private static final String SAVESTATE_TRIED_SET_ENCRYPTION_TAG = "triedSetEncryption"; 73 private static final String SAVESTATE_ACCOUNT_TAG = "account"; 74 75 private static final int REQUEST_ENABLE = 1; 76 private static final int REQUEST_PASSWORD = 2; 77 private static final int REQUEST_ENCRYPTION = 3; 78 79 private boolean mTriedAddAdministrator; 80 private boolean mTriedSetPassword; 81 private boolean mTriedSetEncryption; 82 83 private Account mAccount; 84 85 protected boolean mInitialized; 86 87 private Handler mHandler; 88 private boolean mActivityResumed; 89 90 private static final int ACCOUNT_POLICY_LOADER_ID = 0; 91 private AccountAndPolicyLoaderCallbacks mAPLoaderCallbacks; 92 private Bundle mAPLoaderArgs; 93 getUpdateSecurityUri(final long accountId, final boolean showDialog)94 public static Uri getUpdateSecurityUri(final long accountId, final boolean showDialog) { 95 final Uri.Builder baseUri = Uri.parse("auth://" + EmailContent.EMAIL_PACKAGE_NAME + 96 ".ACCOUNT_SECURITY/").buildUpon(); 97 IntentUtilities.setAccountId(baseUri, accountId); 98 baseUri.appendQueryParameter(EXTRA_SHOW_DIALOG, Boolean.toString(showDialog)); 99 return baseUri.build(); 100 } 101 102 /** 103 * Used for generating intent for this activity (which is intended to be launched 104 * from a notification.) 105 * 106 * @param context Calling context for building the intent 107 * @param accountId The account of interest 108 * @param showDialog If true, a simple warning dialog will be shown before kicking off 109 * the necessary system settings. Should be true anywhere the context of the security settings 110 * is not clear (e.g. any time after the account has been set up). 111 * @return an Intent which can be used to view that account 112 */ actionUpdateSecurityIntent(Context context, long accountId, boolean showDialog)113 public static Intent actionUpdateSecurityIntent(Context context, long accountId, 114 boolean showDialog) { 115 Intent intent = new Intent(context, AccountSecurity.class); 116 intent.putExtra(EXTRA_ACCOUNT_ID, accountId); 117 intent.putExtra(EXTRA_SHOW_DIALOG, showDialog); 118 return intent; 119 } 120 121 /** 122 * Used for generating intent for this activity (which is intended to be launched 123 * from a notification.) This is a special mode of this activity which exists only 124 * to give the user a dialog (for context) about a device pin/password expiration event. 125 */ actionDevicePasswordExpirationIntent(Context context, long accountId, boolean expired)126 public static Intent actionDevicePasswordExpirationIntent(Context context, long accountId, 127 boolean expired) { 128 Intent intent = new ForwardingIntent(context, AccountSecurity.class); 129 intent.putExtra(EXTRA_ACCOUNT_ID, accountId); 130 intent.putExtra(expired ? EXTRA_PASSWORD_EXPIRED : EXTRA_PASSWORD_EXPIRING, true); 131 return intent; 132 } 133 134 @Override onCreate(Bundle savedInstanceState)135 public void onCreate(Bundle savedInstanceState) { 136 super.onCreate(savedInstanceState); 137 138 mHandler = new Handler(); 139 140 final Intent i = getIntent(); 141 final long accountId; 142 Bundle extras = i.getExtras(); 143 if (extras == null) { 144 // We have been invoked via a uri. We need to get our parameters from the URI instead 145 // of looking in the intent extras. 146 extras = new Bundle(); 147 accountId = IntentUtilities.getAccountIdFromIntent(i); 148 extras.putLong(EXTRA_ACCOUNT_ID, accountId); 149 boolean showDialog = false; 150 final String value = i.getData().getQueryParameter(EXTRA_SHOW_DIALOG); 151 if (!TextUtils.isEmpty(value)) { 152 showDialog = Boolean.getBoolean(value); 153 } 154 extras.putBoolean(EXTRA_SHOW_DIALOG, showDialog); 155 } else { 156 accountId = i.getLongExtra(EXTRA_ACCOUNT_ID, -1); 157 extras = i.getExtras(); 158 } 159 160 final SecurityPolicy security = SecurityPolicy.getInstance(this); 161 security.clearNotification(); 162 if (accountId == -1) { 163 finish(); 164 return; 165 } 166 167 if (savedInstanceState != null) { 168 mInitialized = savedInstanceState.getBoolean(SAVESTATE_INITIALIZED_TAG, false); 169 170 mTriedAddAdministrator = 171 savedInstanceState.getBoolean(SAVESTATE_TRIED_ADD_ADMINISTRATOR_TAG, false); 172 mTriedSetPassword = 173 savedInstanceState.getBoolean(SAVESTATE_TRIED_SET_PASSWORD_TAG, false); 174 mTriedSetEncryption = 175 savedInstanceState.getBoolean(SAVESTATE_TRIED_SET_ENCRYPTION_TAG, false); 176 177 mAccount = savedInstanceState.getParcelable(SAVESTATE_ACCOUNT_TAG); 178 } 179 180 if (!mInitialized) { 181 startAccountAndPolicyLoader(extras); 182 } 183 } 184 185 @Override onSaveInstanceState(final Bundle outState)186 protected void onSaveInstanceState(final Bundle outState) { 187 super.onSaveInstanceState(outState); 188 outState.putBoolean(SAVESTATE_INITIALIZED_TAG, mInitialized); 189 190 outState.putBoolean(SAVESTATE_TRIED_ADD_ADMINISTRATOR_TAG, mTriedAddAdministrator); 191 outState.putBoolean(SAVESTATE_TRIED_SET_PASSWORD_TAG, mTriedSetPassword); 192 outState.putBoolean(SAVESTATE_TRIED_SET_ENCRYPTION_TAG, mTriedSetEncryption); 193 194 outState.putParcelable(SAVESTATE_ACCOUNT_TAG, mAccount); 195 } 196 197 @Override onPause()198 protected void onPause() { 199 super.onPause(); 200 mActivityResumed = false; 201 } 202 203 @Override onResume()204 protected void onResume() { 205 super.onResume(); 206 mActivityResumed = true; 207 tickleAccountAndPolicyLoader(); 208 } 209 isActivityResumed()210 protected boolean isActivityResumed() { 211 return mActivityResumed; 212 } 213 tickleAccountAndPolicyLoader()214 private void tickleAccountAndPolicyLoader() { 215 // If we're already initialized we don't need to tickle. 216 if (!mInitialized) { 217 getLoaderManager().initLoader(ACCOUNT_POLICY_LOADER_ID, mAPLoaderArgs, 218 mAPLoaderCallbacks); 219 } 220 } 221 startAccountAndPolicyLoader(final Bundle args)222 private void startAccountAndPolicyLoader(final Bundle args) { 223 mAPLoaderArgs = args; 224 mAPLoaderCallbacks = new AccountAndPolicyLoaderCallbacks(); 225 tickleAccountAndPolicyLoader(); 226 } 227 228 private class AccountAndPolicyLoaderCallbacks 229 implements LoaderManager.LoaderCallbacks<Account> { 230 @Override onCreateLoader(final int id, final Bundle args)231 public Loader<Account> onCreateLoader(final int id, final Bundle args) { 232 final long accountId = args.getLong(EXTRA_ACCOUNT_ID, -1); 233 final boolean showDialog = args.getBoolean(EXTRA_SHOW_DIALOG, false); 234 final boolean passwordExpiring = 235 args.getBoolean(EXTRA_PASSWORD_EXPIRING, false); 236 final boolean passwordExpired = 237 args.getBoolean(EXTRA_PASSWORD_EXPIRED, false); 238 239 return new AccountAndPolicyLoader(getApplicationContext(), accountId, 240 showDialog, passwordExpiring, passwordExpired); 241 } 242 243 @Override onLoadFinished(final Loader<Account> loader, final Account account)244 public void onLoadFinished(final Loader<Account> loader, final Account account) { 245 mHandler.post(new Runnable() { 246 @Override 247 public void run() { 248 final AccountSecurity activity = AccountSecurity.this; 249 if (!activity.isActivityResumed()) { 250 return; 251 } 252 253 if (account == null || (account.mPolicyKey != 0 && account.mPolicy == null)) { 254 activity.finish(); 255 LogUtils.d(TAG, "could not load account or policy in AccountSecurity"); 256 return; 257 } 258 259 if (!activity.mInitialized) { 260 activity.mInitialized = true; 261 262 final AccountAndPolicyLoader apLoader = (AccountAndPolicyLoader) loader; 263 activity.completeCreate(account, apLoader.mShowDialog, 264 apLoader.mPasswordExpiring, apLoader.mPasswordExpired); 265 } 266 } 267 }); 268 } 269 270 @Override onLoaderReset(Loader<Account> loader)271 public void onLoaderReset(Loader<Account> loader) {} 272 } 273 274 private static class AccountAndPolicyLoader extends MailAsyncTaskLoader<Account> { 275 private final long mAccountId; 276 public final boolean mShowDialog; 277 public final boolean mPasswordExpiring; 278 public final boolean mPasswordExpired; 279 280 private final Context mContext; 281 AccountAndPolicyLoader(final Context context, final long accountId, final boolean showDialog, final boolean passwordExpiring, final boolean passwordExpired)282 AccountAndPolicyLoader(final Context context, final long accountId, 283 final boolean showDialog, final boolean passwordExpiring, 284 final boolean passwordExpired) { 285 super(context); 286 mContext = context; 287 mAccountId = accountId; 288 mShowDialog = showDialog; 289 mPasswordExpiring = passwordExpiring; 290 mPasswordExpired = passwordExpired; 291 } 292 293 @Override loadInBackground()294 public Account loadInBackground() { 295 final Account account = Account.restoreAccountWithId(mContext, mAccountId); 296 if (account == null) { 297 return null; 298 } 299 300 final long policyId = account.mPolicyKey; 301 if (policyId != 0) { 302 account.mPolicy = Policy.restorePolicyWithId(mContext, policyId); 303 } 304 305 account.getOrCreateHostAuthRecv(mContext); 306 307 return account; 308 } 309 310 @Override onDiscardResult(Account result)311 protected void onDiscardResult(Account result) {} 312 } 313 completeCreate(final Account account, final boolean showDialog, final boolean passwordExpiring, final boolean passwordExpired)314 protected void completeCreate(final Account account, final boolean showDialog, 315 final boolean passwordExpiring, final boolean passwordExpired) { 316 mAccount = account; 317 318 // Special handling for password expiration events 319 if (passwordExpiring || passwordExpired) { 320 FragmentManager fm = getFragmentManager(); 321 if (fm.findFragmentByTag("password_expiration") == null) { 322 PasswordExpirationDialog dialog = 323 PasswordExpirationDialog.newInstance(mAccount.getDisplayName(), 324 passwordExpired); 325 if (DebugUtils.DEBUG || DEBUG) { 326 LogUtils.d(TAG, "Showing password expiration dialog"); 327 } 328 dialog.show(fm, "password_expiration"); 329 } 330 return; 331 } 332 // Otherwise, handle normal security settings flow 333 if (mAccount.mPolicyKey != 0) { 334 // This account wants to control security 335 if (showDialog) { 336 // Show dialog first, unless already showing (e.g. after rotation) 337 FragmentManager fm = getFragmentManager(); 338 if (fm.findFragmentByTag("security_needed") == null) { 339 SecurityNeededDialog dialog = 340 SecurityNeededDialog.newInstance(mAccount.getDisplayName()); 341 if (DebugUtils.DEBUG || DEBUG) { 342 LogUtils.d(TAG, "Showing security needed dialog"); 343 } 344 dialog.show(fm, "security_needed"); 345 } 346 } else { 347 // Go directly to security settings 348 tryAdvanceSecurity(mAccount); 349 } 350 return; 351 } 352 finish(); 353 } 354 355 /** 356 * After any of the activities return, try to advance to the "next step" 357 */ 358 @Override onActivityResult(int requestCode, int resultCode, Intent data)359 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 360 tryAdvanceSecurity(mAccount); 361 super.onActivityResult(requestCode, resultCode, data); 362 } 363 364 /** 365 * Walk the user through the required steps to become an active administrator and with 366 * the requisite security settings for the given account. 367 * 368 * These steps will be repeated each time we return from a given attempt (e.g. asking the 369 * user to choose a device pin/password). In a typical activation, we may repeat these 370 * steps a few times. It may go as far as step 5 (password) or step 6 (encryption), but it 371 * will terminate when step 2 (isActive()) succeeds. 372 * 373 * If at any point we do not advance beyond a given user step, (e.g. the user cancels 374 * instead of setting a password) we simply repost the security notification, and exit. 375 * We never want to loop here. 376 */ tryAdvanceSecurity(Account account)377 private void tryAdvanceSecurity(Account account) { 378 SecurityPolicy security = SecurityPolicy.getInstance(this); 379 // Step 1. Check if we are an active device administrator, and stop here to activate 380 if (!security.isActiveAdmin()) { 381 if (mTriedAddAdministrator) { 382 if (DebugUtils.DEBUG || DEBUG) { 383 LogUtils.d(TAG, "Not active admin: repost notification"); 384 } 385 repostNotification(account, security); 386 finish(); 387 } else { 388 mTriedAddAdministrator = true; 389 // retrieve name of server for the format string 390 final HostAuth hostAuth = account.mHostAuthRecv; 391 if (hostAuth == null) { 392 if (DebugUtils.DEBUG || DEBUG) { 393 LogUtils.d(TAG, "No HostAuth: repost notification"); 394 } 395 repostNotification(account, security); 396 finish(); 397 } else { 398 if (DebugUtils.DEBUG || DEBUG) { 399 LogUtils.d(TAG, "Not active admin: post initial notification"); 400 } 401 // try to become active - must happen here in activity, to get result 402 Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN); 403 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, 404 security.getAdminComponent()); 405 intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, 406 this.getString(R.string.account_security_policy_explanation_fmt, 407 hostAuth.mAddress)); 408 startActivityForResult(intent, REQUEST_ENABLE); 409 } 410 } 411 return; 412 } 413 414 // Step 2. Check if the current aggregate security policy is being satisfied by the 415 // DevicePolicyManager (the current system security level). 416 if (security.isActive(null)) { 417 if (DebugUtils.DEBUG || DEBUG) { 418 LogUtils.d(TAG, "Security active; clear holds"); 419 } 420 Account.clearSecurityHoldOnAllAccounts(this); 421 security.syncAccount(account); 422 security.clearNotification(); 423 finish(); 424 return; 425 } 426 427 // Step 3. Try to assert the current aggregate security requirements with the system. 428 security.setActivePolicies(); 429 430 // Step 4. Recheck the security policy, and determine what changes are needed (if any) 431 // to satisfy the requirements. 432 int inactiveReasons = security.getInactiveReasons(null); 433 434 // Step 5. If password is needed, try to have the user set it 435 if ((inactiveReasons & SecurityPolicy.INACTIVE_NEED_PASSWORD) != 0) { 436 if (mTriedSetPassword) { 437 if (DebugUtils.DEBUG || DEBUG) { 438 LogUtils.d(TAG, "Password needed; repost notification"); 439 } 440 repostNotification(account, security); 441 finish(); 442 } else { 443 if (DebugUtils.DEBUG || DEBUG) { 444 LogUtils.d(TAG, "Password needed; request it via DPM"); 445 } 446 mTriedSetPassword = true; 447 // launch the activity to have the user set a new password. 448 Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); 449 startActivityForResult(intent, REQUEST_PASSWORD); 450 } 451 return; 452 } 453 454 // Step 6. If encryption is needed, try to have the user set it 455 if ((inactiveReasons & SecurityPolicy.INACTIVE_NEED_ENCRYPTION) != 0) { 456 if (mTriedSetEncryption) { 457 if (DebugUtils.DEBUG || DEBUG) { 458 LogUtils.d(TAG, "Encryption needed; repost notification"); 459 } 460 repostNotification(account, security); 461 finish(); 462 } else { 463 if (DebugUtils.DEBUG || DEBUG) { 464 LogUtils.d(TAG, "Encryption needed; request it via DPM"); 465 } 466 mTriedSetEncryption = true; 467 // launch the activity to start up encryption. 468 Intent intent = new Intent(DevicePolicyManager.ACTION_START_ENCRYPTION); 469 startActivityForResult(intent, REQUEST_ENCRYPTION); 470 } 471 return; 472 } 473 474 // Step 7. No problems were found, so clear holds and exit 475 if (DebugUtils.DEBUG || DEBUG) { 476 LogUtils.d(TAG, "Policies enforced; clear holds"); 477 } 478 Account.clearSecurityHoldOnAllAccounts(this); 479 security.syncAccount(account); 480 security.clearNotification(); 481 finish(); 482 } 483 484 /** 485 * Mark an account as not-ready-for-sync and post a notification to bring the user back here 486 * eventually. 487 */ repostNotification(final Account account, final SecurityPolicy security)488 private static void repostNotification(final Account account, final SecurityPolicy security) { 489 if (account == null) return; 490 new AsyncTask<Void, Void, Void>() { 491 @Override 492 protected Void doInBackground(Void... params) { 493 security.policiesRequired(account.mId); 494 return null; 495 } 496 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 497 } 498 499 /** 500 * Dialog briefly shown in some cases, to indicate the user that a security update is needed. 501 * If the user clicks OK, we proceed into the "tryAdvanceSecurity" flow. If the user cancels, 502 * we repost the notification and finish() the activity. 503 */ 504 public static class SecurityNeededDialog extends DialogFragment 505 implements DialogInterface.OnClickListener { 506 private static final String BUNDLE_KEY_ACCOUNT_NAME = "account_name"; 507 508 // Public no-args constructor needed for fragment re-instantiation SecurityNeededDialog()509 public SecurityNeededDialog() {} 510 511 /** 512 * Create a new dialog. 513 */ newInstance(String accountName)514 public static SecurityNeededDialog newInstance(String accountName) { 515 final SecurityNeededDialog dialog = new SecurityNeededDialog(); 516 Bundle b = new Bundle(); 517 b.putString(BUNDLE_KEY_ACCOUNT_NAME, accountName); 518 dialog.setArguments(b); 519 return dialog; 520 } 521 522 @Override onCreateDialog(Bundle savedInstanceState)523 public Dialog onCreateDialog(Bundle savedInstanceState) { 524 final String accountName = getArguments().getString(BUNDLE_KEY_ACCOUNT_NAME); 525 526 final Context context = getActivity(); 527 final Resources res = context.getResources(); 528 final AlertDialog.Builder b = new AlertDialog.Builder(context); 529 b.setTitle(R.string.account_security_dialog_title); 530 b.setIconAttribute(android.R.attr.alertDialogIcon); 531 b.setMessage(res.getString(R.string.account_security_dialog_content_fmt, accountName)); 532 b.setPositiveButton(android.R.string.ok, this); 533 b.setNegativeButton(android.R.string.cancel, this); 534 if (DebugUtils.DEBUG || DEBUG) { 535 LogUtils.d(TAG, "Posting security needed dialog"); 536 } 537 return b.create(); 538 } 539 540 @Override onClick(DialogInterface dialog, int which)541 public void onClick(DialogInterface dialog, int which) { 542 dismiss(); 543 AccountSecurity activity = (AccountSecurity) getActivity(); 544 if (activity.mAccount == null) { 545 // Clicked before activity fully restored - probably just monkey - exit quickly 546 activity.finish(); 547 return; 548 } 549 switch (which) { 550 case DialogInterface.BUTTON_POSITIVE: 551 if (DebugUtils.DEBUG || DEBUG) { 552 LogUtils.d(TAG, "User accepts; advance to next step"); 553 } 554 activity.tryAdvanceSecurity(activity.mAccount); 555 break; 556 case DialogInterface.BUTTON_NEGATIVE: 557 if (DebugUtils.DEBUG || DEBUG) { 558 LogUtils.d(TAG, "User declines; repost notification"); 559 } 560 AccountSecurity.repostNotification( 561 activity.mAccount, SecurityPolicy.getInstance(activity)); 562 activity.finish(); 563 break; 564 } 565 } 566 } 567 568 /** 569 * Dialog briefly shown in some cases, to indicate the user that the PIN/Password is expiring 570 * or has expired. If the user clicks OK, we launch the password settings screen. 571 */ 572 public static class PasswordExpirationDialog extends DialogFragment 573 implements DialogInterface.OnClickListener { 574 private static final String BUNDLE_KEY_ACCOUNT_NAME = "account_name"; 575 private static final String BUNDLE_KEY_EXPIRED = "expired"; 576 577 /** 578 * Create a new dialog. 579 */ newInstance(String accountName, boolean expired)580 public static PasswordExpirationDialog newInstance(String accountName, boolean expired) { 581 final PasswordExpirationDialog dialog = new PasswordExpirationDialog(); 582 Bundle b = new Bundle(); 583 b.putString(BUNDLE_KEY_ACCOUNT_NAME, accountName); 584 b.putBoolean(BUNDLE_KEY_EXPIRED, expired); 585 dialog.setArguments(b); 586 return dialog; 587 } 588 589 // Public no-args constructor needed for fragment re-instantiation PasswordExpirationDialog()590 public PasswordExpirationDialog() {} 591 592 /** 593 * Note, this actually creates two slightly different dialogs (for expiring vs. expired) 594 */ 595 @Override onCreateDialog(Bundle savedInstanceState)596 public Dialog onCreateDialog(Bundle savedInstanceState) { 597 final String accountName = getArguments().getString(BUNDLE_KEY_ACCOUNT_NAME); 598 final boolean expired = getArguments().getBoolean(BUNDLE_KEY_EXPIRED); 599 final int titleId = expired 600 ? R.string.password_expired_dialog_title 601 : R.string.password_expire_warning_dialog_title; 602 final int contentId = expired 603 ? R.string.password_expired_dialog_content_fmt 604 : R.string.password_expire_warning_dialog_content_fmt; 605 606 final Context context = getActivity(); 607 final Resources res = context.getResources(); 608 return new AlertDialog.Builder(context) 609 .setTitle(titleId) 610 .setIconAttribute(android.R.attr.alertDialogIcon) 611 .setMessage(res.getString(contentId, accountName)) 612 .setPositiveButton(android.R.string.ok, this) 613 .setNegativeButton(android.R.string.cancel, this) 614 .create(); 615 } 616 617 @Override onClick(DialogInterface dialog, int which)618 public void onClick(DialogInterface dialog, int which) { 619 dismiss(); 620 AccountSecurity activity = (AccountSecurity) getActivity(); 621 if (which == DialogInterface.BUTTON_POSITIVE) { 622 Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); 623 activity.startActivity(intent); 624 } 625 activity.finish(); 626 } 627 } 628 } 629