Skip to content

Commit

Permalink
[PCCT-SideSheet] Introduce the onActivityLayout callback
Browse files Browse the repository at this point in the history
Communicate to embedders each time the Custom Tab Activity changes its layout on the screen, including the first time it is rendered. The left-top and right-bottom coordinates will be passed. As part of this the state of the Custom Tab will be shared as well, meaning if the Custom Tab Activity is displayed as full-screen or as bottom-sheet/side-sheet in their minimized/maximized states.

Low-Coverage-Reason: only added a new parameter to the constructor and its functionality is well tested within the class.

Bug: 1406107
Change-Id: Iea6632801949370be5d59d6a17620649ca79ce9d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4343036
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
Reviewed-by: Theresa Sullivan <twellington@chromium.org>
Commit-Queue: Kevin Grosu <kgrosu@google.com>
Cr-Commit-Position: refs/heads/main@{#1120316}
  • Loading branch information
kgrosu authored and Chromium LUCI CQ committed Mar 22, 2023
1 parent e17b007 commit b9ac333
Show file tree
Hide file tree
Showing 16 changed files with 539 additions and 60 deletions.
Expand Up @@ -56,6 +56,7 @@
import org.chromium.chrome.browser.browserservices.PostMessageHandler;
import org.chromium.chrome.browser.browserservices.SessionDataHolder;
import org.chromium.chrome.browser.browserservices.SessionHandler;
import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ActivityLayoutState;
import org.chromium.chrome.browser.customtabs.features.sessionrestore.SessionRestoreManager;
import org.chromium.chrome.browser.customtabs.features.sessionrestore.SessionRestoreManagerImpl;
import org.chromium.chrome.browser.device.DeviceClassManager;
Expand Down Expand Up @@ -171,6 +172,19 @@ public class CustomTabsConnection {
private static final String ON_RESIZED_CALLBACK = "onResized";
private static final String ON_RESIZED_SIZE_EXTRA = "size";

@VisibleForTesting
static final String ON_ACTIVITY_LAYOUT_CALLBACK = "onActivityLayout";
@VisibleForTesting
static final String ON_ACTIVITY_LAYOUT_LEFT_EXTRA = "left";
@VisibleForTesting
static final String ON_ACTIVITY_LAYOUT_TOP_EXTRA = "top";
@VisibleForTesting
static final String ON_ACTIVITY_LAYOUT_RIGHT_EXTRA = "right";
@VisibleForTesting
static final String ON_ACTIVITY_LAYOUT_BOTTOM_EXTRA = "bottom";
@VisibleForTesting
static final String ON_ACTIVITY_LAYOUT_STATE_EXTRA = "state";

private static final String ON_VERTICAL_SCROLL_EVENT_CALLBACK = "onVerticalScrollEvent";
private static final String ON_VERTICAL_SCROLL_EVENT_IS_DIRECTION_UP_EXTRA = "isDirectionUp";
private static final String ON_GREATEST_SCROLL_PERCENTAGE_INCREASED_CALLBACK =
Expand Down Expand Up @@ -1237,6 +1251,28 @@ public void onResized(@Nullable CustomTabsSessionToken session, int height, int
logCallback("onActivityResized()", "(" + height + "x" + width + ")");
}

/**
* Called when the Custom Tab's layout has changed.
* @param left The left coordinate of the custom tab window in pixels
* @param top The top coordinate of the custom tab window in pixels
* @param right The right coordinate of the custom tab window in pixels
* @param bottom The bottom coordinate of the custom tab window in pixels
* @param state The current layout state in which the Custom Tab is displayed.
*/
public void onActivityLayout(@Nullable CustomTabsSessionToken session, int left, int top,
int right, int bottom, @ActivityLayoutState int state) {
Bundle args = new Bundle();
args.putInt(ON_ACTIVITY_LAYOUT_LEFT_EXTRA, left);
args.putInt(ON_ACTIVITY_LAYOUT_TOP_EXTRA, top);
args.putInt(ON_ACTIVITY_LAYOUT_RIGHT_EXTRA, right);
args.putInt(ON_ACTIVITY_LAYOUT_BOTTOM_EXTRA, bottom);
args.putInt(ON_ACTIVITY_LAYOUT_STATE_EXTRA, state);

if (safeExtraCallback(session, ON_ACTIVITY_LAYOUT_CALLBACK, args) && mLogRequests) {
logCallback("extraCallback(" + ON_ACTIVITY_LAYOUT_CALLBACK + ")", args);
}
}

/**
* Notifies the application of a vertical scroll event, i.e. when a scroll started or changed
* direction.
Expand Down
Expand Up @@ -11,6 +11,7 @@
import androidx.annotation.Px;
import androidx.browser.customtabs.CustomTabsSessionToken;

import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ActivityLayoutState;
import org.chromium.chrome.browser.customtabs.CustomTabsConnection;
import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
import org.chromium.chrome.browser.findinpage.FindToolbarObserver;
Expand All @@ -28,6 +29,13 @@ interface OnResizedCallback {
void onResized(int height, int width);
}

/** A callback to be called once the Custom Tab's layout has changed. */
interface OnActivityLayoutCallback {
/** The Custom Tab's layout has changed. */
void onActivityLayout(
int left, int top, int right, int bottom, @ActivityLayoutState int state);
}

public static CustomTabHeightStrategy createStrategy(Activity activity, @Px int initialHeight,
@Px int initialWidth, int breakPointDp, boolean isPartialCustomTabFixedHeight,
CustomTabsConnection connection, @Nullable CustomTabsSessionToken session,
Expand All @@ -44,13 +52,19 @@ public static CustomTabHeightStrategy createStrategy(Activity activity, @Px int
breakPointDp, isPartialCustomTabFixedHeight,
(height, width)
-> connection.onResized(session, height, width),
(left, top, right, bottom, state)
-> connection.onActivityLayout(
session, left, top, right, bottom, state),
lifecycleDispatcher, fullscreenManager, isTablet, interactWithBackground,
showMaximizeButton, decorationType, sideSheetPosition, sideSheetAnimation);
} else {
return new PartialCustomTabBottomSheetStrategy(activity, initialHeight,
isPartialCustomTabFixedHeight,
(height, width)
-> connection.onResized(session, height, width),
(left, top, right, bottom, state)
-> connection.onActivityLayout(
session, left, top, right, bottom, state),
lifecycleDispatcher, fullscreenManager, isTablet, interactWithBackground, false,
new PartialCustomTabHandleStrategyFactory());
}
Expand Down
Expand Up @@ -6,6 +6,8 @@

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;

import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_FULL_SCREEN;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
Expand All @@ -29,7 +31,9 @@
import androidx.annotation.VisibleForTesting;

import org.chromium.chrome.R;
import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ActivityLayoutState;
import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.fullscreen.FullscreenManager;
import org.chromium.chrome.browser.fullscreen.FullscreenOptions;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
Expand All @@ -47,6 +51,7 @@ public abstract class PartialCustomTabBaseStrategy
extends CustomTabHeightStrategy implements FullscreenManager.Observer {
protected final Activity mActivity;
protected final OnResizedCallback mOnResizedCallback;
protected final OnActivityLayoutCallback mOnActivityLayoutCallback;
protected final FullscreenManager mFullscreenManager;
protected final boolean mIsTablet;
protected final boolean mInteractWithBackground;
Expand Down Expand Up @@ -103,10 +108,12 @@ public abstract class PartialCustomTabBaseStrategy
}

public PartialCustomTabBaseStrategy(Activity activity, OnResizedCallback onResizedCallback,
FullscreenManager fullscreenManager, boolean isTablet, boolean interactWithBackground,
OnActivityLayoutCallback onActivityLayoutCallback, FullscreenManager fullscreenManager,
boolean isTablet, boolean interactWithBackground,
PartialCustomTabHandleStrategyFactory handleStrategyFactory) {
mActivity = activity;
mOnResizedCallback = onResizedCallback;
mOnActivityLayoutCallback = onActivityLayoutCallback;
mIsTablet = isTablet;
mInteractWithBackground = interactWithBackground;

Expand Down Expand Up @@ -212,6 +219,15 @@ public void onExitFullscreen(Tab tab) {

protected void maybeInvokeResizeCallback() {
WindowManager.LayoutParams attrs = mActivity.getWindow().getAttributes();

if (ChromeFeatureList.sCctResizableSideSheet.isEnabled()) {
// onActivityLayout should be called before onResized and only when the PCCT is created
// or its size has changed.
if (mHeight != attrs.height || mWidth != attrs.width) {
invokeActivityLayoutCallback();
}
}

if (isFullHeight() || isFullscreen()) {
mOnResizedCallback.onResized(mDisplayHeight, mDisplayWidth);
mHeight = mDisplayHeight;
Expand All @@ -225,9 +241,33 @@ protected void maybeInvokeResizeCallback() {
}
}

protected void invokeActivityLayoutCallback() {
@ActivityLayoutState
int activityLayoutState = getActivityLayoutState();

// If we are in full screen then we manually need to set the values as we are using
// MATCH_PARENT which has the value -1.
int left = 0;
int top = 0;
int right = mDisplayWidth;
int bottom = mDisplayHeight;
if (activityLayoutState != ACTIVITY_LAYOUT_STATE_FULL_SCREEN) {
WindowManager.LayoutParams attrs = mActivity.getWindow().getAttributes();
left = attrs.x;
top = attrs.y;
right = left + attrs.width;
bottom = top + attrs.height;
}

mOnActivityLayoutCallback.onActivityLayout(left, top, right, bottom, activityLayoutState);
}

@PartialCustomTabType
public abstract int getStrategyType();

@ActivityLayoutState
protected abstract int getActivityLayoutState();

protected abstract void updatePosition();

protected abstract int getHandleHeight();
Expand Down
Expand Up @@ -6,6 +6,10 @@

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;

import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_BOTTOM_SHEET;
import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_BOTTOM_SHEET_MAXIMIZED;
import static org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ACTIVITY_LAYOUT_STATE_FULL_SCREEN;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
Expand Down Expand Up @@ -36,6 +40,7 @@
import org.chromium.base.SysUtils;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider.ActivityLayoutState;
import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.fullscreen.FullscreenManager;
Expand Down Expand Up @@ -129,11 +134,12 @@ public class PartialCustomTabBottomSheetStrategy extends PartialCustomTabBaseStr

public PartialCustomTabBottomSheetStrategy(Activity activity, @Px int initialHeight,
boolean isFixedHeight, OnResizedCallback onResizedCallback,
OnActivityLayoutCallback onActivityLayoutCallback,
ActivityLifecycleDispatcher lifecycleDispatcher, FullscreenManager fullscreenManager,
boolean isTablet, boolean interactWithBackground, boolean startMaximized,
PartialCustomTabHandleStrategyFactory handleStrategyFactory) {
super(activity, onResizedCallback, fullscreenManager, isTablet, interactWithBackground,
handleStrategyFactory);
super(activity, onResizedCallback, onActivityLayoutCallback, fullscreenManager, isTablet,
interactWithBackground, handleStrategyFactory);

int animTime = mActivity.getResources().getInteger(android.R.integer.config_mediumAnimTime);
mTabAnimator = new TabAnimator(this, animTime, this::onMoveEnd);
Expand Down Expand Up @@ -290,6 +296,18 @@ protected void cleanupImeStateCallback() {
}
}

@Override
@ActivityLayoutState
protected int getActivityLayoutState() {
if (isFullscreen()) {
return ACTIVITY_LAYOUT_STATE_FULL_SCREEN;
} else if (isMaximized()) {
return ACTIVITY_LAYOUT_STATE_BOTTOM_SHEET_MAXIMIZED;
} else {
return ACTIVITY_LAYOUT_STATE_BOTTOM_SHEET;
}
}

@Override
protected void adjustCornerRadius(GradientDrawable d, int radius) {
d.mutate();
Expand Down Expand Up @@ -397,10 +415,19 @@ private void positionAtWidth(int width) {

int density = (int) (mActivity.getResources().getDisplayMetrics().density);
WindowManager.LayoutParams attrs = mActivity.getWindow().getAttributes();
if (isLandscapeMaxWidth(width)) {
width = BOTTOM_SHEET_MAX_WIDTH_DP_LANDSCAPE * density;
if (isFullHeight() || isFullscreen()) {
attrs.width = MATCH_PARENT;
attrs.x = 0;
} else {
int x = 0;
if (isLandscapeMaxWidth(width)) {
width = BOTTOM_SHEET_MAX_WIDTH_DP_LANDSCAPE * density;
x = (mDisplayWidth - width) / 2;
}
attrs.width = width;
attrs.x = x;
}
attrs.width = width;

mActivity.getWindow().setAttributes(attrs);
}

Expand All @@ -415,9 +442,11 @@ private void positionAtHeight(int height) {
}

if (ChromeFeatureList.sCctResizableSideSheet.isEnabled()) {
attrs.x = 0;
attrs.gravity = Gravity.TOP | Gravity.START;
} else {
attrs.gravity = Gravity.TOP;
}
attrs.gravity = Gravity.TOP;

mActivity.getWindow().setAttributes(attrs);
}

Expand Down Expand Up @@ -787,6 +816,7 @@ public void onEnterFullscreen(Tab tab, FullscreenOptions options) {
// Enter fullscreen i.e. (x, y, height, width) = (0, 0, MATCH_PARENT, MATCH_PARENT)
assert isFullscreen() : "Fullscreen mode should be on";
positionAtHeight(/*height=*/0); // |height| is not used
positionAtWidth(/*width=*/0); // |width| is not used
setTopMargins(0, 0);
maybeInvokeResizeCallback();
}
Expand Down Expand Up @@ -817,6 +847,7 @@ protected boolean shouldDrawDividerLine() {
// Restore the window upon exiting fullscreen.
private void restoreWindow() {
initializeHeight();
positionAtWidth(mVersionCompat.getDisplayWidth());
updateShadowOffset();
maybeInvokeResizeCallback();

Expand Down
Expand Up @@ -45,6 +45,7 @@ public class PartialCustomTabDisplayManager
private final @Px int mUnclampedInitialWidth;
private final boolean mIsFixedHeight;
private final OnResizedCallback mOnResizedCallback;
private final OnActivityLayoutCallback mOnActivityLayoutCallback;
private final ActivityLifecycleDispatcher mActivityLifecycleDispatcher;
private final FullscreenManager mFullscreenManager;
private final boolean mIsTablet;
Expand Down Expand Up @@ -72,16 +73,17 @@ PartialCustomTabBaseStrategy createForType(@PartialCustomTabType int type,

public PartialCustomTabDisplayManager(Activity activity, @Px int initialHeight,
@Px int initialWidth, int breakPointDp, boolean isFixedHeight,
OnResizedCallback onResizedCallback, ActivityLifecycleDispatcher lifecycleDispatcher,
FullscreenManager fullscreenManager, boolean isTablet, boolean interactWithBackground,
boolean showMaximizeButton, int decorationType, int sideSheetPosition,
int sideSheetAnimation) {
OnResizedCallback onResizedCallback, OnActivityLayoutCallback onActivityLayoutCallback,
ActivityLifecycleDispatcher lifecycleDispatcher, FullscreenManager fullscreenManager,
boolean isTablet, boolean interactWithBackground, boolean showMaximizeButton,
int decorationType, int sideSheetPosition, int sideSheetAnimation) {
mActivity = activity;
mUnclampedInitialHeight = initialHeight;
mUnclampedInitialWidth = initialWidth;
mBreakPointDp = breakPointDp;
mIsFixedHeight = isFixedHeight;
mOnResizedCallback = onResizedCallback;
mOnActivityLayoutCallback = onActivityLayoutCallback;
mFullscreenManager = fullscreenManager;
mIsTablet = isTablet;
mInteractWithBackground = interactWithBackground;
Expand Down Expand Up @@ -287,20 +289,21 @@ private PartialCustomTabBaseStrategy createSizeStrategy(@PartialCustomTabType in
switch (type) {
case PartialCustomTabType.BOTTOM_SHEET: {
return new PartialCustomTabBottomSheetStrategy(mActivity, mUnclampedInitialHeight,
mIsFixedHeight, mOnResizedCallback, mActivityLifecycleDispatcher,
mFullscreenManager, mIsTablet, mInteractWithBackground, maximized,
mHandleStrategyFactory);
mIsFixedHeight, mOnResizedCallback, mOnActivityLayoutCallback,
mActivityLifecycleDispatcher, mFullscreenManager, mIsTablet,
mInteractWithBackground, maximized, mHandleStrategyFactory);
}
case PartialCustomTabType.SIDE_SHEET: {
return new PartialCustomTabSideSheetStrategy(mActivity, mUnclampedInitialWidth,
mOnResizedCallback, mFullscreenManager, mIsTablet, mInteractWithBackground,
mShowMaximizeButton, maximized, sideSheetPosition, sideSheetAnimation,
mHandleStrategyFactory, mDecorationType);
mOnResizedCallback, mOnActivityLayoutCallback, mFullscreenManager,
mIsTablet, mInteractWithBackground, mShowMaximizeButton, maximized,
sideSheetPosition, sideSheetAnimation, mHandleStrategyFactory,
mDecorationType);
}
case PartialCustomTabType.FULL_SIZE: {
return new PartialCustomTabFullSizeStrategy(mActivity, mOnResizedCallback,
mFullscreenManager, mIsTablet, mInteractWithBackground,
mHandleStrategyFactory);
mOnActivityLayoutCallback, mFullscreenManager, mIsTablet,
mInteractWithBackground, mHandleStrategyFactory);
}
default: {
assert false : "Partial Custom Tab type not supported: " + type;
Expand Down

0 comments on commit b9ac333

Please sign in to comment.