Commit fbc145ee authored by Patrick Noland's avatar Patrick Noland Committed by Commit Bot

[ToolbarMVC] Reimplement MenuButton internals to follow MVC

This adds the familiar MVC pieces, in addition to the existing Coordinator and View: a Mediator, a ViewBinder, and a Properties class. Logic is moved out of the MenuButton and MenuButtonCoordinator to the Mediator. Of note, there are two compound properties for combinations of properties that need to be set together:
* show/hide badge and shouldAnimate
* useLight and ColorStateList

Bug: 1086676
Change-Id: I12fb7aa1e21b78b0cddf6b72c322e3c030fae78e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2406378
Commit-Queue: Patrick Noland <pnoland@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#809896}
parent e2b1a235
......@@ -1574,6 +1574,9 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/toolbar/load_progress/LoadProgressViewBinder.java",
"java/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButton.java",
"java/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButtonCoordinator.java",
"java/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButtonMediator.java",
"java/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButtonProperties.java",
"java/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButtonViewBinder.java",
"java/src/org/chromium/chrome/browser/toolbar/top/ActionModeController.java",
"java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbar.java",
"java/src/org/chromium/chrome/browser/toolbar/top/CustomTabToolbarAnimationDelegate.java",
......
......@@ -235,6 +235,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java",
"junit/src/org/chromium/chrome/browser/toolbar/ToolbarTabControllerImplTest.java",
"junit/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButtonCoordinatorTest.java",
"junit/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButtonMediatorTest.java",
"junit/src/org/chromium/chrome/browser/toolbar/menu_button/MenuButtonTest.java",
"junit/src/org/chromium/chrome/browser/toolbar/top/OptionalBrowsingModeButtonControllerTest.java",
"junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java",
......
......@@ -25,7 +25,6 @@ import androidx.annotation.VisibleForTesting;
import androidx.core.view.ViewCompat;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ThemeColorProvider;
import org.chromium.chrome.browser.ThemeColorProvider.TintObserver;
import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper.MenuButtonState;
......@@ -51,12 +50,10 @@ public class MenuButton extends FrameLayout implements TintObserver {
private boolean mHighlightingMenu;
private PulseDrawable mHighlightDrawable;
private boolean mSuppressAppMenuUpdateBadge;
private AnimatorSet mMenuBadgeAnimatorSet;
private boolean mIsMenuBadgeAnimationRunning;
/** A provider that notifies components when the theme color changes.*/
private ThemeColorProvider mThemeColorProvider;
private BitmapDrawable mMenuImageButtonAnimationDrawable;
private BitmapDrawable mUpdateBadgeAnimationDrawable;
......@@ -98,7 +95,6 @@ public class MenuButton extends FrameLayout implements TintObserver {
if (mUpdateBadgeView == null) return;
mUpdateBadgeView.setVisibility(visible ? View.VISIBLE : View.GONE);
if (visible) updateImageResources();
updateContentDescription(visible);
}
@Override
......@@ -147,14 +143,12 @@ public class MenuButton extends FrameLayout implements TintObserver {
* Show the update badge on the app menu button.
* @param animate Whether to animate the showing of the update badge.
*/
public void showAppMenuUpdateBadgeIfAvailable(boolean animate) {
if (mUpdateBadgeView == null || mMenuImageButton == null || mSuppressAppMenuUpdateBadge
|| !isBadgeAvailable()) {
void showAppMenuUpdateBadge(boolean animate) {
if (mUpdateBadgeView == null || mMenuImageButton == null) {
return;
}
updateImageResources();
updateContentDescription(true);
if (!animate || mIsMenuBadgeAnimationRunning) {
setUpdateBadgeVisibility(true);
return;
......@@ -190,9 +184,8 @@ public class MenuButton extends FrameLayout implements TintObserver {
* Remove the update badge on the app menu button.
* @param animate Whether to animate the hiding of the update badge.
*/
public void removeAppMenuUpdateBadge(boolean animate) {
void removeAppMenuUpdateBadge(boolean animate) {
if (mUpdateBadgeView == null || !isShowingAppMenuUpdateBadge()) return;
updateContentDescription(false);
if (!animate) {
setUpdateBadgeVisibility(false);
......@@ -228,52 +221,22 @@ public class MenuButton extends FrameLayout implements TintObserver {
mMenuBadgeAnimatorSet.start();
}
/**
* @param suppress Whether to prevent the update badge from being show. This is currently only
* used to prevent the badge from being shown in the tablet tab switcher.
*/
public void setAppMenuUpdateBadgeSuppressed(boolean suppress) {
mSuppressAppMenuUpdateBadge = suppress;
if (mSuppressAppMenuUpdateBadge) {
removeAppMenuUpdateBadge(false);
} else {
showAppMenuUpdateBadgeIfAvailable(false);
}
}
/**
* @return Whether the update badge is showing.
*/
public boolean isShowingAppMenuUpdateBadge() {
boolean isShowingAppMenuUpdateBadge() {
return mUpdateBadgeView != null && mUpdateBadgeView.getVisibility() == View.VISIBLE;
}
private static boolean isBadgeAvailable() {
return UpdateMenuItemHelper.getInstance().getUiState().buttonState != null;
}
/**
* Sets the content description for the menu button.
* @param isUpdateBadgeVisible Whether the update menu badge is visible.
*/
private void updateContentDescription(boolean isUpdateBadgeVisible) {
if (isUpdateBadgeVisible) {
MenuButtonState buttonState =
UpdateMenuItemHelper.getInstance().getUiState().buttonState;
assert buttonState != null : "No button state when trying to show the badge.";
mMenuImageButton.setContentDescription(
getResources().getString(buttonState.menuContentDescription));
} else {
mMenuImageButton.setContentDescription(
getResources().getString(R.string.accessibility_toolbar_btn_menu));
}
void updateContentDescription(String description) {
mMenuImageButton.setContentDescription(description);
}
/**
* Sets the menu button's background depending on whether or not we are highlighting and whether
* or not we are using light or dark assets.
*/
public void setMenuButtonHighlightDrawable() {
private void updateMenuButtonHighlightDrawable() {
// Return if onFinishInflate didn't finish
if (mMenuImageButton == null) return;
......@@ -294,15 +257,9 @@ public class MenuButton extends FrameLayout implements TintObserver {
}
}
public void setMenuButtonHighlight(boolean highlight) {
void setMenuButtonHighlight(boolean highlight) {
mHighlightingMenu = highlight;
setMenuButtonHighlightDrawable();
}
public void setThemeColorProvider(ThemeColorProvider themeColorProvider) {
mThemeColorProvider = themeColorProvider;
mThemeColorProvider.addTintObserver(this);
onTintChanged(themeColorProvider.getTint(), themeColorProvider.useLight());
updateMenuButtonHighlightDrawable();
}
/**
......@@ -322,13 +279,7 @@ public class MenuButton extends FrameLayout implements TintObserver {
ApiCompatibilityUtils.setImageTintList(mMenuImageButton, tintList);
mUseLightDrawables = useLight;
updateImageResources();
}
public void destroy() {
if (mThemeColorProvider != null) {
mThemeColorProvider.removeTintObserver(this);
mThemeColorProvider = null;
}
updateMenuButtonHighlightDrawable();
}
@VisibleForTesting
......
// 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.menu_button;
import android.content.res.ColorStateList;
import androidx.annotation.NonNull;
import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey;
import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey;
class MenuButtonProperties {
static class ThemeProperty {
@NonNull
public ColorStateList mColorStateList;
public boolean mUseLightColors;
public ThemeProperty(@NonNull ColorStateList colorStateList, boolean useLight) {
mColorStateList = colorStateList;
mUseLightColors = useLight;
}
}
static class ShowBadgeProperty {
public boolean mShowUpdateBadge;
public boolean mShouldAnimate;
public ShowBadgeProperty(boolean showUpdateBadge, boolean shouldAnimate) {
mShowUpdateBadge = showUpdateBadge;
mShouldAnimate = shouldAnimate;
}
}
public static final WritableObjectPropertyKey<AppMenuButtonHelper> APP_MENU_BUTTON_HELPER =
new WritableObjectPropertyKey<>();
public static final WritableObjectPropertyKey<String> CONTENT_DESCRIPTION =
new WritableObjectPropertyKey<>();
public static final WritableBooleanPropertyKey IS_CLICKABLE = new WritableBooleanPropertyKey();
public static final WritableBooleanPropertyKey IS_HIGHLIGHTING =
new WritableBooleanPropertyKey();
public static final WritableBooleanPropertyKey IS_VISIBLE = new WritableBooleanPropertyKey();
public static final WritableObjectPropertyKey<ShowBadgeProperty> SHOW_UPDATE_BADGE =
new WritableObjectPropertyKey(true);
public static final WritableObjectPropertyKey<ThemeProperty> THEME =
new WritableObjectPropertyKey<>(true);
public static final PropertyKey[] ALL_KEYS =
new PropertyKey[] {APP_MENU_BUTTON_HELPER, CONTENT_DESCRIPTION, IS_CLICKABLE,
IS_HIGHLIGHTING, IS_VISIBLE, SHOW_UPDATE_BADGE, THEME};
}
// 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.menu_button;
import android.view.View;
import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonProperties.ShowBadgeProperty;
import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonProperties.ThemeProperty;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder;
class MenuButtonViewBinder implements ViewBinder<PropertyModel, MenuButton, PropertyKey> {
@Override
public void bind(PropertyModel model, MenuButton view, PropertyKey propertyKey) {
if (propertyKey == MenuButtonProperties.APP_MENU_BUTTON_HELPER) {
view.setAppMenuButtonHelper(model.get(MenuButtonProperties.APP_MENU_BUTTON_HELPER));
} else if (propertyKey == MenuButtonProperties.CONTENT_DESCRIPTION) {
view.updateContentDescription(model.get(MenuButtonProperties.CONTENT_DESCRIPTION));
} else if (propertyKey == MenuButtonProperties.IS_CLICKABLE) {
view.setClickable(model.get(MenuButtonProperties.IS_CLICKABLE));
} else if (propertyKey == MenuButtonProperties.IS_HIGHLIGHTING) {
view.setMenuButtonHighlight(model.get(MenuButtonProperties.IS_HIGHLIGHTING));
} else if (propertyKey == MenuButtonProperties.IS_VISIBLE) {
view.setVisibility(
model.get(MenuButtonProperties.IS_VISIBLE) ? View.VISIBLE : View.GONE);
} else if (propertyKey == MenuButtonProperties.SHOW_UPDATE_BADGE) {
ShowBadgeProperty showBadgeProperty = model.get(MenuButtonProperties.SHOW_UPDATE_BADGE);
if (showBadgeProperty.mShowUpdateBadge) {
view.showAppMenuUpdateBadge(showBadgeProperty.mShouldAnimate);
} else {
view.removeAppMenuUpdateBadge(showBadgeProperty.mShouldAnimate);
}
} else if (propertyKey == MenuButtonProperties.THEME) {
ThemeProperty themeProperty = model.get(MenuButtonProperties.THEME);
view.onTintChanged(themeProperty.mColorStateList, themeProperty.mUseLightColors);
}
}
}
......@@ -227,8 +227,7 @@ public class StartSurfaceToolbarCoordinator {
mView = (StartSurfaceToolbarView) mStub.inflate();
mMenuButtonCoordinator.setMenuButton(mView.findViewById(R.id.menu_button_wrapper));
mMenuButtonCoordinator.setVisibility(
mPropertyModel.get(StartSurfaceToolbarProperties.MENU_IS_VISIBLE) ? View.VISIBLE
: View.GONE);
mPropertyModel.get(StartSurfaceToolbarProperties.MENU_IS_VISIBLE));
mPropertyModelChangeProcessor = PropertyModelChangeProcessor.create(
mPropertyModel, mView, StartSurfaceToolbarViewBinder::bind);
if (LibraryLoader.getInstance().isInitialized()) {
......
......@@ -118,7 +118,6 @@ public class TabSwitcherModeTTPhone extends OptimizedFrameLayout
mIncognitoToggleTabLayout = null;
}
if (mMenuButton != null) {
mMenuButton.destroy();
mMenuButton = null;
}
}
......
......@@ -365,7 +365,7 @@ public class ToolbarPhone extends ToolbarLayout implements Invalidator.Client, O
setLayoutTransition(null);
if (getMenuButtonCoordinator() != null) {
getMenuButtonCoordinator().setVisibility(View.VISIBLE);
getMenuButtonCoordinator().setVisibility(true);
}
inflateTabSwitchingResources();
......@@ -1881,7 +1881,7 @@ public class ToolbarPhone extends ToolbarLayout implements Invalidator.Client, O
mToggleTabStackButton.setVisibility(isGone ? GONE : VISIBLE);
}
getMenuButtonCoordinator().setVisibility(inTabSwitcherMode ? GONE : VISIBLE);
getMenuButtonCoordinator().setVisibility(!inTabSwitcherMode);
triggerUrlFocusAnimation(inTabSwitcherMode && !urlHasFocus());
......@@ -2509,8 +2509,7 @@ public class ToolbarPhone extends ToolbarLayout implements Invalidator.Client, O
updateNtpTransitionAnimation();
}
getMenuButtonCoordinator().setMenuButtonHighlightDrawable();
getMenuButtonCoordinator().setVisibility(View.VISIBLE);
getMenuButtonCoordinator().setVisibility(true);
DrawableCompat.setTint(mLocationBarBackground,
isIncognito() ? Color.WHITE
......
......@@ -499,7 +499,7 @@ public class ToolbarTablet extends ToolbarLayout
void initialize(ToolbarDataProvider toolbarDataProvider, ToolbarTabController tabController,
MenuButtonCoordinator menuButtonCoordinator) {
super.initialize(toolbarDataProvider, tabController, menuButtonCoordinator);
menuButtonCoordinator.setVisibility(View.VISIBLE);
menuButtonCoordinator.setVisibility(true);
}
@Override
......
......@@ -4,13 +4,12 @@
package org.chromium.chrome.browser.toolbar.menu_button;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.Activity;
import android.widget.ImageButton;
import org.junit.Before;
import org.junit.Test;
......@@ -23,12 +22,10 @@ import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.ThemeColorProvider;
import org.chromium.chrome.browser.browser_controls.BrowserStateBrowserControlsVisibilityDelegate;
import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
import org.chromium.chrome.browser.omnibox.LocationBar;
import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
import org.chromium.chrome.browser.ui.appmenu.AppMenuCoordinator;
import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate;
import org.chromium.ui.util.TokenHolder;
/**
* Unit tests for ToolbarAppMenuManager.
......@@ -50,6 +47,8 @@ public class MenuButtonCoordinatorTest {
@Mock
MenuButton mMenuButton;
@Mock
ImageButton mImageButton;
@Mock
private AppMenuPropertiesDelegate mAppMenuPropertiesDelegate;
@Mock
private UpdateMenuItemHelper mUpdateMenuItemHelper;
......@@ -77,6 +76,7 @@ public class MenuButtonCoordinatorTest {
doReturn(mMenuButton)
.when(mActivity)
.findViewById(org.chromium.chrome.R.id.menu_button_wrapper);
doReturn(mImageButton).when(mMenuButton).getImageButton();
mMenuButtonCoordinator = new MenuButtonCoordinator(mAppMenuSupplier,
mControlsVisibilityDelegate, mActivity, mFocusFunction, mRequestRenderRunnable,
......@@ -85,129 +85,14 @@ public class MenuButtonCoordinatorTest {
}
@Test
public void testInitialization() {
mAppMenuSupplier.set(mAppMenuCoordinator);
verify(mAppMenuHandler).addObserver(mMenuButtonCoordinator);
verify(mAppMenuHandler).createAppMenuButtonHelper();
}
@Test
public void testSetMenuButton() {
mMenuButtonCoordinator = new MenuButtonCoordinator(mAppMenuSupplier,
mControlsVisibilityDelegate, mActivity, mFocusFunction, mRequestRenderRunnable,
true, () -> false, mThemeColorProvider, org.chromium.chrome.R.id.none);
mAppMenuSupplier.set(mAppMenuCoordinator);
mMenuButtonCoordinator.setMenuButton(mMenuButton);
verify(mMenuButton, times(2)).setAppMenuButtonHelper(mAppMenuButtonHelper);
verify(mMenuButton, times(2)).setThemeColorProvider(mThemeColorProvider);
}
@Test
public void testAppMenuVisiblityChange_badgeShowing() {
mAppMenuSupplier.set(mAppMenuCoordinator);
doReturn(42)
.when(mControlsVisibilityDelegate)
.showControlsPersistentAndClearOldToken(TokenHolder.INVALID_TOKEN);
doReturn(true).when(mMenuButton).isShowingAppMenuUpdateBadge();
mMenuButtonCoordinator.onMenuVisibilityChanged(true);
verify(mFocusFunction).setFocus(false, LocationBar.OmniboxFocusReason.UNFOCUS);
verify(mMenuButton).removeAppMenuUpdateBadge(true);
verify(mUpdateMenuItemHelper).onMenuButtonClicked();
mMenuButtonCoordinator.onMenuVisibilityChanged(false);
verify(mControlsVisibilityDelegate).releasePersistentShowingToken(42);
}
@Test
public void testAppMenuHighlightChange() {
public void testEnterKeyPress() {
mAppMenuSupplier.set(mAppMenuCoordinator);
doReturn(42)
.when(mControlsVisibilityDelegate)
.showControlsPersistentAndClearOldToken(TokenHolder.INVALID_TOKEN);
mMenuButtonCoordinator.onMenuHighlightChanged(true);
verify(mMenuButton).setMenuButtonHighlight(true);
mMenuButtonCoordinator.onMenuHighlightChanged(false);
verify(mMenuButton).setMenuButtonHighlight(false);
verify(mControlsVisibilityDelegate).releasePersistentShowingToken(42);
}
mMenuButtonCoordinator.onEnterKeyPress();
verify(mAppMenuButtonHelper).onEnterKeyPress(mImageButton);
@Test
public void testAppMenuUpdateBadge() {
mAppMenuSupplier.set(mAppMenuCoordinator);
doReturn(true).when(mActivity).isDestroyed();
mMenuButtonCoordinator.updateStateChanged();
verify(mMenuButton, never()).showAppMenuUpdateBadgeIfAvailable(anyBoolean());
verify(mRequestRenderRunnable, never()).run();
verify(mMenuButton, never()).removeAppMenuUpdateBadge(false);
doReturn(false).when(mActivity).isDestroyed();
mMenuButtonCoordinator.updateStateChanged();
verify(mMenuButton, never()).showAppMenuUpdateBadgeIfAvailable(anyBoolean());
verify(mRequestRenderRunnable, never()).run();
verify(mMenuButton, times(1)).removeAppMenuUpdateBadge(false);
mMenuUiState.buttonState = new UpdateMenuItemHelper.MenuButtonState();
mMenuButtonCoordinator.updateStateChanged();
verify(mMenuButton).showAppMenuUpdateBadgeIfAvailable(true);
verify(mRequestRenderRunnable).run();
verify(mMenuButton, times(1)).removeAppMenuUpdateBadge(false);
}
@Test
public void testAppMenuUpdateBadge_activityShouldNotShow() {
MenuButtonCoordinator newCoordinator = new MenuButtonCoordinator(mAppMenuSupplier,
mControlsVisibilityDelegate, mActivity, mFocusFunction, mRequestRenderRunnable,
false,
() -> false, mThemeColorProvider, org.chromium.chrome.R.id.menu_button_wrapper);
doReturn(true).when(mActivity).isDestroyed();
newCoordinator.updateStateChanged();
verify(mMenuButton, never()).showAppMenuUpdateBadgeIfAvailable(anyBoolean());
verify(mRequestRenderRunnable, never()).run();
verify(mMenuButton, never()).removeAppMenuUpdateBadge(false);
doReturn(false).when(mActivity).isDestroyed();
newCoordinator.updateStateChanged();
verify(mMenuButton, never()).showAppMenuUpdateBadgeIfAvailable(anyBoolean());
verify(mRequestRenderRunnable, never()).run();
verify(mMenuButton, never()).removeAppMenuUpdateBadge(false);
mMenuUiState.buttonState = new UpdateMenuItemHelper.MenuButtonState();
newCoordinator.updateStateChanged();
verify(mMenuButton, never()).showAppMenuUpdateBadgeIfAvailable(anyBoolean());
verify(mRequestRenderRunnable, never()).run();
verify(mMenuButton, never()).removeAppMenuUpdateBadge(false);
}
@Test
public void testDestroyIsSafe() {
mMenuButtonCoordinator.destroy();
// It should be crash-safe to call public methods, but the results aren't meaningful.
mMenuButtonCoordinator.getMenuButtonHelperSupplier();
mMenuButtonCoordinator.onMenuHighlightChanged(true);
mMenuButtonCoordinator.onMenuVisibilityChanged(false);
mMenuButtonCoordinator.onNativeInitialized();
mMenuButtonCoordinator.setAppMenuUpdateBadgeSuppressed(true);
mMenuButtonCoordinator.updateReloadingState(true);
mMenuButtonCoordinator.updateStateChanged();
}
@Test
public void testDisableDestroysButton() {
mMenuButtonCoordinator.disableMenuButton();
verify(mMenuButton).destroy();
mMenuButtonCoordinator.onEnterKeyPress();
verify(mAppMenuButtonHelper, times(1)).onEnterKeyPress(mImageButton);
}
}
// 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.menu_button;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.app.Activity;
import android.content.res.Resources;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.chromium.base.supplier.OneshotSupplierImpl;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.ThemeColorProvider;
import org.chromium.chrome.browser.browser_controls.BrowserStateBrowserControlsVisibilityDelegate;
import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
import org.chromium.chrome.browser.omnibox.LocationBar;
import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonProperties.ShowBadgeProperty;
import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonProperties.ThemeProperty;
import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
import org.chromium.chrome.browser.ui.appmenu.AppMenuCoordinator;
import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.util.TokenHolder;
/**
* Unit tests for ToolbarAppMenuManager.
*/
@RunWith(BaseRobolectricTestRunner.class)
public class MenuButtonMediatorTest {
@Mock
private BrowserStateBrowserControlsVisibilityDelegate mControlsVisibilityDelegate;
@Mock
private Activity mActivity;
@Mock
private MenuButtonCoordinator.SetFocusFunction mFocusFunction;
@Mock
private AppMenuCoordinator mAppMenuCoordinator;
@Mock
private AppMenuHandler mAppMenuHandler;
@Mock
private AppMenuButtonHelper mAppMenuButtonHelper;
@Mock
private AppMenuPropertiesDelegate mAppMenuPropertiesDelegate;
@Mock
private UpdateMenuItemHelper mUpdateMenuItemHelper;
@Mock
private Runnable mRequestRenderRunnable;
@Mock
ThemeColorProvider mThemeColorProvider;
@Mock
Resources mResources;
private UpdateMenuItemHelper.MenuUiState mMenuUiState;
private OneshotSupplierImpl<AppMenuCoordinator> mAppMenuSupplier;
private PropertyModel mPropertyModel;
private MenuButtonMediator mMenuButtonMediator;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mPropertyModel = new PropertyModel.Builder(MenuButtonProperties.ALL_KEYS)
.with(MenuButtonProperties.SHOW_UPDATE_BADGE,
new ShowBadgeProperty(false, false))
.with(MenuButtonProperties.THEME,
new ThemeProperty(mThemeColorProvider.getTint(),
mThemeColorProvider.useLight()))
.with(MenuButtonProperties.IS_VISIBLE, true)
.build();
doReturn(mAppMenuHandler).when(mAppMenuCoordinator).getAppMenuHandler();
doReturn(mAppMenuButtonHelper).when(mAppMenuHandler).createAppMenuButtonHelper();
doReturn(mAppMenuPropertiesDelegate)
.when(mAppMenuCoordinator)
.getAppMenuPropertiesDelegate();
UpdateMenuItemHelper.setInstanceForTesting(mUpdateMenuItemHelper);
mAppMenuSupplier = new OneshotSupplierImpl<>();
mMenuUiState = new UpdateMenuItemHelper.MenuUiState();
doReturn(mMenuUiState).when(mUpdateMenuItemHelper).getUiState();
mMenuButtonMediator = new MenuButtonMediator(mPropertyModel, true,
()
-> false,
mRequestRenderRunnable, mThemeColorProvider,
()
-> false,
mControlsVisibilityDelegate, mFocusFunction, mAppMenuSupplier, mResources);
}
@Test
public void testInitialization() {
mAppMenuSupplier.set(mAppMenuCoordinator);
verify(mAppMenuHandler).addObserver(mMenuButtonMediator);
verify(mAppMenuHandler).createAppMenuButtonHelper();
}
@Test
public void testAppMenuVisiblityChange_badgeShowing() {
mAppMenuSupplier.set(mAppMenuCoordinator);
doReturn(42)
.when(mControlsVisibilityDelegate)
.showControlsPersistentAndClearOldToken(TokenHolder.INVALID_TOKEN);
mPropertyModel.set(
MenuButtonProperties.SHOW_UPDATE_BADGE, new ShowBadgeProperty(true, false));
mMenuButtonMediator.onMenuVisibilityChanged(true);
verify(mFocusFunction).setFocus(false, LocationBar.OmniboxFocusReason.UNFOCUS);
assertFalse(mPropertyModel.get(MenuButtonProperties.SHOW_UPDATE_BADGE).mShowUpdateBadge);
verify(mUpdateMenuItemHelper).onMenuButtonClicked();
mMenuButtonMediator.onMenuVisibilityChanged(false);
verify(mControlsVisibilityDelegate).releasePersistentShowingToken(42);
}
@Test
public void testAppMenuHighlightChange() {
mAppMenuSupplier.set(mAppMenuCoordinator);
doReturn(42)
.when(mControlsVisibilityDelegate)
.showControlsPersistentAndClearOldToken(TokenHolder.INVALID_TOKEN);
mMenuButtonMediator.onMenuHighlightChanged(true);
assertTrue(mPropertyModel.get(MenuButtonProperties.IS_HIGHLIGHTING));
mMenuButtonMediator.onMenuHighlightChanged(false);
assertFalse(mPropertyModel.get(MenuButtonProperties.IS_HIGHLIGHTING));
verify(mControlsVisibilityDelegate).releasePersistentShowingToken(42);
}
@Test
public void testAppMenuUpdateBadge() {
mAppMenuSupplier.set(mAppMenuCoordinator);
doReturn(true).when(mActivity).isDestroyed();
mMenuButtonMediator.updateStateChanged();
assertFalse(mPropertyModel.get(MenuButtonProperties.SHOW_UPDATE_BADGE).mShowUpdateBadge);
verify(mRequestRenderRunnable, never()).run();
doReturn(false).when(mActivity).isDestroyed();
mMenuButtonMediator.updateStateChanged();
assertFalse(mPropertyModel.get(MenuButtonProperties.SHOW_UPDATE_BADGE).mShowUpdateBadge);
verify(mRequestRenderRunnable, never()).run();
mMenuUiState.buttonState = new UpdateMenuItemHelper.MenuButtonState();
mMenuButtonMediator.updateStateChanged();
assertTrue(mPropertyModel.get(MenuButtonProperties.SHOW_UPDATE_BADGE).mShowUpdateBadge);
verify(mRequestRenderRunnable).run();
}
@Test
public void testAppMenuUpdateBadge_activityShouldNotShow() {
MenuButtonMediator newMediator = new MenuButtonMediator(mPropertyModel, false,
()
-> false,
mRequestRenderRunnable, mThemeColorProvider,
()
-> false,
mControlsVisibilityDelegate, mFocusFunction, mAppMenuSupplier, mResources);
doReturn(true).when(mActivity).isDestroyed();
newMediator.updateStateChanged();
assertFalse(mPropertyModel.get(MenuButtonProperties.SHOW_UPDATE_BADGE).mShowUpdateBadge);
verify(mRequestRenderRunnable, never()).run();
doReturn(false).when(mActivity).isDestroyed();
newMediator.updateStateChanged();
assertFalse(mPropertyModel.get(MenuButtonProperties.SHOW_UPDATE_BADGE).mShowUpdateBadge);
verify(mRequestRenderRunnable, never()).run();
mMenuUiState.buttonState = new UpdateMenuItemHelper.MenuButtonState();
newMediator.updateStateChanged();
assertFalse(mPropertyModel.get(MenuButtonProperties.SHOW_UPDATE_BADGE).mShowUpdateBadge);
verify(mRequestRenderRunnable, never()).run();
}
@Test
public void testDestroyIsSafe() {
mMenuButtonMediator.destroy();
// It should be crash-safe to call public methods, but the results aren't meaningful.
mMenuButtonMediator.getMenuButtonHelperSupplier();
mMenuButtonMediator.onMenuHighlightChanged(true);
mMenuButtonMediator.onMenuVisibilityChanged(false);
mMenuButtonMediator.onNativeInitialized();
mMenuButtonMediator.setAppMenuUpdateBadgeSuppressed(true);
mMenuButtonMediator.updateReloadingState(true);
mMenuButtonMediator.updateStateChanged();
}
}
......@@ -92,7 +92,7 @@ public class MenuButtonTest {
ShadowDrawable darkDrawable = shadowOf(ApiCompatibilityUtils.getDrawable(
mActivity.getResources(), mMenuUiState.buttonState.darkBadgeIcon));
mMenuButton.showAppMenuUpdateBadgeIfAvailable(false);
mMenuButton.showAppMenuUpdateBadge(false);
ShadowDrawable drawnDrawable = shadowOf(mMenuButton.getTabSwitcherAnimationDrawable());
assertEquals(drawnDrawable.getCreatedFromResId(), darkDrawable.getCreatedFromResId());
assertNotEquals(drawnDrawable.getCreatedFromResId(), lightDrawable.getCreatedFromResId());
......@@ -105,8 +105,7 @@ public class MenuButtonTest {
@Test
public void testDrawTabSwitcherAnimationOverlay_updateBadgeNotAvailable() {
mMenuUiState.buttonState = null;
mMenuButton.showAppMenuUpdateBadgeIfAvailable(false);
mMenuButton.removeAppMenuUpdateBadge(false);
Bitmap drawnBitmap =
((BitmapDrawable) mMenuButton.getTabSwitcherAnimationDrawable()).getBitmap();
......@@ -117,8 +116,7 @@ public class MenuButtonTest {
@Test
public void testDrawTabSwitcherAnimationOverlay_correctBoundsAfterThemeChange() {
mMenuUiState.buttonState = null;
mMenuButton.showAppMenuUpdateBadgeIfAvailable(false);
mMenuButton.removeAppMenuUpdateBadge(false);
mMenuButton.onTintChanged(mColorStateList, true);
// Run a manual layout pass so that mMenuButton's children get assigned sizes.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment