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