chromium/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/button_group_component/KeyboardAccessoryButtonGroupView.java

// Copyright 2022 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.keyboard_accessory.button_group_component;

import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.LinearLayout;

import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.RecyclerView;

import org.chromium.chrome.browser.keyboard_accessory.R;
import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.ui.widget.ChromeImageButton;

import java.util.ArrayList;

/**
 * A {@link LinearLayout} containing the sheet opener buttons in the keyboard
 * accessory.
 */
public class KeyboardAccessoryButtonGroupView extends LinearLayout {
    private final ArrayList<ChromeImageButton> mButtons = new ArrayList<>();
    private KeyboardAccessoryButtonGroupListener mListener;

    /**
     * This interface should be implemented by classes which want to observe clicks on the buttons
     * in this view.
     */
    interface KeyboardAccessoryButtonGroupListener {
        void onButtonClicked(int position);
    }

    /** Constructor for inflating from XML. */
    public KeyboardAccessoryButtonGroupView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setGravity(Gravity.CENTER);
    }

    /**
     * Creates a new button and appends it to the end of the button group at the end of the bar.
     * @param id The id of the tab
     * @param icon The icon to be displayed in the button.
     * @param contentDescription The contentDescription to be used for the button.
     */
    public void addButton(Drawable icon, CharSequence contentDescription) {
        ChromeImageButton button = new ChromeImageButton(getContext());
        button.setMaxWidth(
                getResources().getDimensionPixelSize(R.dimen.keyboard_accessory_tab_icon_width));
        button.setMaxHeight(
                getResources().getDimensionPixelSize(R.dimen.keyboard_accessory_tab_size));
        button.setMinimumWidth(button.getMaxWidth());
        button.setMinimumHeight(button.getMaxHeight());
        button.setPaddingRelative(
                getResources().getDimensionPixelSize(R.dimen.keyboard_accessory_bar_item_padding),
                0,
                getResources().getDimensionPixelSize(R.dimen.keyboard_accessory_bar_item_padding),
                0);
        button.setImageDrawable(icon.mutate()); // mutate() needed to change the active tint.
        button.getDrawable()
                .setColorFilter(
                        SemanticColorUtils.getDefaultIconColor(getContext()),
                        PorterDuff.Mode.SRC_IN);
        button.setContentDescription(contentDescription);
        button.setBackground(null);
        button.setOnClickListener(
                view -> {
                    if (mListener == null) return;
                    mListener.onButtonClicked(mButtons.indexOf(view));
                });
        mButtons.add(button);
        addView(button);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // The parent, which is KeyboardAccessoryView's recycler view may measure
        // StickyLastItemDecoration offsets before the buttons are added. Notify the parent to
        // recalculate the offset during each measurement.
        // TODO(crbug.com/40898366): Find a better alternative.
        if (getParent() == null || !(getParent() instanceof RecyclerView)) return;
        RecyclerView parent = (RecyclerView) getParent();
        parent.post(parent::invalidateItemDecorations);
    }

    void removeAllButtons() {
        mButtons.clear();
        removeAllViews();
    }

    void setButtonSelectionListener(KeyboardAccessoryButtonGroupListener listener) {
        mListener = listener;
    }

    @VisibleForTesting
    public ArrayList<ChromeImageButton> getButtons() {
        return mButtons;
    }
}