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

// Copyright 2017 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.net.Uri;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;

import org.jni_zero.CalledByNative;

import org.chromium.chrome.R;
import org.chromium.components.infobars.InfoBar;
import org.chromium.components.infobars.InfoBarCompactLayout;
import org.chromium.components.infobars.InfoBarControlLayout;
import org.chromium.components.infobars.InfoBarLayout;
import org.chromium.components.url_formatter.UrlFormatter;

/**
 * This InfoBar is shown to let the user know about a blocked Framebust and offer to
 * continue the redirection by tapping on a link.
 */
public class FramebustBlockInfoBar extends InfoBar {

    private final String mBlockedUrl;

    /** Whether the infobar should be shown as a mini-infobar or a classic expanded one. */
    private boolean mIsExpanded;

    @VisibleForTesting
    public FramebustBlockInfoBar(String blockedUrl) {
        super(R.drawable.infobar_chrome, R.color.infobar_icon_drawable_color, null, null);
        mBlockedUrl = blockedUrl;
    }

    @Override
    public void onButtonClicked(boolean isPrimaryButton) {
        assert isPrimaryButton;
        onButtonClicked(ActionType.OK);
    }

    @Override
    public void createContent(InfoBarLayout layout) {
        layout.setMessage(getString(R.string.redirect_blocked_message));
        InfoBarControlLayout control = layout.addControlLayout();

        ViewGroup ellipsizerView =
                (ViewGroup)
                        LayoutInflater.from(getContext())
                                .inflate(R.layout.infobar_control_url_ellipsizer, control, false);

        // Formatting the URL and requesting to omit the scheme might still include it for some of
        // them (e.g. file, filesystem). We split the output of the formatting to make sure we don't
        // end up duplicating it.
        final String schemeSeparator = "://";
        String scheme = Uri.parse(mBlockedUrl).getScheme();

        // In case mBlockedUrl does not specify a scheme, formatUrlForSecurityDisplay returns an
        // empty string. Temporarily adding scheme separator allows it to parse the URL correctly.
        String urlWithScheme = mBlockedUrl;
        if (scheme == null) {
            scheme = "";
            urlWithScheme = schemeSeparator + mBlockedUrl;
        }

        String textToEllipsize =
                UrlFormatter.formatUrlForSecurityDisplay(urlWithScheme)
                        .substring(scheme.length() + schemeSeparator.length());

        TextView schemeView = ellipsizerView.findViewById(R.id.url_scheme);
        schemeView.setText(scheme);

        TextView urlView = ellipsizerView.findViewById(R.id.url_minus_scheme);
        urlView.setText(textToEllipsize);

        ellipsizerView.setOnClickListener(view -> onLinkClicked());

        control.addView(ellipsizerView);
        layout.setButtons(
                getContext().getResources().getString(R.string.always_allow_redirects), null);
    }

    @Override
    protected void createCompactLayoutContent(InfoBarCompactLayout layout) {
        new InfoBarCompactLayout.MessageBuilder(layout)
                .withText(getString(R.string.redirect_blocked_short_message))
                .withLink(R.string.details_link, view -> onLinkClicked())
                .buildAndInsert();
    }

    @Override
    protected boolean usesCompactLayout() {
        return !mIsExpanded;
    }

    @Override
    public void onLinkClicked() {
        if (!mIsExpanded) {
            mIsExpanded = true;
            replaceView(createView());
            return;
        }

        super.onLinkClicked();
    }

    @VisibleForTesting
    public String getBlockedUrl() {
        return mBlockedUrl;
    }

    private String getString(@StringRes int stringResId) {
        return getContext().getString(stringResId);
    }

    @CalledByNative
    private static FramebustBlockInfoBar create(String blockedUrl) {
        return new FramebustBlockInfoBar(blockedUrl);
    }
}