chromium/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/tile/TileView.java

// Copyright 2019 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.components.browser_ui.widget.tile;

import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.core.widget.ImageViewCompat;

import org.chromium.components.browser_ui.widget.R;
import org.chromium.components.browser_ui.widget.RoundedCornerOutlineProvider;

/**
 * The view for a tile with icon and text.
 *
 * Displays the title of the site beneath a large icon.
 */
public class TileView extends FrameLayout {
    private ImageView mBadgeView;
    private TextView mTitleView;
    private Runnable mOnFocusViaSelectionListener;
    private RoundedCornerOutlineProvider mRoundingOutline;
    protected ImageView mIconView;
    protected View mIconBackgroundView;

    /** Constructor for inflating from XML. */
    public TileView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * See {@link View#onFinishInflate} for details.
     *
     * Important:
     * This method will never be called when the layout is inflated from a <merge> fragment.
     * LayoutInflater explicitly avoids invoking this method with merge fragments.
     * Make sure your layouts explicitly reference the TileView as the top component, rather
     * than deferring to <merge> tags.
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        mIconView = findViewById(R.id.tile_view_icon);
        mBadgeView = findViewById(R.id.offline_badge);
        mTitleView = findViewById(R.id.tile_view_title);
        mIconBackgroundView = findViewById(R.id.tile_view_icon_background);
        mRoundingOutline = new RoundedCornerOutlineProvider();
        mIconView.setOutlineProvider(mRoundingOutline);
        mIconView.setClipToOutline(true);
    }

    /**
     * Initializes the view. Non-MVC components should call this immediately after inflation.
     *
     * @param title The title of the tile.
     * @param showOfflineBadge Whether to show the offline badge.
     * @param icon The icon to display on the tile.
     * @param titleLines The number of text lines to use for the tile title.
     */
    protected void initialize(
            String title, boolean showOfflineBadge, Drawable icon, int titleLines) {
        setOfflineBadgeVisibility(showOfflineBadge);
        setIconDrawable(icon);
        setTitle(title, titleLines);
    }

    /** Renders the icon or clears it from the view if the icon is null. */
    public void setIconDrawable(Drawable icon) {
        mIconView.setImageDrawable(icon);
    }

    /** Applies or clears icon tint. */
    public void setIconTint(ColorStateList color) {
        ImageViewCompat.setImageTintList(mIconView, color);
    }

    /** Shows or hides the offline badge to reflect the offline availability. */
    protected void setOfflineBadgeVisibility(boolean showOfflineBadge) {
        mBadgeView.setVisibility(showOfflineBadge ? VISIBLE : GONE);
    }

    /** Sets the title text and number lines. */
    public void setTitle(String title, int titleLines) {
        mTitleView.setLines(titleLines);
        mTitleView.setText(title);
    }

    /** Specify the handler that will be invoked when this tile is highlighted by the user. */
    void setOnFocusViaSelectionListener(Runnable listener) {
        mOnFocusViaSelectionListener = listener;
    }

    /** Sets the radius used to round the image content. */
    void setRoundingRadius(int radius) {
        mRoundingOutline.setRadius(radius);
    }

    /** Retrieves the radius used to round the image content. */
    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
    int getRoundingRadiusForTesting() {
        return mRoundingOutline.getRadiusForTesting();
    }

    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
    public @NonNull TextView getTitleView() {
        return mTitleView;
    }

    @Override
    public void setSelected(boolean isSelected) {
        super.setSelected(isSelected);
        if (isSelected && mOnFocusViaSelectionListener != null) {
            mOnFocusViaSelectionListener.run();
        }
    }

    @Override
    public boolean isFocused() {
        return super.isFocused() || isSelected();
    }
}