blob: 0c7755789f3fb129a1e12f3caa13a870c9d1770c [file] [log] [blame]
// 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.toolbar;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.View.OnClickListener;
import androidx.annotation.CallSuper;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import org.chromium.base.FeatureList;
import org.chromium.base.ObserverList;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarButtonVariant;
import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarFeatures;
import org.chromium.chrome.browser.user_education.IPHCommandBuilder;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogManagerObserver;
import org.chromium.ui.modelutil.PropertyModel;
/**
* Base class for button data providers used on the adaptive toolbar.
*/
public abstract class BaseButtonDataProvider implements ButtonDataProvider, OnClickListener {
protected final ButtonDataImpl mButtonData;
protected final Supplier<Tab> mActiveTabSupplier;
private final ObserverList<ButtonDataObserver> mObservers = new ObserverList<>();
private final ModalDialogManager mModalDialogManager;
private ModalDialogManagerObserver mModalDialogObserver;
private boolean mShouldShowOnIncognitoTabs;
private @StringRes int mActionChipResourceId;
/**
* Creates a new instance of {@code BaseButtonDataProvider}.
* @param activeTabSupplier Supplier for the current active tab.
* @param modalDialogManager Modal dialog manager, used to disable the button when a dialog is
* visible. Can be null to disable this behavior.
* @param buttonDrawable Drawable for the button icon.
* @param contentDescriptionResId Resource ID for the button's content description.
* @param supportsTinting Whether the button's icon should be tinted.
* @param iphCommandBuilder An IPH command builder instance to show when the button is
* displayed, can be null.
* @param adaptiveButtonVariant Enum value of {@link AdaptiveToolbarButtonVariant}, used for
* metrics.
*/
public BaseButtonDataProvider(Supplier<Tab> activeTabSupplier,
@Nullable ModalDialogManager modalDialogManager, Drawable buttonDrawable,
@StringRes int contentDescriptionResId, @StringRes int actionChipLabelResId,
boolean supportsTinting, @Nullable IPHCommandBuilder iphCommandBuilder,
@AdaptiveToolbarButtonVariant int adaptiveButtonVariant) {
mActiveTabSupplier = activeTabSupplier;
mModalDialogManager = modalDialogManager;
if (mModalDialogManager != null) {
mModalDialogObserver = new ModalDialogManagerObserver() {
@Override
public void onDialogAdded(PropertyModel model) {
mButtonData.setEnabled(false);
notifyObservers(mButtonData.canShow());
}
@Override
public void onLastDialogDismissed() {
mButtonData.setEnabled(true);
notifyObservers(mButtonData.canShow());
}
};
mModalDialogManager.addObserver(mModalDialogObserver);
}
if (!AdaptiveToolbarFeatures.isDynamicAction(adaptiveButtonVariant)) {
assert actionChipLabelResId
== Resources.ID_NULL : "Action chip should only be used on dynamic actions";
}
mButtonData = new ButtonDataImpl(/*canShow=*/false, buttonDrawable,
/* onClickListener= */ this, contentDescriptionResId, actionChipLabelResId,
supportsTinting,
/* iphCommandBuilder= */ iphCommandBuilder, /*isEnabled=*/true,
adaptiveButtonVariant);
}
/**
* Checks if the button should be shown for the current tab. Called every time {@code get()} is
* invoked.
* @param tab Current tab.
* @return whether the button should be shown for the current tab.
*/
@CallSuper
protected boolean shouldShowButton(Tab tab) {
if (tab == null) return false;
if (tab.isIncognito() && !mShouldShowOnIncognitoTabs) return false;
return true;
}
protected void notifyObservers(boolean hint) {
for (ButtonDataObserver observer : mObservers) {
observer.buttonDataChanged(hint);
}
}
/**
* Sets the button's {@link IPHCommandBuilder} if needed, called every time {@code get()} is
* invoked.
* @param tab Current tab.
*/
private void maybeSetIphCommandBuilder(Tab tab) {
if (mButtonData.getButtonSpec().getIPHCommandBuilder() != null || tab == null
|| !FeatureList.isInitialized() || !AdaptiveToolbarFeatures.isCustomizationEnabled()
|| AdaptiveToolbarFeatures.shouldShowActionChip(
mButtonData.getButtonSpec().getButtonVariant())) {
return;
}
mButtonData.updateIPHCommandBuilder(getIphCommandBuilder(tab));
}
private void maybeSetActionChipResourceId() {
if (!mButtonData.getButtonSpec().isDynamicAction() || !FeatureList.isInitialized()
|| !AdaptiveToolbarFeatures.shouldShowActionChip(
mButtonData.getButtonSpec().getButtonVariant())
|| mButtonData.getButtonSpec().getActionChipLabelResId() != Resources.ID_NULL) {
return;
}
mButtonData.updateActionChipResourceId(mActionChipResourceId);
}
/**
* Sets whether the button should be shown on incognito tabs, default is false.
*/
protected void setShouldShowOnIncognitoTabs(boolean shouldShowOnIncognitoTabs) {
mShouldShowOnIncognitoTabs = shouldShowOnIncognitoTabs;
}
/**
* Sets a string resource ID to be used when the action chip variant is enabled, only used on
* dynamic actions.
* @param actionChipResourceId A string resource to use as the action chip label.
*/
protected void setActionChipResourceId(@StringRes int actionChipResourceId) {
mActionChipResourceId = actionChipResourceId;
}
/**
* Gets an {@link IPHCommandBuilder} builder instance to use on this button. Only called when
* native is initialized and when there's no IPHCommandBuilder set.
* @param tab Current tab.
* @return An {@link org.chromium.chrome.browser.user_education.IPHCommand} instance to set on
* this button, or null if no IPH should be used.
*/
protected IPHCommandBuilder getIphCommandBuilder(Tab tab) {
return null;
}
/** ButtonDataProvider implementation. */
@Override
public void addObserver(ButtonDataObserver obs) {
mObservers.addObserver(obs);
}
@Override
public void removeObserver(ButtonDataObserver obs) {
mObservers.removeObserver(obs);
}
@Override
public ButtonData get(Tab tab) {
mButtonData.setCanShow(shouldShowButton(tab));
maybeSetIphCommandBuilder(tab);
maybeSetActionChipResourceId();
return mButtonData;
}
@Override
@CallSuper
public void destroy() {
mObservers.clear();
if (mModalDialogManager != null) {
mModalDialogManager.removeObserver(mModalDialogObserver);
}
}
/* OnClickListener implementation. */
@Override
public abstract void onClick(View view);
}