Commit e2093705 authored by Pedro Amaral's avatar Pedro Amaral Committed by Commit Bot

Five button refactor

This is the bottom toolbar refactor to allow for 5 buttons in browsing
mode and moving the tab switcher toolbar to the bottom.

This CL breaks the old bottom toolbar MVC component into 2 components:
BrowsingModeBottomToolbar and TabSwitcherBottomToolbar. Those components
have a common root coordinator called BottomToolbarCoordinator. I've
also added two new providers. The first is the TabCountProvider. It
notifies its listeners when the tab count changes. This is useful for
the tab switcher button and the HTS tab layout icon. The other provider
is the IncognitoStateProvider. It notifies its listeners when incognito
mode is entered or exited. It also provides the tint and color for that
state.

Bug: 900759

Change-Id: Idced9f29ff4e5f3b0c6516b761416f32af78efe3

Binary-Size: Overhead from MVC
Change-Id: Idced9f29ff4e5f3b0c6516b761416f32af78efe3
Reviewed-on: https://chromium-review.googlesource.com/c/1292405
Commit-Queue: Pedro Amaral <amaralp@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#606604}
parent 76401fe8
......@@ -3,81 +3,19 @@
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<org.chromium.chrome.browser.toolbar.ScrollingBottomViewResourceFrameLayout
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/bottom_toolbar_control_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/bottom_toolbar_height">
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/bottom_toolbar_top_shadow"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_shadow_height"
android:src="@drawable/modern_toolbar_shadow"
android:scaleType="fitXY"
android:scaleY="-1"
tools:ignore="ContentDescription" />
<include layout="@layout/bottom_toolbar_browsing" />
<org.chromium.chrome.browser.widget.bottomsheet.TouchRestrictingFrameLayout
android:id="@+id/bottom_toolbar_container"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_toolbar_height"
android:layout_marginTop="@dimen/toolbar_shadow_height" >
<ViewStub
android:id="@+id/bottom_toolbar_tab_switcher_mode_stub"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_toolbar_height_with_shadow"
android:inflatedId="@+id/bottom_toolbar_tab_switcher_mode"
android:layout="@layout/bottom_toolbar_tab_switcher"
android:layout_gravity="bottom" />
<LinearLayout
android:id="@+id/bottom_sheet_toolbar"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/modern_primary_color"
android:layout_gravity="top|center_horizontal" >
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
<org.chromium.ui.widget.ChromeImageButton
android:id="@+id/first_button"
style="@style/ToolbarButton"
android:layout_gravity="center" />
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
<org.chromium.ui.widget.ChromeImageButton
android:id="@+id/second_button"
style="@style/ToolbarButton"
android:layout_gravity="center" />
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
<org.chromium.chrome.browser.toolbar.TabSwitcherButtonView
android:id="@+id/tab_switcher_button"
style="@style/ToolbarButton"
android:layout_gravity="center"
android:contentDescription="@string/accessibility_toolbar_btn_tabswitcher_toggle_default" />
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
<include layout="@layout/menu_button"/>
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
</LinearLayout>
</org.chromium.chrome.browser.widget.bottomsheet.TouchRestrictingFrameLayout>
</org.chromium.chrome.browser.toolbar.ScrollingBottomViewResourceFrameLayout>
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 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. -->
<org.chromium.chrome.browser.toolbar.ScrollingBottomViewResourceFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/bottom_toolbar_control_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/bottom_toolbar_height" >
<ImageView
android:id="@+id/bottom_toolbar_top_shadow"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_shadow_height"
android:src="@drawable/modern_toolbar_shadow"
android:scaleType="fitXY"
android:scaleY="-1"
tools:ignore="ContentDescription" />
<org.chromium.chrome.browser.widget.bottomsheet.TouchRestrictingFrameLayout
android:id="@+id/bottom_toolbar_container"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_toolbar_height"
android:layout_marginTop="@dimen/toolbar_shadow_height" >
<LinearLayout
android:id="@+id/bottom_toolbar_buttons"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/modern_primary_color"
android:layout_gravity="top|center_horizontal"
android:paddingStart="@dimen/bottom_toolbar_start_padding"
android:paddingEnd="@dimen/bottom_toolbar_end_padding" >
<org.chromium.chrome.browser.toolbar.HomeButton
android:id="@+id/home_button"
style="@style/BottomToolbarButton"
android:contentDescription="@string/accessibility_toolbar_btn_home" />
<include layout="@layout/toolbar_space" />
<org.chromium.chrome.browser.toolbar.ShareButton
android:id="@+id/share_button"
style="@style/BottomToolbarButton"
android:src="@drawable/ic_share_white_24dp"
app:tint="@color/dark_mode_tint"
android:contentDescription="@string/share" />
<include layout="@layout/toolbar_space" />
<org.chromium.chrome.browser.toolbar.SearchAccelerator
android:id="@+id/search_accelerator"
android:layout_width="@dimen/search_accelerator_width"
android:layout_height="@dimen/search_accelerator_height"
android:layout_gravity="center"
android:paddingTop="@dimen/search_accelerator_height_padding"
android:paddingBottom="@dimen/search_accelerator_height_padding"
android:src="@drawable/ic_search"
android:contentDescription="@string/accessibility_toolbar_btn_search_accelerator" />
<include layout="@layout/toolbar_space" />
<org.chromium.chrome.browser.toolbar.TabSwitcherButtonView
android:id="@+id/tab_switcher_button"
style="@style/BottomToolbarButton"
android:contentDescription="@string/accessibility_toolbar_btn_tabswitcher_toggle_default" />
<include layout="@layout/toolbar_space" />
<include layout="@layout/menu_button" />
</LinearLayout>
</org.chromium.chrome.browser.widget.bottomsheet.TouchRestrictingFrameLayout>
</org.chromium.chrome.browser.toolbar.ScrollingBottomViewResourceFrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 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. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/bottom_toolbar_tab_switcher"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone" >
<ImageView
android:id="@+id/bottom_toolbar_top_shadow"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_shadow_height"
android:src="@drawable/modern_toolbar_shadow"
android:scaleType="fitXY"
android:scaleY="-1"
tools:ignore="ContentDescription" />
<LinearLayout
android:id="@+id/bottom_toolbar_buttons"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_toolbar_height"
android:background="@color/modern_primary_color"
android:paddingStart="@dimen/bottom_toolbar_start_padding"
android:paddingEnd="@dimen/bottom_toolbar_end_padding"
android:layout_marginTop="@dimen/toolbar_shadow_height" >
<org.chromium.chrome.browser.toolbar.NewTabButton
android:id="@+id/new_tab_button"
style="@style/ToolbarButton"
android:layout_gravity="center"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/accessibility_toolbar_btn_new_tab" />
<include layout="@layout/toolbar_space" />
<ViewStub
android:id="@+id/incognito_tabs_stub"
android:inflatedId="@+id/incognito_toggle_tabs"
android:layout="@layout/incognito_toggle_tabs"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center" />
<include layout="@layout/toolbar_space" />
<include layout="@layout/menu_button" />
</LinearLayout>
</FrameLayout>
......@@ -85,7 +85,7 @@
android:visibility="gone" />
<ViewStub
android:id="@+id/bottom_toolbar"
android:id="@+id/bottom_toolbar_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|bottom"
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 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. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
</merge>
......@@ -579,6 +579,11 @@
<item name="android:layout_width">43dp</item>
<item name="android:paddingEnd">3.5dp</item>
</style>
<style name="BottomToolbarButton" parent="ToolbarButton">
<item name="android:layout_height">48dp</item>
<item name="android:layout_gravity">center</item>
</style>
<style name="AppMenuItem">
<item name="android:paddingStart">16dp</item>
<item name="android:paddingEnd">16dp</item>
......
......@@ -222,7 +222,6 @@
<!-- Full Screen Dimensions -->
<!-- Should match toolbar_height_no_shadow -->
<dimen name="control_container_height">56dp</dimen>
<dimen name="bottom_toolbar_height">@dimen/min_touch_target_size</dimen>
<dimen name="custom_tabs_control_container_height">56dp</dimen>
<dimen name="fullscreen_activity_control_container_height">0dp</dimen>
......@@ -272,6 +271,15 @@
<dimen name="tablet_toolbar_end_padding">6dp</dimen>
<dimen name="toolbar_optional_button_animation_translation">10dp</dimen>
<!-- Bottom toolbar dimensions -->
<dimen name="bottom_toolbar_height">@dimen/min_touch_target_size</dimen>
<dimen name="bottom_toolbar_height_with_shadow">56dp</dimen>
<dimen name="bottom_toolbar_start_padding">12dp</dimen>
<dimen name="bottom_toolbar_end_padding">8dp</dimen>
<dimen name="search_accelerator_width">64dp</dimen>
<dimen name="search_accelerator_height">36dp</dimen>
<dimen name="search_accelerator_height_padding">6dp</dimen>
<!-- Modern toolbar dimensions -->
<dimen name="modern_toolbar_background_size">40dp</dimen>
<!-- Sometimes the modern toolbar is shown at 48dp so a corner radius of
......
// Copyright 2018 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;
import android.view.View;
import android.view.View.OnClickListener;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ActivityTabProvider.HintlessActivityTabObserver;
import org.chromium.chrome.browser.appmenu.AppMenuButtonHelper;
import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
import org.chromium.chrome.browser.compositor.layouts.ToolbarSwipeLayout;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.toolbar.BrowsingModeBottomToolbarViewBinder.ViewHolder;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.resources.ResourceManager;
/**
* The coordinator for the browsing mode bottom toolbar. This class has two primary components,
* an Android view that handles user actions and a composited texture that draws when the controls
* are being scrolled off-screen. The Android version does not draw unless the controls offset is 0.
*/
public class BrowsingModeBottomToolbarCoordinator {
/** The mediator that handles events from outside the browsing mode bottom toolbar. */
private final BrowsingModeBottomToolbarMediator mMediator;
/** The home button that lives in the bottom toolbar. */
private final HomeButton mHomeButton;
/** The share button that lives in the bottom toolbar. */
private final ShareButton mShareButton;
/** The search acceleartor that lives in the bottom toolbar. */
private final SearchAccelerator mSearchAccelerator;
/** The tab switcher button component that lives in the bottom toolbar. */
private final TabSwitcherButtonCoordinator mTabSwitcherButtonCoordinator;
/** The menu button that lives in the browsing mode bottom toolbar. */
private final MenuButton mMenuButton;
/**
* Build the coordinator that manages the browsing mode bottom toolbar.
* @param root The root {@link View} for locating the views to inflate.
* @param fullscreenManager A {@link ChromeFullscreenManager} to update the bottom controls
* height for the renderer.
* @param tabProvider The {@link ActivityTabProvider} used for making the IPH.
* @param homeButtonListener The {@link OnClickListener} for the home button.
* @param searchAcceleratorListener The {@link OnClickListener} for the search accelerator.
* @param shareButtonListener The {@link OnClickListener} for the share button.
*/
public BrowsingModeBottomToolbarCoordinator(View root,
ChromeFullscreenManager fullscreenManager, ActivityTabProvider tabProvider,
OnClickListener homeButtonListener, OnClickListener searchAcceleratorListener,
OnClickListener shareButtonListener) {
BrowsingModeBottomToolbarModel model = new BrowsingModeBottomToolbarModel();
final ScrollingBottomViewResourceFrameLayout toolbarRoot =
(ScrollingBottomViewResourceFrameLayout) root.findViewById(
R.id.bottom_toolbar_control_container);
final int shadowHeight =
toolbarRoot.getResources().getDimensionPixelOffset(R.dimen.toolbar_shadow_height);
toolbarRoot.setTopShadowHeight(shadowHeight);
PropertyModelChangeProcessor.create(
model, new ViewHolder(toolbarRoot), new BrowsingModeBottomToolbarViewBinder());
mMediator = new BrowsingModeBottomToolbarMediator(
model, fullscreenManager, toolbarRoot.getResources());
mHomeButton = toolbarRoot.findViewById(R.id.home_button);
mHomeButton.setOnClickListener(homeButtonListener);
mShareButton = toolbarRoot.findViewById(R.id.share_button);
mShareButton.setOnClickListener(shareButtonListener);
mShareButton.setActivityTabProvider(tabProvider);
mSearchAccelerator = toolbarRoot.findViewById(R.id.search_accelerator);
mSearchAccelerator.setOnClickListener(searchAcceleratorListener);
mTabSwitcherButtonCoordinator = new TabSwitcherButtonCoordinator(toolbarRoot);
mMenuButton = toolbarRoot.findViewById(R.id.menu_button_wrapper);
final View iphAnchor = toolbarRoot.findViewById(R.id.bottom_toolbar_container);
tabProvider.addObserverAndTrigger(new HintlessActivityTabObserver() {
@Override
public void onActivityTabChanged(Tab tab) {
if (tab == null) return;
mMediator.showIPH(iphAnchor, TrackerFactory.getTrackerForProfile(tab.getProfile()));
tabProvider.removeObserver(this);
}
});
}
/**
* Initialize the bottom toolbar with the components that had native initialization
* dependencies.
* <p>
* Calling this must occur after the native library have completely loaded.
* @param resourceManager A {@link ResourceManager} for loading textures into the compositor.
* @param layoutManager A {@link LayoutManager} to attach overlays to.
* @param tabSwitcherListener An {@link OnClickListener} that is triggered when the
* tab switcher button is clicked.
* @param menuButtonHelper An {@link AppMenuButtonHelper} that is triggered when the
* menu button is clicked.
* @param overviewModeBehavior The overview mode manager.
* @param windowAndroid A {@link WindowAndroid} for watching keyboard visibility events.
* @param tabCountProvider Updates the tab count number in the tab switcher button.
* @param themeColorProvider Notifies components when theme color changes.
* @param tabModelSelector A {@link TabModelSelector} that the share button uses to know whether
* or not to be enabled.
*/
public void initializeWithNative(ResourceManager resourceManager, LayoutManager layoutManager,
OnClickListener tabSwitcherListener, AppMenuButtonHelper menuButtonHelper,
OverviewModeBehavior overviewModeBehavior, WindowAndroid windowAndroid,
TabCountProvider tabCountProvider, ThemeColorProvider themeColorProvider,
TabModelSelector tabModelSelector) {
mMediator.setLayoutManager(layoutManager);
mMediator.setResourceManager(resourceManager);
mMediator.setToolbarSwipeHandler(layoutManager.getToolbarSwipeHandler());
mMediator.setWindowAndroid(windowAndroid);
mMediator.setOverviewModeBehavior(overviewModeBehavior);
mMediator.setThemeColorProvider(themeColorProvider);
mHomeButton.setThemeColorProvider(themeColorProvider);
mShareButton.setThemeColorProvider(themeColorProvider);
mShareButton.setTabModelSelector(tabModelSelector);
mSearchAccelerator.setThemeColorProvider(themeColorProvider);
mTabSwitcherButtonCoordinator.setTabSwitcherListener(tabSwitcherListener);
mTabSwitcherButtonCoordinator.setThemeColorProvider(themeColorProvider);
mTabSwitcherButtonCoordinator.setTabCountProvider(tabCountProvider);
mMenuButton.setTouchListener(menuButtonHelper);
mMenuButton.setThemeColorProvider(themeColorProvider);
mMenuButton.setAccessibilityDelegate(menuButtonHelper);
}
/**
* Show the update badge over the bottom toolbar's app menu.
*/
public void showAppMenuUpdateBadge() {
mMenuButton.setUpdateBadgeVisibilityIfValidState(true);
}
/**
* Remove the update badge.
*/
public void removeAppMenuUpdateBadge() {
mMenuButton.setUpdateBadgeVisibilityIfValidState(false);
}
/**
* @return Whether the update badge is showing.
*/
public boolean isShowingAppMenuUpdateBadge() {
return mMenuButton.isShowingAppMenuUpdateBadge();
}
/**
* @param layout The {@link ToolbarSwipeLayout} that the bottom toolbar will hook into. This
* allows the bottom toolbar to provide the layout with scene layers with the
* bottom toolbar's texture.
*/
public void setToolbarSwipeLayout(ToolbarSwipeLayout layout) {
mMediator.setToolbarSwipeLayout(layout);
}
/**
* @return The browsing mode bottom toolbar's menu button.
*/
public MenuButton getMenuButton() {
return mMenuButton;
}
/**
* @return Whether the browsing mode toolbar is visible.
*/
public boolean isVisible() {
return mMediator.isVisible();
}
/**
* Clean up any state when the browsing mode bottom toolbar is destroyed.
*/
public void destroy() {
mMediator.destroy();
mHomeButton.destroy();
mShareButton.destroy();
mSearchAccelerator.destroy();
mTabSwitcherButtonCoordinator.destroy();
mMenuButton.destroy();
}
}
......@@ -8,13 +8,13 @@ import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
import org.chromium.chrome.browser.compositor.layouts.ToolbarSwipeLayout;
import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeHandler;
import org.chromium.chrome.browser.modelutil.PropertyModel;
import org.chromium.chrome.browser.toolbar.ToolbarButtonSlotData.ToolbarButtonData;
import org.chromium.ui.resources.ResourceManager;
/**
* All of the state for the bottom toolbar, updated by the {@link BottomToolbarCoordinator}.
* All of the state for the bottom toolbar, updated by the {@link
* BrowsingModeBottomToolbarCoordinator}.
*/
public class BottomToolbarModel extends PropertyModel {
public class BrowsingModeBottomToolbarModel extends PropertyModel {
/** The Y offset of the view in px. */
public static final WritableIntPropertyKey Y_OFFSET = new WritableIntPropertyKey();
......@@ -42,21 +42,16 @@ public class BottomToolbarModel extends PropertyModel {
public static final WritableObjectPropertyKey<EdgeSwipeHandler> TOOLBAR_SWIPE_HANDLER =
new WritableObjectPropertyKey<>();
/** Data used to show the first button. */
public static final WritableObjectPropertyKey<ToolbarButtonData> FIRST_BUTTON_DATA =
new WritableObjectPropertyKey<>();
/** Data used to show the second button. */
public static final WritableObjectPropertyKey<ToolbarButtonData> SECOND_BUTTON_DATA =
new WritableObjectPropertyKey<>();
/** Primary color of bottom toolbar. */
public static final WritableIntPropertyKey PRIMARY_COLOR = new WritableIntPropertyKey();
/** Whether the browsing mode bottom toolbar is visible */
public static final WritableBooleanPropertyKey IS_VISIBLE = new WritableBooleanPropertyKey();
/** Default constructor. */
public BottomToolbarModel() {
public BrowsingModeBottomToolbarModel() {
super(Y_OFFSET, ANDROID_VIEW_VISIBLE, COMPOSITED_VIEW_VISIBLE, LAYOUT_MANAGER,
TOOLBAR_SWIPE_LAYOUT, RESOURCE_MANAGER, TOOLBAR_SWIPE_HANDLER, FIRST_BUTTON_DATA,
SECOND_BUTTON_DATA, PRIMARY_COLOR);
TOOLBAR_SWIPE_LAYOUT, RESOURCE_MANAGER, TOOLBAR_SWIPE_HANDLER, IS_VISIBLE,
PRIMARY_COLOR);
}
}
......@@ -6,26 +6,23 @@ package org.chromium.chrome.browser.toolbar;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.scene_layer.ScrollingBottomViewSceneLayer;
import org.chromium.chrome.browser.modelutil.PropertyKey;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
import org.chromium.chrome.browser.toolbar.ToolbarButtonSlotData.ToolbarButtonData;
import org.chromium.chrome.browser.util.ColorUtils;
/**
* This class is responsible for pushing updates to both the Android view and the compositor
* component of the bottom toolbar. These updates are pulled from the {@link BottomToolbarModel}
* when a notification of an update is received.
* component of the browsing mode bottom toolbar. These updates are pulled from the
* {@link BrowsingModeBottomToolbarModel} when a notification of an update is received.
*/
public class BottomToolbarViewBinder
implements PropertyModelChangeProcessor.ViewBinder<BottomToolbarModel,
BottomToolbarViewBinder.ViewHolder, PropertyKey> {
public class BrowsingModeBottomToolbarViewBinder
implements PropertyModelChangeProcessor.ViewBinder<BrowsingModeBottomToolbarModel,
BrowsingModeBottomToolbarViewBinder.ViewHolder, PropertyKey> {
/**
* A wrapper class that holds a {@link ViewGroup} (the toolbar view) and a composited layer to
* be used with the {@link BottomToolbarViewBinder}.
* be used with the {@link BrowsingModeBottomToolbarViewBinder}.
*/
public static class ViewHolder {
/** A handle to the Android View based version of the toolbar. */
......@@ -34,92 +31,62 @@ public class BottomToolbarViewBinder
/** A handle to the composited bottom toolbar layer. */
public ScrollingBottomViewSceneLayer sceneLayer;
/** Cached {@link ImageButton} of the first button. */
public final ImageButton firstImageButton;
/** Cached {@link ImageButton} of the second button. */
public final ImageButton secondImageButton;
/**
* @param toolbarRootView The Android View based toolbar.
*/
public ViewHolder(ScrollingBottomViewResourceFrameLayout toolbarRootView) {
toolbarRoot = toolbarRootView;
firstImageButton = toolbarRoot.findViewById(R.id.first_button);
secondImageButton = toolbarRoot.findViewById(R.id.second_button);
}
}
/**
* Build a binder that handles interaction between the model and the views that make up the
* bottom toolbar.
* browsing mode bottom toolbar.
*/
public BottomToolbarViewBinder() {}
public BrowsingModeBottomToolbarViewBinder() {}
@Override
public final void bind(BottomToolbarModel model, ViewHolder view, PropertyKey propertyKey) {
if (BottomToolbarModel.Y_OFFSET == propertyKey) {
public final void bind(
BrowsingModeBottomToolbarModel model, ViewHolder view, PropertyKey propertyKey) {
if (BrowsingModeBottomToolbarModel.Y_OFFSET == propertyKey) {
assert view.sceneLayer != null;
view.sceneLayer.setYOffset(model.get(BottomToolbarModel.Y_OFFSET));
} else if (BottomToolbarModel.ANDROID_VIEW_VISIBLE == propertyKey) {
view.toolbarRoot.setVisibility(model.get(BottomToolbarModel.ANDROID_VIEW_VISIBLE)
view.sceneLayer.setYOffset(model.get(BrowsingModeBottomToolbarModel.Y_OFFSET));
} else if (BrowsingModeBottomToolbarModel.ANDROID_VIEW_VISIBLE == propertyKey) {
view.toolbarRoot.setVisibility(
model.get(BrowsingModeBottomToolbarModel.ANDROID_VIEW_VISIBLE)
? View.VISIBLE
: View.INVISIBLE);
} else if (BottomToolbarModel.COMPOSITED_VIEW_VISIBLE == propertyKey) {
view.sceneLayer.setIsVisible(model.get(BottomToolbarModel.COMPOSITED_VIEW_VISIBLE));
model.get(BottomToolbarModel.LAYOUT_MANAGER).requestUpdate();
} else if (BottomToolbarModel.LAYOUT_MANAGER == propertyKey) {
} else if (BrowsingModeBottomToolbarModel.COMPOSITED_VIEW_VISIBLE == propertyKey) {
view.sceneLayer.setIsVisible(
model.get(BrowsingModeBottomToolbarModel.COMPOSITED_VIEW_VISIBLE));
model.get(BrowsingModeBottomToolbarModel.LAYOUT_MANAGER).requestUpdate();
} else if (BrowsingModeBottomToolbarModel.LAYOUT_MANAGER == propertyKey) {
assert view.sceneLayer == null;
view.sceneLayer = new ScrollingBottomViewSceneLayer(
view.toolbarRoot, view.toolbarRoot.getTopShadowHeight());
model.get(BottomToolbarModel.LAYOUT_MANAGER).addSceneOverlayToBack(view.sceneLayer);
} else if (BottomToolbarModel.TOOLBAR_SWIPE_LAYOUT == propertyKey) {
model.get(BrowsingModeBottomToolbarModel.LAYOUT_MANAGER)
.addSceneOverlayToBack(view.sceneLayer);
} else if (BrowsingModeBottomToolbarModel.TOOLBAR_SWIPE_LAYOUT == propertyKey) {
assert view.sceneLayer != null;
model.get(BottomToolbarModel.TOOLBAR_SWIPE_LAYOUT)
model.get(BrowsingModeBottomToolbarModel.TOOLBAR_SWIPE_LAYOUT)
.setBottomToolbarSceneLayers(new ScrollingBottomViewSceneLayer(view.sceneLayer),
new ScrollingBottomViewSceneLayer(view.sceneLayer));
} else if (BottomToolbarModel.RESOURCE_MANAGER == propertyKey) {
model.get(BottomToolbarModel.RESOURCE_MANAGER)
} else if (BrowsingModeBottomToolbarModel.RESOURCE_MANAGER == propertyKey) {
model.get(BrowsingModeBottomToolbarModel.RESOURCE_MANAGER)
.getDynamicResourceLoader()
.registerResource(
view.toolbarRoot.getId(), view.toolbarRoot.getResourceAdapter());
} else if (BottomToolbarModel.TOOLBAR_SWIPE_HANDLER == propertyKey) {
view.toolbarRoot.setSwipeDetector(model.get(BottomToolbarModel.TOOLBAR_SWIPE_HANDLER));
} else if (BottomToolbarModel.FIRST_BUTTON_DATA == propertyKey) {
updateButton(view.firstImageButton, model.get(BottomToolbarModel.FIRST_BUTTON_DATA),
useLightIcons(model));
} else if (BottomToolbarModel.SECOND_BUTTON_DATA == propertyKey) {
updateButton(view.secondImageButton, model.get(BottomToolbarModel.SECOND_BUTTON_DATA),
useLightIcons(model));
} else if (BottomToolbarModel.PRIMARY_COLOR == propertyKey) {
final boolean useLightIcons = useLightIcons(model);
view.toolbarRoot.findViewById(R.id.bottom_sheet_toolbar)
.setBackgroundColor(model.get(BottomToolbarModel.PRIMARY_COLOR));
updateButtonDrawable(view.firstImageButton,
model.get(BottomToolbarModel.FIRST_BUTTON_DATA), useLightIcons);
updateButtonDrawable(view.secondImageButton,
model.get(BottomToolbarModel.SECOND_BUTTON_DATA), useLightIcons);
} else {
assert false : "Unhandled property detected in BottomToolbarViewBinder!";
}
}
private static boolean useLightIcons(BottomToolbarModel model) {
return ColorUtils.shouldUseLightForegroundOnBackground(
model.get(BottomToolbarModel.PRIMARY_COLOR));
}
private static void updateButton(
ImageButton button, ToolbarButtonData buttonData, boolean useLightIcons) {
if (buttonData == null) {
ToolbarButtonData.clearButton(button);
} else if (BrowsingModeBottomToolbarModel.TOOLBAR_SWIPE_HANDLER == propertyKey) {
view.toolbarRoot.setSwipeDetector(
model.get(BrowsingModeBottomToolbarModel.TOOLBAR_SWIPE_HANDLER));
} else if (BrowsingModeBottomToolbarModel.PRIMARY_COLOR == propertyKey) {
view.toolbarRoot.findViewById(R.id.bottom_toolbar_buttons)
.setBackgroundColor(model.get(BrowsingModeBottomToolbarModel.PRIMARY_COLOR));
} else if (BrowsingModeBottomToolbarModel.IS_VISIBLE == propertyKey) {
final boolean isVisible = model.get(BrowsingModeBottomToolbarModel.IS_VISIBLE);
view.toolbarRoot.setVisibility(isVisible ? View.GONE : View.VISIBLE);
} else {
buttonData.updateButton(button, useLightIcons);
assert false : "Unhandled property detected in BrowsingModeBottomToolbarViewBinder!";
}
}
private static void updateButtonDrawable(
ImageButton button, ToolbarButtonData buttonData, boolean useLightIcons) {
if (buttonData != null) buttonData.updateButtonDrawable(button, useLightIcons);
}
}
// Copyright 2018 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;
import android.content.Context;
import android.content.res.ColorStateList;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.toolbar.ThemeColorProvider.ThemeColorObserver;
import org.chromium.chrome.browser.util.FeatureUtilities;
import org.chromium.ui.widget.ChromeImageButton;
/**
* The home button.
*/
class HomeButton extends ChromeImageButton implements ThemeColorObserver {
/** A provider that notifies components when the theme color changes.*/
private ThemeColorProvider mThemeColorProvider;
public HomeButton(Context context, AttributeSet attrs) {
super(context, attrs);
final int homeButtonIcon = FeatureUtilities.isNewTabPageButtonEnabled()
? R.drawable.ic_home
: R.drawable.btn_toolbar_home;
setImageDrawable(ContextCompat.getDrawable(context, homeButtonIcon));
}
void setThemeColorProvider(ThemeColorProvider themeColorProvider) {
mThemeColorProvider = themeColorProvider;
mThemeColorProvider.addObserver(this);
}
void destroy() {
if (mThemeColorProvider != null) {
mThemeColorProvider.removeObserver(this);
mThemeColorProvider = null;
}
}
@Override
public void onThemeColorChanged(ColorStateList tint, int primaryColor) {
ApiCompatibilityUtils.setImageTintList(this, tint);
}
}
// Copyright 2018 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;
import android.content.Context;
import android.content.res.ColorStateList;
import android.support.v7.content.res.AppCompatResources;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ObserverList;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
import org.chromium.chrome.browser.toolbar.ThemeColorProvider.ThemeColorObserver;
/** A provider that notifies its observers when incognito mode is entered or exited. */
public class IncognitoStateProvider implements ThemeColorProvider {
interface IncognitoStateObserver {
void onIncognitoStateChanged(boolean isIncognito);
}
/** List of {@link IncognitoStateObserver}s. These are used to broadcast events to listeners. */
private final ObserverList<ThemeColorObserver> mThemeColorObservers;
/** List of {@link IncognitoStateObserver}s. These are used to broadcast events to listeners. */
private final ObserverList<IncognitoStateObserver> mIncognitoStateObservers;
/** Tint to be used in incognito mode. */
private final ColorStateList mIncognitoTint;
/** Tint to be used in normal mode. */
private final ColorStateList mNormalTint;
/** Primary color for normal mode. */
private final int mNormalPrimaryColor;
/** Primary color for incognito mode. */
private final int mIncognitoPrimaryColor;
/** A {@link TabModelSelectorObserver} used to know when incognito mode is entered or exited. */
private final TabModelSelectorObserver mTabModelSelectorObserver;
/** A {@link TabModelSelector} used to know when incognito mode is entered or exited. */
private TabModelSelector mTabModelSelector;
public IncognitoStateProvider(Context context) {
mThemeColorObservers = new ObserverList<ThemeColorObserver>();
mIncognitoStateObservers = new ObserverList<IncognitoStateObserver>();
mIncognitoTint = AppCompatResources.getColorStateList(context, R.color.light_mode_tint);
mNormalTint = AppCompatResources.getColorStateList(context, R.color.dark_mode_tint);
mNormalPrimaryColor = ApiCompatibilityUtils.getColor(
context.getResources(), R.color.modern_primary_color);
mIncognitoPrimaryColor = ApiCompatibilityUtils.getColor(
context.getResources(), R.color.incognito_modern_primary_color);
mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() {
@Override
public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
incognitoStateChanged(newModel.isIncognito());
}
};
}
/**
* @param observer Add an observer that will have events broadcast to.
*/
public void addObserver(IncognitoStateObserver observer) {
mIncognitoStateObservers.addObserver(observer);
}
/**
* @param observer Remove the observer.
*/
public void removeObserver(IncognitoStateObserver observer) {
mIncognitoStateObservers.removeObserver(observer);
}
@Override
public void addObserver(ThemeColorObserver observer) {
mThemeColorObservers.addObserver(observer);
}
@Override
public void removeObserver(ThemeColorObserver observer) {
mThemeColorObservers.removeObserver(observer);
}
void setTabModelSelector(TabModelSelector tabModelSelector) {
mTabModelSelector = tabModelSelector;
mTabModelSelector.addObserver(mTabModelSelectorObserver);
incognitoStateChanged(mTabModelSelector.isIncognitoSelected());
}
void destroy() {
if (mTabModelSelector != null) {
mTabModelSelector.removeObserver(mTabModelSelectorObserver);
mTabModelSelector = null;
}
mThemeColorObservers.clear();
mIncognitoStateObservers.clear();
}
private void incognitoStateChanged(boolean isIncognito) {
for (IncognitoStateObserver observer : mIncognitoStateObservers) {
observer.onIncognitoStateChanged(isIncognito);
}
final ColorStateList tint = isIncognito ? mIncognitoTint : mNormalTint;
final int primaryColor = isIncognito ? mIncognitoPrimaryColor : mNormalPrimaryColor;
for (ThemeColorObserver observer : mThemeColorObservers) {
observer.onThemeColorChanged(tint, primaryColor);
}
}
}
......@@ -17,12 +17,14 @@ import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
import org.chromium.chrome.browser.toolbar.TabCountProvider.TabCountObserver;
import org.chromium.ui.widget.ChromeImageView;
/**
* TabLayout shown in the Horizontal Tab Switcher.
*/
public class IncognitoToggleTabLayout extends TabLayout {
public class IncognitoToggleTabLayout extends TabLayout implements TabCountObserver {
private TabLayout.Tab mStandardButton;
private TabLayout.Tab mIncognitoButton;
private ImageView mStandardButtonIcon;
......@@ -35,6 +37,8 @@ public class IncognitoToggleTabLayout extends TabLayout {
private ColorStateList mTabIconSelectedLightColor;
private TabModelSelector mTabModelSelector;
private TabCountProvider mTabCountProvider;
private TabModelSelectorObserver mTabModelSelectorObserver;
/**
* Constructor for inflating from XML.
......@@ -88,21 +92,33 @@ public class IncognitoToggleTabLayout extends TabLayout {
public void setTabModelSelector(TabModelSelector selector) {
mTabModelSelector = selector;
if (mTabModelSelector == null) return;
mTabModelSelector.addObserver(new EmptyTabModelSelectorObserver() {
mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() {
@Override
public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
setStateBasedOnModel();
}
});
};
mTabModelSelector.addObserver(mTabModelSelectorObserver);
setStateBasedOnModel();
}
public void setTabCountProvider(TabCountProvider tabCountProvider) {
mTabCountProvider = tabCountProvider;
mTabCountProvider.addObserver(this);
}
/**
* Update the visual state based on number of normal (non-incognito) tabs present.
* @param tabCount The number of normal tabs.
*/
public void updateTabCount(int tabCount) {
mTabSwitcherDrawable.updateForTabCount(tabCount, false);
@Override
public void onTabCountChanged(int tabCount, boolean isIncognito) {
if (!isIncognito) mTabSwitcherDrawable.updateForTabCount(tabCount, isIncognito);
}
public void destroy() {
if (mTabModelSelector != null) mTabModelSelector.removeObserver(mTabModelSelectorObserver);
if (mTabCountProvider != null) mTabCountProvider.removeObserver(this);
}
private void setStateBasedOnModel() {
......
......@@ -16,11 +16,13 @@ import android.widget.ImageView;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
import org.chromium.chrome.browser.toolbar.ThemeColorProvider.ThemeColorObserver;
import org.chromium.chrome.browser.util.ColorUtils;
/**
* The overflow menu button.
*/
class MenuButton extends FrameLayout {
class MenuButton extends FrameLayout implements ThemeColorObserver {
/** The {@link ImageButton} for the menu button. */
private ImageButton mMenuImageButton;
......@@ -28,6 +30,9 @@ class MenuButton extends FrameLayout {
private ImageView mUpdateBadgeView;
private boolean mUseLightDrawables;
/** A provider that notifies components when the theme color changes.*/
private ThemeColorProvider mThemeColorProvider;
public MenuButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
......@@ -144,11 +149,21 @@ class MenuButton extends FrameLayout {
return mMenuImageButton;
}
/**
* @param tintList The {@link ColorStateList} that will tint the menu button (the badge is not
* tinted).
*/
void setTint(ColorStateList tintList) {
void setThemeColorProvider(ThemeColorProvider themeColorProvider) {
mThemeColorProvider = themeColorProvider;
mThemeColorProvider.addObserver(this);
}
@Override
public void onThemeColorChanged(ColorStateList tintList, int primaryColor) {
ApiCompatibilityUtils.setImageTintList(mMenuImageButton, tintList);
setUseLightDrawables(ColorUtils.shouldUseLightForegroundOnBackground(primaryColor));
}
void destroy() {
if (mThemeColorProvider != null) {
mThemeColorProvider.removeObserver(this);
mThemeColorProvider = null;
}
}
}
......@@ -15,17 +15,20 @@ import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.device.DeviceClassManager;
import org.chromium.chrome.browser.toolbar.IncognitoStateProvider.IncognitoStateObserver;
import org.chromium.chrome.browser.util.FeatureUtilities;
import org.chromium.ui.base.DeviceFormFactor;
import org.chromium.ui.widget.ChromeImageButton;
/**
* Button for creating new tabs.
*/
public class NewTabButton extends ChromeImageButton {
public class NewTabButton extends ChromeImageButton implements IncognitoStateObserver {
private final ColorStateList mLightModeTint;
private final ColorStateList mDarkModeTint;
private boolean mIsIncognito;
private boolean mIsNativeReady;
private IncognitoStateProvider mIncognitoStateProvider;
/**
* Constructor for inflating from XML.
......@@ -54,6 +57,7 @@ public class NewTabButton extends ChromeImageButton {
/**
* Updates the visual state based on whether incognito or normal tabs are being created.
* @param incognito Whether the button is now used for creating incognito tabs.
* TODO(amaralp): Get rid of this method in favor of always using IncognitoStateProvider.
*/
public void setIsIncognito(boolean incognito) {
if (mIsIncognito == incognito) return;
......@@ -86,9 +90,30 @@ public class NewTabButton extends ChromeImageButton {
|| (mIsNativeReady
&& (DeviceClassManager.enableAccessibilityLayout()
|| ChromeFeatureList.isEnabled(
ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID))
ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)
|| FeatureUtilities.isBottomToolbarEnabled())
&& mIsIncognito);
ApiCompatibilityUtils.setImageTintList(
this, shouldUseLightMode ? mLightModeTint : mDarkModeTint);
}
public void setIncognitoStateProvider(IncognitoStateProvider incognitoStateProvider) {
mIncognitoStateProvider = incognitoStateProvider;
mIncognitoStateProvider.addObserver(this);
}
@Override
public void onIncognitoStateChanged(boolean isIncognito) {
setIsIncognito(isIncognito);
}
/**
* Clean up any state when the new tab button is destroyed.
*/
public void destroy() {
if (mIncognitoStateProvider != null) {
mIncognitoStateProvider.removeObserver(this);
mIncognitoStateProvider = null;
}
}
}
// Copyright 2018 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;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.toolbar.ThemeColorProvider.ThemeColorObserver;
import org.chromium.chrome.browser.util.ColorUtils;
import org.chromium.ui.widget.ChromeImageButton;
/**
* The search accelerator.
*/
class SearchAccelerator extends ChromeImageButton implements ThemeColorObserver {
/** A provider that notifies components when the theme color changes.*/
private ThemeColorProvider mThemeColorProvider;
/** The gray pill background behind the search icon. */
private final Drawable mBackground;
/** The {@link Resources} used to compute the background color. */
private final Resources mResources;
public SearchAccelerator(Context context, AttributeSet attrs) {
super(context, attrs);
mResources = context.getResources();
mBackground = ApiCompatibilityUtils.getDrawable(mResources, R.drawable.ntp_search_box);
mBackground.mutate();
setBackground(mBackground);
}
void setThemeColorProvider(ThemeColorProvider themeColorProvider) {
mThemeColorProvider = themeColorProvider;
mThemeColorProvider.addObserver(this);
}
void destroy() {
if (mThemeColorProvider != null) {
mThemeColorProvider.removeObserver(this);
mThemeColorProvider = null;
}
}
@Override
public void onThemeColorChanged(ColorStateList tint, int primaryColor) {
ApiCompatibilityUtils.setImageTintList(this, tint);
mBackground.setColorFilter(
ColorUtils.getTextBoxColorForToolbarBackground(mResources, false, primaryColor),
PorterDuff.Mode.SRC_IN);
}
}
// Copyright 2018 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;
import android.content.Context;
import android.content.res.ColorStateList;
import android.util.AttributeSet;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ActivityTabProvider.HintlessActivityTabObserver;
import org.chromium.chrome.browser.UrlConstants;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
import org.chromium.chrome.browser.toolbar.ThemeColorProvider.ThemeColorObserver;
import org.chromium.ui.widget.ChromeImageButton;
/**
* The share button.
*/
class ShareButton extends ChromeImageButton implements ThemeColorObserver {
/** A provider that notifies components when the theme color changes.*/
private ThemeColorProvider mThemeColorProvider;
/** The {@link HintlessActivityTabObserver} used to know when the activity tab changed. */
private HintlessActivityTabObserver mHintlessActivityTabObserver;
/** The {@link ActivityTabProvider} used to know when the activity tab changed. */
private ActivityTabProvider mActivityTabProvider;
/** A {@link TabModelSelector} used to know when a new page has loaded. */
private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
public ShareButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
void setThemeColorProvider(ThemeColorProvider themeStateProvider) {
mThemeColorProvider = themeStateProvider;
mThemeColorProvider.addObserver(this);
}
void setActivityTabProvider(ActivityTabProvider activityTabProvider) {
mActivityTabProvider = activityTabProvider;
mHintlessActivityTabObserver = new HintlessActivityTabObserver() {
@Override
public void onActivityTabChanged(Tab tab) {
if (tab == null) return;
setEnabled(shouldEnableShare(tab));
}
};
mActivityTabProvider.addObserverAndTrigger(mHintlessActivityTabObserver);
}
void setTabModelSelector(TabModelSelector tabModelSelector) {
mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(tabModelSelector) {
@Override
public void onPageLoadFinished(Tab tab) {
if (tab == null) return;
setEnabled(shouldEnableShare(tab));
}
};
}
void destroy() {
if (mThemeColorProvider != null) {
mThemeColorProvider.removeObserver(this);
mThemeColorProvider = null;
}
if (mTabModelSelectorTabObserver != null) {
mTabModelSelectorTabObserver.destroy();
mTabModelSelectorTabObserver = null;
}
if (mActivityTabProvider != null) {
mActivityTabProvider.removeObserver(mHintlessActivityTabObserver);
mActivityTabProvider = null;
}
}
private static boolean shouldEnableShare(Tab tab) {
final String url = tab.getUrl();
final boolean isChromeScheme = url.startsWith(UrlConstants.CHROME_URL_PREFIX)
|| url.startsWith(UrlConstants.CHROME_NATIVE_URL_PREFIX);
return !isChromeScheme && !tab.isShowingInterstitialPage();
}
@Override
public void onThemeColorChanged(ColorStateList tint, int primaryColor) {
ApiCompatibilityUtils.setImageTintList(this, tint);
}
}
// Copyright 2018 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;
import org.chromium.base.ObserverList;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
import java.util.List;
class TabCountProvider {
/** An observer that is notified of changes to the number of open tabs. */
interface TabCountObserver {
/**
* @param tabCount Number of open tabs in the selected tab model.
* @param isIncognito Whether the selected tab model is incognito.
*/
void onTabCountChanged(int tabCount, boolean isIncognito);
}
/** List of {@link TabCountObserver}s. These are used to broadcast events to listeners. */
private final ObserverList<TabCountObserver> mTabCountObservers;
/** The {@link TabModelSelector} this class will observe. */
private TabModelSelector mTabModelSelector;
/** The {@link TabModelSelectorObserver} that observes when the tab count may have changed. */
private TabModelSelectorObserver mTabModelSelectorObserver;
/**
* The {@link TabModelSelectorTabModelObserver} that observes when the tab count may have
* changed.
*/
private TabModelSelectorTabModelObserver mTabModelSelectorTabModelObserver;
private int mTabCount = 0;
private boolean mIsIncognito = false;
TabCountProvider() {
mTabCountObservers = new ObserverList<TabCountObserver>();
}
/**
* @param observer The observer that will have events broadcast to.
*/
void addObserver(TabCountObserver observer) {
mTabCountObservers.addObserver(observer);
}
/**
* @param observer The observer that will be removed.
*/
void removeObserver(TabCountObserver observer) {
mTabCountObservers.removeObserver(observer);
}
/**
* @param tabModelSelector The {@link TabModelSelectorObserver} that observes when the tab count
* may have changed.
*/
void setTabModelSelector(TabModelSelector tabModelSelector) {
mTabModelSelector = tabModelSelector;
mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() {
@Override
public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
updateTabCount();
}
@Override
public void onTabStateInitialized() {
updateTabCount();
}
};
mTabModelSelector.addObserver(mTabModelSelectorObserver);
mTabModelSelectorTabModelObserver =
new TabModelSelectorTabModelObserver(mTabModelSelector) {
@Override
public void didAddTab(Tab tab, @TabLaunchType int type) {
updateTabCount();
}
@Override
public void tabClosureUndone(Tab tab) {
updateTabCount();
}
@Override
public void didCloseTab(int tabId, boolean incognito) {
updateTabCount();
}
@Override
public void tabPendingClosure(Tab tab) {
updateTabCount();
}
@Override
public void allTabsPendingClosure(List<Tab> tabs) {
updateTabCount();
}
@Override
public void tabRemoved(Tab tab) {
updateTabCount();
}
};
updateTabCount();
}
/**
* Clean up any state when the TabCountProvider is destroyed.
*/
void destroy() {
if (mTabModelSelector != null) {
mTabModelSelector.removeObserver(mTabModelSelectorObserver);
mTabModelSelector = null;
}
if (mTabModelSelectorTabModelObserver != null) {
mTabModelSelectorTabModelObserver.destroy();
mTabModelSelectorTabModelObserver = null;
}
mTabCountObservers.clear();
}
private void updateTabCount() {
final int tabCount = mTabModelSelector.getCurrentModel().getCount();
final boolean isIncognito = mTabModelSelector.isIncognitoSelected();
if (mTabCount == tabCount && mIsIncognito == isIncognito) return;
mTabCount = tabCount;
mIsIncognito = isIncognito;
for (TabCountObserver observer : mTabCountObservers) {
observer.onTabCountChanged(tabCount, isIncognito);
}
}
}
// Copyright 2018 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;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewStub;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.appmenu.AppMenuButtonHelper;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
import org.chromium.chrome.browser.device.DeviceClassManager;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
/**
* The coordinator for the tab switcher mode bottom toolbar. This class handles all interactions
* that the tab switcher bottom toolbar has with the outside world.
*/
public class TabSwitcherBottomToolbarCoordinator {
/** The mediator that handles events from outside the tab switcher bottom toolbar. */
private final TabSwitcherBottomToolbarMediator mMediator;
/** The new tab button that lives in the bottom toolbar. */
private final NewTabButton mNewTabButton;
/** The incognito toggle tab layout that lives in bottom toolbar. */
private final IncognitoToggleTabLayout mIncognitoToggleTabLayout;
/** The menu button that lives in the tab switcher bottom toolbar. */
private final MenuButton mMenuButton;
/**
* Build the coordinator that manages the tab switcher bottom toolbar.
* @param stub The tab switcher bottom toolbar {@link ViewStub} to inflate.
* @param incognitoStateProvider Notifies components when incognito mode is entered or exited.
* @param newTabClickListener An {@link OnClickListener} that is triggered when the
* new tab button is clicked.
* @param menuButtonHelper An {@link AppMenuButtonHelper} that is triggered when the
* menu button is clicked.
* @param tabModelSelector A {@link TabModelSelector} that incognito toggle tab layout uses to
* switch between normal and incognito tabs.
* @param overviewModeBehavior The overview mode manager.
* @param tabCountProvider Updates the tab count number in the tab switcher button and in the
* incognito toggle tab layout.
*/
public TabSwitcherBottomToolbarCoordinator(ViewStub stub,
IncognitoStateProvider incognitoStateProvider, OnClickListener newTabClickListener,
AppMenuButtonHelper menuButtonHelper, TabModelSelector tabModelSelector,
OverviewModeBehavior overviewModeBehavior, TabCountProvider tabCountProvider) {
final View root = stub.inflate();
TabSwitcherBottomToolbarModel model = new TabSwitcherBottomToolbarModel();
PropertyModelChangeProcessor.create(model, root, new TabSwitcherBottomToolbarViewBinder());
mMediator = new TabSwitcherBottomToolbarMediator(
model, incognitoStateProvider, overviewModeBehavior);
mNewTabButton = root.findViewById(R.id.new_tab_button);
mNewTabButton.setIncognitoStateProvider(incognitoStateProvider);
mNewTabButton.setOnClickListener(newTabClickListener);
mNewTabButton.postNativeInitialization();
mMenuButton = root.findViewById(R.id.menu_button_wrapper);
mMenuButton.setThemeColorProvider(incognitoStateProvider);
mMenuButton.setTouchListener(menuButtonHelper);
mMenuButton.setAccessibilityDelegate(menuButtonHelper);
if (!DeviceClassManager.enableAccessibilityLayout()
&& ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)) {
ViewStub incognitoToggleTabsStub = root.findViewById(R.id.incognito_tabs_stub);
mIncognitoToggleTabLayout =
(IncognitoToggleTabLayout) incognitoToggleTabsStub.inflate();
mIncognitoToggleTabLayout.setTabModelSelector(tabModelSelector);
mIncognitoToggleTabLayout.setTabCountProvider(tabCountProvider);
} else {
mIncognitoToggleTabLayout = null;
}
}
/**
* Show the update badge over the bottom toolbar's app menu.
*/
public void showAppMenuUpdateBadge() {
mMenuButton.setUpdateBadgeVisibilityIfValidState(true);
}
/**
* Remove the update badge.
*/
public void removeAppMenuUpdateBadge() {
mMenuButton.setUpdateBadgeVisibilityIfValidState(false);
}
/**
* @return Whether the update badge is showing.
*/
public boolean isShowingAppMenuUpdateBadge() {
return mMenuButton.isShowingAppMenuUpdateBadge();
}
/**
* @return The tab switcher mode bottom toolbar's menu button.
*/
public MenuButton getMenuButton() {
return mMenuButton;
}
/**
* Clean up any state when the bottom toolbar is destroyed.
*/
public void destroy() {
mMediator.destroy();
mNewTabButton.destroy();
if (mIncognitoToggleTabLayout != null) mIncognitoToggleTabLayout.destroy();
mMenuButton.destroy();
}
}
// Copyright 2018 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;
import android.content.res.ColorStateList;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
import org.chromium.chrome.browser.toolbar.ThemeColorProvider.ThemeColorObserver;
/**
* This class is responsible for reacting to events from the outside world, interacting with other
* coordinators, running most of the business logic associated with the tab switcher bottom toolbar,
* and updating the model accordingly.
*/
class TabSwitcherBottomToolbarMediator implements OverviewModeObserver, ThemeColorObserver {
/** The model for the tab switcher bottom toolbar that holds all of its state. */
private final TabSwitcherBottomToolbarModel mModel;
/** A provider that notifies components when the theme color changes.*/
private final ThemeColorProvider mThemeColorProvider;
/** The overview mode manager. */
private final OverviewModeBehavior mOverviewModeBehavior;
/**
* Build a new mediator that handles events from outside the tab switcher bottom toolbar.
* @param model The {@link TabSwitcherBottomToolbarModel} that holds all the state for the
* tab switcher bottom toolbar.
* @param themeColorProvider Notifies components when the theme color changes.
* @param overviewModeBehavior The overview mode manager.
*/
TabSwitcherBottomToolbarMediator(TabSwitcherBottomToolbarModel model,
ThemeColorProvider themeColorProvider, OverviewModeBehavior overviewModeBehavior) {
mModel = model;
mThemeColorProvider = themeColorProvider;
mThemeColorProvider.addObserver(this);
mOverviewModeBehavior = overviewModeBehavior;
mOverviewModeBehavior.addOverviewModeObserver(this);
}
/**
* Clean up anything that needs to be when the tab switcher bottom toolbar is destroyed.
*/
void destroy() {
if (mOverviewModeBehavior != null) mOverviewModeBehavior.removeOverviewModeObserver(this);
if (mThemeColorProvider != null) mThemeColorProvider.removeObserver(this);
}
@Override
public void onOverviewModeStartedShowing(boolean showToolbar) {
mModel.set(TabSwitcherBottomToolbarModel.IS_VISIBLE, true);
}
@Override
public void onOverviewModeFinishedShowing() {}
@Override
public void onOverviewModeStartedHiding(boolean showToolbar, boolean delayAnimation) {
mModel.set(TabSwitcherBottomToolbarModel.IS_VISIBLE, false);
}
@Override
public void onOverviewModeFinishedHiding() {}
@Override
public void onThemeColorChanged(ColorStateList tint, int primaryColor) {
mModel.set(TabSwitcherBottomToolbarModel.PRIMARY_COLOR, primaryColor);
}
}
// Copyright 2018 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;
import org.chromium.chrome.browser.modelutil.PropertyModel;
/**
* All of the state for the tab switcher bottom toolbar, updated by the
* {@link TabSwitcherBottomToolbarCoordinator}.
*/
public class TabSwitcherBottomToolbarModel extends PropertyModel {
/** Primary color of tab switcher bottom toolbar. */
public static final WritableIntPropertyKey PRIMARY_COLOR = new WritableIntPropertyKey();
/** Whether the tab switcher bottom toolbar is visible */
public static final WritableBooleanPropertyKey IS_VISIBLE = new WritableBooleanPropertyKey();
/** Default constructor. */
public TabSwitcherBottomToolbarModel() {
super(PRIMARY_COLOR, IS_VISIBLE);
}
}
// Copyright 2018 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;
import android.view.View;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.modelutil.PropertyKey;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
/**
* This class is responsible for pushing updates the view of the tab switcher bottom toolbar. These
* updates are pulled from the {@link TabSwitcherBottomToolbarModel} when a notification of an
* update is received.
*/
public class TabSwitcherBottomToolbarViewBinder
implements PropertyModelChangeProcessor
.ViewBinder<TabSwitcherBottomToolbarModel, View, PropertyKey> {
/**
* Build a binder that handles interaction between the model and the tab switcher bottom toolbar
* view.
*/
public TabSwitcherBottomToolbarViewBinder() {}
@Override
public final void bind(
TabSwitcherBottomToolbarModel model, View view, PropertyKey propertyKey) {
if (TabSwitcherBottomToolbarModel.IS_VISIBLE == propertyKey) {
view.setVisibility(
model.get(TabSwitcherBottomToolbarModel.IS_VISIBLE) ? View.VISIBLE : View.GONE);
} else if (TabSwitcherBottomToolbarModel.PRIMARY_COLOR == propertyKey) {
view.findViewById(R.id.bottom_toolbar_buttons)
.setBackgroundColor(model.get(TabSwitcherBottomToolbarModel.PRIMARY_COLOR));
} else {
assert false : "Unhandled property detected in TabSwitcherBottomToolbarViewBinder!";
}
}
}
......@@ -11,17 +11,13 @@ import android.view.ViewGroup;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.modelutil.PropertyModel;
import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
import org.chromium.chrome.browser.toolbar.TabCountProvider.TabCountObserver;
import org.chromium.chrome.browser.toolbar.ThemeColorProvider.ThemeColorObserver;
import org.chromium.chrome.browser.util.AccessibilityUtil;
import java.util.List;
/**
* The controller for the tab switcher button. This class handles all interactions that the tab
* switcher button has with the outside world.
......@@ -39,6 +35,12 @@ public class TabSwitcherButtonCoordinator {
private TabModelSelectorObserver mTabModelSelectorObserver;
private TabModelSelectorTabModelObserver mTabModelSelectorTabModelObserver;
private ThemeColorProvider mThemeColorProvider;
private ThemeColorObserver mThemeColorObserver;
private TabCountProvider mTabCountProvider;
private TabCountObserver mTabCountObserver;
/**
* Build the controller that manages the tab switcher button.
* @param root The root {@link ViewGroup} for locating the view to inflate.
......@@ -61,75 +63,36 @@ public class TabSwitcherButtonCoordinator {
mTabSwitcherButtonModel.set(TabSwitcherButtonProperties.ON_CLICK_LISTENER, onClickListener);
}
/**
* @param tabModelSelector A {@link TabModelSelector} that the tab switcher button uses to
* keep its tab count updated.
*/
public void setTabModelSelector(TabModelSelector tabModelSelector) {
mTabModelSelector = tabModelSelector;
mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() {
@Override
public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
updateTabCount();
}
public void setThemeColorProvider(ThemeColorProvider themeColorProvider) {
mThemeColorProvider = themeColorProvider;
mThemeColorObserver = new ThemeColorObserver() {
@Override
public void onTabStateInitialized() {
updateTabCount();
public void onThemeColorChanged(ColorStateList tint, int primaryColor) {
mTabSwitcherButtonModel.set(TabSwitcherButtonProperties.TINT, tint);
}
};
mTabModelSelector.addObserver(mTabModelSelectorObserver);
mTabModelSelectorTabModelObserver = new TabModelSelectorTabModelObserver(tabModelSelector) {
@Override
public void didAddTab(Tab tab, @TabLaunchType int type) {
updateTabCount();
}
@Override
public void tabClosureUndone(Tab tab) {
updateTabCount();
}
@Override
public void didCloseTab(int tabId, boolean incognito) {
updateTabCount();
}
@Override
public void tabPendingClosure(Tab tab) {
updateTabCount();
}
@Override
public void allTabsPendingClosure(List<Tab> tabs) {
updateTabCount();
}
mThemeColorProvider.addObserver(mThemeColorObserver);
}
public void setTabCountProvider(TabCountProvider tabCountProvider) {
mTabCountProvider = tabCountProvider;
mTabCountObserver = new TabCountObserver() {
@Override
public void tabRemoved(Tab tab) {
updateTabCount();
public void onTabCountChanged(int tabCount, boolean isIncognito) {
mTabSwitcherButtonModel.set(TabSwitcherButtonProperties.NUMBER_OF_TABS, tabCount);
}
};
updateTabCount();
}
/**
* @param tint The {@link ColorStateList} used to tint the button.
*/
public void setTint(ColorStateList tint) {
mTabSwitcherButtonModel.set(TabSwitcherButtonProperties.TINT, tint);
mTabCountProvider.addObserver(mTabCountObserver);
}
public void destroy() {
if (mTabModelSelector != null) mTabModelSelector.removeObserver(mTabModelSelectorObserver);
if (mTabModelSelectorTabModelObserver != null) mTabModelSelectorTabModelObserver.destroy();
}
private void updateTabCount() {
mTabSwitcherButtonModel.set(TabSwitcherButtonProperties.NUMBER_OF_TABS,
mTabModelSelector.getCurrentModel().getCount());
if (mThemeColorProvider != null) {
mThemeColorProvider.removeObserver(mThemeColorObserver);
mThemeColorProvider = null;
}
if (mTabCountProvider != null) {
mTabCountProvider.removeObserver(mTabCountObserver);
mTabCountProvider = null;
}
}
}
// Copyright 2018 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;
import android.content.res.ColorStateList;
/**
* An interface that provides the current theme color.
*/
public interface ThemeColorProvider {
/**
* An interface to be notified about changes to the theme color.
*/
public interface ThemeColorObserver {
void onThemeColorChanged(ColorStateList tint, int primaryColor);
}
/**
* @param observer Add an observer that will have events broadcast to.
*/
void addObserver(ThemeColorObserver observer);
/**
* @param observer Remove the observer.
*/
void removeObserver(ThemeColorObserver observer);
}
// Copyright 2018 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;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.content.res.AppCompatResources;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import org.chromium.chrome.R;
import org.chromium.ui.interpolators.BakedBezierInterpolator;
/**
* This class can hold two buttons, one to be shown in browsing mode and one for tab switching mode.
*/
class ToolbarButtonSlotData {
/** The button to be shown when in browsing mode. */
public final ToolbarButtonData browsingModeButtonData;
/** The button to be shown when in tab switcher mode. */
public ToolbarButtonData tabSwitcherModeButtonData;
/** Fade in/out time in milliseconds. */
private static final int FADE_DURATION = 300;
/**
* @param browsingModeButton The button to be shown when in browsing mode.
* @param tabSwitcherModeButton The button to be shown when in tab switcher mode.
*/
ToolbarButtonSlotData(ToolbarButtonData browsingModeButton) {
browsingModeButtonData = browsingModeButton;
}
/**
* A class that holds all the state for a bottom toolbar button. It is used to swap between
* buttons when entering or leaving tab switching mode.
*/
static class ToolbarButtonData {
private final Drawable mDrawable;
private final CharSequence mIncognitoAccessibilityString;
private final CharSequence mNormalAccessibilityString;
private final OnClickListener mOnClickListener;
private final ColorStateList mLightTint;
private final ColorStateList mDarkTint;
/**
* @param drawable The {@link Drawable} that will be shown in the button slot.
* @param normalAccessibilityString The accessibility string to be used in normal mode.
* @param incognitoAccessibilityString The accessibility string to be used in incognito
* mode.
* @param onClickListener The listener that will be fired when this button is clicked.
* @param context The {@link Context} that is used to obtain tinting information.
*/
ToolbarButtonData(Drawable drawable, CharSequence normalAccessibilityString,
CharSequence incognitoAccessibilityString, OnClickListener onClickListener,
Context context) {
mLightTint = AppCompatResources.getColorStateList(context, R.color.light_mode_tint);
mDarkTint = AppCompatResources.getColorStateList(context, R.color.dark_mode_tint);
mDrawable = drawable != null ? DrawableCompat.wrap(drawable) : null;
mNormalAccessibilityString = normalAccessibilityString;
mIncognitoAccessibilityString = incognitoAccessibilityString;
mOnClickListener = onClickListener;
}
/**
* @param imageButton The {@link ImageButton} this button data will fill.
* @param isLight Whether or not to use light mode.
*/
void updateButton(ImageButton imageButton, boolean isLight) {
imageButton.setOnClickListener(mOnClickListener);
updateButtonDrawable(imageButton, isLight);
}
/**
* @param imageButton The {@link ImageButton} this button data will fill.
* @param isLight Whether or not to use light mode.
*/
void updateButtonDrawable(ImageButton imageButton, boolean isLight) {
ObjectAnimator fadeOutAnim =
ObjectAnimator.ofFloat(imageButton, View.ALPHA, 1.0f, 0.0f);
fadeOutAnim.setDuration(FADE_DURATION / 2);
fadeOutAnim.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
ObjectAnimator fadeInAnim = ObjectAnimator.ofFloat(imageButton, View.ALPHA, 0.0f, 1.0f);
fadeInAnim.setDuration(FADE_DURATION / 2);
fadeInAnim.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE);
fadeInAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
if (mDrawable != null) {
imageButton.setEnabled(true);
imageButton.setVisibility(View.VISIBLE);
DrawableCompat.setTintList(mDrawable, isLight ? mLightTint : mDarkTint);
}
imageButton.setImageDrawable(mDrawable);
imageButton.setContentDescription(
isLight ? mIncognitoAccessibilityString : mNormalAccessibilityString);
imageButton.invalidate();
}
@Override
public void onAnimationEnd(Animator animator) {
imageButton.setEnabled(mDrawable != null);
imageButton.setVisibility(mDrawable != null ? View.VISIBLE : View.INVISIBLE);
imageButton.setOnClickListener(mOnClickListener);
}
});
imageButton.setOnClickListener(null);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(fadeOutAnim, fadeInAnim);
animatorSet.start();
}
static void clearButton(ImageButton button) {
ToolbarButtonData emptyButtonData =
new ToolbarButtonData(null, "", "", null, button.getContext());
emptyButtonData.updateButton(button, false);
}
}
}
......@@ -612,11 +612,10 @@ public abstract class ToolbarLayout extends FrameLayout implements Toolbar {
protected void onTabSwitcherTransitionFinished() { }
/**
* Gives inheriting classes the chance to update themselves based on the
* number of tabs in the current TabModel.
* @param numberOfTabs The number of tabs in the current model.
* Gives inheriting classes the chance to observe tab count changes.
* @param tabCountProvider The {@link TabCountProvider} subclasses can observe.
*/
protected void updateTabCountVisuals(int numberOfTabs) { }
protected void setTabCountProvider(TabCountProvider tabCountProvider) {}
/**
* Gives inheriting classes the chance to update themselves based on default search engine
......
......@@ -69,6 +69,7 @@ import org.chromium.chrome.browser.preferences.PrefServiceBridge;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.toolbar.TabCountProvider.TabCountObserver;
import org.chromium.chrome.browser.util.AccessibilityUtil;
import org.chromium.chrome.browser.util.ColorUtils;
import org.chromium.chrome.browser.util.FeatureUtilities;
......@@ -90,10 +91,9 @@ import java.util.Set;
/**
* Phone specific toolbar implementation.
*/
public class ToolbarPhone extends ToolbarLayout
implements Invalidator.Client, OnClickListener, OnLongClickListener,
NewTabPage.OnSearchBoxScrollListener {
public class ToolbarPhone
extends ToolbarLayout implements Invalidator.Client, OnClickListener, OnLongClickListener,
NewTabPage.OnSearchBoxScrollListener, TabCountObserver {
/** The amount of time transitioning from one theme color to another should take in ms. */
public static final long THEME_COLOR_TRANSITION_DURATION = 250;
......@@ -135,6 +135,7 @@ public class ToolbarPhone extends ToolbarLayout
new FastOutSlowInInterpolator();
private TabModelSelector mTabModelSelector;
private TabCountProvider mTabCountProvider;
protected LocationBarPhone mLocationBar;
......@@ -1817,8 +1818,10 @@ public class ToolbarPhone extends ToolbarLayout
mIncognitoToggleTabLayout =
(IncognitoToggleTabLayout) incognitoToggleTabsStub.inflate();
mIncognitoToggleTabLayout.setTabModelSelector(mTabModelSelector);
mIncognitoToggleTabLayout.setTabCountProvider(mTabCountProvider);
mIncognitoToggleTabLayout.onTabCountChanged(
mTabModelSelector.getModel(false).getCount(), false);
mTabSwitcherModeViews.add(mIncognitoToggleTabLayout);
mIncognitoToggleTabLayout.updateTabCount(mTabModelSelector.getModel(false).getCount());
mBrowsingModeViews.add(mToggleTabStackButton);
}
......@@ -2218,7 +2221,13 @@ public class ToolbarPhone extends ToolbarLayout
protected void onUrlFocusChangeAnimationFinished() {}
@Override
protected void updateTabCountVisuals(int numberOfTabs) {
protected void setTabCountProvider(TabCountProvider tabCountProvider) {
mTabCountProvider = tabCountProvider;
mTabCountProvider.addObserver(this);
}
@Override
public void onTabCountChanged(int numberOfTabs, boolean isIncognito) {
if (mHomeButton != null) mHomeButton.setEnabled(true);
if (mToggleTabStackButton == null) return;
......@@ -2228,15 +2237,11 @@ public class ToolbarPhone extends ToolbarLayout
getResources().getQuantityString(
R.plurals.accessibility_toolbar_btn_tabswitcher_toggle,
numberOfTabs, numberOfTabs));
mTabSwitcherButtonDrawableLight.updateForTabCount(numberOfTabs, isIncognito());
mTabSwitcherButtonDrawable.updateForTabCount(numberOfTabs, isIncognito());
if (!isIncognito() && mIncognitoToggleTabLayout != null) {
mIncognitoToggleTabLayout.updateTabCount(numberOfTabs);
}
mTabSwitcherButtonDrawableLight.updateForTabCount(numberOfTabs, isIncognito);
mTabSwitcherButtonDrawable.updateForTabCount(numberOfTabs, isIncognito);
boolean useTabStackDrawableLight = isIncognito()
|| ColorUtils.shouldUseLightForegroundOnBackground(getTabThemeColor());
boolean useTabStackDrawableLight =
isIncognito || ColorUtils.shouldUseLightForegroundOnBackground(getTabThemeColor());
if (mTabSwitcherAnimationTabStackDrawable == null
|| mIsOverlayTabStackDrawableLight != useTabStackDrawableLight) {
mTabSwitcherAnimationTabStackDrawable = TabSwitcherDrawable.createTabSwitcherDrawable(
......@@ -2249,8 +2254,7 @@ public class ToolbarPhone extends ToolbarLayout
}
if (mTabSwitcherAnimationTabStackDrawable != null) {
mTabSwitcherAnimationTabStackDrawable.updateForTabCount(
numberOfTabs, isIncognito());
mTabSwitcherAnimationTabStackDrawable.updateForTabCount(numberOfTabs, isIncognito);
}
}
......
......@@ -32,6 +32,7 @@ import org.chromium.chrome.browser.omnibox.LocationBarTablet;
import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.TabCountProvider.TabCountObserver;
import org.chromium.chrome.browser.util.AccessibilityUtil;
import org.chromium.chrome.browser.util.ColorUtils;
import org.chromium.chrome.browser.util.FeatureUtilities;
......@@ -44,8 +45,8 @@ import java.util.Collection;
* The Toolbar object for Tablet screens.
*/
@SuppressLint("Instantiatable")
public class ToolbarTablet
extends ToolbarLayout implements OnClickListener, View.OnLongClickListener {
public class ToolbarTablet extends ToolbarLayout
implements OnClickListener, View.OnLongClickListener, TabCountObserver {
// The number of toolbar buttons that can be hidden at small widths (reload, back, forward).
public static final int HIDEABLE_BUTTON_COUNT = 3;
......@@ -529,13 +530,18 @@ public class ToolbarTablet
}
@Override
protected void updateTabCountVisuals(int numberOfTabs) {
public void onTabCountChanged(int numberOfTabs, boolean isIncognito) {
mAccessibilitySwitcherButton.setContentDescription(
getResources().getQuantityString(
R.plurals.accessibility_toolbar_btn_tabswitcher_toggle,
numberOfTabs, numberOfTabs));
mTabSwitcherButtonDrawable.updateForTabCount(numberOfTabs, isIncognito());
mTabSwitcherButtonDrawableLight.updateForTabCount(numberOfTabs, isIncognito());
mTabSwitcherButtonDrawable.updateForTabCount(numberOfTabs, isIncognito);
mTabSwitcherButtonDrawableLight.updateForTabCount(numberOfTabs, isIncognito);
}
@Override
protected void setTabCountProvider(TabCountProvider tabCountProvider) {
tabCountProvider.addObserver(this);
}
@Override
......
......@@ -1554,27 +1554,37 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/tasks/TasksUma.java",
"java/src/org/chromium/chrome/browser/toolbar/ActionModeController.java",
"java/src/org/chromium/chrome/browser/toolbar/BottomToolbarCoordinator.java",
"java/src/org/chromium/chrome/browser/toolbar/BottomToolbarMediator.java",
"java/src/org/chromium/chrome/browser/toolbar/BottomToolbarModel.java",
"java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java",
"java/src/org/chromium/chrome/browser/toolbar/BrowsingModeBottomToolbarCoordinator.java",
"java/src/org/chromium/chrome/browser/toolbar/BrowsingModeBottomToolbarMediator.java",
"java/src/org/chromium/chrome/browser/toolbar/BrowsingModeBottomToolbarModel.java",
"java/src/org/chromium/chrome/browser/toolbar/BrowsingModeBottomToolbarViewBinder.java",
"java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java",
"java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbarAnimationDelegate.java",
"java/src/org/chromium/chrome/browser/toolbar/HomePageButton.java",
"java/src/org/chromium/chrome/browser/toolbar/HomeButton.java",
"java/src/org/chromium/chrome/browser/toolbar/IncognitoStateProvider.java",
"java/src/org/chromium/chrome/browser/toolbar/IncognitoToggleTabLayout.java",
"java/src/org/chromium/chrome/browser/toolbar/KeyboardNavigationListener.java",
"java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java",
"java/src/org/chromium/chrome/browser/toolbar/MenuButton.java",
"java/src/org/chromium/chrome/browser/toolbar/NewTabButton.java",
"java/src/org/chromium/chrome/browser/toolbar/ScrollingBottomViewResourceFrameLayout.java",
"java/src/org/chromium/chrome/browser/toolbar/SearchAccelerator.java",
"java/src/org/chromium/chrome/browser/toolbar/ShareButton.java",
"java/src/org/chromium/chrome/browser/toolbar/TabCountProvider.java",
"java/src/org/chromium/chrome/browser/toolbar/TabSwitcherBottomToolbarCoordinator.java",
"java/src/org/chromium/chrome/browser/toolbar/TabSwitcherBottomToolbarMediator.java",
"java/src/org/chromium/chrome/browser/toolbar/TabSwitcherBottomToolbarModel.java",
"java/src/org/chromium/chrome/browser/toolbar/TabSwitcherBottomToolbarViewBinder.java",
"java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonViewBinder.java",
"java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonCoordinator.java",
"java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonProperties.java",
"java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonView.java",
"java/src/org/chromium/chrome/browser/toolbar/TabSwitcherDrawable.java",
"java/src/org/chromium/chrome/browser/toolbar/ThemeColorProvider.java",
"java/src/org/chromium/chrome/browser/toolbar/Toolbar.java",
"java/src/org/chromium/chrome/browser/toolbar/ToolbarActionModeCallback.java",
"java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java",
"java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java",
"java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java",
"java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java",
"java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java",
......
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