Commit 9e8ccd38 authored by Jinsuk Kim's avatar Jinsuk Kim Committed by Commit Bot

EphemeralTab: Overlay for Ephemeral Tab

Initial implementation of ephemeral tab based on overlay panel.
See go/ephemeral for the design.

Final design may be subject to change. and there are many TODO's
still left.

    non-trivial amount of time trying to reduce its number of methods.

Bug: 894619
Change-Id: I2833c6aaf820d9cf40be4d465ef135f5d5f8a9f6
Binary-Size: Increase needed to implement a feature, and I've already spent a
Reviewed-on: https://chromium-review.googlesource.com/c/1282043
Commit-Queue: Jinsuk Kim <jinsukkim@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarDonn Denman <donnd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610325}
parent c5f8df51
<?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. -->
<!-- Ephemeral Tab bar text -->
<!-- TODO(jinsukkim): Define Ephemeral Tab's own text view style -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ephemeral_tab_text_view"
style="@style/ContextualSearchTextViewLayout" >
<TextView
android:id="@+id/ephemeral_tab_text"
style="@style/ContextualSearchTextView"
android:layout_width="match_parent"
android:layout_gravity="bottom"
android:background="@android:color/white"
android:layout_marginStart="7dp"
android:layout_marginEnd="7dp" />
</FrameLayout>
......@@ -92,6 +92,7 @@
<item type="id" name="contextmenu_save_image" />
<item type="id" name="contextmenu_open_image" />
<item type="id" name="contextmenu_open_image_in_new_tab" />
<item type="id" name="contextmenu_open_image_in_ephemeral_tab" />
<item type="id" name="contextmenu_search_by_image" />
<item type="id" name="contextmenu_share_image" />
......
......@@ -63,6 +63,7 @@ import org.chromium.chrome.browser.bookmarks.BookmarkModel;
import org.chromium.chrome.browser.bookmarks.BookmarkUtils;
import org.chromium.chrome.browser.compositor.CompositorViewHolder;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel;
import org.chromium.chrome.browser.compositor.layouts.Layout;
import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
import org.chromium.chrome.browser.compositor.layouts.SceneChangeObserver;
......@@ -263,6 +264,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
private CompositorViewHolder mCompositorViewHolder;
private InsetObserverView mInsetObserverView;
private ContextualSearchManager mContextualSearchManager;
private EphemeralTabPanel mEphemeralTabPanel;
protected ReaderModeManager mReaderModeManager;
private SnackbarManager mSnackbarManager;
private DataReductionPromoSnackbarController mDataReductionPromoSnackbarController;
......@@ -1533,6 +1535,10 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
return false;
}
if (getEphemeralTabPanel() != null && getEphemeralTabPanel().isPanelOpened()) {
return false;
}
// Do not show the menu if we are in find in page view.
if (mFindToolbarManager != null && mFindToolbarManager.isShowing() && !isTablet()) {
return false;
......@@ -1800,6 +1806,10 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
return mReaderModeManager;
}
public EphemeralTabPanel getEphemeralTabPanel() {
return getCompositorViewHolder().getLayoutManager().getEphemeralTabPanel();
}
/**
* Create a full-screen manager to be used by this activity.
* Note: This is called during {@link #postInflationStartup}, so native code may not have been
......@@ -1859,6 +1869,8 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
}
mActivityTabProvider.setLayoutManager(layoutManager);
EphemeralTabPanel panel = layoutManager.getEphemeralTabPanel();
if (panel != null) panel.setChromeActivity(this);
}
/**
......@@ -2085,6 +2097,9 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
if (mContextualSearchManager != null) {
getContextualSearchManager().hideContextualSearch(StateChangeReason.UNKNOWN);
}
if (getEphemeralTabPanel() != null) {
getEphemeralTabPanel().closePanel(StateChangeReason.UNKNOWN, true);
}
if (fromMenu) {
RecordUserAction.record("MobileMenuFindInPage");
} else {
......
......@@ -25,4 +25,3 @@ public class OverlayContentProgressObserver {
*/
public void onProgressBarFinished() {}
}
......@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.compositor.bottombar;
import android.app.Activity;
import android.content.Context;
import android.graphics.RectF;
import android.os.Handler;
import android.support.annotation.IntDef;
import android.view.ViewGroup;
......@@ -47,6 +48,9 @@ public class OverlayPanel extends OverlayPanelAnimation implements ActivityState
/** The extra dp added around the close button touch target. */
private static final int CLOSE_BUTTON_TOUCH_SLOP_DP = 5;
/** The delay after which the hide progress will be hidden. */
private static final long HIDE_PROGRESS_BAR_DELAY_MS = 1000 / 60 * 4;
/** State of the Overlay Panel. */
public static enum PanelState {
// TODO(pedrosimonetti): consider removing the UNDEFINED state
......@@ -400,6 +404,37 @@ public class OverlayPanel extends OverlayPanelAnimation implements ActivityState
if (mContent != null) mContent.onLoadUrlFailed();
}
/**
* Progress observer progress indicator animation for a panel.
*/
public class PanelProgressObserver extends OverlayContentProgressObserver {
@Override
public void onProgressBarStarted() {
setProgressBarCompletion(0);
setProgressBarVisible(true);
requestUpdate();
}
@Override
public void onProgressBarUpdated(int progress) {
setProgressBarCompletion(progress);
requestUpdate();
}
@Override
public void onProgressBarFinished() {
// Hides the Progress Bar after a delay to make sure it is rendered for at least
// a few frames, otherwise its completion won't be visually noticeable.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
setProgressBarVisible(false);
requestUpdate();
}
}, HIDE_PROGRESS_BAR_DELAY_MS);
}
}
/**
* Create a new OverlayPanelContent object. This can be overridden for tests.
* @return A new OverlayPanelContent object.
......
......@@ -8,15 +8,14 @@ import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import org.chromium.base.ActivityState;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.LayerTitleCache;
import org.chromium.chrome.browser.compositor.bottombar.OverlayContentProgressObserver;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelProgressObserver;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelContent;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager.PanelPriority;
......@@ -37,12 +36,6 @@ import org.chromium.ui.resources.ResourceManager;
* Controls the Contextual Search Panel.
*/
public class ContextualSearchPanel extends OverlayPanel {
/**
* The delay after which the hide progress will be hidden.
*/
private static final long HIDE_PROGRESS_BAR_DELAY = 1000 / 60 * 4;
/** When using the Generic UX we never show the Arrow Icon */
private static final float ARROW_ICON_OPACITY_GENERIC_UX = 0.f;
......@@ -125,38 +118,6 @@ public class ContextualSearchPanel extends OverlayPanel {
new PanelProgressObserver(), mActivity, getBarHeight());
}
/**
* Default loading animation for a panel.
*/
public class PanelProgressObserver extends OverlayContentProgressObserver {
@Override
public void onProgressBarStarted() {
setProgressBarCompletion(0);
setProgressBarVisible(true);
requestUpdate();
}
@Override
public void onProgressBarUpdated(int progress) {
setProgressBarCompletion(progress);
requestUpdate();
}
@Override
public void onProgressBarFinished() {
// Hides the Progress Bar after a delay to make sure it is rendered for at least
// a few frames, otherwise its completion won't be visually noticeable.
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
setProgressBarVisible(false);
requestUpdate();
}
}, HIDE_PROGRESS_BAR_DELAY);
}
}
// ============================================================================================
// Scene Overlay
// ============================================================================================
......
// 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.compositor.bottombar.ephemeraltab;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelInflater;
import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
/**
* Top control used for ephemeral tab.
*/
public class EphemeralTabBarControl extends OverlayPanelInflater {
/**
* The tab title View.
*/
private TextView mBarText;
/**
* @param panel The panel.
* @param context The Android Context used to inflate the View.
* @param container The container View used to inflate the View.
* @param resourceLoader The resource loader that will handle the snapshot capturing.
*/
public EphemeralTabBarControl(OverlayPanel panel, Context context, ViewGroup container,
DynamicResourceLoader resourceLoader) {
super(panel, R.layout.ephemeral_tab_text_view, R.id.ephemeral_tab_text_view, context,
container, resourceLoader);
invalidate();
}
/**
* Set the text in the panel.
* @param text The string to set the text to.
*/
public void setBarText(String text) {
inflate();
mBarText.setText(text);
invalidate();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
View view = getView();
mBarText = (TextView) view.findViewById(R.id.ephemeral_tab_text);
}
}
// 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.compositor.bottombar.ephemeraltab;
import android.content.Context;
import android.graphics.RectF;
import android.view.MotionEvent;
import org.chromium.base.SysUtils;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.compositor.LayerTitleCache;
import org.chromium.chrome.browser.compositor.bottombar.OverlayContentDelegate;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelProgressObserver;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelContent;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager.PanelPriority;
import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
import org.chromium.chrome.browser.compositor.layouts.eventfilter.OverlayPanelEventFilter;
import org.chromium.chrome.browser.compositor.scene_layer.EphemeralTabSceneLayer;
import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.resources.ResourceManager;
/**
* The panel containing an ephemeral tab.
* TODO(jinsukkim): Make panel height in peeked state bigger to show the progress indicator clearly.
*/
public class EphemeralTabPanel extends OverlayPanel {
/** The compositor layer used for drawing the panel. */
private EphemeralTabSceneLayer mSceneLayer;
/**
* Checks if this feature (a.k.a. "Sneak peek") for html and image is supported.
* @return {@code true} if the feature is enabled.
*/
public static boolean isSupported() {
return ChromeFeatureList.isEnabled(ChromeFeatureList.EPHEMERAL_TAB)
&& !SysUtils.isLowEndDevice();
}
/**
* @param context The current Android {@link Context}.
* @param updateHost The {@link LayoutUpdateHost} used to request updates in the Layout.
* @param panelManager The {@link OverlayPanelManager} used to control panel show/hide.
*/
public EphemeralTabPanel(
Context context, LayoutUpdateHost updateHost, OverlayPanelManager panelManager) {
super(context, updateHost, panelManager);
mSceneLayer =
new EphemeralTabSceneLayer(mContext.getResources().getDisplayMetrics().density);
mEventFilter = new OverlayPanelEventFilter(mContext, this) {
@Override
public boolean onInterceptTouchEventInternal(MotionEvent e, boolean isKeyboardShowing) {
OverlayPanel panel = EphemeralTabPanel.this;
if (panel.isShowing() && panel.isPeeking()
&& panel.isCoordinateInsideBar(e.getX() * mPxToDp, e.getY() * mPxToDp)) {
// Events go to base panel in peeked mode to scroll base page.
return super.onInterceptTouchEventInternal(e, isKeyboardShowing);
}
if (panel.isShowing() && panel.isMaximized()) return true;
return false;
}
};
}
@Override
public OverlayPanelContent createNewOverlayPanelContent() {
return new OverlayPanelContent(new OverlayContentDelegate(), new PanelProgressObserver(),
mActivity, getBarHeight());
}
@Override
protected float getMaximizedHeight() {
// Max height does not cover the entire content screen.
return getTabHeight() * 0.9f;
}
@Override
public float getProgressBarOpacity() {
return 1.0f;
}
// Scene Overlay
@Override
public SceneOverlayLayer getUpdatedSceneOverlayTree(RectF viewport, RectF visibleViewport,
LayerTitleCache layerTitleCache, ResourceManager resourceManager, float yOffset) {
mSceneLayer.update(resourceManager, this, getBarTextViewId(), 1.0f);
return mSceneLayer;
}
@Override
public boolean updateOverlay(long time, long dt) {
// Allow WebContents to size itself appropriately (includes browser controls height).
updateBrowserControlsState();
return super.updateOverlay(time, dt);
}
// Generic Event Handling
@Override
public void handleBarClick(float x, float y) {
super.handleBarClick(x, y);
if (isCoordinateInsideCloseButton(x)) {
closePanel(StateChangeReason.CLOSE_BUTTON, true);
} else {
maximizePanel(StateChangeReason.SEARCH_BAR_TAP);
}
}
// Panel base methods
@Override
public void destroyComponents() {
super.destroyComponents();
destroyEphemeralTabBarControl();
}
@Override
public @PanelPriority int getPriority() {
return PanelPriority.HIGH;
}
@Override
protected boolean isSupportedState(PanelState state) {
return state != PanelState.EXPANDED;
}
@Override
protected void onClosed(@StateChangeReason int reason) {
super.onClosed(reason);
if (mSceneLayer != null) mSceneLayer.hideTree();
}
/**
* Request opening the ephemeral tab panel when triggered from context menu.
* @param url URL of the content to open in the panel
* @param text Link text which will appear on the tab bar.
*/
public void requestOpenPanel(String url, String text) {
loadUrlInPanel(url);
WebContents panelWebContents = getWebContents();
if (panelWebContents != null) panelWebContents.onShow();
getEphemeralTabBarControl().setBarText(text);
requestPanelShow(StateChangeReason.CLICK);
}
@Override
public void onLayoutChanged(float width, float height, float visibleViewportOffsetY) {
if (width != getWidth()) destroyEphemeralTabBarControl();
super.onLayoutChanged(width, height, visibleViewportOffsetY);
}
private EphemeralTabBarControl mEphemeralTabBarControl;
/**
* @return The Id of the Search Term View.
*/
public int getBarTextViewId() {
return getEphemeralTabBarControl().getViewId();
}
/**
* Creates the EphemeralTabBarControl, if needed. The Views are set to INVISIBLE, because
* they won't actually be displayed on the screen (their snapshots will be displayed instead).
*/
protected EphemeralTabBarControl getEphemeralTabBarControl() {
assert mContainerView != null;
assert mResourceLoader != null;
if (mEphemeralTabBarControl == null) {
mEphemeralTabBarControl =
new EphemeralTabBarControl(this, mContext, mContainerView, mResourceLoader);
}
assert mEphemeralTabBarControl != null;
return mEphemeralTabBarControl;
}
/**
* Destroys the EphemeralTabBarControl.
*/
protected void destroyEphemeralTabBarControl() {
if (mEphemeralTabBarControl != null) {
mEphemeralTabBarControl.destroy();
mEphemeralTabBarControl = null;
}
}
}
......@@ -23,6 +23,7 @@ import org.chromium.chrome.browser.compositor.animation.CompositorAnimationHandl
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelContentViewDelegate;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager;
import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel;
import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation;
import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
import org.chromium.chrome.browser.compositor.layouts.components.VirtualView;
......@@ -108,6 +109,7 @@ public class LayoutManager implements LayoutUpdateHost, LayoutProvider,
private int mControlsHidingToken = FullscreenManager.INVALID_TOKEN;
private boolean mUpdateRequested;
private final ContextualSearchPanel mContextualSearchPanel;
private final EphemeralTabPanel mEphemeralTabPanel;
private final OverlayPanelManager mOverlayPanelManager;
private final ToolbarSceneLayer mToolbarOverlay;
......@@ -220,6 +222,10 @@ public class LayoutManager implements LayoutUpdateHost, LayoutProvider,
// Contextual Search scene overlay.
mContextualSearchPanel = new ContextualSearchPanel(mContext, this, mOverlayPanelManager);
mEphemeralTabPanel = EphemeralTabPanel.isSupported()
? new EphemeralTabPanel(mContext, this, mOverlayPanelManager)
: null;
// Set up layout parameters
mStaticLayout.setLayoutHandlesTabLifecycles(true);
......@@ -233,6 +239,13 @@ public class LayoutManager implements LayoutUpdateHost, LayoutProvider,
return mOverlayPanelManager;
}
/**
* @return The layout manager's ephemeral tab panel manager.
*/
public EphemeralTabPanel getEphemeralTabPanel() {
return mEphemeralTabPanel;
}
@Override
public CompositorAnimationHandler getAnimationHandler() {
return mAnimationHandler;
......@@ -862,6 +875,7 @@ public class LayoutManager implements LayoutUpdateHost, LayoutProvider,
protected void addAllSceneOverlays() {
addGlobalSceneOverlay(mToolbarOverlay);
mStaticLayout.addSceneOverlay(mContextualSearchPanel);
if (mEphemeralTabPanel != null) mStaticLayout.addSceneOverlay(mEphemeralTabPanel);
}
/**
......
......@@ -11,6 +11,7 @@ import org.chromium.base.ObserverList;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.browser.compositor.TitleCache;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
import org.chromium.chrome.browser.compositor.layouts.components.VirtualView;
import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
......@@ -188,11 +189,14 @@ public class LayoutManagerChrome extends LayoutManager implements OverviewModeBe
Layout layoutBeingShown = getActiveLayout();
// Check if a layout is showing that should hide the contextual search bar.
if (mContextualSearchDelegate != null
&& (isOverviewLayout(layoutBeingShown)
|| layoutBeingShown == mToolbarSwipeLayout)) {
mContextualSearchDelegate.dismissContextualSearchBar();
// Check if a layout is showing that should hide the overlay panels.
if (isOverviewLayout(layoutBeingShown) || layoutBeingShown == mToolbarSwipeLayout) {
if (mContextualSearchDelegate != null) {
mContextualSearchDelegate.dismissContextualSearchBar();
}
if (getEphemeralTabPanel() != null) {
getEphemeralTabPanel().closePanel(StateChangeReason.UNKNOWN, false);
}
}
// Check if we should notify OverviewModeObservers.
......
// 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.compositor.scene_layer;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.resources.ResourceManager;
/**
* A SceneLayer to render layers for Ephemeral Tab.
*/
@JNINamespace("android")
public class EphemeralTabSceneLayer extends SceneOverlayLayer {
/** Pointer to native EphemeralTabSceneLayer. */
private long mNativePtr;
/** If the scene layer has been initialized. */
private boolean mIsInitialized;
/** The conversion multiple from dp to px. */
private final float mDpToPx;
/**
* @param dpToPx The conversion multiple from dp to px for the device.
*/
public EphemeralTabSceneLayer(float dpToPx) {
mDpToPx = dpToPx;
}
/**
* Update the scene layer to draw an OverlayPanel.
* @param resourceManager Manager to get view and image resources.
* @param panel The OverlayPanel to render.
* @param barTextViewId The ID of the view containing the ephemeral tab bar.
* @param barTextOpacity The opacity of the text specified by {@code barTextViewId}.
*/
public void update(ResourceManager resourceManager, OverlayPanel panel, int barTextViewId,
float barTextOpacity) {
// Don't try to update the layer if not initialized or showing.
if (resourceManager == null || !panel.isShowing()) return;
if (!mIsInitialized) {
nativeCreateEphemeralTabLayer(mNativePtr, resourceManager);
// TODO(jinsukkim): Find the right icon/background resource for the tab bar.
nativeSetResourceIds(mNativePtr, barTextViewId,
R.drawable.contextual_search_bar_background, R.drawable.modern_toolbar_shadow,
R.drawable.infobar_chrome, R.drawable.btn_close);
mIsInitialized = true;
}
boolean isProgressBarVisible = panel.isProgressBarVisible();
float progressBarHeight = panel.getProgressBarHeight();
float progressBarOpacity = panel.getProgressBarOpacity();
int progressBarCompletion = panel.getProgressBarCompletion();
WebContents panelWebContents = panel.getWebContents();
nativeUpdate(mNativePtr, R.drawable.progress_bar_background,
R.drawable.progress_bar_foreground, mDpToPx, panel.getBasePageBrightness(),
panel.getBasePageY() * mDpToPx, panelWebContents, panel.getOffsetX() * mDpToPx,
panel.getOffsetY() * mDpToPx, panel.getWidth() * mDpToPx,
panel.getHeight() * mDpToPx, panel.getBarMarginSide() * mDpToPx,
panel.getBarHeight() * mDpToPx, barTextOpacity, panel.isBarBorderVisible(),
panel.getBarBorderHeight() * mDpToPx, panel.getBarShadowVisible(),
panel.getBarShadowOpacity(), isProgressBarVisible, progressBarHeight * mDpToPx,
progressBarOpacity, progressBarCompletion);
}
@Override
public void setContentTree(SceneLayer contentTree) {
nativeSetContentTree(mNativePtr, contentTree);
}
/**
* Hide the layer tree; for use if the panel is not being shown.
*/
public void hideTree() {
if (!mIsInitialized) return;
nativeHideTree(mNativePtr);
}
@Override
protected void initializeNative() {
if (mNativePtr == 0) {
mNativePtr = nativeInit();
}
assert mNativePtr != 0;
}
/**
* Destroys this object and the corresponding native component.
*/
@Override
public void destroy() {
super.destroy();
mIsInitialized = false;
mNativePtr = 0;
}
private native long nativeInit();
private native void nativeCreateEphemeralTabLayer(
long nativeEphemeralTabSceneLayer, ResourceManager resourceManager);
private native void nativeSetContentTree(
long nativeEphemeralTabSceneLayer, SceneLayer contentTree);
private native void nativeHideTree(long nativeEphemeralTabSceneLayer);
private native void nativeSetResourceIds(long nativeEphemeralTabSceneLayer,
int barTextResourceId, int barBackgroundResourceId, int barShadowResourceId,
int panelIconResourceId, int closeIconResourceId);
private native void nativeUpdate(long nativeEphemeralTabSceneLayer,
int progressBarBackgroundResourceId, int progressBarResourceId, float dpToPx,
float basePageBrightness, float basePageYOffset, WebContents webContents, float panelX,
float panelY, float panelWidth, float panelHeight, float barMarginSide, float barHeight,
float textOpacity, boolean barBorderVisible, float barBorderHeight,
boolean barShadowVisible, float barShadowOpacity, boolean isProgressBarVisible,
float progressBarHeight, float progressBarOpacity, int progressBarCompletion);
}
......@@ -26,9 +26,9 @@ public class ChromeContextMenuItem implements ContextMenuItem {
Item.OPEN_IN_BROWSER_ID, Item.OPEN_IN_NEW_TAB, Item.OPEN_IN_INCOGNITO_TAB,
Item.OPEN_IN_OTHER_WINDOW, Item.OPEN_IN_EPHEMERAL_TAB, Item.COPY_LINK_ADDRESS,
Item.COPY_LINK_TEXT, Item.SAVE_LINK_AS, Item.LOAD_ORIGINAL_IMAGE, Item.SAVE_IMAGE,
Item.OPEN_IMAGE, Item.OPEN_IMAGE_IN_NEW_TAB, Item.SEARCH_BY_IMAGE, Item.CALL,
Item.SEND_MESSAGE, Item.ADD_TO_CONTACTS, Item.COPY, Item.SAVE_VIDEO,
Item.OPEN_IN_CHROME, Item.BROWSER_ACTIONS_OPEN_IN_BACKGROUND,
Item.OPEN_IMAGE, Item.OPEN_IMAGE_IN_NEW_TAB, Item.OPEN_IMAGE_IN_EPHEMERAL_TAB,
Item.SEARCH_BY_IMAGE, Item.CALL, Item.SEND_MESSAGE, Item.ADD_TO_CONTACTS, Item.COPY,
Item.SAVE_VIDEO, Item.OPEN_IN_CHROME, Item.BROWSER_ACTIONS_OPEN_IN_BACKGROUND,
Item.BROWSER_ACTIONS_OPEN_IN_INCOGNITO_TAB, Item.BROWSER_ACTION_SAVE_LINK_AS,
Item.BROWSER_ACTIONS_COPY_ADDRESS})
@Retention(RetentionPolicy.SOURCE)
......@@ -52,23 +52,24 @@ public class ChromeContextMenuItem implements ContextMenuItem {
int SAVE_IMAGE = 11;
int OPEN_IMAGE = 12;
int OPEN_IMAGE_IN_NEW_TAB = 13;
int SEARCH_BY_IMAGE = 14;
int OPEN_IMAGE_IN_EPHEMERAL_TAB = 14;
int SEARCH_BY_IMAGE = 15;
// Message Group
int CALL = 15;
int SEND_MESSAGE = 16;
int ADD_TO_CONTACTS = 17;
int COPY = 18;
int CALL = 16;
int SEND_MESSAGE = 17;
int ADD_TO_CONTACTS = 18;
int COPY = 19;
// Video Group
int SAVE_VIDEO = 19;
int SAVE_VIDEO = 20;
// Other
int OPEN_IN_CHROME = 20;
int OPEN_IN_CHROME = 21;
// Browser Action Items
int BROWSER_ACTIONS_OPEN_IN_BACKGROUND = 21;
int BROWSER_ACTIONS_OPEN_IN_INCOGNITO_TAB = 22;
int BROWSER_ACTION_SAVE_LINK_AS = 23;
int BROWSER_ACTIONS_COPY_ADDRESS = 24;
int BROWSER_ACTIONS_OPEN_IN_BACKGROUND = 22;
int BROWSER_ACTIONS_OPEN_IN_INCOGNITO_TAB = 23;
int BROWSER_ACTION_SAVE_LINK_AS = 24;
int BROWSER_ACTIONS_COPY_ADDRESS = 25;
// ALWAYS UPDATE!
int NUM_ENTRIES = 25;
int NUM_ENTRIES = 26;
}
/**
......@@ -89,6 +90,7 @@ public class ChromeContextMenuItem implements ContextMenuItem {
R.id.contextmenu_save_image, // Item.SAVE_IMAGE
R.id.contextmenu_open_image, // Item.OPEN_IMAGE
R.id.contextmenu_open_image_in_new_tab, // Item.OPEN_IMAGE_IN_NEW_TAB
R.id.contextmenu_open_image_in_ephemeral_tab, // Item.OPEN_IMAGE_IN_EPHEMERAL_TAB
R.id.contextmenu_search_by_image, // Item.SEARCH_BY_IMAGE
R.id.contextmenu_call, // Item.CALL
R.id.contextmenu_send_message, // Item.SEND_MESSAGE
......@@ -120,6 +122,7 @@ public class ChromeContextMenuItem implements ContextMenuItem {
R.string.contextmenu_save_image, // Item.SAVE_IMAGE:
R.string.contextmenu_open_image, // Item.OPEN_IMAGE:
R.string.contextmenu_open_image_in_new_tab, // Item.OPEN_IMAGE_IN_NEW_TAB:
R.string.contextmenu_open_image_in_ephemeral_tab, // Item.OPEN_IMAGE_IN_EPHEMERAL_TAB:
R.string.contextmenu_search_web_for_image, // Item.SEARCH_BY_IMAGE:
R.string.contextmenu_call, // Item.CALL:
R.string.contextmenu_send_message, // Item.SEND_MESSAGE:
......
......@@ -16,8 +16,8 @@ import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel;
import org.chromium.chrome.browser.contextmenu.ChromeContextMenuItem.Item;
import org.chromium.chrome.browser.experiments.EphemeralTab;
import org.chromium.chrome.browser.firstrun.FirstRunStatus;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
......@@ -79,7 +79,7 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
Action.ADD_TO_CONTACTS, Action.CALL, Action.SEND_TEXT_MESSAGE,
Action.COPY_PHONE_NUMBER, Action.OPEN_IN_NEW_CHROME_TAB,
Action.OPEN_IN_CHROME_INCOGNITO_TAB, Action.OPEN_IN_BROWSER, Action.OPEN_IN_CHROME,
Action.SHARE_LINK, Action.OPEN_IN_EPHEMERAL_TAB,
Action.SHARE_LINK, Action.OPEN_IN_EPHEMERAL_TAB, Action.OPEN_IMAGE_IN_EPHEMERAL_TAB,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Action {
......@@ -108,7 +108,8 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
int OPEN_IN_CHROME = 36;
int SHARE_LINK = 37;
int OPEN_IN_EPHEMERAL_TAB = 38;
int NUM_ENTRIES = 39;
int OPEN_IMAGE_IN_EPHEMERAL_TAB = 39;
int NUM_ENTRIES = 40;
}
// Note: these values must match the ContextMenuSaveLinkType enum in enums.xml.
......@@ -258,7 +259,7 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
if (mDelegate.isOpenInOtherWindowSupported()) {
linkTab.add(new ChromeContextMenuItem(Item.OPEN_IN_OTHER_WINDOW));
}
if (EphemeralTab.isCapable()) {
if (EphemeralTabPanel.isSupported()) {
linkTab.add(new ChromeContextMenuItem(Item.OPEN_IN_EPHEMERAL_TAB));
}
}
......@@ -327,6 +328,9 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
if (mMode == ContextMenuMode.NORMAL) {
imageTab.add(new ChromeContextMenuItem(Item.OPEN_IMAGE_IN_NEW_TAB));
}
if (EphemeralTabPanel.isSupported()) {
imageTab.add(new ChromeContextMenuItem(Item.OPEN_IMAGE_IN_EPHEMERAL_TAB));
}
if (isSrcDownloadableScheme) {
imageTab.add(new ChromeContextMenuItem(Item.SAVE_IMAGE));
hasSaveImage = true;
......@@ -417,13 +421,16 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
mDelegate.onOpenInOtherWindow(params.getUrl(), params.getReferrer());
} else if (itemId == R.id.contextmenu_open_in_ephemeral_tab) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IN_EPHEMERAL_TAB);
mDelegate.onOpenInEphemeralTab(params.getUrl(), params.getReferrer());
mDelegate.onOpenInEphemeralTab(params.getUrl(), params.getLinkText());
} else if (itemId == R.id.contextmenu_open_image) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IMAGE);
mDelegate.onOpenImageUrl(params.getSrcUrl(), params.getReferrer());
} else if (itemId == R.id.contextmenu_open_image_in_new_tab) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IMAGE_IN_NEW_TAB);
mDelegate.onOpenImageInNewTab(params.getSrcUrl(), params.getReferrer());
} else if (itemId == R.id.contextmenu_open_image_in_ephemeral_tab) {
ContextMenuUma.record(params, ContextMenuUma.Action.OPEN_IMAGE_IN_EPHEMERAL_TAB);
mDelegate.onOpenInEphemeralTab(params.getSrcUrl(), params.getTitleText());
} else if (itemId == R.id.contextmenu_load_original_image) {
ContextMenuUma.record(params, ContextMenuUma.Action.LOAD_ORIGINAL_IMAGE);
DataReductionProxyUma.previewsLoFiContextMenuAction(
......
......@@ -186,9 +186,9 @@ public interface ContextMenuItemDelegate {
void onOpenInDefaultBrowser(String url);
/**
* Called when the {@code url} should be opened in an Ephemeral tab with the same incognito
* state as the current {@link Tab}.
* Called when the {@code url} should be opened in an ephemeral tab.
* @param url The URL to open.
* @param title The title text to show on top control.
*/
void onOpenInEphemeralTab(String url, Referrer referrer);
void onOpenInEphemeralTab(String url, String title);
}
// 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.experiments;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.content_public.common.Referrer;
/**
* Manages an Ephemeral Tab, which allows a "sneak peek" at a linked page using the Overlay Panel.
*/
public class EphemeralTab {
/** @return whether this feature is currently capable of being used. */
public static boolean isCapable() {
// TODO(donnd): check if all the conditions are right to support an Overlay.
return isEnabled();
}
/**
* Called when an Open operation needs to be taken.
* @param url The URL of the page to open.
* @param referrer The current {@link Referrer}.
* @param isIncognito Whether the Overlay should use Incognito.
*/
public static void onOpen(String url, Referrer referrer, boolean isIncognito) {
// TODO(donnd): Implement.
}
/** @return Whether this feature is enabled. */
private static boolean isEnabled() {
return ChromeFeatureList.isEnabled(ChromeFeatureList.EPHEMERAL_TAB);
}
}
......@@ -22,7 +22,6 @@ import org.chromium.chrome.browser.UrlConstants;
import org.chromium.chrome.browser.contextmenu.ContextMenuItemDelegate;
import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.chrome.browser.download.ChromeDownloadDelegate;
import org.chromium.chrome.browser.experiments.EphemeralTab;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
import org.chromium.chrome.browser.preferences.PrefServiceBridge;
......@@ -222,6 +221,11 @@ public class TabContextMenuItemDelegate implements ContextMenuItemDelegate {
TabLaunchType.FROM_LONGPRESS_BACKGROUND, mTab, isIncognito());
}
@Override
public void onOpenInEphemeralTab(String url, String title) {
mTab.getActivity().getEphemeralTabPanel().requestOpenPanel(url, title);
}
@Override
public void onOpenInChrome(String linkUrl, String pageUrl) {
Context applicationContext = ContextUtils.getApplicationContext();
......@@ -293,11 +297,6 @@ public class TabContextMenuItemDelegate implements ContextMenuItemDelegate {
IntentUtils.safeStartActivity(mTab.getActivity(), intent);
}
@Override
public void onOpenInEphemeralTab(String url, Referrer referrer) {
EphemeralTab.onOpen(url, referrer, isIncognito());
}
/**
* Checks if spdy proxy is enabled for input url.
* @param url Input url to check for spdy setting.
......
......@@ -2105,6 +2105,9 @@ To change this setting, <ph name="BEGIN_LINK">&lt;resetlink&gt;</ph>reset sync<p
<message name="IDS_CONTEXTMENU_OPEN_IMAGE_IN_NEW_TAB" desc="Context sensitive menu item for opening/viewing the selected image in a new tab. [CHAR-LIMIT=30]">
Open image in new tab
</message>
<message name="IDS_CONTEXTMENU_OPEN_IMAGE_IN_EPHEMERAL_TAB" desc="Context-sensitive menu item to open a quick preview of the selected image. In English we're currently calling this 'Sneak peek' which implies that it's a quick preview without commitment (to making a new Tab). The selected link will open in an overlay panel on top of the current tab which will go away easily too. [CHAR-LIMIT=30]">
Sneak peek
</message>
<message name="IDS_CONTEXTMENU_LOAD_ORIGINAL_IMAGE" desc="Context sensitive menu item for Data Saver low fidelity placeholder images that loads the original version in place. [CHAR-LIMIT=30]">
Load image
</message>
......
......@@ -242,6 +242,8 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPromoControl.java",
"java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchQuickActionControl.java",
"java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchTermControl.java",
"java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java",
"java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java",
"java/src/org/chromium/chrome/browser/compositor/layouts/ChromeAnimation.java",
"java/src/org/chromium/chrome/browser/compositor/layouts/EmptyOverviewModeObserver.java",
"java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java",
......@@ -296,6 +298,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/compositor/resources/ResourceFactory.java",
"java/src/org/chromium/chrome/browser/compositor/resources/StaticResourcePreloads.java",
"java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java",
"java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java",
"java/src/org/chromium/chrome/browser/compositor/scene_layer/SceneLayer.java",
"java/src/org/chromium/chrome/browser/compositor/scene_layer/SceneOverlayLayer.java",
"java/src/org/chromium/chrome/browser/compositor/scene_layer/ScrollingBottomViewSceneLayer.java",
......@@ -610,7 +613,6 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/download/ui/OfflineGroupHeaderView.java",
"java/src/org/chromium/chrome/browser/download/ui/SpaceDisplay.java",
"java/src/org/chromium/chrome/browser/engagement/SiteEngagementService.java",
"java/src/org/chromium/chrome/browser/experiments/EphemeralTab.java",
"java/src/org/chromium/chrome/browser/explore_sites/CategoryCardAdapter.java",
"java/src/org/chromium/chrome/browser/explore_sites/CategoryCardViewHolderFactory.java",
"java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java",
......
......@@ -2046,6 +2046,8 @@ jumbo_split_static_library("browser") {
"android/compositor/layer/content_layer.h",
"android/compositor/layer/contextual_search_layer.cc",
"android/compositor/layer/contextual_search_layer.h",
"android/compositor/layer/ephemeral_tab_layer.cc",
"android/compositor/layer/ephemeral_tab_layer.h",
"android/compositor/layer/layer.h",
"android/compositor/layer/overlay_panel_layer.cc",
"android/compositor/layer/overlay_panel_layer.h",
......@@ -2065,6 +2067,8 @@ jumbo_split_static_library("browser") {
"android/compositor/resources/toolbar_resource.h",
"android/compositor/scene_layer/contextual_search_scene_layer.cc",
"android/compositor/scene_layer/contextual_search_scene_layer.h",
"android/compositor/scene_layer/ephemeral_tab_scene_layer.cc",
"android/compositor/scene_layer/ephemeral_tab_scene_layer.h",
"android/compositor/scene_layer/scene_layer.cc",
"android/compositor/scene_layer/scene_layer.h",
"android/compositor/scene_layer/scrolling_bottom_view_scene_layer.cc",
......@@ -4663,6 +4667,7 @@ if (is_android) {
"../android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java",
"../android/java/src/org/chromium/chrome/browser/compositor/resources/ResourceFactory.java",
"../android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java",
"../android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java",
"../android/java/src/org/chromium/chrome/browser/compositor/scene_layer/SceneLayer.java",
"../android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ScrollingBottomViewSceneLayer.java",
"../android/java/src/org/chromium/chrome/browser/compositor/scene_layer/StaticTabSceneLayer.java",
......
// 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.
#include "chrome/browser/android/compositor/layer/ephemeral_tab_layer.h"
#include "cc/layers/layer.h"
#include "cc/layers/nine_patch_layer.h"
#include "cc/resources/scoped_ui_resource.h"
#include "content/public/browser/android/compositor.h"
#include "ui/android/resources/nine_patch_resource.h"
#include "ui/android/resources/resource_manager.h"
namespace android {
// static
scoped_refptr<EphemeralTabLayer> EphemeralTabLayer::Create(
ui::ResourceManager* resource_manager) {
return base::WrapRefCounted(new EphemeralTabLayer(resource_manager));
}
void EphemeralTabLayer::SetProperties(
int progress_bar_background_resource_id,
int progress_bar_resource_id,
float dp_to_px,
const scoped_refptr<cc::Layer>& content_layer,
float panel_x,
float panel_y,
float panel_width,
float panel_height,
float bar_margin_side,
float bar_height,
float text_opacity,
bool bar_border_visible,
float bar_border_height,
bool bar_shadow_visible,
float bar_shadow_opacity,
bool progress_bar_visible,
float progress_bar_height,
float progress_bar_opacity,
int progress_bar_completion) {
// Round values to avoid pixel gap between layers.
bar_height = floor(bar_height);
float bar_top = 0.f;
float bar_bottom = bar_top + bar_height;
bool should_render_progress_bar =
progress_bar_visible && progress_bar_opacity > 0.f;
OverlayPanelLayer::SetProperties(
dp_to_px, content_layer, bar_height, panel_x, panel_y, panel_width,
panel_height, bar_margin_side, bar_height, 0.0f, text_opacity,
bar_border_visible, bar_border_height, bar_shadow_visible,
bar_shadow_opacity, 1.0f);
// ---------------------------------------------------------------------------
// Progress Bar
// ---------------------------------------------------------------------------
if (should_render_progress_bar) {
ui::NinePatchResource* progress_bar_background_resource =
ui::NinePatchResource::From(resource_manager_->GetResource(
ui::ANDROID_RESOURCE_TYPE_STATIC,
progress_bar_background_resource_id));
ui::NinePatchResource* progress_bar_resource =
ui::NinePatchResource::From(resource_manager_->GetResource(
ui::ANDROID_RESOURCE_TYPE_STATIC, progress_bar_resource_id));
DCHECK(progress_bar_background_resource);
DCHECK(progress_bar_resource);
// Progress Bar Background
if (progress_bar_background_->parent() != layer_)
layer_->AddChild(progress_bar_background_);
float progress_bar_y = bar_bottom - progress_bar_height;
gfx::Size progress_bar_background_size(panel_width, progress_bar_height);
progress_bar_background_->SetUIResourceId(
progress_bar_background_resource->ui_resource()->id());
progress_bar_background_->SetBorder(
progress_bar_background_resource->Border(progress_bar_background_size));
progress_bar_background_->SetAperture(
progress_bar_background_resource->aperture());
progress_bar_background_->SetBounds(progress_bar_background_size);
progress_bar_background_->SetPosition(gfx::PointF(0.f, progress_bar_y));
progress_bar_background_->SetOpacity(progress_bar_opacity);
// Progress Bar
if (progress_bar_->parent() != layer_)
layer_->AddChild(progress_bar_);
float progress_bar_width =
floor(panel_width * progress_bar_completion / 100.f);
gfx::Size progress_bar_size(progress_bar_width, progress_bar_height);
progress_bar_->SetUIResourceId(progress_bar_resource->ui_resource()->id());
progress_bar_->SetBorder(progress_bar_resource->Border(progress_bar_size));
progress_bar_->SetAperture(progress_bar_resource->aperture());
progress_bar_->SetBounds(progress_bar_size);
progress_bar_->SetPosition(gfx::PointF(0.f, progress_bar_y));
progress_bar_->SetOpacity(progress_bar_opacity);
} else {
// Removes Progress Bar and its Background from the Layer Tree.
if (progress_bar_background_.get() && progress_bar_background_->parent())
progress_bar_background_->RemoveFromParent();
if (progress_bar_.get() && progress_bar_->parent())
progress_bar_->RemoveFromParent();
}
}
EphemeralTabLayer::EphemeralTabLayer(ui::ResourceManager* resource_manager)
: OverlayPanelLayer(resource_manager),
progress_bar_(cc::NinePatchLayer::Create()),
progress_bar_background_(cc::NinePatchLayer::Create()) {
progress_bar_background_->SetIsDrawable(true);
progress_bar_background_->SetFillCenter(true);
progress_bar_->SetIsDrawable(true);
progress_bar_->SetFillCenter(true);
}
EphemeralTabLayer::~EphemeralTabLayer() {}
} // namespace android
// 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.
#ifndef CHROME_BROWSER_ANDROID_COMPOSITOR_LAYER_EPHEMERAL_TAB_LAYER_H_
#define CHROME_BROWSER_ANDROID_COMPOSITOR_LAYER_EPHEMERAL_TAB_LAYER_H_
#include <memory>
#include "chrome/browser/android/compositor/layer/overlay_panel_layer.h"
namespace cc {
class Layer;
class NinePatchLayer;
} // namespace cc
namespace ui {
class ResourceManager;
}
namespace android {
class EphemeralTabLayer : public OverlayPanelLayer {
public:
static scoped_refptr<EphemeralTabLayer> Create(
ui::ResourceManager* resource_manager);
void SetProperties(int progress_bar_background_resource_id,
int progress_bar_resource_id,
float dp_to_px,
const scoped_refptr<cc::Layer>& content_layer,
float panel_x,
float panel_y,
float panel_width,
float panel_height,
float bar_margin_side,
float bar_height,
float text_opacity,
bool bar_border_visible,
float bar_border_height,
bool bar_shadow_visible,
float bar_shadow_opacity,
bool progress_bar_visible,
float progress_bar_height,
float progress_bar_opacity,
int progress_bar_completion);
protected:
explicit EphemeralTabLayer(ui::ResourceManager* resource_manager);
~EphemeralTabLayer() override;
private:
scoped_refptr<cc::NinePatchLayer> progress_bar_;
scoped_refptr<cc::NinePatchLayer> progress_bar_background_;
};
} // namespace android
#endif // CHROME_BROWSER_ANDROID_COMPOSITOR_LAYER_EPHEMERAL_TAB_LAYER_H_
// 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.
#include "chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h"
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "cc/layers/solid_color_layer.h"
#include "chrome/browser/android/compositor/layer/ephemeral_tab_layer.h"
#include "content/public/browser/android/compositor.h"
#include "content/public/browser/web_contents.h"
#include "jni/EphemeralTabSceneLayer_jni.h"
#include "ui/android/resources/resource_manager_impl.h"
#include "ui/android/view_android.h"
#include "ui/gfx/android/java_bitmap.h"
using base::android::JavaParamRef;
using base::android::JavaRef;
namespace android {
EphemeralTabSceneLayer::EphemeralTabSceneLayer(JNIEnv* env,
const JavaRef<jobject>& jobj)
: SceneLayer(env, jobj),
base_page_brightness_(1.0f),
content_container_(cc::Layer::Create()) {
// Responsible for moving the base page without modifying the layer itself.
content_container_->SetIsDrawable(true);
content_container_->SetPosition(gfx::PointF(0.0f, 0.0f));
layer()->AddChild(content_container_);
}
EphemeralTabSceneLayer::~EphemeralTabSceneLayer() {}
void EphemeralTabSceneLayer::CreateEphemeralTabLayer(
JNIEnv* env,
const JavaParamRef<jobject>& object,
const JavaParamRef<jobject>& jresource_manager) {
ui::ResourceManager* resource_manager =
ui::ResourceManagerImpl::FromJavaObject(jresource_manager);
ephemeral_tab_layer_ = EphemeralTabLayer::Create(resource_manager);
// The layer is initially invisible.
ephemeral_tab_layer_->layer()->SetHideLayerAndSubtree(true);
layer()->AddChild(ephemeral_tab_layer_->layer());
}
void EphemeralTabSceneLayer::SetResourceIds(JNIEnv* env,
const JavaParamRef<jobject>& object,
jint text_resource_id,
jint bar_background_resource_id,
jint bar_shadow_resource_id,
jint panel_icon_resource_id,
jint close_icon_resource_id) {
ephemeral_tab_layer_->SetResourceIds(
text_resource_id, bar_background_resource_id, bar_shadow_resource_id,
panel_icon_resource_id, close_icon_resource_id);
}
void EphemeralTabSceneLayer::Update(JNIEnv* env,
const JavaParamRef<jobject>& object,
jint progress_bar_background_resource_id,
jint progress_bar_resource_id,
jfloat dp_to_px,
jfloat base_page_brightness,
jfloat base_page_offset,
const JavaParamRef<jobject>& jweb_contents,
jfloat panel_X,
jfloat panel_y,
jfloat panel_width,
jfloat panel_height,
jfloat bar_margin_side,
jfloat bar_height,
jfloat text_opacity,
jboolean bar_border_visible,
jfloat bar_border_height,
jboolean bar_shadow_visible,
jfloat bar_shadow_opacity,
jboolean progress_bar_visible,
jfloat progress_bar_height,
jfloat progress_bar_opacity,
jint progress_bar_completion) {
// NOTE(mdjones): It is possible to render the panel before content has been
// created. If this is the case, do not attempt to access the WebContents
// and instead pass null.
content::WebContents* web_contents =
content::WebContents::FromJavaWebContents(jweb_contents);
scoped_refptr<cc::Layer> content_layer =
web_contents ? web_contents->GetNativeView()->GetLayer() : nullptr;
// Fade the base page out.
if (base_page_brightness_ != base_page_brightness) {
base_page_brightness_ = base_page_brightness;
cc::FilterOperations filters;
if (base_page_brightness < 1.f) {
filters.Append(
cc::FilterOperation::CreateBrightnessFilter(base_page_brightness));
}
content_container_->SetFilters(filters);
}
// Move the base page contents up.
content_container_->SetPosition(gfx::PointF(0.0f, base_page_offset));
ephemeral_tab_layer_->SetProperties(
progress_bar_background_resource_id, progress_bar_resource_id, dp_to_px,
content_layer, panel_X, panel_y, panel_width, panel_height,
bar_margin_side, bar_height, text_opacity, bar_border_visible,
bar_border_height, bar_shadow_visible, bar_shadow_opacity,
progress_bar_visible, progress_bar_height, progress_bar_opacity,
progress_bar_completion);
// Make the layer visible if it is not already.
ephemeral_tab_layer_->layer()->SetHideLayerAndSubtree(false);
}
void EphemeralTabSceneLayer::SetContentTree(
JNIEnv* env,
const JavaParamRef<jobject>& jobj,
const JavaParamRef<jobject>& jcontent_tree) {
SceneLayer* content_tree = FromJavaObject(env, jcontent_tree);
if (!content_tree || !content_tree->layer())
return;
if (!content_tree->layer()->parent() ||
(content_tree->layer()->parent()->id() != content_container_->id())) {
content_container_->AddChild(content_tree->layer());
}
}
void EphemeralTabSceneLayer::HideTree(JNIEnv* env,
const JavaParamRef<jobject>& jobj) {
// TODO(mdjones): Create super class for this logic.
if (ephemeral_tab_layer_) {
ephemeral_tab_layer_->layer()->SetHideLayerAndSubtree(true);
}
// Reset base page brightness.
cc::FilterOperations filters;
filters.Append(cc::FilterOperation::CreateBrightnessFilter(1.0f));
content_container_->SetFilters(filters);
// Reset base page offset.
content_container_->SetPosition(gfx::PointF(0.0f, 0.0f));
}
static jlong JNI_EphemeralTabSceneLayer_Init(
JNIEnv* env,
const JavaParamRef<jobject>& jobj) {
// This will automatically bind to the Java object and pass ownership there.
EphemeralTabSceneLayer* ephemeral_tab_scene_layer =
new EphemeralTabSceneLayer(env, jobj);
return reinterpret_cast<intptr_t>(ephemeral_tab_scene_layer);
}
} // namespace android
// 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.
#ifndef CHROME_BROWSER_ANDROID_COMPOSITOR_SCENE_LAYER_EPHEMERAL_TAB_SCENE_LAYER_H_
#define CHROME_BROWSER_ANDROID_COMPOSITOR_SCENE_LAYER_EPHEMERAL_TAB_SCENE_LAYER_H_
#include <memory>
#include <vector>
#include "base/android/jni_android.h"
#include "base/android/jni_weak_ref.h"
#include "base/android/scoped_java_ref.h"
#include "base/macros.h"
#include "chrome/browser/android/compositor/scene_layer/scene_layer.h"
#include "ui/android/resources/resource_manager_impl.h"
namespace cc {
class Layer;
class SolidColorLayer;
} // namespace cc
namespace android {
class EphemeralTabLayer;
class EphemeralTabSceneLayer : public SceneLayer {
public:
EphemeralTabSceneLayer(JNIEnv* env,
const base::android::JavaRef<jobject>& jobj);
~EphemeralTabSceneLayer() override;
void CreateEphemeralTabLayer(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& object,
const base::android::JavaParamRef<jobject>& jresource_manager);
void SetResourceIds(JNIEnv* env,
const base::android::JavaParamRef<jobject>& object,
jint text_resource_id,
jint bar_background_resource_id,
jint bar_shadow_resource_id,
jint panel_icon_resource_id,
jint close_icon_resource_id);
void Update(JNIEnv* env,
const base::android::JavaParamRef<jobject>& object,
jint progress_bar_background_resource_id,
jint progress_bar_resource_id,
jfloat dp_to_px,
jfloat base_page_brightness,
jfloat base_page_offset,
const base::android::JavaParamRef<jobject>& jcontent_view_core,
jfloat panel_X,
jfloat panel_y,
jfloat panel_width,
jfloat panel_height,
jfloat bar_margin_side,
jfloat bar_height,
jfloat text_opacity,
jboolean bar_border_visible,
jfloat bar_border_height,
jboolean bar_shadow_visible,
jfloat bar_shadow_opacity,
jboolean progress_bar_visible,
jfloat progress_bar_height,
jfloat progress_bar_opacity,
jint progress_bar_completion);
void SetContentTree(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& jobj,
const base::android::JavaParamRef<jobject>& jcontent_tree);
void HideTree(JNIEnv* env, const base::android::JavaParamRef<jobject>& jobj);
private:
float base_page_brightness_;
scoped_refptr<cc::Layer> content_layer_;
scoped_refptr<EphemeralTabLayer> ephemeral_tab_layer_;
scoped_refptr<cc::SolidColorLayer> color_overlay_;
scoped_refptr<cc::Layer> content_container_;
DISALLOW_COPY_AND_ASSIGN(EphemeralTabSceneLayer);
};
bool RegisterEphemeralTabSceneLayer(JNIEnv* env);
} // namespace android
#endif // CHROME_BROWSER_ANDROID_COMPOSITOR_SCENE_LAYER_EPHEMERAL_TAB_SCENE_LAYER_H_
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