Home | History | Annotate | Download | only in accounts
      1 /*
      2  * Copyright (C) 2017 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 package com.android.settings.accounts;
     17 
     18 import android.accounts.Account;
     19 import android.accounts.AccountManager;
     20 import android.accounts.AccountManagerCallback;
     21 import android.accounts.AccountManagerFuture;
     22 import android.accounts.AuthenticatorException;
     23 import android.accounts.OperationCanceledException;
     24 import android.app.admin.DevicePolicyManager;
     25 import android.app.Activity;
     26 import android.app.AlertDialog;
     27 import android.app.Dialog;
     28 import android.app.Fragment;
     29 import android.content.Context;
     30 import android.content.DialogInterface;
     31 import android.content.Intent;
     32 import android.os.Bundle;
     33 import android.os.UserHandle;
     34 import android.os.UserManager;
     35 import android.support.v7.preference.PreferenceScreen;
     36 import android.view.View;
     37 import android.view.View.OnClickListener;
     38 import android.widget.Button;
     39 
     40 import com.android.internal.annotations.VisibleForTesting;
     41 import com.android.internal.logging.nano.MetricsProto;
     42 import com.android.settings.R;
     43 import com.android.settings.applications.LayoutPreference;
     44 import com.android.settings.core.PreferenceControllerMixin;
     45 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
     46 import com.android.settings.enterprise.DevicePolicyManagerWrapper;
     47 import com.android.settings.enterprise.DevicePolicyManagerWrapperImpl;
     48 import com.android.settingslib.core.AbstractPreferenceController;
     49 
     50 import java.io.IOException;
     51 
     52 public class RemoveAccountPreferenceController extends AbstractPreferenceController
     53         implements PreferenceControllerMixin, OnClickListener {
     54 
     55     private static final String KEY_REMOVE_ACCOUNT = "remove_account";
     56 
     57     private Account mAccount;
     58     private Fragment mParentFragment;
     59     private UserHandle mUserHandle;
     60     private DevicePolicyManagerWrapper mDpm;
     61 
     62     public RemoveAccountPreferenceController(Context context, Fragment parent) {
     63         this(context, parent, new DevicePolicyManagerWrapperImpl(
     64                 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE)));
     65     }
     66 
     67     @VisibleForTesting
     68     RemoveAccountPreferenceController(Context context, Fragment parent,
     69             DevicePolicyManagerWrapper dpm) {
     70         super(context);
     71         mParentFragment = parent;
     72         mDpm = dpm;
     73     }
     74 
     75     @Override
     76     public void displayPreference(PreferenceScreen screen) {
     77         super.displayPreference(screen);
     78         final LayoutPreference removeAccountPreference =
     79             (LayoutPreference) screen.findPreference(KEY_REMOVE_ACCOUNT);
     80         Button removeAccountButton = (Button) removeAccountPreference.findViewById(R.id.button);
     81         removeAccountButton.setOnClickListener(this);
     82     }
     83 
     84     @Override
     85     public boolean isAvailable() {
     86         return true;
     87     }
     88 
     89     @Override
     90     public String getPreferenceKey() {
     91         return KEY_REMOVE_ACCOUNT;
     92     }
     93 
     94     @Override
     95     public void onClick(View v) {
     96         final Intent intent = mDpm.createAdminSupportIntent(UserManager.DISALLOW_MODIFY_ACCOUNTS);
     97         if (intent != null) {
     98             // DISALLOW_MODIFY_ACCOUNTS is active, show admin support dialog
     99             mContext.startActivity(intent);
    100             return;
    101         }
    102         ConfirmRemoveAccountDialog.show(mParentFragment, mAccount, mUserHandle);
    103     }
    104 
    105     public void init(Account account, UserHandle userHandle) {
    106         mAccount = account;
    107         mUserHandle = userHandle;
    108     }
    109 
    110     /**
    111      * Dialog to confirm with user about account removal
    112      */
    113     public static class ConfirmRemoveAccountDialog extends InstrumentedDialogFragment implements
    114             DialogInterface.OnClickListener {
    115         private static final String KEY_ACCOUNT = "account";
    116         private static final String REMOVE_ACCOUNT_DIALOG = "confirmRemoveAccount";
    117         private Account mAccount;
    118         private UserHandle mUserHandle;
    119 
    120         public static ConfirmRemoveAccountDialog show(
    121                 Fragment parent, Account account, UserHandle userHandle) {
    122             if (!parent.isAdded()) {
    123                 return null;
    124             }
    125             final ConfirmRemoveAccountDialog dialog = new ConfirmRemoveAccountDialog();
    126             Bundle bundle = new Bundle();
    127             bundle.putParcelable(KEY_ACCOUNT, account);
    128             bundle.putParcelable(Intent.EXTRA_USER, userHandle);
    129             dialog.setArguments(bundle);
    130             dialog.setTargetFragment(parent, 0);
    131             dialog.show(parent.getFragmentManager(), REMOVE_ACCOUNT_DIALOG);
    132             return dialog;
    133         }
    134 
    135         @Override
    136         public void onCreate(Bundle savedInstanceState) {
    137             super.onCreate(savedInstanceState);
    138             final Bundle arguments = getArguments();
    139             mAccount = arguments.getParcelable(KEY_ACCOUNT);
    140             mUserHandle = arguments.getParcelable(Intent.EXTRA_USER);
    141         }
    142 
    143         @Override
    144         public Dialog onCreateDialog(Bundle savedInstanceState) {
    145             final Context context = getActivity();
    146             return new AlertDialog.Builder(context)
    147                 .setTitle(R.string.really_remove_account_title)
    148                 .setMessage(R.string.really_remove_account_message)
    149                 .setNegativeButton(android.R.string.cancel, null)
    150                 .setPositiveButton(R.string.remove_account_label, this)
    151                 .create();
    152         }
    153 
    154         @Override
    155         public int getMetricsCategory() {
    156             return MetricsProto.MetricsEvent.DIALOG_ACCOUNT_SYNC_REMOVE;
    157         }
    158 
    159         @Override
    160         public void onClick(DialogInterface dialog, int which) {
    161             Activity activity = getTargetFragment().getActivity();
    162             AccountManager.get(activity).removeAccountAsUser(mAccount, activity,
    163                     new AccountManagerCallback<Bundle>() {
    164                         @Override
    165                         public void run(AccountManagerFuture<Bundle> future) {
    166                             // If already out of this screen, don't proceed.
    167                             if (!getTargetFragment().isResumed()) {
    168                                 return;
    169                             }
    170                             boolean failed = true;
    171                             try {
    172                                 if (future.getResult()
    173                                     .getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
    174                                     failed = false;
    175                                 }
    176                             } catch (OperationCanceledException e) {
    177                                 // handled below
    178                             } catch (IOException e) {
    179                                 // handled below
    180                             } catch (AuthenticatorException e) {
    181                                 // handled below
    182                             }
    183                             final Activity activity = getTargetFragment().getActivity();
    184                             if (failed && activity != null && !activity.isFinishing()) {
    185                                 RemoveAccountFailureDialog.show(getTargetFragment());
    186                             } else {
    187                                 activity.finish();
    188                             }
    189                         }
    190                     }, null, mUserHandle);
    191         }
    192     }
    193 
    194     /**
    195      * Dialog to tell user about account removal failure
    196      */
    197     public static class RemoveAccountFailureDialog extends InstrumentedDialogFragment {
    198 
    199         private static final String FAILED_REMOVAL_DIALOG = "removeAccountFailed";
    200 
    201         public static void show(Fragment parent) {
    202             if (!parent.isAdded()) {
    203                 return;
    204             }
    205             final RemoveAccountFailureDialog dialog = new RemoveAccountFailureDialog();
    206             dialog.setTargetFragment(parent, 0);
    207             dialog.show(parent.getFragmentManager(), FAILED_REMOVAL_DIALOG);
    208         }
    209 
    210         @Override
    211         public Dialog onCreateDialog(Bundle savedInstanceState) {
    212             final Context context = getActivity();
    213 
    214             return new AlertDialog.Builder(context)
    215                 .setTitle(R.string.really_remove_account_title)
    216                 .setMessage(R.string.remove_account_failed)
    217                 .setPositiveButton(android.R.string.ok, null)
    218                 .create();
    219         }
    220 
    221         @Override
    222         public int getMetricsCategory() {
    223             return MetricsProto.MetricsEvent.DIALOG_ACCOUNT_SYNC_FAILED_REMOVAL;
    224         }
    225 
    226     }
    227 }
    228