blob: f07c94712f1c89c2b6818ea399692bbf0779afb1 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.settings.accounts;
import static android.os.UserManager.DISALLOW_MODIFY_ACCOUNTS;
import static com.android.car.settings.enterprise.ActionDisabledByAdminDialogFragment.DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG;
import static com.android.car.settings.enterprise.EnterpriseUtils.hasUserRestrictionByDpm;
import static com.android.car.settings.enterprise.EnterpriseUtils.hasUserRestrictionByUm;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.car.drivingstate.CarUxRestrictions;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.CallSuper;
import androidx.annotation.VisibleForTesting;
import com.android.car.settings.R;
import com.android.car.settings.common.ActivityResultCallback;
import com.android.car.settings.common.ConfirmationDialogFragment;
import com.android.car.settings.common.ErrorDialog;
import com.android.car.settings.common.FragmentController;
import com.android.car.settings.common.Logger;
import com.android.car.settings.enterprise.EnterpriseUtils;
import com.android.car.settings.profiles.ProfileHelper;
import java.io.IOException;
/**
* Controller for the preference that shows the details of an account. It also handles a secondary
* button for account removal.
*/
public class AccountDetailsPreferenceController extends AccountDetailsBasePreferenceController
implements ActivityResultCallback {
private static final Logger LOG = new Logger(AccountDetailsPreferenceController.class);
private static final int REMOVE_ACCOUNT_REQUEST = 101;
private AccountManagerCallback<Bundle> mCallback =
future -> {
// If already out of this screen, don't proceed.
if (!isStarted()) {
return;
}
boolean done = true;
boolean success = false;
try {
Bundle result = future.getResult();
Intent removeIntent = result.getParcelable(AccountManager.KEY_INTENT);
if (removeIntent != null) {
done = false;
getFragmentController().startActivityForResult(new Intent(removeIntent),
REMOVE_ACCOUNT_REQUEST, this);
} else {
success = future.getResult().getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
}
} catch (OperationCanceledException | IOException | AuthenticatorException e) {
LOG.v("removeAccount error: " + e);
}
if (done) {
if (!success) {
showErrorDialog();
} else {
getFragmentController().goBack();
}
}
};
private ConfirmationDialogFragment.ConfirmListener mConfirmListener = arguments -> {
AccountManager.get(getContext()).removeAccountAsUser(getAccount(), /* activity= */ null,
mCallback, null, getUserHandle());
ConfirmationDialogFragment dialog =
(ConfirmationDialogFragment) getFragmentController().findDialogByTag(
ConfirmationDialogFragment.TAG);
if (dialog != null) {
dialog.dismiss();
}
};
public AccountDetailsPreferenceController(Context context, String preferenceKey,
FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
super(context, preferenceKey, fragmentController, uxRestrictions);
}
@Override
@CallSuper
protected void onCreateInternal() {
super.onCreateInternal();
ConfirmationDialogFragment dialog =
(ConfirmationDialogFragment) getFragmentController().findDialogByTag(
ConfirmationDialogFragment.TAG);
ConfirmationDialogFragment.resetListeners(
dialog,
mConfirmListener,
/* rejectListener= */ null,
/* neutralListener= */ null);
getPreference().setSecondaryActionVisible(
getSecondaryActionAvailabilityStatus() == AVAILABLE
|| getSecondaryActionAvailabilityStatus() == AVAILABLE_FOR_VIEWING);
getPreference().setSecondaryActionEnabled(
getSecondaryActionAvailabilityStatus() != DISABLED_FOR_PROFILE);
getPreference().setOnSecondaryActionClickListener(this::onRemoveAccountClicked);
}
@Override
public void processActivityResult(int requestCode, int resultCode, Intent data) {
if (!isStarted()) {
return;
}
if (requestCode == REMOVE_ACCOUNT_REQUEST) {
// Activity result code may not adequately reflect the account removal status, so
// KEY_BOOLEAN_RESULT is used here instead. If the intent does not have this value
// included, a no-op will be performed and the account update listener in
// {@link AccountDetailsFragment} will still handle the back navigation upon removal.
if (data != null && data.hasExtra(AccountManager.KEY_BOOLEAN_RESULT)) {
boolean success = data.getBooleanExtra(AccountManager.KEY_BOOLEAN_RESULT, false);
if (success) {
getFragmentController().goBack();
} else {
showErrorDialog();
}
}
}
}
private int getSecondaryActionAvailabilityStatus() {
ProfileHelper profileHelper = getProfileHelper();
if (profileHelper.canCurrentProcessModifyAccounts()) {
return AVAILABLE;
}
if (profileHelper.isDemoOrGuest()
|| hasUserRestrictionByUm(getContext(), DISALLOW_MODIFY_ACCOUNTS)) {
return DISABLED_FOR_PROFILE;
}
return AVAILABLE_FOR_VIEWING;
}
private void onRemoveAccountClicked() {
if (hasUserRestrictionByDpm(getContext(), DISALLOW_MODIFY_ACCOUNTS)) {
showActionDisabledByAdminDialog();
}
ConfirmationDialogFragment dialog =
new ConfirmationDialogFragment.Builder(getContext())
.setTitle(R.string.really_remove_account_title)
.setMessage(R.string.really_remove_account_message)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.remove_account_title, mConfirmListener)
.build();
getFragmentController().showDialog(dialog, ConfirmationDialogFragment.TAG);
}
private void showErrorDialog() {
getFragmentController().showDialog(
ErrorDialog.newInstance(R.string.remove_account_error_title), /* tag= */ null);
}
private void showActionDisabledByAdminDialog() {
getFragmentController().showDialog(
EnterpriseUtils.getActionDisabledByAdminDialog(getContext(),
DISALLOW_MODIFY_ACCOUNTS),
DISABLED_BY_ADMIN_CONFIRM_DIALOG_TAG);
}
@VisibleForTesting
ProfileHelper getProfileHelper() {
return ProfileHelper.getInstance(getContext());
}
}