chromium/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/IdentityErrorCardPreference.java

// Copyright 2024 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.settings;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.appcompat.content.res.AppCompatResources;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;

import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.sync.SyncServiceFactory;
import org.chromium.chrome.browser.sync.settings.SyncSettingsUtils.ErrorCardDetails;
import org.chromium.chrome.browser.sync.settings.SyncSettingsUtils.ErrorUiAction;
import org.chromium.chrome.browser.sync.settings.SyncSettingsUtils.SyncError;
import org.chromium.components.sync.SyncService;

public class IdentityErrorCardPreference extends Preference
        implements SyncService.SyncStateChangedListener {
    public interface Listener {
        /** Called when the user clicks the button. */
        void onIdentityErrorCardButtonClicked(@SyncError int error);
    }

    private Profile mProfile;
    private SyncService mSyncService;
    private Listener mListener;

    private @SyncError int mIdentityError;

    public IdentityErrorCardPreference(Context context, AttributeSet attrs) {
        super(context, attrs);

        setLayoutResource(R.layout.signin_settings_card_view);
        mIdentityError = SyncError.NO_ERROR;
    }

    /**
     * Initialize the dependencies for the IdentityErrorCardPreference and update the error card.
     */
    public void initialize(Profile profile, Listener listener) {
        assert getParent() != null : "Not attached to any parent.";

        mProfile = profile;
        mSyncService = SyncServiceFactory.getForProfile(mProfile);
        mListener = listener;

        if (mSyncService != null) {
            mSyncService.addSyncStateChangedListener(this);
        }
        update();
    }

    @Override
    public void onDetached() {
        super.onDetached();
        if (mSyncService != null) {
            mSyncService.removeSyncStateChangedListener(this);
        }
    }

    @Override
    public void onBindViewHolder(PreferenceViewHolder holder) {
        super.onBindViewHolder(holder);

        if (mIdentityError == SyncError.NO_ERROR) {
            return;
        }
        holder.setDividerAllowedAbove(false);
        setupIdentityErrorCardView(holder.findViewById(R.id.signin_settings_card));
    }

    private void update() {
        @SyncError int error = SyncSettingsUtils.getIdentityError(mProfile);
        if (error == mIdentityError) {
            // Nothing changed.
            return;
        }
        mIdentityError = error;
        if (shouldShowErrorCard()) {
            setVisible(true);
            notifyChanged();
            RecordHistogram.recordEnumeratedHistogram(
                    "Sync.IdentityErrorCard"
                            + SyncSettingsUtils.getHistogramSuffixForError(mIdentityError),
                    ErrorUiAction.SHOWN,
                    ErrorUiAction.NUM_ENTRIES);
        } else {
            setVisible(false);
        }
    }

    private void setupIdentityErrorCardView(View card) {
        Context context = getContext();

        ImageView image = (ImageView) card.findViewById(R.id.signin_settings_card_icon);
        image.setContentDescription(
                context.getResources()
                        .getString(R.string.accessibility_account_management_row_account_error));
        image.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.ic_error));

        TextView error = card.findViewById(R.id.signin_settings_card_description);
        Button button = card.findViewById(R.id.signin_settings_card_button);

        ErrorCardDetails error_card_details =
                SyncSettingsUtils.getIdentityErrorErrorCardDetails(mIdentityError);
        error.setText(context.getString(error_card_details.message));
        button.setText(context.getString(error_card_details.buttonLabel));

        button.setOnClickListener(
                v -> {
                    RecordHistogram.recordEnumeratedHistogram(
                            "Sync.IdentityErrorCard"
                                    + SyncSettingsUtils.getHistogramSuffixForError(mIdentityError),
                            ErrorUiAction.BUTTON_CLICKED,
                            ErrorUiAction.NUM_ENTRIES);
                    mListener.onIdentityErrorCardButtonClicked(mIdentityError);
                });
    }

    /** {@link SyncService.SyncStateChangedListener} implementation. */
    @Override
    public void syncStateChanged() {
        update();
    }

    private boolean shouldShowErrorCard() {
        return mIdentityError != SyncError.NO_ERROR;
    }
}