chromium/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java

// Copyright 2016 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.infobar;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.Nullable;

import org.jni_zero.CalledByNative;
import org.jni_zero.NativeMethods;

import org.chromium.chrome.R;
import org.chromium.components.autofill.payments.CardDetail;
import org.chromium.components.autofill.payments.LegalMessageLine;
import org.chromium.components.browser_ui.widget.RoundedCornerImageView;
import org.chromium.components.infobars.ConfirmInfoBar;
import org.chromium.components.infobars.InfoBarControlLayout;
import org.chromium.components.infobars.InfoBarLayout;
import org.chromium.ui.UiUtils;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/** An infobar for saving credit card information. */
public class AutofillSaveCardInfoBar extends ConfirmInfoBar {

    private final @Nullable String mAccountFooterEmail;
    private final @Nullable Bitmap mAccountFooterAvatar;
    private final long mNativeAutofillSaveCardInfoBar;
    private final List<CardDetail> mCardDetails = new ArrayList<>();
    private int mIconDrawableId = -1;
    private String mTitleText;
    private String mDescriptionText;
    private boolean mIsGooglePayBrandingEnabled;
    private final LinkedList<LegalMessageLine> mLegalMessageLines =
            new LinkedList<LegalMessageLine>();

    /**
     * Creates a new instance of the infobar.
     *
     * @param nativeAutofillSaveCardInfoBar The pointer to the native object for callbacks.
     * @param iconId ID corresponding to the icon that will be shown for the InfoBar.
     * @param iconBitmap Bitmap to use if there is no equivalent Java resource for iconId.
     * @param message Title of the infobar to display along the icon.
     * @param linkText Link text to display in addition to the message.
     * @param buttonOk String to display on the OK button.
     * @param buttonCancel String to display on the Cancel button.
     * @param accountFooterEmail The email to be shown on the footer, or null. The footer is
     * only shown if both this and |accountFooterAvatar| are provided.
     * @param accountFooterAvatar The avatar to be shown on the footer, or null. The footer is
     * only shown if both this and |accountFooterEmail| are provided.
     */
    private AutofillSaveCardInfoBar(
            long nativeAutofillSaveCardInfoBar,
            int iconId,
            Bitmap iconBitmap,
            String message,
            String linkText,
            String buttonOk,
            String buttonCancel,
            boolean isGooglePayBrandingEnabled,
            @Nullable String accountFooterEmail,
            @Nullable Bitmap accountFooterAvatar) {
        // If Google Pay branding is enabled, no icon is specified here; it is rather added in
        // |createContent|. This hides the ImageView that normally shows the icon and gets rid of
        // the left padding of the infobar content.
        super(
                isGooglePayBrandingEnabled ? 0 : iconId,
                isGooglePayBrandingEnabled ? 0 : R.color.infobar_icon_drawable_color,
                iconBitmap,
                message,
                linkText,
                buttonOk,
                buttonCancel);
        mIconDrawableId = iconId;
        mTitleText = message;
        mIsGooglePayBrandingEnabled = isGooglePayBrandingEnabled;
        mNativeAutofillSaveCardInfoBar = nativeAutofillSaveCardInfoBar;
        mAccountFooterEmail = accountFooterEmail;
        mAccountFooterAvatar = accountFooterAvatar;
    }

    /**
     * Creates an infobar for saving a credit card.
     *
     * @param nativeAutofillSaveCardInfoBar The pointer to the native object for callbacks.
     * @param iconId ID corresponding to the icon that will be shown for the InfoBar.
     * @param iconBitmap Bitmap to use if there is no equivalent Java resource for iconId.
     * @param message Title of the infobar to display along the icon.
     * @param linkText Link text to display in addition to the message.
     * @param buttonOk String to display on the OK button.
     * @param buttonCancel String to display on the Cancel button.
     * @param accountFooterEmail The email to be shown on the footer, or null. The footer is
     * only shown if both this and |accountFooterAvatar| are provided.
     * @param accountFooterAvatar The avatar to be shown on the footer, or null. The footer is
     * only shown if both this and |accountFooterEmail| are provided.
     * @return A new instance of the infobar.
     */
    @CalledByNative
    private static AutofillSaveCardInfoBar create(
            long nativeAutofillSaveCardInfoBar,
            int iconId,
            Bitmap iconBitmap,
            String message,
            String linkText,
            String buttonOk,
            String buttonCancel,
            boolean isGooglePayBrandingEnabled,
            @Nullable String accountFooterEmail,
            @Nullable Bitmap accountFooterAvatar) {
        return new AutofillSaveCardInfoBar(
                nativeAutofillSaveCardInfoBar,
                iconId,
                iconBitmap,
                message,
                linkText,
                buttonOk,
                buttonCancel,
                isGooglePayBrandingEnabled,
                accountFooterEmail,
                accountFooterAvatar);
    }

