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