chromium/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogToolbarView.java

// Copyright 2018 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.tasks.tab_management;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.TouchDelegate;
import android.view.View;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;

import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.widget.ImageViewCompat;

import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.tab_ui.R;
import org.chromium.components.tab_groups.TabGroupColorId;
import org.chromium.ui.KeyboardVisibilityDelegate;
import org.chromium.ui.widget.ButtonCompat;
import org.chromium.ui.widget.ChromeImageView;

/** Toolbar used in the tab grid dialog see {@link TabGridDialogCoordinator}. */
public class TabGridDialogToolbarView extends FrameLayout {
    private ChromeImageView mNewTabButton;
    private ChromeImageView mBackButton;
    private ChromeImageView mMenuButton;
    private EditText mTitleTextView;
    private LinearLayout mMainContent;
    private FrameLayout mColorIconContainer;
    private ImageView mColorIcon;
    private @Nullable FrameLayout mShareButtonContainer;
    private @Nullable ButtonCompat mShareButton;
    private @Nullable FrameLayout mImageTilesContainer;

    public TabGridDialogToolbarView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        mBackButton = findViewById(R.id.toolbar_back_button);
        mNewTabButton = findViewById(R.id.toolbar_new_tab_button);
        mMenuButton = findViewById(R.id.toolbar_menu_button);
        mTitleTextView = (EditText) findViewById(R.id.title);
        mMainContent = findViewById(R.id.main_content);
        mColorIconContainer = findViewById(R.id.tab_group_color_icon_container);
        mColorIcon = findViewById(R.id.tab_group_color_icon);
        mShareButtonContainer = findViewById(R.id.share_button_container);
        mShareButton = findViewById(R.id.share_button);
        mImageTilesContainer = findViewById(R.id.image_tiles_container);
    }

    @Override
    @SuppressLint("ClickableViewAccessibility")
    public boolean onTouchEvent(MotionEvent motionEvent) {
        super.onTouchEvent(motionEvent);
        // Prevent touch events from "falling through" to views below.
        return true;
    }

    void setBackButtonOnClickListener(OnClickListener listener) {
        mBackButton.setOnClickListener(listener);
    }

    void setNewTabButtonOnClickListener(OnClickListener listener) {
        mNewTabButton.setOnClickListener(listener);
    }

    void setMenuButtonOnClickListener(OnClickListener listener) {
        mMenuButton.setOnClickListener(listener);
    }

    void setTitleTextOnChangedListener(TextWatcher textWatcher) {
        mTitleTextView.addTextChangedListener(textWatcher);
    }

    void setTitleTextOnFocusChangeListener(OnFocusChangeListener listener) {
        mTitleTextView.setOnFocusChangeListener(listener);
    }

    void setTitleCursorVisibility(boolean isVisible) {
        mTitleTextView.setCursorVisible(isVisible);
    }

    void updateTitleTextFocus(boolean shouldFocus) {
        if (mTitleTextView.isFocused() == shouldFocus) return;
        if (shouldFocus) {
            mTitleTextView.requestFocus();
        } else {
            clearTitleTextFocus();
        }
    }

    void updateKeyboardVisibility(boolean shouldShow) {
        // This is equal to the animation duration of toolbar menu hiding.
        int showKeyboardDelay = 150;
        if (shouldShow) {
            // TODO(crbug.com/40144823) Figure out why a call to show keyboard without delay still
            // won't work when the window gets focus in onWindowFocusChanged call.
            // Wait until the current window has focus to show the keyboard. This is to deal with
            // the case where the keyboard showing is caused by toolbar menu. In this case, we need
            // to wait for the menu window to hide and current window to gain focus so that we can
            // show the keyboard.
            KeyboardVisibilityDelegate delegate = KeyboardVisibilityDelegate.getInstance();
            postDelayed(
                    new Runnable() {
                        @Override
                        public void run() {
                            assert hasWindowFocus();
                            delegate.showKeyboard(mTitleTextView);
                        }
                    },
                    showKeyboardDelay);
        } else {
            hideKeyboard();
        }
    }

    void clearTitleTextFocus() {
        mTitleTextView.clearFocus();
    }

    void hideKeyboard() {
        KeyboardVisibilityDelegate delegate = KeyboardVisibilityDelegate.getInstance();
        delegate.hideKeyboard(this);
    }

    void setTitle(String title) {
        mTitleTextView.setText(title);
    }

    void setIsIncognito(boolean isIncognito) {
        @ColorRes
        int tintListRes =
                isIncognito
                        ? R.color.default_icon_color_light_tint_list
                        : R.color.default_icon_color_tint_list;
        ColorStateList tintList = ContextCompat.getColorStateList(getContext(), tintListRes);
        setTint(tintList);
    }

    void setContentBackgroundColor(int color) {
        mMainContent.setBackgroundColor(color);
    }

    void setTint(ColorStateList tint) {
        ImageViewCompat.setImageTintList(mBackButton, tint);
        ImageViewCompat.setImageTintList(mNewTabButton, tint);
        if (mTitleTextView != null) mTitleTextView.setTextColor(tint);
        if (mMenuButton != null) {
            ImageViewCompat.setImageTintList(mMenuButton, tint);
        }
    }

    void setBackgroundColorTint(int color) {
        DrawableCompat.setTint(getBackground(), color);
    }

    /** Setup the drawable in the left button. */
    void setBackButtonDrawableId(int drawableId) {
        mBackButton.setImageResource(drawableId);
    }

    /** Set the content description of the left button. */
    void setBackButtonContentDescription(String string) {
        mBackButton.setContentDescription(string);
    }

    /** Set the content description of the right button. */
    void setNewTabButtonContentDescription(String string) {
        mNewTabButton.setContentDescription(string);
    }

    void setImageTilesVisibility(boolean isVisible) {
        if (mImageTilesContainer == null) return;

        mImageTilesContainer.setVisibility(isVisible ? View.VISIBLE : View.GONE);
    }

    void setShareButtonVisibility(boolean isVisible) {
        if (mShareButtonContainer == null || mShareButton == null) return;
        mShareButtonContainer.setVisibility(isVisible ? View.VISIBLE : View.GONE);
        if (isVisible) {
            // Post this so that getHitRect() returns the correct size as by
            // default the view is GONE.
            mShareButtonContainer.post(
                    () -> {
                        Rect rect = new Rect();
                        mShareButton.getHitRect(rect);
                        Resources res = mShareButton.getContext().getResources();
                        int delta =
                                res.getDimensionPixelSize(R.dimen.min_touch_target_size)
                                        - rect.height();
                        if (delta > 0) {
                            int halfDelta = Math.round(delta / 2.0f);
                            rect.top -= halfDelta;
                            rect.bottom += halfDelta;
                        }
                        mShareButtonContainer.setTouchDelegate(
                                new TouchDelegate(rect, mShareButton));
                    });
        }
    }

    void setShareButtonClickListener(OnClickListener listener) {
        if (mShareButton == null) return;
        mShareButton.setOnClickListener(listener);
    }

    void setImageTilesClickListener(OnClickListener listener) {
        if (mImageTilesContainer == null) return;
        mImageTilesContainer.setOnClickListener(listener);
    }

    /** Set the color icon of type {@link TabGroupColorId} on the tab group card view. */
    void setColorIconColor(@TabGroupColorId int colorId, boolean isIncognito) {
        if (ChromeFeatureList.sTabGroupParityAndroid.isEnabled()) {
            mColorIconContainer.setVisibility(View.VISIBLE);

            final @ColorInt int color =
                    ColorPickerUtils.getTabGroupColorPickerItemColor(
                            getContext(), colorId, isIncognito);

            GradientDrawable gradientDrawable = (GradientDrawable) mColorIcon.getBackground();
            gradientDrawable.setColor(color);

            // Set accessibility content for the color icon.
            Resources res = getContext().getResources();
            final @StringRes int colorDescRes =
                    ColorPickerUtils.getTabGroupColorPickerItemColorAccessibilityString(colorId);
            String colorDesc = res.getString(colorDescRes);
            String contentDescription =
                    res.getString(
                            R.string.accessibility_tab_group_color_icon_description, colorDesc);
            mColorIconContainer.setContentDescription(contentDescription);
        } else {
            mColorIconContainer.setVisibility(View.GONE);
        }
    }

    void setColorIconOnClickListener(OnClickListener listener) {
        mColorIconContainer.setOnClickListener(listener);
    }
}