Commit dfa4fead authored by Jinsuk Kim's avatar Jinsuk Kim Committed by Commit Bot

Reland "Android: Remove OverlayPanel-based Preview Tab code"

This reverts commit fb7edd8c.

Reason for revert: Not the culprit!

Original change's description:
> Revert "Android: Remove OverlayPanel-based Preview Tab code"
> 
> This reverts commit 928037da.
> 
> Reason for revert: Speculative fix for a mysterious crash in
> Contextual Search when animating the Overlay.  Issue 1050431.
> 
> BUG=1050431
> 
> Original change's description:
> > Android: Remove OverlayPanel-based Preview Tab code
> > 
> > Now that Preview Tab is working on top of ThinWebView and BottomSheet,
> > this CL deletes the old implementation that based it on OverlayPanel.
> > 
> > Bug: 1043677
> > Change-Id: Icccc93cca3f09e9ae122b1e0dcb7537331136ac0
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2032466
> > Commit-Queue: Jinsuk Kim <jinsukkim@chromium.org>
> > Reviewed-by: David Trainor <dtrainor@chromium.org>
> > Reviewed-by: Donn Denman <donnd@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#739094}
> 
> TBR=dtrainor@chromium.org,donnd@chromium.org,yusufo@chromium.org,jinsukkim@chromium.org
> 
> # Not skipping CQ checks because original CL landed > 1 day ago.
> 
> Bug: 1043677
> Change-Id: I7c9fa71c3aba77e3e1c8938db8f1b9f7f28a2b22
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2049206
> Reviewed-by: Donn Denman <donnd@chromium.org>
> Commit-Queue: Donn Denman <donnd@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#740156}

TBR=dtrainor@chromium.org,donnd@chromium.org,yusufo@chromium.org,jinsukkim@chromium.org

