From 27c9cd90f106df93d966d72c8acda657de1ff32d Mon Sep 17 00:00:00 2001 From: Zach Katz Date: Fri, 27 Jan 2023 23:59:40 +0000 Subject: [PATCH] [PCCT-SideSheet] 1P/3P gating with width getters - Add intent extras for width - #getInitialActivityWidth Bug: 1409751 Change-Id: Id2b61058e6885c86489929da2e0507bc14a13727 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4195686 Reviewed-by: Jinsuk Kim Reviewed-by: Kevin Grosu Reviewed-by: Theresa Sullivan Commit-Queue: Zach Katz Cr-Commit-Position: refs/heads/main@{#1098191} --- .../CustomTabIntentDataProvider.java | 37 +++++++++++++- .../customtabs/CustomTabsFeatureUsage.java | 6 ++- .../CustomTabIntentDataProviderTest.java | 50 +++++++++++++++++++ .../BrowserServicesIntentDataProvider.java | 19 ++++++- 4 files changed, 107 insertions(+), 5 deletions(-) diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java index 90a3afedea789..1f7c1813031cb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java @@ -240,6 +240,13 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid public static final String EXTRA_ACTIVITY_HEIGHT_RESIZE_BEHAVIOR = "androidx.browser.customtabs.extra.ACTIVITY_HEIGHT_RESIZE_BEHAVIOR"; + /** + * Extra that, if set, makes the Custom Tab Activity's width to be x pixels, the Custom Tab + * will behave as a side sheet. x will be clamped between 33% and 100% of screen width. + */ + public static final String EXTRA_INITIAL_ACTIVITY_WIDTH_PX = + "androidx.browser.customtabs.extra.INITIAL_ACTIVITY_WIDTH_PX"; + /** * Extra that, if set, makes the toolbar's top corner radii to be x pixels. This will only have * effect if the custom tab is behaving as a bottom sheet. Currently, this is capped at 16dp. @@ -318,6 +325,7 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid private final ColorProvider mColorProvider; private final @Px int mInitialActivityHeight; + private final @Px int mInitialActivityWidth; private final @Px int mPartialTabToolbarCornerRadius; private final boolean mIsPartialCustomTabFixedHeight; @@ -360,7 +368,9 @@ private static String getClientPackageNameFromSessionOrCallingActivity( } public static void configureIntentForResizableCustomTab(Context context, Intent intent) { - if (getInitialActivityHeightFromIntent(intent) == 0) { + if (getInitialActivityHeightFromIntent(intent) == 0 + && (!ChromeFeatureList.sCctResizableSideSheet.isEnabled() + || getInitialActivityWidthFromIntent(intent) == 0)) { // fallback to normal Custom Tab. return; } @@ -379,6 +389,12 @@ private static int getInitialActivityHeightFromIntent(Intent intent) { return heightPx2 > 0 ? heightPx2 : 0; } + private static int getInitialActivityWidthFromIntent(Intent intent) { + int widthPx = IntentUtils.safeGetIntExtra( + intent, CustomTabIntentDataProvider.EXTRA_INITIAL_ACTIVITY_WIDTH_PX, 0); + return widthPx > 0 ? widthPx : 0; + } + /** * Get the package name from {@link #getReferrerUriString(Activity)}. If the referrer format * is invalid, return an empty string. @@ -494,6 +510,7 @@ public CustomTabIntentDataProvider(Intent intent, Context context, int colorSche CustomTabsConnection.getInstance().setupDynamicFeatures(intent); mInitialActivityHeight = getInitialActivityHeightFromIntent(intent); + mInitialActivityWidth = getInitialActivityWidthFromIntent(intent); mPartialTabToolbarCornerRadius = getToolbarCornerRadiusFromIntent(context, intent); // The default behavior is that the PCCT's height is resizable. @@ -799,6 +816,9 @@ private void logCustomTabFeatures( if (isPartialHeightCustomTab()) { featureUsage.log(CustomTabsFeature.CTF_PARTIAL); } + if (isPartialWidthCustomTab()) { + featureUsage.log(CustomTabsFeature.CTF_PARTIAL_SIDE_SHEET); + } if (mRemoteViewsPendingIntent != null) { featureUsage.log(CustomTabsFeature.EXTRA_REMOTEVIEWS_PENDINGINTENT); } @@ -877,6 +897,11 @@ public boolean isPartialHeightCustomTab() { return getInitialActivityHeight() > 0; } + @Override + public boolean isPartialWidthCustomTab() { + return getInitialActivityWidth() > 0; + } + @Override public boolean shouldAnimateOnFinish() { return mAnimationBundle != null && getClientPackageName() != null; @@ -1136,6 +1161,16 @@ public int[] getGsaExperimentIds() { return (mIsTrustedIntent || enabledDueToThirdParty) ? mInitialActivityHeight : 0; } + @Override + public @Px int getInitialActivityWidth() { + if (!ChromeFeatureList.sCctResizableSideSheet.isEnabled()) return 0; + + boolean enabledDueToThirdParty = + ChromeFeatureList.sCctResizableSideSheetForThirdParties.isEnabled() + && isAllowedThirdParty(getClientPackageName()); + return (mIsTrustedIntent || enabledDueToThirdParty) ? mInitialActivityWidth : 0; + } + boolean isAllowedThirdParty(String packageName) { if (packageName == null) return false; String defaultPolicy = THIRD_PARTIES_DEFAULT_POLICY.getValue(); diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsFeatureUsage.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsFeatureUsage.java index 1a136d99fa7df..0e7f74ec4f96e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsFeatureUsage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsFeatureUsage.java @@ -46,7 +46,8 @@ public class CustomTabsFeatureUsage { CustomTabsFeature.EXTRA_ADDITIONAL_TRUSTED_ORIGINS, CustomTabsFeature.EXTRA_ENABLE_URLBAR_HIDING, CustomTabsFeature.EXTRA_AUTO_TRANSLATE_LANGUAGE, - CustomTabsFeature.EXTRA_INTENT_FEATURE_OVERRIDES, CustomTabsFeature.COUNT}) + CustomTabsFeature.EXTRA_INTENT_FEATURE_OVERRIDES, + CustomTabsFeature.CTF_PARTIAL_SIDE_SHEET, CustomTabsFeature.COUNT}) @Retention(RetentionPolicy.SOURCE) public @interface CustomTabsFeature { /** Special enum for the start of a session. */ @@ -94,9 +95,10 @@ public class CustomTabsFeatureUsage { int EXTRA_ENABLE_URLBAR_HIDING = 41; int EXTRA_AUTO_TRANSLATE_LANGUAGE = 42; int EXTRA_INTENT_FEATURE_OVERRIDES = 43; + int CTF_PARTIAL_SIDE_SHEET = 44; /** Total count of entries. */ - int COUNT = 44; + int COUNT = 45; } // Whether flag-enabled or not. diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java index 79c5294a44b99..79a05712bb0f7 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProviderTest.java @@ -312,6 +312,56 @@ public void testInitialActivityHeight_1stParty() { assertEquals(50, dataProvider.getInitialActivityHeight()); } + @Test + public void testInitialActivityWidth_1Pdisabled() { + ChromeFeatureList.sCctResizableSideSheet.setForTesting(false); + Intent intent = new CustomTabsIntent.Builder().build().intent; + intent.putExtra(CustomTabIntentDataProvider.EXTRA_INITIAL_ACTIVITY_WIDTH_PX, 50); + var dataProvider = new CustomTabIntentDataProvider(intent, mContext, COLOR_SCHEME_LIGHT); + assertEquals("Width should be 0", 0, dataProvider.getInitialActivityWidth()); + } + + @Test + public void testInitialActivityWidth_3Penabled_notdenied() { + ChromeFeatureList.sCctResizableSideSheet.setForTesting(true); + ChromeFeatureList.sCctResizableSideSheetForThirdParties.setForTesting(true); + Intent intent = new CustomTabsIntent.Builder().build().intent; + intent.putExtra(CustomTabIntentDataProvider.EXTRA_INITIAL_ACTIVITY_WIDTH_PX, 50); + CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class); + when(connection.getClientPackageNameForSession(any())).thenReturn("com.pixar.woody"); + CustomTabsConnection.setInstanceForTesting(connection); + var dataProvider = new CustomTabIntentDataProvider(intent, mContext, COLOR_SCHEME_LIGHT); + assertEquals("Width should be 50", 50, dataProvider.getInitialActivityWidth()); + } + + @Test + public void testInitialActivityWidth_3Penabled_denied() { + ChromeFeatureList.sCctResizableSideSheet.setForTesting(true); + ChromeFeatureList.sCctResizableSideSheetForThirdParties.setForTesting(true); + Intent intent = new CustomTabsIntent.Builder().build().intent; + intent.putExtra(CustomTabIntentDataProvider.EXTRA_INITIAL_ACTIVITY_WIDTH_PX, 50); + CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class); + when(connection.getClientPackageNameForSession(any())).thenReturn("com.dc.joker"); + CustomTabsConnection.setInstanceForTesting(connection); + var dataProvider = new CustomTabIntentDataProvider(intent, mContext, COLOR_SCHEME_LIGHT); + CustomTabIntentDataProvider.DENYLIST_ENTRIES.setForTesting( + "com.dc.joker|com.marvel.thanos"); + assertEquals("Width should be 0", 0, dataProvider.getInitialActivityWidth()); + } + + @Test + public void testInitialActivityWidth_3Pdisabled() { + ChromeFeatureList.sCctResizableSideSheet.setForTesting(true); + ChromeFeatureList.sCctResizableSideSheetForThirdParties.setForTesting(false); + Intent intent = new CustomTabsIntent.Builder().build().intent; + intent.putExtra(CustomTabIntentDataProvider.EXTRA_INITIAL_ACTIVITY_WIDTH_PX, 50); + CustomTabsConnection connection = Mockito.mock(CustomTabsConnection.class); + when(connection.isFirstParty(any())).thenReturn(true); + CustomTabsConnection.setInstanceForTesting(connection); + var dataProvider = new CustomTabIntentDataProvider(intent, mContext, COLOR_SCHEME_LIGHT); + assertEquals("Width should be 50", 50, dataProvider.getInitialActivityWidth()); + } + @Test public void partialCustomTabHeightResizeBehavior_Default() { Intent intent = new Intent().putExtra( diff --git a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java index c62477117ef46..49667dce23563 100644 --- a/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java +++ b/chrome/browser/android/browserservices/intents/java/src/org/chromium/chrome/browser/browserservices/intents/BrowserServicesIntentDataProvider.java @@ -474,20 +474,35 @@ public int[] getGsaExperimentIds() { } /** - * @return Whether the intent is for partial-height custom tabs. + * @return Whether the intent is for partial custom tabs bottom sheet. */ public boolean isPartialHeightCustomTab() { return false; } /** - * @return The value in pixels of the initial height of the Activity. It will return 0 if there + * @return Whether the intent is for partial custom tabs side sheet. + */ + public boolean isPartialWidthCustomTab() { + return false; + } + + /** + * @return The value in pixels of the initial height of the Activity. It will return 0 if there * is no value set. */ public @Px int getInitialActivityHeight() { return 0; } + /** + * @return The value in pixels of the initial width of the Activity. It will return 0 if there + * is no value set. + */ + public @Px int getInitialActivityWidth() { + return 0; + } + /** * Returns the {@link CloseButtonPosition}. */