blob: dbf5e742919c1c71efafc4eda2c540a7abb1caaf [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// 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.top;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.ButtonData;
import org.chromium.chrome.browser.toolbar.ButtonDataProvider;
import org.chromium.chrome.browser.user_education.UserEducationHelper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Helper class that encapsulates the logic for which optional button is displayed on the browsing
* mode toolbar.
*/
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public class OptionalBrowsingModeButtonController {
private final UserEducationHelper mUserEducationHelper;
private final Map<ButtonDataProvider, ButtonDataProvider.ButtonDataObserver> mObserverMap;
private ButtonDataProvider mCurrentProvider;
private List<ButtonDataProvider> mButtonDataProviders;
private final ToolbarLayout mToolbarLayout;
private final Supplier<Tab> mTabSupplier;
/**
* Creates a new OptionalBrowsingModeButtonController.
* @param buttonDataProviders List of button data providers in precedence order.
* @param userEducationHelper Helper for displaying in-product help on a button.
* @param toolbarLayout Toolbar layout where buttons will be displayed.
*/
OptionalBrowsingModeButtonController(List<ButtonDataProvider> buttonDataProviders,
UserEducationHelper userEducationHelper, ToolbarLayout toolbarLayout,
Supplier<Tab> tabSupplier) {
mButtonDataProviders = buttonDataProviders;
mUserEducationHelper = userEducationHelper;
mToolbarLayout = toolbarLayout;
mTabSupplier = tabSupplier;
mObserverMap = new HashMap<>(buttonDataProviders.size());
for (ButtonDataProvider provider : buttonDataProviders) {
ButtonDataProvider.ButtonDataObserver callback =
(hint) -> buttonDataProviderChanged(provider, hint);
provider.addObserver(callback);
mObserverMap.put(provider, callback);
}
}
public void destroy() {
for (Map.Entry<ButtonDataProvider, ButtonDataProvider.ButtonDataObserver> entry :
mObserverMap.entrySet()) {
entry.getKey().removeObserver(entry.getValue());
}
mObserverMap.clear();
}
void updateButtonVisibility() {
showHighestPrecedenceOptionalButton();
}
@VisibleForTesting
void buttonDataProviderChanged(ButtonDataProvider provider, boolean canShowHint) {
// If the updated button is showing, update it.
if (provider == mCurrentProvider) {
updateCurrentOptionalButton(provider);
return;
}
// If the updated button isn't showing but could be, re-evaluate the highest precedence
// button and show it.
if (canShowHint) {
showHighestPrecedenceOptionalButton();
}
// Otherwise, the updated button wasn't showing before and can't show now, so there's
// nothing to do.
}
/**
* Show the highest precedence optional button, hiding the optional button if none can be shown.
*/
private void showHighestPrecedenceOptionalButton() {
if (mButtonDataProviders == null) return;
for (ButtonDataProvider provider : mButtonDataProviders) {
ButtonData buttonData = provider.get(mTabSupplier.get());
if (buttonData != null && buttonData.canShow()) {
// Same-provider updates are handled in updateCurrentOptionalButton; the below check
// prevents us from pointlessly updating with the same button data.
if (provider == mCurrentProvider) return;
setCurrentOptionalButton(provider, buttonData);
return;
}
}
// If no buttons can show, hide the currently showing button.
hideCurrentOptionalButton();
}
/**
* Sets the current optional button to reflect the given provider and button data, either
* showing the button or updating it in place.
*/
private void setCurrentOptionalButton(ButtonDataProvider provider, ButtonData buttonData) {
mCurrentProvider = provider;
mToolbarLayout.updateOptionalButton(buttonData);
if (buttonData.getButtonSpec().getIPHCommandBuilder() != null) {
mUserEducationHelper.requestShowIPH(
buttonData.getButtonSpec()
.getIPHCommandBuilder()
.setAnchorView(mToolbarLayout.getOptionalButtonView())
.build());
}
}
private void hideCurrentOptionalButton() {
mToolbarLayout.hideOptionalButton();
mCurrentProvider = null;
}
/**
* Processes an update to the current optional button, either mutating the view to reflect
* ButtonData changes or hiding it entirely if it can no longer show.
*/
private void updateCurrentOptionalButton(ButtonDataProvider provider) {
ButtonData buttonData = provider.get(mTabSupplier.get());
if (buttonData.canShow()) {
setCurrentOptionalButton(provider, buttonData);
} else {
hideCurrentOptionalButton();
showHighestPrecedenceOptionalButton();
}
}
/** Returns the list of {@link ButtonDataProvider}s. */
@VisibleForTesting
public List<ButtonDataProvider> getButtonDataProvidersForTesting() {
return mButtonDataProviders;
}
}