    /**
     * Adds information to the infobar about the credit card that will be saved.
     *
     * @param iconId ID corresponding to the icon that will be shown for this credit card.
     * @param label The credit card label, for example "***1234".
     * @param subLabel The credit card sub-label, for example "Exp: 06/17".
     */
    @CalledByNative
    private void addDetail(int iconId, String label, String subLabel) {
        mCardDetails.add(new CardDetail(iconId, label, subLabel));
    }

    /**
     * Sets description line to the infobar.
     *
     * @param text description line text.
     */
    @CalledByNative
    private void setDescriptionText(String text) {
        mDescriptionText = text;
    }

    /**
     * Adds a line of legal message plain text to the infobar.
     *
     * @param text The legal message plain text.
     */
    @CalledByNative
    private void addLegalMessageLine(String text) {
        mLegalMessageLines.add(new LegalMessageLine(text));
    }

    /**
     * Marks up the last added line of legal message text with a link.
     *
     * @param start The inclusive offset of the start of the link in the text.
     * @param end The exclusive offset of the end of the link in the text.
     * @param url The URL to open when the link is clicked.
     */
    @CalledByNative
    private void addLinkToLastLegalMessageLine(int start, int end, String url) {
        mLegalMessageLines.getLast().links.add(new LegalMessageLine.Link(start, end, url));
    }

    @Override
    public void createContent(InfoBarLayout layout) {
        super.createContent(layout);

        // If Google Pay branding is enabled, add both the icon and the title message to the message
        // container, since no icon was added to the ImageView that normally shows the icon.
        if (mIsGooglePayBrandingEnabled) {
            UiUtils.removeViewFromParent(layout.getMessageTextView());
            layout.getMessageLayout().addIconTitle(mIconDrawableId, mTitleText);
        }

        InfoBarControlLayout control = layout.addControlLayout();
        if (!TextUtils.isEmpty(mDescriptionText)) {
            control.addDescription(mDescriptionText);
        }

        for (int i = 0; i < mCardDetails.size(); i++) {
            CardDetail detail = mCardDetails.get(i);
            control.addIcon(
                    detail.issuerIconDrawableId,
                    0,
                    detail.label,
                    detail.subLabel,
                    R.dimen.infobar_descriptive_text_size);
        }

        for (LegalMessageLine line : mLegalMessageLines) {
            SpannableString text = new SpannableString(line.text);
            for (final LegalMessageLine.Link link : line.links) {
                text.setSpan(
                        new ClickableSpan() {
                            @Override
                            public void onClick(View view) {
                                AutofillSaveCardInfoBarJni.get()
                                        .onLegalMessageLinkClicked(
                                                mNativeAutofillSaveCardInfoBar,
                                                AutofillSaveCardInfoBar.this,
                                                link.url);
                            }
                        },
                        link.start,
                        link.end,
                        Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
            }
            control.addDescription(text);
        }

        if (mAccountFooterEmail != null && mAccountFooterAvatar != null) {
            Resources res = layout.getResources();
            int smallIconSize = res.getDimensionPixelSize(R.dimen.infobar_small_icon_size);
            int padding = res.getDimensionPixelOffset(R.dimen.infobar_padding);

            LinearLayout footer =
                    (LinearLayout)
                            LayoutInflater.from(layout.getContext())
                                    .inflate(R.layout.infobar_footer, null, false);

            TextView emailView = footer.findViewById(R.id.infobar_footer_email);
            emailView.setText(mAccountFooterEmail);

            RoundedCornerImageView profilePicView =
                    footer.findViewById(R.id.infobar_footer_profile_pic);
            Bitmap resizedProfilePic =
                    Bitmap.createScaledBitmap(
                            mAccountFooterAvatar, smallIconSize, smallIconSize, false);
            profilePicView.setRoundedCorners(
                    smallIconSize / 2, smallIconSize / 2, smallIconSize / 2, smallIconSize / 2);
            profilePicView.setImageBitmap(resizedProfilePic);

            layout.addFooterView(footer);
        }
    }

    @NativeMethods
    interface Natives {
        void onLegalMessageLinkClicked(
                long nativeAutofillSaveCardInfoBar, AutofillSaveCardInfoBar caller, String url);
    }
}