blob: 903b4b6a92c1ec83492761e45335fae2fcab3a6f [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.signin;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.IntDef;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.preferences.ManagedPreferencesUtils;
import org.chromium.chrome.browser.widget.RadioButtonWithDescription;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.List;
/**
* A dialog that is displayed when the user switches the account they are syncing to. It gives the
* option to merge the data of the two accounts or to keep them separate.
*/
public class ConfirmImportSyncDataDialog extends DialogFragment
implements DialogInterface.OnClickListener {
/**
* Callback for completion of the dialog. Only one of {@link Listener#onConfirm} or
* {@link Listener#onCancel} will be called and it will only be called once.
*/
public interface Listener {
/**
* The user has completed the dialog using the positive button.
* @param wipeData Whether the user requested that existing data should be wiped.
*/
void onConfirm(boolean wipeData);
/**
* The user dismisses the dialog through any means other than the positive button.
*/
void onCancel();
}
/**
* The situation ConfirmImportSyncDataDialog is created for - whether the user had previously
* been signed into another account, had signed out then signed into a different one, or
* if they directly switched accounts. This changes the strings displayed.
*/
@IntDef({ImportSyncType.SWITCHING_SYNC_ACCOUNTS, ImportSyncType.PREVIOUS_DATA_FOUND})
@Retention(RetentionPolicy.SOURCE)
public @interface ImportSyncType {
int SWITCHING_SYNC_ACCOUNTS = 0;
int PREVIOUS_DATA_FOUND = 1;
}
@VisibleForTesting
public static final String CONFIRM_IMPORT_SYNC_DATA_DIALOG_TAG =
"sync_account_switch_import_data_tag";
private static final String KEY_OLD_ACCOUNT_NAME = "lastAccountName";
private static final String KEY_NEW_ACCOUNT_NAME = "newAccountName";
private static final String KEY_IMPORT_SYNC_TYPE = "importSyncType";
private RadioButtonWithDescription mConfirmImportOption;
private RadioButtonWithDescription mKeepSeparateOption;
private Listener mListener;
private boolean mListenerCalled;
private static ConfirmImportSyncDataDialog newInstance(
String oldAccountName, String newAccountName, @ImportSyncType int importSyncType) {
ConfirmImportSyncDataDialog fragment = new ConfirmImportSyncDataDialog();
Bundle args = new Bundle();
args.putString(KEY_OLD_ACCOUNT_NAME, oldAccountName);
args.putString(KEY_NEW_ACCOUNT_NAME, newAccountName);
args.putInt(KEY_IMPORT_SYNC_TYPE, importSyncType);
fragment.setArguments(args);
return fragment;
}
/**
* Creates and shows a new instance of ConfirmImportSyncDataFragment, a dialog that gives the
* user the option to merge data between the account they are attempting to sign in to and the
* account they were previously signed into, or to keep the data separate.
* @param oldAccountName The previous sync account name.
* @param newAccountName The potential next sync account name.
* @param importSyncType The situation the dialog is created in - either when directly changing
* the sync account or signing in after being signed out (this changes
* displayed strings).
* @param fragmentManager FragmentManager to attach the dialog to.
* @param callback Callback to be called if the user completes the dialog (as opposed to
* hitting cancel).
*/
public static void showNewInstance(String oldAccountName, String newAccountName,
@ImportSyncType int importSyncType, FragmentManager fragmentManager,
Listener callback) {
ConfirmImportSyncDataDialog confirmSync =
newInstance(oldAccountName, newAccountName, importSyncType);
confirmSync.setListener(callback);
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(confirmSync, CONFIRM_IMPORT_SYNC_DATA_DIALOG_TAG);
transaction.commitAllowingStateLoss();
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// If the dialog is being recreated it won't have the listener set and so won't be
// functional. Therefore we dismiss, and the user will need to open the dialog again.
if (savedInstanceState != null) {
dismiss();
}
String oldAccountName = getArguments().getString(KEY_OLD_ACCOUNT_NAME);
String newAccountName = getArguments().getString(KEY_NEW_ACCOUNT_NAME);
@ImportSyncType
int importSyncType = getArguments().getInt(KEY_IMPORT_SYNC_TYPE);
LayoutInflater inflater = getActivity().getLayoutInflater();
View v = inflater.inflate(R.layout.confirm_import_sync_data, null);
TextView prompt = v.findViewById(R.id.sync_import_data_prompt);
prompt.setText(getActivity().getString(R.string.sync_import_data_prompt, oldAccountName));
mConfirmImportOption = v.findViewById(R.id.sync_confirm_import_choice);
mKeepSeparateOption = v.findViewById(R.id.sync_keep_separate_choice);
mConfirmImportOption.setDescriptionText(getActivity().getString(
R.string.sync_import_existing_data_subtext, newAccountName));
if (importSyncType == ImportSyncType.SWITCHING_SYNC_ACCOUNTS) {
mKeepSeparateOption.setDescriptionText(getActivity().getString(
R.string.sync_keep_existing_data_separate_subtext_switching_accounts,
oldAccountName));
} else {
mKeepSeparateOption.setDescriptionText(getActivity().getString(
R.string.sync_keep_existing_data_separate_subtext_existing_data));
}
List<RadioButtonWithDescription> radioGroup =
Arrays.asList(mConfirmImportOption, mKeepSeparateOption);
mConfirmImportOption.setRadioButtonGroup(radioGroup);
mKeepSeparateOption.setRadioButtonGroup(radioGroup);
// If the account is managed, disallow merging information.
if (SigninManager.get().getManagementDomain() != null) {
mKeepSeparateOption.setChecked(true);
mConfirmImportOption.setOnClickListener(
view -> ManagedPreferencesUtils.showManagedByAdministratorToast(getActivity()));
} else {
if (importSyncType == ImportSyncType.SWITCHING_SYNC_ACCOUNTS) {
mKeepSeparateOption.setChecked(true);
} else {
mConfirmImportOption.setChecked(true);
}
}
if (importSyncType == ImportSyncType.SWITCHING_SYNC_ACCOUNTS) {
// Re-order the buttons so that Import Data is last and Don't Import (the default) is
// at the top.
LinearLayout layout = v.findViewById(R.id.sync_import_data_content);
layout.removeView(mConfirmImportOption);
layout.addView(mConfirmImportOption);
}
return new AlertDialog.Builder(getActivity(), R.style.Theme_Chromium_AlertDialog)
.setPositiveButton(R.string.continue_button, this)
.setNegativeButton(R.string.cancel, this)
.setView(v)
.create();
}
private void setListener(Listener listener) {
assert mListener == null;
mListener = listener;
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (mListener == null) return;
if (which == AlertDialog.BUTTON_POSITIVE) {
assert mConfirmImportOption.isChecked() ^ mKeepSeparateOption.isChecked();
RecordUserAction.record(mKeepSeparateOption.isChecked()
? "Signin_ImportDataPrompt_DontImport"
: "Signin_ImportDataPrompt_ImportData");
mListener.onConfirm(mKeepSeparateOption.isChecked());
} else {
assert which == AlertDialog.BUTTON_NEGATIVE;
RecordUserAction.record("Signin_ImportDataPrompt_Cancel");
mListener.onCancel();
}
mListenerCalled = true;
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (mListener != null && !mListenerCalled) {
mListener.onCancel();
}
}
}