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