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