Change-Id: Ifbf3c03cc955bd942bfbcbf791cbddac8cf96e70
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 1050431, 1043677
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2050404Reviewed-by: default avatarJinsuk Kim <jinsukkim@chromium.org>
Commit-Queue: Jinsuk Kim <jinsukkim@chromium.org>
Cr-Commit-Position: refs/heads/master@{#740461}
parent 0ab877ac
......@@ -2593,7 +2593,6 @@ generate_jni("chrome_jni_headers") {
"java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java",
"java/src/org/chromium/chrome/browser/compositor/resources/ResourceFactory.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/ScrollingBottomViewSceneLayer.java",
"java/src/org/chromium/chrome/browser/compositor/scene_layer/StaticTabSceneLayer.java",
......
......@@ -232,13 +232,9 @@ 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/EphemeralTabCaptionControl.java",
"java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCoordinator.java",
"java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabMetrics.java",
"java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java",
"java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabSheetContent.java",
"java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabTitleControl.java",
"java/src/org/chromium/chrome/browser/compositor/layouts/EmptyOverviewModeObserver.java",
"java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java",
"java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java",
......@@ -294,7 +290,6 @@ 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",
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 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 caption view where we display 'Open in new tab'. Hidden in
peeked state, and gets visible only when being expanded to maximized state.
In the new layout, we display security level information with URL like in
CCT header. Always visible. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/ephemeral_tab_caption_view"
android:orientation="horizontal"
android:gravity="center"
style="@style/ContextualSearchTextViewLayout" >
<TextView
android:id="@+id/ephemeral_tab_caption"
style="@style/ContextualSearchCaptionTextView" />
</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. -->
<!-- Ephemeral Tab bar text -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ephemeral_tab_text_view"
style="@style/OverlayPanelTextViewLayout" >
<TextView
android:id="@+id/ephemeral_tab_text"
style="@style/OverlayPanelTextView"
android:layout_width="match_parent"
android:layout_gravity="bottom"
android:background="@color/overlay_panel_bar_background_color"
android:layout_marginStart="7dp"
android:layout_marginEnd="7dp" />
</FrameLayout>
......@@ -62,7 +62,6 @@ 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.ephemeraltab.EphemeralTabCoordinator;
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.OverviewModeBehavior;
......@@ -1369,7 +1368,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
getCompositorViewHolder().addCompositorViewResizer(
mManualFillingComponent.getKeyboardExtensionViewResizer());
if (ChromeFeatureList.isEnabled(ChromeFeatureList.EPHEMERAL_TAB_USING_BOTTOM_SHEET)) {
if (EphemeralTabCoordinator.isSupported()) {
mEphemeralTabCoordinator =
new EphemeralTabCoordinator(this, getBottomSheetController());
}
......@@ -1719,14 +1718,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
return mReaderModeManager;
}
/**
* @return The {@code EphemeralTabPanel} or {@code null} if none.
*/
public EphemeralTabPanel getEphemeralTabPanel() {
LayoutManager layoutManager = getCompositorViewHolder().getLayoutManager();
return layoutManager != null ? layoutManager.getEphemeralTabPanel() : null;
}
/**
* Create a full-screen manager to be used by this activity.
* Note: This may be called before native code is initialized.
......@@ -1788,8 +1779,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
}
mActivityTabProvider.setLayoutManager(layoutManager);
EphemeralTabPanel panel = layoutManager.getEphemeralTabPanel();
if (panel != null) panel.setChromeActivity(this);
}
/**
......
// 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.ViewGroup;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
/**
* Top control used for ephemeral tab.
*/
public class EphemeralTabBarControl {
/** Full opacity -- fully visible. */
private static final float SOLID_OPAQUE = 1.0f;
/** Transparent opacity -- completely transparent (not visible). */
private static final float SOLID_TRANSPARENT = 0.0f;
private final EphemeralTabTitleControl mTitle;
private final EphemeralTabCaptionControl mCaption;
// Dimensions used for laying out the controls in the bar.
private final float mTextLayerMinHeight;
private final float mTitleCaptionSpacing;
/**
* @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 loader The resource loader that will handle the snapshot capturing.
*/
public EphemeralTabBarControl(EphemeralTabPanel panel, Context context, ViewGroup container,
DynamicResourceLoader loader) {
mTitle = new EphemeralTabTitleControl(panel, context, container, loader);
mCaption = OverlayPanel.isNewLayout() || panel.canPromoteToNewTab()
? new EphemeralTabCaptionControl(panel, context, container, loader)
: null;
mTextLayerMinHeight =
context.getResources().getDimension(R.dimen.overlay_panel_text_layer_min_height);
mTitleCaptionSpacing =
context.getResources().getDimension(R.dimen.contextual_search_term_caption_spacing);
}
/**
* Returns the minimum height that the text layer (containing the title and the caption)
* should be.
*/
public float getTextLayerMinHeight() {
return mTextLayerMinHeight;
}
/**
* Returns the spacing that should be placed between the title and the caption.
*/
public float getTitleCaptionSpacing() {
return mTitleCaptionSpacing;
}
/**
* Updates this bar when in transition to closed/peeked states.
* @param percentage The percentage to the more opened state.
*/
public void updateForCloseOrPeek(float percentage) {
if (OverlayPanel.isNewLayout()) {
updateForMaximize(SOLID_OPAQUE);
} else {
if (percentage == SOLID_OPAQUE) updateForMaximize(SOLID_TRANSPARENT);
// When the panel is completely closed the caption should be hidden.
if (percentage == SOLID_TRANSPARENT && mCaption != null) mCaption.hide();
}
}
/**
* Updates this bar when in transition to maximized states.
* @param percentage The percentage to the more opened state.
*/
public void updateForMaximize(float percentage) {
if (mCaption != null) mCaption.updatePanelForMaximization(percentage);
}
/**
* Set the text in the panel.
* @param text The string to set the text to.
*/
public void setBarText(String text) {
mTitle.setBarText(text);
}
/**
* @return {@link EphemeralTabTitleControl} object.
*/
public EphemeralTabTitleControl getTitleControl() {
return mTitle;
}
/**
* @return {@link EphemeralTabCaptionControl} object.
*/
public EphemeralTabCaptionControl getCaptionControl() {
return mCaption;
}
/**
* Gets the current animation percentage for the Caption control, which guides the vertical
* position and opacity of the caption.
* @return The animation percentage ranging from 0.0 to 1.0.
*
*/
public float getCaptionAnimationPercentage() {
return mCaption.getAnimationPercentage();
}
/**
* Removes the bottom bar views from the parent container.
*/
public void destroy() {
mTitle.destroy();
if (mCaption != null) mCaption.destroy();
}
}
// Copyright 2019 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.view.ViewGroup.MarginLayoutParams;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelTextViewInflater;
import org.chromium.components.url_formatter.SchemeDisplay;
import org.chromium.components.url_formatter.UrlFormatter;
import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
/**
* Controls the Caption View that is shown at the bottom of the control and used
* as a dynamic resource.
*/
public class EphemeralTabCaptionControl extends OverlayPanelTextViewInflater {
/** Space for security icon. Caption is pushed to right by this amount if the icon is shown. */
private final int mIconMargin;
/** The caption View. */
private TextView mCaption;
/** Whether the caption is showing. */
private boolean mShowingCaption;
/** The caption visibility. */
private boolean mIsVisible;
private Supplier<String> mUrl;
/**
* The caption animation percentage, which controls how and where to draw. It is
* 0 when the Contextual Search bar is peeking and 1 when it is maxmized.
*/
private float mAnimationPercentage;
private @DrawableRes int mIconId;
private float mIconOpacity;
/**
* @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 EphemeralTabCaptionControl(EphemeralTabPanel panel, Context context, ViewGroup container,
DynamicResourceLoader resourceLoader) {
super(panel, R.layout.ephemeral_tab_caption_view, R.id.ephemeral_tab_caption_view, context,
container, resourceLoader,
(OverlayPanel.isNewLayout() ? R.dimen.overlay_panel_end_buttons_width
: R.dimen.overlay_panel_padded_button_width),
(OverlayPanel.isNewLayout() ? R.dimen.overlay_panel_end_buttons_width
: R.dimen.overlay_panel_padded_button_width));
mUrl = panel::getUrl;
mIconMargin = context.getResources().getDimensionPixelSize(
R.dimen.preview_tab_security_icon_size);
}
/**
* Updates the caption when in transition between peeked to maximized states.
* @param percentage The percentage to the more opened state.
*/
public void updatePanelForMaximization(float percentage) {
// If the caption is not showing, show it now.
if (!mShowingCaption && percentage > 0.f) {
mShowingCaption = true;
if (mCaption == null) {
// |mCaption| gets initialized synchronously in |onFinishInflate|.
inflate();
if (OverlayPanel.isNewLayout()) {
mCaption.setText(UrlFormatter.formatUrlForSecurityDisplay(
mUrl.get(), SchemeDisplay.OMIT_HTTP_AND_HTTPS));
} else {
mCaption.setText(R.string.contextmenu_open_in_new_tab);
}
}
invalidate();
mIsVisible = true;
}
mAnimationPercentage = percentage;
if (mAnimationPercentage == 0.f) mShowingCaption = false;
}
/** Sets the security icon. */
public void setSecurityIcon(@DrawableRes int resId) {
mIconId = resId;
}
/** @return Security icon resource ID */
public @DrawableRes int getIconId() {
return mIconId;
}
/** Sets the security icon opacity. */
public void setIconOpacity(float opacity) {
mIconOpacity = opacity;
}
/** @return Security icon opacity. */
public float getIconOpacity() {
return mIconOpacity;
}
/**
* Hides the caption.
*/
public void hide() {
if (mShowingCaption) {
mIsVisible = false;
mAnimationPercentage = 0.f;
}
}
/**
* Controls whether the caption is visible and can be rendered.
* The caption must be visible in order to draw it and take a snapshot.
* Even though the caption is visible the user might not be able to see it due to a
* completely transparent opacity associated with an animation percentage of zero.
* @return Whether the caption is visible or not.
*/
public boolean getIsVisible() {
return mIsVisible;
}
/**
* Gets the animation percentage which controls the drawing of the caption and how high to
* position it in the Bar.
* @return The current percentage ranging from 0.0 to 1.0.
*/
public float getAnimationPercentage() {
return OverlayPanel.isNewLayout() ? 1.f : mAnimationPercentage;
}
/**
* Sets caption text.
* @param text String to use for caption.
*/
public void setCaptionText(String text) {
if (mCaption == null) return;
mCaption.setText(text);
invalidate();
}
// OverlayPanelTextViewInflater
@Override
protected TextView getTextView() {
return mCaption;
}
// OverlayPanelInflater
@Override
protected void onFinishInflate() {
super.onFinishInflate();
View view = getView();
mCaption = (TextView) view.findViewById(R.id.ephemeral_tab_caption);
if (OverlayPanel.isNewLayout()) {
((MarginLayoutParams) mCaption.getLayoutParams()).leftMargin = mIconMargin;
}
}
}
......@@ -12,6 +12,7 @@ import android.text.TextUtils;
import android.view.View;
import org.chromium.base.Callback;
import org.chromium.base.SysUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.compositor.bottombar.OverlayContentDelegate;
......@@ -21,6 +22,7 @@ import org.chromium.chrome.browser.favicon.FaviconHelper;
import org.chromium.chrome.browser.favicon.FaviconUtils;
import org.chromium.chrome.browser.favicon.RoundedIconGenerator;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.ntp.NewTabPage;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.ssl.SecurityStateModel;
......@@ -57,6 +59,7 @@ public class EphemeralTabCoordinator implements View.OnLayoutChangeListener {
private WebContentsObserver mWebContentsObserver;
private EphemeralTabSheetContent mSheetContent;
private boolean mIsIncognito;
private boolean mOpened;
private String mUrl;
private int mCurrentMaxSheetHeight;
......@@ -83,6 +86,7 @@ public class EphemeralTabCoordinator implements View.OnLayoutChangeListener {
if (mSheetContent == null) return;
switch (newState) {
case SheetState.PEEK:
mOpened = true;
mMetrics.recordMetricsForPeeked();
break;
case SheetState.FULL:
......@@ -96,6 +100,7 @@ public class EphemeralTabCoordinator implements View.OnLayoutChangeListener {
// "Closed" actually means "Peek" for bottom sheet. Save the reason to log
// when the sheet goes to hidden state.
mCloseReason = reason;
mOpened = false;
}
@Override
......@@ -107,6 +112,22 @@ public class EphemeralTabCoordinator implements View.OnLayoutChangeListener {
});
}
/**
* Checks if this feature (a.k.a. "Preview page/image") is supported.
* @return {@code true} if the feature is enabled.
*/
public static boolean isSupported() {
return ChromeFeatureList.isEnabled(ChromeFeatureList.EPHEMERAL_TAB_USING_BOTTOM_SHEET)
&& !SysUtils.isLowEndDevice();
}
/**
* Checks if the preview tab is in open state.
*/
public boolean isOpened() {
return mOpened;
}
/**
* Entry point for ephemeral tab flow. This will create an ephemeral tab and show it in the
* bottom sheet.
......@@ -145,6 +166,7 @@ public class EphemeralTabCoordinator implements View.OnLayoutChangeListener {
private void destroyContent() {
mSheetContent = null; // Will be destroyed by BottomSheet controller.
mOpened = false;
if (mPanelContent != null) {
mPanelContent.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.compositor.bottombar.ephemeraltab;
import android.content.Context;
import android.graphics.RectF;
import android.text.TextUtils;
import android.view.MotionEvent;
import org.chromium.base.SysUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.LayerTitleCache;
import org.chromium.chrome.browser.compositor.animation.CompositorAnimator;
import org.chromium.chrome.browser.compositor.animation.CompositorAnimator.AnimatorUpdateListener;
import org.chromium.chrome.browser.compositor.bottombar.OverlayContentDelegate;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
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.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.ntp.NewTabPage;
import org.chromium.chrome.browser.ssl.SecurityStateModel;
import org.chromium.chrome.browser.tab.SadTab;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tab.TabSelectionType;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
import org.chromium.components.url_formatter.SchemeDisplay;
import org.chromium.components.url_formatter.UrlFormatter;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.resources.ResourceManager;
/**
* The panel containing an ephemeral tab.
* TODO(jinsukkim): Write tests.
* Add animation effect upon opening ephemeral tab.
*/
public class EphemeralTabPanel extends OverlayPanel {
/** The compositor layer used for drawing the panel. */
private EphemeralTabSceneLayer mSceneLayer;
/** True if the Tab from which the panel is opened is in incognito mode. */
private boolean mIsIncognito;
/** Url for which this epehemral tab was created. */
private String mUrl;
/** Observers detecting various signals indicating the panel needs closing. */
private TabModelSelectorTabModelObserver mTabModelObserver;
private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
/** Favicon opacity. Fully visible when 1.f. */
private float mFaviconOpacity;
/** Animation effect for favicon display. */
private CompositorAnimator mFaviconAnimation;
/** Animation effect for security icon display . */
private CompositorAnimator mCaptionAnimation;
private final AnimatorUpdateListener mFadeInAnimatorListener =
animator -> mFaviconOpacity = animator.getAnimatedValue();
private final AnimatorUpdateListener mFadeOutAnimatorListener =
animator -> mFaviconOpacity = 1.f - animator.getAnimatedValue();
private final AnimatorUpdateListener mSecurityIconAnimationListener = animator
-> getBarControl().getCaptionControl().setIconOpacity(animator.getAnimatedValue());
/**
* Checks if this feature (a.k.a. "Preview page/image") is supported.
* @return {@code true} if the feature is enabled.
*/
public static boolean isSupported() {
return ChromeFeatureList.isEnabled(ChromeFeatureList.EPHEMERAL_TAB_USING_BOTTOM_SHEET)
&& !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,
mContext.getResources().getDimensionPixelSize(
R.dimen.compositor_tab_title_favicon_size));
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 void destroy() {
stopListeningForCloseConditions();
}
private class EphemeralTabPanelContentDelegate extends OverlayContentDelegate {
/** Whether the currently loaded page is an error (interstitial) page. */
private boolean mIsOnErrorPage;
@Override
public void onMainFrameLoadStarted(String url, boolean isExternalUrl) {
if (TextUtils.equals(mUrl, url)) return;
if (mIsOnErrorPage && NewTabPage.isNTPUrl(url)) {
// "Back to safety" on interstitial page leads to NTP.
// We just close the panel in response.
closePanel(StateChangeReason.NAVIGATION, true);
mUrl = null;
return;
}
mUrl = url;
// Resets to default icon if favicon may need updating.
startFaviconAnimation(false);
}
@Override
public void onMainFrameNavigation(
String url, boolean isExternalUrl, boolean isFailure, boolean isError) {
updateCaption();
mIsOnErrorPage = isError;
}
@Override
public void onTitleUpdated(String title) {
getBarControl().setBarText(title);
}
@Override
public void onSSLStateUpdated() {
if (isNewLayout()) updateCaption();
}
@Override
public void onOpenNewTabRequested(String url) {
// We never open a separate tab when navigating in an overlay.
getWebContents().getNavigationController().loadUrl(new LoadUrlParams(url));
requestPanelShow(StateChangeReason.CLICK);
}
}
@Override
public OverlayPanelContent createNewOverlayPanelContent() {
if (mTabModelObserver == null) startListeningForCloseConditions();
return new OverlayPanelContent(new EphemeralTabPanelContentDelegate(),
new PanelProgressObserver(), mActivity, mIsIncognito, getBarHeight());
}
private void startListeningForCloseConditions() {
TabModelSelector selector = mActivity.getTabModelSelector();
mTabModelObserver = new TabModelSelectorTabModelObserver(selector) {
@Override
public void didSelectTab(Tab tab, @TabSelectionType int type, int lastId) {
closeTab();
}
@Override
public void didAddTab(Tab tab, @TabLaunchType int type) {
closeTab();
}
};
mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(selector) {
@Override
public void onPageLoadStarted(Tab tab, String url) {
// Hides the panel if the base page navigates.
closeTab();
}
@Override
public void onCrash(Tab tab) {
// Hides the panel if the foreground tab crashed
if (SadTab.isShowing(tab)) closeTab();
}
@Override
public void onClosingStateChanged(Tab tab, boolean closing) {
if (closing) closeTab();
}
};
}
private void stopListeningForCloseConditions() {
if (mTabModelObserver == null) return;
mTabModelObserver.destroy();
mTabModelSelectorTabObserver.destroy();
mTabModelObserver = null;
mTabModelSelectorTabObserver = null;
}
private void closeTab() {
closePanel(StateChangeReason.UNKNOWN, false);
}
@Override
protected float getPeekedHeight() {
return getBarHeight() * 1.5f;
}
@Override
protected float getMaximizedHeight() {
// Max height does not cover the entire content screen.
return getTabHeight() * 0.9f;
}
@Override
public boolean isPanelOpened() {
return getHeight() > getPeekedHeight();
}
@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, getBarControl(),
getBarControl().getTitleControl(), getBarControl().getCaptionControl());
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);
}
/**
* Starts animation effect on the favicon.
* @param showFavicon If {@code true} show the favicon with fade-in effect. Otherwise
* fade out the favicon to show the default one.
*/
public void startFaviconAnimation(boolean showFavicon) {
if (mFaviconAnimation != null) mFaviconAnimation.cancel();
mFaviconAnimation = new CompositorAnimator(getAnimationHandler());
mFaviconAnimation.setDuration(BASE_ANIMATION_DURATION_MS);
mFaviconAnimation.removeAllListeners();
mFaviconAnimation.addUpdateListener(
showFavicon ? mFadeInAnimatorListener : mFadeOutAnimatorListener);
mFaviconOpacity = showFavicon ? 0.f : 1.f;
mFaviconAnimation.start();
}
private void updateCaption() {
if (mCaptionAnimation != null) mCaptionAnimation.cancel();
int securityLevel = SecurityStateModel.getSecurityLevelForWebContents(getWebContents());
EphemeralTabCaptionControl caption = getBarControl().getCaptionControl();
caption.setCaptionText(
UrlFormatter.formatUrlForSecurityDisplay(mUrl, SchemeDisplay.OMIT_HTTP_AND_HTTPS));
caption.setSecurityIcon(EphemeralTabCoordinator.getSecurityIconResource(securityLevel));
mCaptionAnimation = new CompositorAnimator(getAnimationHandler());
mCaptionAnimation.setDuration(BASE_ANIMATION_DURATION_MS);
mCaptionAnimation.removeAllListeners();
mCaptionAnimation.addUpdateListener(mSecurityIconAnimationListener);
mCaptionAnimation.start();
}
/**
* @return Snaptshot value of the favicon opacity.
*/
public float getFaviconOpacity() {
return mFaviconOpacity;
}
// Generic Event Handling
@Override
public void handleBarClick(float x, float y) {
super.handleBarClick(x, y);
// TODO(donnd): Remove one of these cases when experiment is resolved.
if (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)) {
if (isCoordinateInsideCloseButton(x)) {
closePanel(StateChangeReason.CLOSE_BUTTON, true);
} else if (isCoordinateInsideOpenTabButton(x)) {
if (canPromoteToNewTab() && mUrl != null) {
closePanel(StateChangeReason.TAB_PROMOTION, false);
mActivity.getCurrentTabCreator().createNewTab(
new LoadUrlParams(mUrl, PageTransition.LINK), TabLaunchType.FROM_LINK,
mActivity.getActivityTabProvider().get());
}
} else if (isPeeking()) {
maximizePanel(StateChangeReason.SEARCH_BAR_TAP);
}
} else {
// To keep things simple for now we just have both cases verbatim (without optimizing).
if (isCoordinateInsideCloseButton(x)) {
closePanel(StateChangeReason.CLOSE_BUTTON, true);
} else {
if (isPeeking()) {
maximizePanel(StateChangeReason.SEARCH_BAR_TAP);
} else if (canPromoteToNewTab() && mUrl != null) {
closePanel(StateChangeReason.TAB_PROMOTION, false);
mActivity.getCurrentTabCreator().createNewTab(
new LoadUrlParams(mUrl, PageTransition.LINK), TabLaunchType.FROM_LINK,
mActivity.getActivityTabProvider().get());
}
}
}
}
/**
* @return Whether the panel content can be displayed in a new tab.
*/
public boolean canPromoteToNewTab() {
return !mActivity.isCustomTab();
}
/**
* @return URL of the page to open in the panel.
*/
public String getUrl() {
return mUrl;
}
// Panel base methods
@Override
public void destroyComponents() {
super.destroyComponents();
destroyBarControl();
}
@Override
public @PanelPriority int getPriority() {
return PanelPriority.HIGH;
}
@Override
protected boolean isSupportedState(@PanelState int state) {
return state != PanelState.EXPANDED;
}
@Override
protected void onClosed(@StateChangeReason int reason) {
super.onClosed(reason);
mFaviconOpacity = 0.f;
if (mSceneLayer != null) mSceneLayer.hideTree();
}
@Override
protected void updatePanelForCloseOrPeek(float percentage) {
super.updatePanelForCloseOrPeek(percentage);
getBarControl().updateForCloseOrPeek(percentage);
}
@Override
protected void updatePanelForMaximization(float percentage) {
super.updatePanelForMaximization(percentage);
getBarControl().updateForMaximize(percentage);
}
/**
* 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.
* @param isIncognito {@link True} if the panel is opened from an incognito tab.
*/
public void requestOpenPanel(String url, String text, boolean isIncognito) {
if (isShowing()) closePanel(StateChangeReason.RESET, false);
mIsIncognito = isIncognito;
mUrl = url;
loadUrlInPanel(url);
WebContents panelWebContents = getWebContents();
if (panelWebContents != null) panelWebContents.onShow();
getBarControl().setBarText(text);
requestPanelShow(StateChangeReason.CLICK);
}
@Override
public void onLayoutChanged(float width, float height, float visibleViewportOffsetY) {
if (width != getWidth()) destroyBarControl();
super.onLayoutChanged(width, height, visibleViewportOffsetY);
}
private EphemeralTabBarControl mEphemeralTabBarControl;
/**
* 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).
*/
private EphemeralTabBarControl getBarControl() {
assert mContainerView != null;
assert mResourceLoader != null;
if (mEphemeralTabBarControl == null) {
mEphemeralTabBarControl =
new EphemeralTabBarControl(this, mContext, mContainerView, mResourceLoader);
}
assert mEphemeralTabBarControl != null;
return mEphemeralTabBarControl;
}
/**
* Destroys the EphemeralTabBarControl.
*/
private void destroyBarControl() {
if (mEphemeralTabBarControl != null) {
mEphemeralTabBarControl.destroy();
mEphemeralTabBarControl = null;
}
}
}
// Copyright 2019 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.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.OverlayPanelTextViewInflater;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
/**
* Title control showing URL for ephemeral tab.
*/
public class EphemeralTabTitleControl extends OverlayPanelTextViewInflater {
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 EphemeralTabTitleControl(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,
(ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
? R.dimen.overlay_panel_end_buttons_width
: R.dimen.overlay_panel_padded_button_width),
(ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
? R.dimen.overlay_panel_end_buttons_width
: R.dimen.overlay_panel_padded_button_width));
invalidate();
}
void setBarText(String text) {
if (mBarText == null) inflate();
mBarText.setText(text);
invalidate();
}
// OverlayPanelTextViewInflater
@Override
protected TextView getTextView() {
return mBarText;
}
// OverlayPanelInflater
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mBarText = (TextView) getView().findViewById(R.id.ephemeral_tab_text);
}
}
......@@ -23,7 +23,6 @@ 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;
......@@ -115,7 +114,6 @@ public class LayoutManager implements LayoutUpdateHost, LayoutProvider,
private int mControlsHidingToken = TokenHolder.INVALID_TOKEN;
private boolean mUpdateRequested;
private final ContextualSearchPanel mContextualSearchPanel;
private final EphemeralTabPanel mEphemeralTabPanel;
private final OverlayPanelManager mOverlayPanelManager;
private final ToolbarSceneLayer mToolbarOverlay;
private SceneOverlay mStatusIndicatorSceneOverlay;
......@@ -230,10 +228,6 @@ 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);
......@@ -247,13 +241,6 @@ 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;
......@@ -463,7 +450,6 @@ public class LayoutManager implements LayoutUpdateHost, LayoutProvider,
mSceneChangeObservers.clear();
if (mStaticLayout != null) mStaticLayout.destroy();
if (mOverlayPanelManager != null) mOverlayPanelManager.destroy();
if (mEphemeralTabPanel != null) mEphemeralTabPanel.destroy();
if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.destroy();
if (mTabModelSelectorObserver != null) {
getTabModelSelector().removeObserver(mTabModelSelectorObserver);
......@@ -907,7 +893,6 @@ public class LayoutManager implements LayoutUpdateHost, LayoutProvider,
addGlobalSceneOverlay(mStatusIndicatorSceneOverlay);
}
mStaticLayout.addSceneOverlay(mContextualSearchPanel);
if (mEphemeralTabPanel != null) mStaticLayout.addSceneOverlay(mEphemeralTabPanel);
}
/**
......
......@@ -14,7 +14,6 @@ import org.chromium.base.ObserverList;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.browser.accessibility_tab_switcher.OverviewListLayout;
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;
......@@ -228,9 +227,6 @@ public class LayoutManagerChrome extends LayoutManager implements OverviewModeCo
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 androidx.annotation.Nullable;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabBarControl;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCaptionControl;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabTitleControl;
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;
/** Interface to get notified that favicon is available. */
interface FaviconCallback {
/**
* Called when a favicon becomes available. Used to start the animation fading
* out the default icon and fading in the favicon.
*/
@CalledByNative("FaviconCallback")
void onAvailable();
}
/**
* @param dpToPx The conversion multiple from dp to px for the device.
* @param faviconSizeDp Preferred size of the favicon to fetch.
*/
public EphemeralTabSceneLayer(float dpToPx, int faviconSizeDp) {
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 bar {@link EphemeralTabBarControl} object.
* @param title {@link EphemeralTabTitleControl} object.
* @param caption {@link EphemeralTabCaptionControl} object.
*/
public void update(ResourceManager resourceManager, EphemeralTabPanel panel,
EphemeralTabBarControl bar, EphemeralTabTitleControl title,
@Nullable EphemeralTabCaptionControl caption) {
// Don't try to update the layer if not initialized or showing.
if (resourceManager == null || !panel.isShowing()) return;
if (!mIsInitialized) {
EphemeralTabSceneLayerJni.get().createEphemeralTabLayer(mNativePtr,
EphemeralTabSceneLayer.this, resourceManager,
() -> panel.startFaviconAnimation(true));
int openInTabIconId = (OverlayPanel.isNewLayout() && panel.canPromoteToNewTab())
? R.drawable.open_in_new_tab
: INVALID_RESOURCE_ID;
int dragHandlebarId =
OverlayPanel.isNewLayout() ? R.drawable.drag_handlebar : INVALID_RESOURCE_ID;
int roundedBarTopId =
OverlayPanel.isNewLayout() ? R.drawable.top_round : INVALID_RESOURCE_ID;
// The panel shadow goes all the way around in the old layout, but in the new layout
// the top_round resource also includes the shadow so we only need a side shadow.
// In either case there's just one shadow-only resource needed.
int panelShadowResourceId = OverlayPanel.isNewLayout()
? R.drawable.overlay_side_shadow
: R.drawable.contextual_search_bar_background;
EphemeralTabSceneLayerJni.get().setResourceIds(mNativePtr, EphemeralTabSceneLayer.this,
title.getViewId(), panelShadowResourceId, roundedBarTopId,
R.drawable.modern_toolbar_shadow, R.drawable.infobar_chrome, dragHandlebarId,
openInTabIconId, R.drawable.btn_close);
mIsInitialized = true;
}
int titleViewId = title.getViewId();
int captionViewId = 0;
int captionIconId = 0;
float captionIconOpacity = 0.f;
float captionAnimationPercentage = 0.f;
boolean captionVisible = false;
if (caption != null) {
captionViewId = caption.getViewId();
captionAnimationPercentage = caption.getAnimationPercentage();
captionIconOpacity = caption.getIconOpacity();
captionVisible = caption.getIsVisible();
captionIconId = caption.getIconId();
}
boolean isProgressBarVisible = panel.isProgressBarVisible();
float progressBarHeight = panel.getProgressBarHeight();
float progressBarOpacity = panel.getProgressBarOpacity();
float progressBarCompletion = panel.getProgressBarCompletion();
int separatorLineColor = panel.getSeparatorLineColor();
WebContents panelWebContents = panel.getWebContents();
EphemeralTabSceneLayerJni.get().update(mNativePtr, EphemeralTabSceneLayer.this, titleViewId,
captionViewId, captionIconId, captionIconOpacity, captionAnimationPercentage,
bar.getTextLayerMinHeight(), bar.getTitleCaptionSpacing(), captionVisible,
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.getBarBackgroundColor(), panel.getBarMarginSide() * mDpToPx,
panel.getBarMarginTop() * mDpToPx, panel.getBarHeight() * mDpToPx,
panel.isBarBorderVisible(), panel.getBarBorderHeight() * mDpToPx,
panel.getIconColor(), panel.getDragHandlebarColor(), panel.getFaviconOpacity(),
isProgressBarVisible, progressBarHeight * mDpToPx, progressBarOpacity,
progressBarCompletion, separatorLineColor);
}
@Override
public void setContentTree(SceneLayer contentTree) {
EphemeralTabSceneLayerJni.get().setContentTree(
mNativePtr, EphemeralTabSceneLayer.this, contentTree);
}
/**
* Hide the layer tree; for use if the panel is not being shown.
*/
public void hideTree() {
if (!mIsInitialized) return;
EphemeralTabSceneLayerJni.get().hideTree(mNativePtr, EphemeralTabSceneLayer.this);
}
@Override
protected void initializeNative() {
if (mNativePtr == 0) {
mNativePtr = EphemeralTabSceneLayerJni.get().init(EphemeralTabSceneLayer.this);
}
assert mNativePtr != 0;
}
/**
* Destroys this object and the corresponding native component.
*/
@Override
public void destroy() {
super.destroy();
mIsInitialized = false;
mNativePtr = 0;
}
@NativeMethods
interface Natives {
long init(EphemeralTabSceneLayer caller);
void createEphemeralTabLayer(long nativeEphemeralTabSceneLayer,
EphemeralTabSceneLayer caller, ResourceManager resourceManager,
FaviconCallback callback);
void setContentTree(long nativeEphemeralTabSceneLayer, EphemeralTabSceneLayer caller,
SceneLayer contentTree);
void hideTree(long nativeEphemeralTabSceneLayer, EphemeralTabSceneLayer caller);
void setResourceIds(long nativeEphemeralTabSceneLayer, EphemeralTabSceneLayer caller,
int barTextResourceId, int barBackgroundResourceId, int roundedBarTopResourceId,
int barShadowResourceId, int panelIconResourceId, int dragHandlebarResourceId,
int openTabIconResourceId, int closeIconResourceId);
void update(long nativeEphemeralTabSceneLayer, EphemeralTabSceneLayer caller,
int titleViewId, int captionViewId, int captionIconId, float captionIconOpacity,
float captionAnimationPercentage, float textLayerMinHeight,
float titleCaptionSpacing, boolean captionVisible,
int progressBarBackgroundResourceId, int progressBarResourceId, float dpToPx,
float basePageBrightness, float basePageYOffset, WebContents webContents,
float panelX, float panelY, float panelWidth, float panelHeight,
int barBackgroundColor, float barMarginSide, float barMarginTop, float barHeight,
boolean barBorderVisible, float barBorderHeight, int iconColor,
int dragHandlebarColor, float faviconOpacity, boolean isProgressBarVisible,
float progressBarHeight, float progressBarOpacity, float progressBarCompletion,
int separatorLineColor);
}
}
......@@ -20,7 +20,7 @@ import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCoordinator;
import org.chromium.chrome.browser.contextmenu.ChromeContextMenuItem.Item;
import org.chromium.chrome.browser.contextmenu.ContextMenuParams.PerformanceClass;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
......@@ -336,7 +336,7 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
if (mDelegate.isOpenInOtherWindowSupported()) {
linkTab.add(new ChromeContextMenuItem(Item.OPEN_IN_OTHER_WINDOW));
}
if (EphemeralTabPanel.isSupported()) {
if (EphemeralTabCoordinator.isSupported()) {
ContextMenuItem item = new ChromeContextMenuItem(Item.OPEN_IN_EPHEMERAL_TAB);
mShowEphemeralTabNewLabel = shouldTriggerEphemeralTabHelpUi();
if (mShowEphemeralTabNewLabel) item.setShowInProductHelp();
......@@ -399,7 +399,7 @@ public class ChromeContextMenuPopulator implements ContextMenuPopulator {
if (mMode == ContextMenuMode.NORMAL) {
imageTab.add(new ChromeContextMenuItem(Item.OPEN_IMAGE_IN_NEW_TAB));
}
if (EphemeralTabPanel.isSupported()) {
if (EphemeralTabCoordinator.isSupported()) {
ContextMenuItem item =
new ChromeContextMenuItem(Item.OPEN_IMAGE_IN_EPHEMERAL_TAB);
if (mShowEphemeralTabNewLabel == null) {
......
......@@ -8,7 +8,6 @@ import android.net.Uri;
import android.text.TextUtils;
import org.chromium.base.Log;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel;
import org.chromium.chrome.browser.contextualsearch.ContextualSearchContext;
import org.chromium.chrome.browser.contextualsearch.ResolvedSearchTerm;
import org.chromium.chrome.browser.contextualsearch.ResolvedSearchTerm.CardTag;
......@@ -126,28 +125,13 @@ public class TaskRecognizer extends EmptyTabObserver implements ResolveResponse
&& resolvedSearchTerm.caption().contains(UNICODE_STAR));
}
/**
* Creates an {@code EphemeralTab} for the given searchUrl using details from the given
* {@code ResolvedSearchterm}.
*/
private void createEphemeralTabFor(
Tab activeTab, ResolvedSearchTerm resolvedSearchTerm, Uri searchUrl) {
if (activeTab == null || ((TabImpl) activeTab).getActivity() == null) return;
EphemeralTabPanel displayPanel = ((TabImpl) activeTab).getActivity().getEphemeralTabPanel();
if (displayPanel != null) {
displayPanel.requestOpenPanel(searchUrl.toString(), resolvedSearchTerm.displayText(),
activeTab.isIncognito());
}
}
/** ResolveResponse overrides. */
@Override
public void onResolveResponse(ResolvedSearchTerm resolvedSearchTerm, Uri searchUri) {
Tab activeTab = mTabInUse;
mTabInUse = null;
if (looksLikeAProduct(resolvedSearchTerm) && activeTab != null) {
createEphemeralTabFor(activeTab, resolvedSearchTerm, searchUri);
// Do something here to show the resolved search term.
}
}
......
......@@ -275,8 +275,8 @@ public class RootUiCoordinator
@Override
public boolean canShowAppMenu() {
// TODO(https:crbug.com/931496): Eventually the ContextualSearchManager, EphemeralTabPanel,
// and FindToolbarManager will all be owned by this class.
// TODO(https:crbug.com/931496): Eventually the ContextualSearchManager,
// EphemeralTabCoordinator, and FindToolbarManager will all be owned by this class.
// Do not show the menu if Contextual Search panel is opened.
if (mActivity.getContextualSearchManager() != null
......@@ -284,8 +284,8 @@ public class RootUiCoordinator
return false;
}
if (mActivity.getEphemeralTabPanel() != null
&& mActivity.getEphemeralTabPanel().isPanelOpened()) {
if (mActivity.getEphemeralTabCoordinator() != null
&& mActivity.getEphemeralTabCoordinator().isOpened()) {
return false;
}
......@@ -462,10 +462,6 @@ public class RootUiCoordinator
mActivity.getContextualSearchManager().hideContextualSearch(
OverlayPanel.StateChangeReason.UNKNOWN);
}
if (mActivity.getEphemeralTabPanel() != null) {
mActivity.getEphemeralTabPanel().closePanel(
OverlayPanel.StateChangeReason.UNKNOWN, true);
}
}
@Override
......
......@@ -31,7 +31,7 @@ import org.chromium.base.test.util.FlakyTest;
import org.chromium.base.test.util.RetryOnFailure;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCoordinator;
import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
import org.chromium.chrome.browser.download.DownloadTestRule;
import org.chromium.chrome.browser.download.DownloadTestRule.CustomMainActivityStart;
......@@ -429,7 +429,8 @@ public class ContextMenuTest implements CustomMainActivityStart {
R.id.contextmenu_copy_link_text, R.id.contextmenu_copy_link_address,
R.id.contextmenu_share_link};
Integer[] featureItems = {R.id.contextmenu_open_in_ephemeral_tab};
expectedItems = addItemsIf(EphemeralTabPanel.isSupported(), expectedItems, featureItems);
expectedItems =
addItemsIf(EphemeralTabCoordinator.isSupported(), expectedItems, featureItems);
assertMenuItemsAreEqual(menu, expectedItems);
}
......@@ -446,7 +447,8 @@ public class ContextMenuTest implements CustomMainActivityStart {
R.id.contextmenu_open_image_in_new_tab, R.id.contextmenu_search_by_image,
R.id.contextmenu_share_image};
Integer[] featureItems = {R.id.contextmenu_open_image_in_ephemeral_tab};
expectedItems = addItemsIf(EphemeralTabPanel.isSupported(), expectedItems, featureItems);
expectedItems =
addItemsIf(EphemeralTabCoordinator.isSupported(), expectedItems, featureItems);
assertMenuItemsAreEqual(menu, expectedItems);
}
......@@ -464,7 +466,8 @@ public class ContextMenuTest implements CustomMainActivityStart {
R.id.contextmenu_open_image_in_new_tab, R.id.contextmenu_search_with_google_lens,
R.id.contextmenu_share_image};
Integer[] featureItems = {R.id.contextmenu_open_image_in_ephemeral_tab};
expectedItems = addItemsIf(EphemeralTabPanel.isSupported(), expectedItems, featureItems);
expectedItems =
addItemsIf(EphemeralTabCoordinator.isSupported(), expectedItems, featureItems);
assertMenuItemsAreEqual(menu, expectedItems);
}
......@@ -484,7 +487,8 @@ public class ContextMenuTest implements CustomMainActivityStart {
R.id.contextmenu_open_image_in_new_tab, R.id.contextmenu_search_by_image,
R.id.contextmenu_share_image};
Integer[] featureItems = {R.id.contextmenu_open_image_in_ephemeral_tab};
expectedItems = addItemsIf(EphemeralTabPanel.isSupported(), expectedItems, featureItems);
expectedItems =
addItemsIf(EphemeralTabCoordinator.isSupported(), expectedItems, featureItems);
assertMenuItemsAreEqual(menu, expectedItems);
}
......@@ -502,7 +506,8 @@ public class ContextMenuTest implements CustomMainActivityStart {
Integer[] expectedItems = {R.id.contextmenu_save_image,
R.id.contextmenu_open_image_in_new_tab, R.id.contextmenu_share_image};
Integer[] featureItems = {R.id.contextmenu_open_image_in_ephemeral_tab};
expectedItems = addItemsIf(EphemeralTabPanel.isSupported(), expectedItems, featureItems);
expectedItems =
addItemsIf(EphemeralTabCoordinator.isSupported(), expectedItems, featureItems);
assertMenuItemsAreEqual(menu, expectedItems);
}
......@@ -522,7 +527,8 @@ public class ContextMenuTest implements CustomMainActivityStart {
Integer[] expectedItems = {R.id.contextmenu_save_image,
R.id.contextmenu_open_image_in_new_tab, R.id.contextmenu_share_image};
Integer[] featureItems = {R.id.contextmenu_open_image_in_ephemeral_tab};
expectedItems = addItemsIf(EphemeralTabPanel.isSupported(), expectedItems, featureItems);
expectedItems =
addItemsIf(EphemeralTabCoordinator.isSupported(), expectedItems, featureItems);
assertMenuItemsAreEqual(menu, expectedItems);
}
......@@ -541,7 +547,8 @@ public class ContextMenuTest implements CustomMainActivityStart {
R.id.contextmenu_share_image, R.id.contextmenu_share_link};
Integer[] featureItems = {R.id.contextmenu_open_in_ephemeral_tab,
R.id.contextmenu_open_image_in_ephemeral_tab};
expectedItems = addItemsIf(EphemeralTabPanel.isSupported(), expectedItems, featureItems);
expectedItems =
addItemsIf(EphemeralTabCoordinator.isSupported(), expectedItems, featureItems);
assertMenuItemsAreEqual(menu, expectedItems);
}
......@@ -563,7 +570,8 @@ public class ContextMenuTest implements CustomMainActivityStart {
R.id.contextmenu_share_image, R.id.contextmenu_share_link};
Integer[] featureItems = {R.id.contextmenu_open_in_ephemeral_tab,
R.id.contextmenu_open_image_in_ephemeral_tab};
expectedItems = addItemsIf(EphemeralTabPanel.isSupported(), expectedItems, featureItems);
expectedItems =
addItemsIf(EphemeralTabCoordinator.isSupported(), expectedItems, featureItems);
assertMenuItemsAreEqual(menu, expectedItems);
}
......@@ -589,7 +597,8 @@ public class ContextMenuTest implements CustomMainActivityStart {
R.id.contextmenu_share_image, R.id.contextmenu_share_link};
Integer[] featureItems = {R.id.contextmenu_open_in_ephemeral_tab,
R.id.contextmenu_open_image_in_ephemeral_tab};
expectedItems = addItemsIf(EphemeralTabPanel.isSupported(), expectedItems, featureItems);
expectedItems =
addItemsIf(EphemeralTabCoordinator.isSupported(), expectedItems, featureItems);
assertMenuItemsAreEqual(menu, expectedItems);
}
......
......@@ -2360,8 +2360,6 @@ jumbo_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",
......@@ -2386,8 +2384,6 @@ jumbo_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",
......
// 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 "base/task/cancelable_task_tracker.h"
#include "cc/layers/layer.h"
#include "cc/layers/ui_resource_layer.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "components/favicon/content/content_favicon_driver.h"
#include "content/public/browser/web_contents.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/android/resources/resource_manager.h"
#include "ui/base/l10n/l10n_util_android.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
#include "url/gurl.h"
namespace {
void DisplayFavicon(scoped_refptr<cc::UIResourceLayer> layer,
const SkBitmap& favicon,
const float dp_to_px,
const float panel_width,
const float bar_height,
const float bar_margin,
const base::RepeatingCallback<void()>& favicon_callback) {
const float bounds_width =
android::EphemeralTabLayer::kFaviconWidthDp * dp_to_px;
// Dimension to which favicons are resized - half the size of default icon.
const float icon_size = bounds_width / 2.0f;
const float padding = bar_margin + (bounds_width - icon_size) / 2.0f;
layer->SetBitmap(favicon);
layer->SetBounds(gfx::Size(icon_size, icon_size));
bool is_rtl = l10n_util::IsLayoutRtl();
float icon_x = is_rtl ? panel_width - icon_size - padding : padding;
float icon_y = (bar_height - icon_size) / 2;
layer->SetPosition(gfx::PointF(icon_x, icon_y));
favicon_callback.Run();
}
} // namespace
namespace android {
// static
scoped_refptr<EphemeralTabLayer> EphemeralTabLayer::Create(
ui::ResourceManager* resource_manager,
base::RepeatingCallback<void()>&& favicon_callback) {
return base::WrapRefCounted(
new EphemeralTabLayer(resource_manager, std::move(favicon_callback)));
}
void EphemeralTabLayer::SetProperties(
content::WebContents* web_contents,
int title_view_resource_id,
int caption_view_resource_id,
int security_icon_resource_id,
jfloat security_icon_opacity,
jfloat caption_animation_percentage,
jfloat text_layer_min_height,
jfloat title_caption_spacing,
jboolean caption_visible,
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,
int bar_background_color,
float bar_margin_side,
float bar_margin_top,
float bar_height,
bool bar_border_visible,
float bar_border_height,
int icon_color,
int drag_handlebar_color,
jfloat favicon_opacity,
bool progress_bar_visible,
float progress_bar_height,
float progress_bar_opacity,
float progress_bar_completion,
int separator_line_color,
bool is_new_layout) {
if (web_contents_ != web_contents) {
web_contents_ = web_contents;
if (web_contents_) {
auto* favicon_driver =
favicon::ContentFaviconDriver::FromWebContents(web_contents_);
if (favicon_driver)
favicon_driver->AddObserver(this);
// No need to remove the observer from the previous WebContents since
// it is already destroyed by the time it reaches this point.
}
}
// 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;
float title_opacity = 0.f;
OverlayPanelLayer::SetProperties(
dp_to_px, content_layer, bar_height, panel_x, panel_y, panel_width,
panel_height, bar_background_color, bar_margin_side, bar_margin_top,
bar_height, 0.0f, title_opacity, bar_border_visible, bar_border_height,
icon_color, drag_handlebar_color, 1.0f /* icon opacity */,
separator_line_color);
// Content setup, to center in space below drag handle (when present).
int content_top = bar_top;
int content_height = bar_height;
if (is_new_layout) {
content_top += bar_margin_top;
content_height -= bar_margin_top;
}
SetupTextLayer(content_top, content_height, text_layer_min_height,
caption_view_resource_id, security_icon_resource_id,
security_icon_opacity, caption_animation_percentage,
caption_visible, title_view_resource_id,
title_caption_spacing);
OverlayPanelLayer::SetProgressBar(
progress_bar_background_resource_id, progress_bar_resource_id,
progress_bar_visible, bar_bottom, progress_bar_height,
progress_bar_opacity, progress_bar_completion, panel_width);
dp_to_px_ = dp_to_px;
panel_width_ = panel_width;
bar_height_ = bar_height;
bar_margin_side_ = bar_margin_side;
if (favicon_opacity > 0.f)
favicon_layer_->SetIsDrawable(true);
favicon_layer_->SetOpacity(favicon_opacity);
panel_icon_->SetOpacity(1 - favicon_opacity);
}
void EphemeralTabLayer::SetupTextLayer(float content_top,
float content_height,
float text_layer_min_height,
int caption_view_resource_id,
int security_icon_resource_id,
float security_icon_opacity,
float animation_percentage,
bool caption_visible,
int title_resource_id,
float title_caption_spacing) {
// ---------------------------------------------------------------------------
// Setup the Drawing Hierarchy
// ---------------------------------------------------------------------------
DCHECK(text_layer_.get());
DCHECK(caption_.get());
DCHECK(title_.get());
// Title
ui::Resource* title_resource = resource_manager_->GetResource(
ui::ANDROID_RESOURCE_TYPE_DYNAMIC, title_resource_id);
if (title_resource) {
title_->SetUIResourceId(title_resource->ui_resource()->id());
title_->SetBounds(title_resource->size());
}
// Caption
ui::Resource* caption_resource = nullptr;
if (caption_visible) {
// Grabs the dynamic Search Caption resource so we can get a snapshot.
caption_resource = resource_manager_->GetResource(
ui::ANDROID_RESOURCE_TYPE_DYNAMIC, caption_view_resource_id);
}
if (animation_percentage != 0.f) {
if (caption_->parent() != text_layer_)
text_layer_->AddChild(caption_);
if (security_icon_layer_->parent() != text_layer_)
text_layer_->AddChild(security_icon_layer_);
if (caption_resource) {
caption_->SetUIResourceId(caption_resource->ui_resource()->id());
caption_->SetBounds(caption_resource->size());
}
} else {
if (caption_->parent())
caption_->RemoveFromParent();
if (security_icon_layer_->parent())
security_icon_layer_->RemoveFromParent();
}
// Set up security icon layer
if (security_icon_resource_id) {
ui::Resource* security_icon_resource =
resource_manager_->GetStaticResourceWithTint(security_icon_resource_id,
0);
security_icon_layer_->SetUIResourceId(
security_icon_resource->ui_resource()->id());
security_icon_layer_->SetBounds(gfx::ScaleToRoundedSize(
security_icon_resource->size(), kSecurityIconScale));
}
// ---------------------------------------------------------------------------
// Calculate Text Layer Size
// ---------------------------------------------------------------------------
float title_height = title_->bounds().height();
float caption_height = caption_visible ? caption_->bounds().height() : 0.f;
float layer_height =
std::max(text_layer_min_height,
title_height + caption_height + title_caption_spacing);
float layer_width =
std::max(title_->bounds().width(), caption_->bounds().width());
float layer_top = content_top + (content_height - layer_height) / 2;
text_layer_->SetBounds(gfx::Size(layer_width, layer_height));
text_layer_->SetPosition(gfx::PointF(0.f, layer_top));
text_layer_->SetMasksToBounds(true);
// ---------------------------------------------------------------------------
// Layout Text Layer
// ---------------------------------------------------------------------------
// ---Top of Panel Bar--- <- bar_top
//
// ---Top of Text Layer--- <- layer_top
// } remaining_height / 2
// Title } title_height
// --Bottom of Text Layer-
//
// --Bottom of Panel Bar-
float title_top = (layer_height - title_height) / 2;
// If we aren't displaying the caption we're done.
if (animation_percentage == 0.f || !caption_resource) {
title_->SetPosition(gfx::PointF(0.f, title_top));
return;
}
// Calculate the positions for the Title and Caption when the Caption
// animation is complete.
float remaining_height =
layer_height - title_height - title_caption_spacing - caption_height;
float title_top_end = remaining_height / 2;
float caption_top_end = title_top_end + title_height + title_caption_spacing;
// Interpolate between the animation start and end positions (short cut
// if the animation is at the end or start).
title_top = title_top * (1.f - animation_percentage) +
title_top_end * animation_percentage;
// The Caption starts off the bottom of the Text Layer.
float caption_top = layer_height * (1.f - animation_percentage) +
caption_top_end * animation_percentage;
title_->SetPosition(gfx::PointF(0.f, title_top));
bool is_rtl = l10n_util::IsLayoutRtl();
float caption_left = 0.f;
if (is_rtl && security_icon_resource_id) {
caption_left = security_icon_layer_->bounds().width();
}
caption_->SetPosition(gfx::PointF(caption_left, caption_top));
// Security icon
if (!security_icon_resource_id)
return;
float icon_x;
if (is_rtl) {
icon_x = bar_margin_side_ * 2 + close_icon_->bounds().width();
if (open_tab_icon_resource_id_ != kInvalidResourceID) {
icon_x += bar_margin_side_ * 2 + open_tab_icon_->bounds().width();
}
} else {
icon_x = bar_margin_side_ +
(kFaviconWidthDp + kSecurityIconMarginStartDp) * dp_to_px_;
}
float icon_y = caption_top + (caption_->bounds().height() -
security_icon_layer_->bounds().height()) /
2;
security_icon_layer_->SetPosition(gfx::PointF(icon_x, icon_y));
security_icon_layer_->SetOpacity(security_icon_opacity);
}
void EphemeralTabLayer::OnFaviconUpdated(
favicon::FaviconDriver* favicon_driver,
NotificationIconType notification_icon_type,
const GURL& icon_url,
bool icon_url_changed,
const gfx::Image& image) {
SkBitmap favicon_bitmap =
image.AsImageSkia().GetRepresentation(1.0f).GetBitmap();
if (favicon_bitmap.empty())
return;
std::string host = icon_url.host();
if (host == favicon_url_host_)
return;
favicon_url_host_ = host;
favicon_bitmap.setImmutable();
DisplayFavicon(favicon_layer_, favicon_bitmap, dp_to_px_, panel_width_,
bar_height_, bar_margin_side_, favicon_callback_);
}
void EphemeralTabLayer::OnHide() {
favicon_layer_->SetIsDrawable(false);
favicon_url_host_.clear();
web_contents_ = nullptr;
}
EphemeralTabLayer::EphemeralTabLayer(
ui::ResourceManager* resource_manager,
base::RepeatingCallback<void()>&& favicon_callback)
: OverlayPanelLayer(resource_manager),
favicon_callback_(std::move(favicon_callback)),
title_(cc::UIResourceLayer::Create()),
caption_(cc::UIResourceLayer::Create()),
favicon_layer_(cc::UIResourceLayer::Create()),
security_icon_layer_(cc::UIResourceLayer::Create()),
text_layer_(cc::UIResourceLayer::Create()) {
// Content layer
text_layer_->SetIsDrawable(true);
title_->SetIsDrawable(true);
caption_->SetIsDrawable(true);
security_icon_layer_->SetIsDrawable(true);
AddBarTextLayer(text_layer_);
text_layer_->AddChild(title_);
favicon_layer_->SetIsDrawable(true);
layer_->AddChild(favicon_layer_);
cancelable_task_tracker_.reset(new base::CancelableTaskTracker());
}
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 "chrome/browser/android/compositor/layer/overlay_panel_layer.h"
#include "base/callback.h"
#include "components/favicon/core/favicon_driver_observer.h"
namespace base {
class CancelableTaskTracker;
}
namespace cc {
class Layer;
}
namespace content {
class WebContents;
}
namespace favicon {
class FaviconDriver;
}
namespace ui {
class ResourceManager;
}
namespace android {
class EphemeralTabLayer : public OverlayPanelLayer,
public favicon::FaviconDriverObserver {
public:
static constexpr float kFaviconWidthDp =
OverlayPanelLayer::kDefaultIconWidthDp;
// Scale factor used to make the security icon size smaller to fit in the
// header.
static constexpr float kSecurityIconScale = 0.8f;
// Left margin that positions the icon in front of the caption.
static constexpr float kSecurityIconMarginStartDp = 8.f;
static scoped_refptr<EphemeralTabLayer> Create(
ui::ResourceManager* resource_manager,
base::RepeatingCallback<void()>&& favicon_callback);
void SetProperties(content::WebContents* web_contents,
int title_view_resource_id,
int caption_view_resource_id,
int security_icon_resource_id,
jfloat security_icon_opacity,
jfloat caption_animation_percentage,
jfloat text_layer_min_height,
jfloat title_caption_spacing,
jboolean caption_visible,
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,
int bar_background_color,
float bar_margin_side,
float bar_margin_top,
float bar_height,
bool bar_border_visible,
float bar_border_height,
int icon_color,
int drag_handlebar_color,
jfloat favicon_opacity,
bool progress_bar_visible,
float progress_bar_height,
float progress_bar_opacity,
float progress_bar_completion,
int separator_line_color,
bool is_new_layout);
void SetupTextLayer(float bar_top,
float bar_height,
float text_layer_min_height,
int caption_view_resource_id,
int security_icon_resource_id,
float security_icon_opacity,
float animation_percentage,
bool caption_visible,
int context_resource_id,
float title_caption_spacing);
void OnHide();
// favicon::FaviconDriverObserver
void OnFaviconUpdated(favicon::FaviconDriver* favicon_driver,
NotificationIconType notification_icon_type,
const GURL& icon_url,
bool icon_url_changed,
const gfx::Image& image) override;
protected:
EphemeralTabLayer(ui::ResourceManager* resource_manager,
base::RepeatingCallback<void()>&& favicon_callback);
~EphemeralTabLayer() override;
private:
content::WebContents* web_contents_ = nullptr;
float dp_to_px_;
float panel_width_;
float bar_height_;
float bar_margin_side_;
std::string favicon_url_host_;
base::RepeatingCallback<void()> favicon_callback_;
scoped_refptr<cc::UIResourceLayer> title_;
scoped_refptr<cc::UIResourceLayer> caption_;
scoped_refptr<cc::UIResourceLayer> favicon_layer_;
scoped_refptr<cc::UIResourceLayer> security_icon_layer_;
scoped_refptr<cc::UIResourceLayer> text_layer_;
std::unique_ptr<base::CancelableTaskTracker> cancelable_task_tracker_;
};
} // 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/callback.h"
#include "cc/layers/solid_color_layer.h"
#include "chrome/android/chrome_jni_headers/EphemeralTabSceneLayer_jni.h"
#include "chrome/browser/android/compositor/layer/ephemeral_tab_layer.h"
#include "content/public/browser/web_contents.h"
#include "ui/android/resources/resource_manager_impl.h"
#include "ui/android/view_android.h"
using base::android::JavaParamRef;
using base::android::JavaRef;
using base::android::ScopedJavaGlobalRef;
namespace {
void OnFaviconAvailable(const ScopedJavaGlobalRef<jobject>& object) {
JNIEnv* env = base::android::AttachCurrentThread();
android::Java_FaviconCallback_onAvailable(env, object);
}
} // namespace
namespace android {
EphemeralTabSceneLayer::EphemeralTabSceneLayer(JNIEnv* env,
const JavaRef<jobject>& jobj)
: SceneLayer(env, jobj),
base_page_brightness_(1.0f),
content_container_(cc::Layer::Create()),
is_new_layout_(false) {
// 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,
const JavaParamRef<jobject>& jcallback) {
ui::ResourceManager* resource_manager =
ui::ResourceManagerImpl::FromJavaObject(jresource_manager);
ScopedJavaGlobalRef<jobject> java_obj(jcallback);
ephemeral_tab_layer_ = EphemeralTabLayer::Create(
resource_manager, base::BindRepeating(&OnFaviconAvailable, java_obj));
// 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 panel_shadow_resource_id,
jint rounded_bar_top_resource_id,
jint bar_shadow_resource_id,
jint panel_icon_resource_id,
jint drag_handlebar_resource_id,
jint open_tab_icon_resource_id,
jint close_icon_resource_id) {
is_new_layout_ = rounded_bar_top_resource_id > 0;
ephemeral_tab_layer_->SetResourceIds(
text_resource_id, panel_shadow_resource_id, rounded_bar_top_resource_id,
bar_shadow_resource_id, panel_icon_resource_id,
drag_handlebar_resource_id, open_tab_icon_resource_id,
close_icon_resource_id);
}
void EphemeralTabSceneLayer::Update(JNIEnv* env,
const JavaParamRef<jobject>& object,
jint title_view_resource_id,
jint caption_view_resource_id,
jint caption_icon_resource_id,
jfloat caption_icon_opacity,
jfloat caption_animation_percentage,
jfloat text_layer_min_height,
jfloat title_caption_spacing,
jboolean caption_visible,
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,
jint bar_background_color,
jfloat bar_margin_side,
jfloat bar_margin_top,
jfloat bar_height,
jboolean bar_border_visible,
jfloat bar_border_height,
jint icon_color,
jint drag_handlebar_color,
jfloat favicon_opacity,
jboolean progress_bar_visible,
jfloat progress_bar_height,
jfloat progress_bar_opacity,
jfloat progress_bar_completion,
jint separator_line_color) {
// 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(
web_contents, title_view_resource_id, caption_view_resource_id,
caption_icon_resource_id, caption_icon_opacity,
caption_animation_percentage, text_layer_min_height,
title_caption_spacing, caption_visible,
progress_bar_background_resource_id, progress_bar_resource_id, dp_to_px,
content_layer, panel_x, panel_y, panel_width, panel_height,
bar_background_color, bar_margin_side, bar_margin_top, bar_height,
bar_border_visible, bar_border_height, icon_color, drag_handlebar_color,
favicon_opacity, progress_bar_visible, progress_bar_height,
progress_bar_opacity, progress_bar_completion, separator_line_color,
is_new_layout_);
// 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_->OnHide();
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 "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "chrome/browser/android/compositor/scene_layer/scene_layer.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,
const base::android::JavaParamRef<jobject>& jfavicon_callback);
void SetResourceIds(JNIEnv* env,
const base::android::JavaParamRef<jobject>& object,
jint text_resource_id,
jint panel_shadow_resource_id,
jint rounded_bar_top_resource_id,
jint bar_shadow_resource_id,
jint panel_icon_resource_id,
jint drag_handlebar_resource_id,
jint open_tab_icon_resource_id,
jint close_icon_resource_id);
void Update(JNIEnv* env,
const base::android::JavaParamRef<jobject>& object,
jint title_view_resource_id,
jint caption_view_resource_id,
jint caption_icon_resource_id,
jfloat caption_icon_opacity,
jfloat caption_animation_percentage,
jfloat text_layer_min_height,
jfloat term_caption_spacing,
jboolean caption_visible,
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,
jint bar_background_color,
jfloat bar_margin_side,
jfloat bar_margin_top,
jfloat bar_height,
jboolean bar_border_visible,
jfloat bar_border_height,
jint icon_color,
jint drag_handlebar_color,
jfloat favicon_opacity,
jboolean progress_bar_visible,
jfloat progress_bar_height,
jfloat progress_bar_opacity,
jfloat progress_bar_completion,
jint separator_line_color);
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_;
bool is_new_layout_;
DISALLOW_COPY_AND_ASSIGN(EphemeralTabSceneLayer);
};
bool RegisterEphemeralTabSceneLayer(JNIEnv* env);
} // namespace android
#endif // CHROME_BROWSER_ANDROID_COMPOSITOR_SCENE_LAYER_EPHEMERAL_TAB_SCENE_LAYER_H_
......@@ -76,7 +76,6 @@ extern const base::Feature kDownloadProgressInfoBar;
extern const base::Feature kDownloadRename;
extern const base::Feature kDrawVerticallyEdgeToEdge;
extern const base::Feature kDuetTabStripIntegrationAndroid;
extern const base::Feature kEphemeralTab;
extern const base::Feature kEphemeralTabUsingBottomSheet;
extern const base::Feature kExploreSites;
extern const base::Feature kFocusOmniboxInIncognitoTabIntents;
......
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