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