chromium/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseCreationDialogFragment.java

// Copyright 2015 The Chromium Authors
// 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.sync.ui;

import android.app.Dialog;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;

import org.chromium.chrome.R;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.settings.ProfileDependentSetting;
import org.chromium.chrome.browser.sync.SyncServiceFactory;
import org.chromium.chrome.browser.sync.settings.SyncSettingsUtils;
import org.chromium.ui.text.SpanApplier;
import org.chromium.ui.text.SpanApplier.SpanInfo;

/** Dialog to ask the user to enter a new custom passphrase. */
public class PassphraseCreationDialogFragment extends DialogFragment
        implements ProfileDependentSetting {
    public interface Listener {
        void onPassphraseCreated(String passphrase);
    }

    private Profile mProfile;
    private EditText mEnterPassphrase;
    private EditText mConfirmPassphrase;

    @Override
    public void setProfile(@NonNull Profile profile) {
        mProfile = profile;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        super.onCreateDialog(savedInstanceState);
        LayoutInflater inflater = getActivity().getLayoutInflater();
        View view = inflater.inflate(R.layout.sync_custom_passphrase, null);
        mEnterPassphrase = view.findViewById(R.id.passphrase);
        mConfirmPassphrase = view.findViewById(R.id.confirm_passphrase);

        mConfirmPassphrase.setOnEditorActionListener(
                new OnEditorActionListener() {
                    @Override
                    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                        if (actionId == EditorInfo.IME_ACTION_DONE) {
                            tryToSubmitPassphrase();
                        }
                        return false;
                    }
                });

        TextView instructionsView = view.findViewById(R.id.custom_passphrase_instructions);
        instructionsView.setMovementMethod(LinkMovementMethod.getInstance());
        instructionsView.setText(getInstructionsText());

        AlertDialog dialog =
                new AlertDialog.Builder(getActivity(), R.style.ThemeOverlay_BrowserUI_AlertDialog)
                        .setView(view)
                        .setTitle(R.string.sync_passphrase_type_custom_dialog_title)
                        .setPositiveButton(R.string.save, null)
                        .setNegativeButton(R.string.cancel, null)
                        .create();
        dialog.getDelegate().setHandleNativeActionModesEnabled(false);
        return dialog;
    }

    private SpannableString getInstructionsText() {
        boolean shouldReplaceSyncSettingsWithAccountSettings =
                ChromeFeatureList.isEnabled(
                                ChromeFeatureList.REPLACE_SYNC_PROMOS_WITH_SIGN_IN_PROMOS)
                        && !SyncServiceFactory.getForProfile(mProfile).hasSyncConsent();
        return SpanApplier.applySpans(
                getString(
                        shouldReplaceSyncSettingsWithAccountSettings
                                ? R.string.sync_encryption_create_passphrase
                                : R.string.legacy_sync_encryption_create_passphrase),
                new SpanInfo(
                        "BEGIN_LINK",
                        "END_LINK",
                        new ClickableSpan() {
                            @Override
                            public void onClick(View view) {
                                SyncSettingsUtils.openSyncDashboard(getActivity());
                            }
                        }));
    }

    @Override
    public void onStart() {
        super.onStart();
        AlertDialog d = (AlertDialog) getDialog();
        if (d != null) {
            // Override the button's onClick listener. The default gets set in the dialog's
            // onCreate, when it is shown (in super.onStart()), so we have to do this here.
            // Otherwise the dialog will close when the button is clicked regardless of what else we
            // do.
            d.getButton(Dialog.BUTTON_POSITIVE)
                    .setOnClickListener(
                            new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    tryToSubmitPassphrase();
                                }
                            });
        }
    }

    private void tryToSubmitPassphrase() {
        String passphrase = mEnterPassphrase.getText().toString();
        String confirmPassphrase = mConfirmPassphrase.getText().toString();

        if (!passphrase.equals(confirmPassphrase)) {
            mEnterPassphrase.setError(null);
            mConfirmPassphrase.setError(getString(R.string.sync_passphrases_do_not_match));
            mConfirmPassphrase.requestFocus();
            return;
        } else if (passphrase.isEmpty()) {
            mConfirmPassphrase.setError(null);
            mEnterPassphrase.setError(getString(R.string.sync_passphrase_cannot_be_blank));
            mEnterPassphrase.requestFocus();
            return;
        }

        // The passphrase is not empty and matches.
        ((Listener) getTargetFragment()).onPassphraseCreated(passphrase);
        getDialog().dismiss();
    }
}