Commit 658133b6 authored by Peter Kotwicz's avatar Peter Kotwicz Committed by Commit Bot

[Android Webapps] Use CurrentPageVerifier in WebappActivity

This CL:
- Makes WebappActivity use CurrentPageVerifier
- Adds homescreen-shortcut and WebAPK subclasses of Verifier
- Introduces WebappActiveTabUmaTracker for recording metrics about
active tab
- Makes
CustomTabDelegateFactory#shouldDisableExternalIntentRequestsForUrl() use
ExternalIntentsPolicyProvider for Webapps & WebAPKs

BUG=1054718
TESTS=WebApkInitializationTest.testInitialization
      AddToHomescreenCurrentPageVerifierTest.*
      WebApkCurrentPageVerifierTest.*
      CustomTabExternalNavigationTest.testShouldDisableExternalIntentRequestsForUrl

Change-Id: I2bbd0505f28b99569c4bed8fb4e6e10295620eaa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2068116
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Reviewed-by: default avatarPeter Conn <peconn@chromium.org>
Reviewed-by: default avatarGlenn Hartmann <hartmanng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#751874}
parent 3c12eaaf
...@@ -1771,6 +1771,7 @@ chrome_java_sources = [ ...@@ -1771,6 +1771,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/vr/ArDelegateProvider.java", "java/src/org/chromium/chrome/browser/vr/ArDelegateProvider.java",
"java/src/org/chromium/chrome/browser/webapps/ActivateWebApkActivity.java", "java/src/org/chromium/chrome/browser/webapps/ActivateWebApkActivity.java",
"java/src/org/chromium/chrome/browser/webapps/ActivityAssigner.java", "java/src/org/chromium/chrome/browser/webapps/ActivityAssigner.java",
"java/src/org/chromium/chrome/browser/webapps/AddToHomescreenVerifier.java",
"java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java", "java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java",
"java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHostSignature.java", "java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHostSignature.java",
"java/src/org/chromium/chrome/browser/webapps/GooglePlayWebApkInstallDelegate.java", "java/src/org/chromium/chrome/browser/webapps/GooglePlayWebApkInstallDelegate.java",
...@@ -1807,9 +1808,11 @@ chrome_java_sources = [ ...@@ -1807,9 +1808,11 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java",
"java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java",
"java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java",
"java/src/org/chromium/chrome/browser/webapps/WebApkVerifier.java",
"java/src/org/chromium/chrome/browser/webapps/WebApkVersionManager.java", "java/src/org/chromium/chrome/browser/webapps/WebApkVersionManager.java",
"java/src/org/chromium/chrome/browser/webapps/WebDisplayMode.java", "java/src/org/chromium/chrome/browser/webapps/WebDisplayMode.java",
"java/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationManager.java", "java/src/org/chromium/chrome/browser/webapps/WebappActionsNotificationManager.java",
"java/src/org/chromium/chrome/browser/webapps/WebappActiveTabUmaTracker.java",
"java/src/org/chromium/chrome/browser/webapps/WebappActivity.java", "java/src/org/chromium/chrome/browser/webapps/WebappActivity.java",
"java/src/org/chromium/chrome/browser/webapps/WebappActivity0.java", "java/src/org/chromium/chrome/browser/webapps/WebappActivity0.java",
"java/src/org/chromium/chrome/browser/webapps/WebappActivity1.java", "java/src/org/chromium/chrome/browser/webapps/WebappActivity1.java",
...@@ -1838,8 +1841,8 @@ chrome_java_sources = [ ...@@ -1838,8 +1841,8 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java", "java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java",
"java/src/org/chromium/chrome/browser/webapps/WebappManagedActivity.java", "java/src/org/chromium/chrome/browser/webapps/WebappManagedActivity.java",
"java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java", "java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java",
"java/src/org/chromium/chrome/browser/webapps/WebappScopePolicy.java",
"java/src/org/chromium/chrome/browser/webapps/WebappSplashDelegate.java", "java/src/org/chromium/chrome/browser/webapps/WebappSplashDelegate.java",
"java/src/org/chromium/chrome/browser/webapps/WebappVerifier.java",
"java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenCoordinator.java", "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenCoordinator.java",
"java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogView.java", "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenDialogView.java",
"java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenInstaller.java", "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenInstaller.java",
......
...@@ -76,6 +76,7 @@ chrome_test_java_sources = [ ...@@ -76,6 +76,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityTestUtil.java", "javatests/src/org/chromium/chrome/browser/browserservices/TrustedWebActivityTestUtil.java",
"javatests/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPermissionsTest.java", "javatests/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPermissionsTest.java",
"javatests/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPreferencesUiTest.java", "javatests/src/org/chromium/chrome/browser/browserservices/permissiondelegation/TrustedWebActivityPreferencesUiTest.java",
"javatests/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityCurrentPageVerifierTest.java",
"javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataBridgeTest.java", "javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataBridgeTest.java",
"javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java",
"javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataTest.java", "javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataTest.java",
...@@ -522,8 +523,10 @@ chrome_test_java_sources = [ ...@@ -522,8 +523,10 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java", "javatests/src/org/chromium/chrome/browser/video/FullscreenVideoTest.java",
"javatests/src/org/chromium/chrome/browser/video/VideoTest.java", "javatests/src/org/chromium/chrome/browser/video/VideoTest.java",
"javatests/src/org/chromium/chrome/browser/webapps/ActivityAssignerTest.java", "javatests/src/org/chromium/chrome/browser/webapps/ActivityAssignerTest.java",
"javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenCurrentPageVerifierTest.java",
"javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTest.java", "javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTest.java",
"javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTestRule.java", "javatests/src/org/chromium/chrome/browser/webapps/WebApkActivityTestRule.java",
"javatests/src/org/chromium/chrome/browser/webapps/WebApkCurrentPageVerifierTest.java",
"javatests/src/org/chromium/chrome/browser/webapps/WebApkInitializationTest.java", "javatests/src/org/chromium/chrome/browser/webapps/WebApkInitializationTest.java",
"javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/webapps/WebApkIntegrationTest.java",
"javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java", "javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java",
......
...@@ -65,7 +65,10 @@ public class CurrentPageVerifier implements NativeInitObserver { ...@@ -65,7 +65,10 @@ public class CurrentPageVerifier implements NativeInitObserver {
private final CustomTabTabObserver mVerifyOnPageLoadObserver = new CustomTabTabObserver() { private final CustomTabTabObserver mVerifyOnPageLoadObserver = new CustomTabTabObserver() {
@Override @Override
public void onDidFinishNavigation(Tab tab, NavigationHandle navigation) { public void onDidFinishNavigation(Tab tab, NavigationHandle navigation) {
if (!navigation.hasCommitted() || !navigation.isInMainFrame()) return; if (!navigation.hasCommitted() || !navigation.isInMainFrame()
|| navigation.isSameDocument()) {
return;
}
verify(navigation.getUrl()); verify(navigation.getUrl());
} }
......
...@@ -50,7 +50,6 @@ import org.chromium.chrome.browser.webapps.WebappActivity; ...@@ -50,7 +50,6 @@ import org.chromium.chrome.browser.webapps.WebappActivity;
import org.chromium.chrome.browser.webapps.WebappExtras; import org.chromium.chrome.browser.webapps.WebappExtras;
import org.chromium.chrome.browser.webapps.WebappInfo; import org.chromium.chrome.browser.webapps.WebappInfo;
import org.chromium.chrome.browser.webapps.WebappLauncherActivity; import org.chromium.chrome.browser.webapps.WebappLauncherActivity;
import org.chromium.chrome.browser.webapps.WebappScopePolicy;
import org.chromium.components.browser_ui.util.BrowserControlsVisibilityDelegate; import org.chromium.components.browser_ui.util.BrowserControlsVisibilityDelegate;
import org.chromium.components.browser_ui.util.ComposedBrowserControlsVisibilityDelegate; import org.chromium.components.browser_ui.util.ComposedBrowserControlsVisibilityDelegate;
import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid; import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid;
...@@ -107,8 +106,8 @@ public class CustomTabDelegateFactory implements TabDelegateFactory { ...@@ -107,8 +106,8 @@ public class CustomTabDelegateFactory implements TabDelegateFactory {
@Override @Override
public boolean startActivityIfNeeded(Intent intent, boolean proxy) { public boolean startActivityIfNeeded(Intent intent, boolean proxy) {
// Note: This method will not be called if applyWebappScopePolicyForUrl returns // Note: This method will not be called if shouldDisableExternalIntentRequestsForUrl()
// IGNORE_EXTERNAL_INTENT_REQUESTS. // returns false.
boolean isExternalProtocol = !UrlUtilities.isAcceptedScheme(intent.toUri(0)); boolean isExternalProtocol = !UrlUtilities.isAcceptedScheme(intent.toUri(0));
boolean hasDefaultHandler = hasDefaultHandler(intent); boolean hasDefaultHandler = hasDefaultHandler(intent);
...@@ -180,29 +179,10 @@ public class CustomTabDelegateFactory implements TabDelegateFactory { ...@@ -180,29 +179,10 @@ public class CustomTabDelegateFactory implements TabDelegateFactory {
return mHasActivityStarted; return mHasActivityStarted;
} }
/**
* If the current activity is a webapp, applies the webapp's scope policy and returns the
* result. Returns {@link WebappScopePolicy#NavigationDirective#NORMAL_BEHAVIOR} if the
* current activity is not a webapp. Protected to allow subclasses to customize the logic.
*/
protected @WebappScopePolicy.NavigationDirective int applyWebappScopePolicyForUrl(
String url) {
Context context = getAvailableContext();
if (context instanceof WebappActivity) {
WebappActivity webappActivity = (WebappActivity) context;
return WebappScopePolicy.applyPolicyForNavigationToUrl(
webappActivity.scopePolicy(), webappActivity.getWebappInfo(), url);
}
return WebappScopePolicy.NavigationDirective.NORMAL_BEHAVIOR;
}
@Override @Override
public boolean shouldDisableExternalIntentRequestsForUrl(String url) { public boolean shouldDisableExternalIntentRequestsForUrl(String url) {
// http://crbug.com/647569 : Stay in a PWA window for a URL within the same scope. // http://crbug.com/647569 : Do not forward URL requests to external intents for URLs
if (applyWebappScopePolicyForUrl(url) // within the Webapp/TWA's scope.
== WebappScopePolicy.NavigationDirective.IGNORE_EXTERNAL_INTENT_REQUESTS) {
return true;
}
return mExternalIntentsPolicyProvider.shouldIgnoreExternalIntentHandlers(url); return mExternalIntentsPolicyProvider.shouldIgnoreExternalIntentHandlers(url);
} }
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.customtabs.dependency_injection; package org.chromium.chrome.browser.customtabs.dependency_injection;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.TwaFinishHandler; import org.chromium.chrome.browser.browserservices.trustedwebactivityui.TwaFinishHandler;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.CurrentPageVerifier;
import org.chromium.chrome.browser.customtabs.CustomTabCompositorContentInitializer; import org.chromium.chrome.browser.customtabs.CustomTabCompositorContentInitializer;
import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory; import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory;
import org.chromium.chrome.browser.customtabs.CustomTabStatusBarColorProvider; import org.chromium.chrome.browser.customtabs.CustomTabStatusBarColorProvider;
...@@ -25,6 +26,7 @@ import org.chromium.chrome.browser.webapps.WebappActivityCoordinator; ...@@ -25,6 +26,7 @@ import org.chromium.chrome.browser.webapps.WebappActivityCoordinator;
* {@link WebappActivityComponent}. * {@link WebappActivityComponent}.
*/ */
public interface BaseCustomTabActivityComponent extends ChromeActivityComponent { public interface BaseCustomTabActivityComponent extends ChromeActivityComponent {
CurrentPageVerifier resolveCurrentPageVerifier();
CustomTabActivityNavigationController resolveNavigationController(); CustomTabActivityNavigationController resolveNavigationController();
CustomTabActivityTabFactory resolveTabFactory(); CustomTabActivityTabFactory resolveTabFactory();
CustomTabActivityTabProvider resolveTabProvider(); CustomTabActivityTabProvider resolveTabProvider();
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
package org.chromium.chrome.browser.customtabs.dependency_injection; package org.chromium.chrome.browser.customtabs.dependency_injection;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.TrustedWebActivityCoordinator; import org.chromium.chrome.browser.browserservices.trustedwebactivityui.TrustedWebActivityCoordinator;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.CurrentPageVerifier;
import org.chromium.chrome.browser.customtabs.CustomTabActivityClientConnectionKeeper; import org.chromium.chrome.browser.customtabs.CustomTabActivityClientConnectionKeeper;
import org.chromium.chrome.browser.customtabs.CustomTabActivityLifecycleUmaTracker; import org.chromium.chrome.browser.customtabs.CustomTabActivityLifecycleUmaTracker;
import org.chromium.chrome.browser.customtabs.CustomTabBottomBarDelegate; import org.chromium.chrome.browser.customtabs.CustomTabBottomBarDelegate;
...@@ -31,7 +30,6 @@ import dagger.Subcomponent; ...@@ -31,7 +30,6 @@ import dagger.Subcomponent;
public interface CustomTabActivityComponent extends BaseCustomTabActivityComponent { public interface CustomTabActivityComponent extends BaseCustomTabActivityComponent {
TrustedWebActivityCoordinator resolveTrustedWebActivityCoordinator(); TrustedWebActivityCoordinator resolveTrustedWebActivityCoordinator();
CurrentPageVerifier resolveCurrentPageVerifier();
CustomTabBottomBarDelegate resolveBottomBarDelegate(); CustomTabBottomBarDelegate resolveBottomBarDelegate();
CustomTabActivityTabController resolveTabController(); CustomTabActivityTabController resolveTabController();
CustomTabActivityLifecycleUmaTracker resolveUmaTracker(); CustomTabActivityLifecycleUmaTracker resolveUmaTracker();
......
// Copyright 2020 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.webapps;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.components.embedder_support.util.Origin;
import org.chromium.components.embedder_support.util.UrlUtilities;
import javax.inject.Inject;
/**
* Provides homescreen-shortcut specific behaviour for the {@link CurrentPageVerifier}.
*/
@ActivityScope
public class AddToHomescreenVerifier extends WebappVerifier {
private final WebappExtras mWebappExtras;
@Inject
public AddToHomescreenVerifier(BrowserServicesIntentDataProvider intentDataProvider) {
mWebappExtras = intentDataProvider.getWebappExtras();
assert mWebappExtras != null;
}
@Override
protected String getScope() {
Origin origin = Origin.create(mWebappExtras.url);
if (origin == null) return null;
return origin.toString();
}
@Override
protected boolean isUrlInScope(String url) {
return UrlUtilities.sameDomainOrHost(mWebappExtras.url, url, true);
}
}
...@@ -19,11 +19,6 @@ import org.chromium.webapk.lib.common.WebApkConstants; ...@@ -19,11 +19,6 @@ import org.chromium.webapk.lib.common.WebApkConstants;
public class WebApkActivity extends WebappActivity { public class WebApkActivity extends WebappActivity {
private static final String TAG = "WebApkActivity"; private static final String TAG = "WebApkActivity";
@Override
public @WebappScopePolicy.Type int scopePolicy() {
return WebappScopePolicy.Type.STRICT;
}
@Override @Override
protected WebappInfo createWebappInfo(Intent intent) { protected WebappInfo createWebappInfo(Intent intent) {
return (intent == null) ? WebApkInfo.createEmpty() : WebApkInfo.create(intent); return (intent == null) ? WebApkInfo.createEmpty() : WebApkInfo.create(intent);
......
// Copyright 2020 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.webapps;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.components.embedder_support.util.UrlUtilities;
import javax.inject.Inject;
/**
* Provides WebAPK specific behaviour for the {@link CurrentPageVerifier}.
*/
@ActivityScope
public class WebApkVerifier extends WebappVerifier {
private final WebappExtras mWebappExtras;
@Inject
public WebApkVerifier(BrowserServicesIntentDataProvider intentDataProvider) {
mWebappExtras = intentDataProvider.getWebappExtras();
assert mWebappExtras != null;
}
@Override
protected String getScope() {
return mWebappExtras.scopeUrl;
}
@Override
protected boolean isUrlInScope(String url) {
return UrlUtilities.isUrlWithinScope(url, mWebappExtras.scopeUrl);
}
}
// Copyright 2020 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.webapps;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ActivityTabProvider.ActivityTabTabObserver;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.CurrentPageVerifier;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.CurrentPageVerifier.VerificationState;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.CurrentPageVerifier.VerificationStatus;
import org.chromium.chrome.browser.metrics.WebApkUma;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.content_public.browser.NavigationHandle;
/**
* Handles recording user metrics for active tab.
*/
public class WebappActiveTabUmaTracker extends ActivityTabTabObserver {
@VisibleForTesting
public static final String HISTOGRAM_NAVIGATION_STATUS = "Webapp.NavigationStatus";
private BrowserServicesIntentDataProvider mIntentDataProvider;
private CurrentPageVerifier mCurrentPageVerifier;
public WebappActiveTabUmaTracker(ActivityTabProvider tabProvider,
BrowserServicesIntentDataProvider intentDataProvider,
CurrentPageVerifier currentPageVerifier) {
super(tabProvider);
mIntentDataProvider = intentDataProvider;
mCurrentPageVerifier = currentPageVerifier;
}
@Override
public void onDidFinishNavigation(Tab tab, NavigationHandle navigation) {
if (navigation.hasCommitted() && navigation.isInMainFrame()
&& !navigation.isSameDocument()) {
RecordHistogram.recordBooleanHistogram(
HISTOGRAM_NAVIGATION_STATUS, !navigation.isErrorPage());
if (mIntentDataProvider.isWebApkActivity()) {
VerificationState verificationState = mCurrentPageVerifier.getState();
boolean isNavigationInScope = (verificationState == null
|| verificationState.status != VerificationStatus.FAILURE);
boolean isChildTab = (tab.getParentId() != Tab.INVALID_TAB_ID);
WebApkUma.recordNavigation(isChildTab, isNavigationInScope);
}
}
}
}
...@@ -17,14 +17,12 @@ import android.os.StrictMode; ...@@ -17,14 +17,12 @@ import android.os.StrictMode;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.ActivityState; import org.chromium.base.ActivityState;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ApplicationStatus; import org.chromium.base.ApplicationStatus;
import org.chromium.base.Log; import org.chromium.base.Log;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.metrics.RecordUserAction;
import org.chromium.base.task.PostTask; import org.chromium.base.task.PostTask;
import org.chromium.chrome.R; import org.chromium.chrome.R;
...@@ -33,7 +31,6 @@ import org.chromium.chrome.browser.IntentHandler; ...@@ -33,7 +31,6 @@ import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.WarmupManager; import org.chromium.chrome.browser.WarmupManager;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider.CustomTabsUiType; import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider.CustomTabsUiType;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.TrustedWebActivityBrowserControlsVisibilityManager;
import org.chromium.chrome.browser.customtabs.BaseCustomTabActivity; import org.chromium.chrome.browser.customtabs.BaseCustomTabActivity;
import org.chromium.chrome.browser.customtabs.CustomTabAppMenuPropertiesDelegate; import org.chromium.chrome.browser.customtabs.CustomTabAppMenuPropertiesDelegate;
import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory; import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory;
...@@ -43,7 +40,6 @@ import org.chromium.chrome.browser.customtabs.features.ImmersiveModeController; ...@@ -43,7 +40,6 @@ import org.chromium.chrome.browser.customtabs.features.ImmersiveModeController;
import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule; import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule;
import org.chromium.chrome.browser.document.ChromeLauncherActivity; import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.chrome.browser.flags.ActivityType; import org.chromium.chrome.browser.flags.ActivityType;
import org.chromium.chrome.browser.metrics.WebApkUma;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper; import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper;
import org.chromium.chrome.browser.tab.TabDelegateFactory; import org.chromium.chrome.browser.tab.TabDelegateFactory;
...@@ -71,7 +67,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen ...@@ -71,7 +67,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
public static final String WEBAPP_SCHEME = "webapp"; public static final String WEBAPP_SCHEME = "webapp";
private static final String TAG = "WebappActivity"; private static final String TAG = "WebappActivity";
private static final String HISTOGRAM_NAVIGATION_STATUS = "Webapp.NavigationStatus";
private static final long MS_BEFORE_NAVIGATING_BACK_FROM_INTERSTITIAL = 1000; private static final long MS_BEFORE_NAVIGATING_BACK_FROM_INTERSTITIAL = 1000;
protected static final String BUNDLE_TAB_ID = "tabId"; protected static final String BUNDLE_TAB_ID = "tabId";
...@@ -79,7 +74,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen ...@@ -79,7 +74,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
private WebappInfo mWebappInfo; private WebappInfo mWebappInfo;
private BrowserServicesIntentDataProvider mIntentDataProvider; private BrowserServicesIntentDataProvider mIntentDataProvider;
private TrustedWebActivityBrowserControlsVisibilityManager mBrowserControlsVisibilityManager;
private WebappActivityTabController mTabController; private WebappActivityTabController mTabController;
private SplashController mSplashController; private SplashController mSplashController;
private TabObserverRegistrar mTabObserverRegistrar; private TabObserverRegistrar mTabObserverRegistrar;
...@@ -340,7 +334,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen ...@@ -340,7 +334,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
onComponentCreated(component); onComponentCreated(component);
mTabController = component.resolveTabController(); mTabController = component.resolveTabController();
mBrowserControlsVisibilityManager = component.resolveBrowserControlsVisibilityManager();
mSplashController = component.resolveSplashController(); mSplashController = component.resolveSplashController();
mTabObserverRegistrar = component.resolveTabObserverRegistrar(); mTabObserverRegistrar = component.resolveTabObserverRegistrar();
mDelegateFactory = component.resolveTabDelegateFactory(); mDelegateFactory = component.resolveTabDelegateFactory();
...@@ -349,8 +342,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen ...@@ -349,8 +342,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
mStatusBarColorProvider.setUseTabThemeColor(true /* useTabThemeColor */); mStatusBarColorProvider.setUseTabThemeColor(true /* useTabThemeColor */);
mNavigationController.setFinishHandler((reason) -> { handleFinishAndClose(); }); mNavigationController.setFinishHandler((reason) -> { handleFinishAndClose(); });
mNavigationController.setLandingPageOnCloseCriterion(
url -> WebappScopePolicy.isUrlInScope(scopePolicy(), getWebappInfo(), url));
return component; return component;
} }
...@@ -408,13 +399,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen ...@@ -408,13 +399,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
return mWebappInfo; return mWebappInfo;
} }
/**
* @return A string containing the scope of the webapp opened in this activity.
*/
public String getWebappScope() {
return mWebappInfo.scopeUrl();
}
WebContentsDelegateAndroid getWebContentsDelegate() { WebContentsDelegateAndroid getWebContentsDelegate() {
assert mDelegateFactory != null; assert mDelegateFactory != null;
return mDelegateFactory.getWebContentsDelegate(); return mDelegateFactory.getWebContentsDelegate();
...@@ -438,17 +422,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen ...@@ -438,17 +422,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
// not apply to fullscreen content views. // not apply to fullscreen content views.
TabBrowserControlsConstraintsHelper.update( TabBrowserControlsConstraintsHelper.update(
tab, TabBrowserControlsConstraintsHelper.getConstraints(tab), true); tab, TabBrowserControlsConstraintsHelper.getConstraints(tab), true);
RecordHistogram.recordBooleanHistogram(
HISTOGRAM_NAVIGATION_STATUS, !navigation.isErrorPage());
boolean isNavigationInScope = WebappScopePolicy.isUrlInScope(
scopePolicy(), mWebappInfo, navigation.getUrl());
mBrowserControlsVisibilityManager.updateIsInTwaMode(isNavigationInScope);
if (mWebappInfo.isForWebApk()) {
boolean isChildTab = (tab.getParentId() != Tab.INVALID_TAB_ID);
WebApkUma.recordNavigation(isChildTab, isNavigationInScope);
}
} }
} }
...@@ -480,20 +453,9 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen ...@@ -480,20 +453,9 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
} }
}, MS_BEFORE_NAVIGATING_BACK_FROM_INTERSTITIAL); }, MS_BEFORE_NAVIGATING_BACK_FROM_INTERSTITIAL);
} }
@Override
public void onObservingDifferentTab(@NonNull Tab tab) {
boolean isNavigationInScope = WebappScopePolicy.isUrlInScope(
scopePolicy(), mWebappInfo, tab.getUrlString());
mBrowserControlsVisibilityManager.updateIsInTwaMode(isNavigationInScope);
}
}; };
} }
public @WebappScopePolicy.Type int scopePolicy() {
return WebappScopePolicy.Type.LEGACY;
}
@Override @Override
public boolean onMenuOrKeyboardAction(int id, boolean fromMenu) { public boolean onMenuOrKeyboardAction(int id, boolean fromMenu) {
// Disable creating bookmark. // Disable creating bookmark.
......
...@@ -6,9 +6,17 @@ package org.chromium.chrome.browser.webapps; ...@@ -6,9 +6,17 @@ package org.chromium.chrome.browser.webapps;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.CurrentPageVerifier;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.TrustedWebActivityBrowserControlsVisibilityManager;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.Verifier;
import org.chromium.chrome.browser.customtabs.ExternalIntentsPolicyProvider;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityNavigationController;
import org.chromium.chrome.browser.dependency_injection.ActivityScope; import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.InflationObserver;
import javax.inject.Inject; import javax.inject.Inject;
...@@ -17,22 +25,42 @@ import javax.inject.Inject; ...@@ -17,22 +25,42 @@ import javax.inject.Inject;
* Add methods here if other components need to communicate with either of these components. * Add methods here if other components need to communicate with either of these components.
*/ */
@ActivityScope @ActivityScope
public class WebappActivityCoordinator { public class WebappActivityCoordinator implements InflationObserver {
private final WebappActivity mActivity; private final WebappActivity mActivity;
private final BrowserServicesIntentDataProvider mIntentDataProvider; private final BrowserServicesIntentDataProvider mIntentDataProvider;
private final CurrentPageVerifier mCurrentPageVerifier;
private TrustedWebActivityBrowserControlsVisibilityManager mBrowserControlsVisibilityManager;
private final WebappDeferredStartupWithStorageHandler mDeferredStartupWithStorageHandler; private final WebappDeferredStartupWithStorageHandler mDeferredStartupWithStorageHandler;
// Whether the current page is within the webapp's scope.
private boolean mInScope = true;
@Inject @Inject
public WebappActivityCoordinator(ChromeActivity<?> activity, public WebappActivityCoordinator(ChromeActivity<?> activity,
BrowserServicesIntentDataProvider intentDataProvider, BrowserServicesIntentDataProvider intentDataProvider,
ActivityTabProvider activityTabProvider, CurrentPageVerifier currentPageVerifier,
Verifier verifier, CustomTabActivityNavigationController navigationController,
ExternalIntentsPolicyProvider externalIntentsPolicyProvider,
WebappDeferredStartupWithStorageHandler deferredStartupWithStorageHandler, WebappDeferredStartupWithStorageHandler deferredStartupWithStorageHandler,
WebappActionsNotificationManager actionsNotificationManager) { WebappActionsNotificationManager actionsNotificationManager,
ActivityLifecycleDispatcher lifecycleDispatcher,
TrustedWebActivityBrowserControlsVisibilityManager browserControlsVisibilityManager) {
// We don't need to do anything with |actionsNotificationManager|. We just need to resolve // We don't need to do anything with |actionsNotificationManager|. We just need to resolve
// it so that it starts working. // it so that it starts working.
mActivity = (WebappActivity) activity; mActivity = (WebappActivity) activity;
mIntentDataProvider = intentDataProvider; mIntentDataProvider = intentDataProvider;
mCurrentPageVerifier = currentPageVerifier;
mDeferredStartupWithStorageHandler = deferredStartupWithStorageHandler; mDeferredStartupWithStorageHandler = deferredStartupWithStorageHandler;
mBrowserControlsVisibilityManager = browserControlsVisibilityManager;
// WebappActiveTabUmaTracker sets itself as an observer of |activityTabProvider|.
new WebappActiveTabUmaTracker(
activityTabProvider, intentDataProvider, mCurrentPageVerifier);
navigationController.setLandingPageOnCloseCriterion(verifier::wasPreviouslyVerified);
externalIntentsPolicyProvider.setPolicyCriteria(
verifier::shouldIgnoreExternalIntentHandlers);
mDeferredStartupWithStorageHandler.addTask((storage, didCreateStorage) -> { mDeferredStartupWithStorageHandler.addTask((storage, didCreateStorage) -> {
if (activity.isActivityFinishingOrDestroyed()) return; if (activity.isActivityFinishingOrDestroyed()) return;
...@@ -41,6 +69,9 @@ public class WebappActivityCoordinator { ...@@ -41,6 +69,9 @@ public class WebappActivityCoordinator {
updateStorage(storage); updateStorage(storage);
} }
}); });
currentPageVerifier.addVerificationObserver(this::onVerificationUpdate);
lifecycleDispatcher.register(this);
} }
/** /**
...@@ -50,6 +81,32 @@ public class WebappActivityCoordinator { ...@@ -50,6 +81,32 @@ public class WebappActivityCoordinator {
mDeferredStartupWithStorageHandler.initDeferredStartupForActivity(); mDeferredStartupWithStorageHandler.initDeferredStartupForActivity();
} }
@Override
public void onPreInflationStartup() {}
@Override
public void onPostInflationStartup() {
// Before verification completes, optimistically expect it to be successful.
if (mCurrentPageVerifier.getState() == null) {
updateUi(true);
}
}
private void onVerificationUpdate() {
CurrentPageVerifier.VerificationState state = mCurrentPageVerifier.getState();
// Consider null |state| to be 'in scope' to mimic TWA logic. |state| should never be null
// for webapps.
boolean inScope =
state == null || state.status != CurrentPageVerifier.VerificationStatus.FAILURE;
if (inScope == mInScope) return;
mInScope = inScope;
updateUi(inScope);
}
private void updateUi(boolean inScope) {
mBrowserControlsVisibilityManager.updateIsInTwaMode(inScope);
}
private void updateStorage(@NonNull WebappDataStorage storage) { private void updateStorage(@NonNull WebappDataStorage storage) {
// The information in the WebappDataStorage may have been purged by the // The information in the WebappDataStorage may have been purged by the
// user clearing their history or not launching the web app recently. // user clearing their history or not launching the web app recently.
......
...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.webapps; ...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.webapps;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsIntent; import androidx.browser.customtabs.CustomTabsIntent;
import androidx.browser.trusted.sharing.ShareData; import androidx.browser.trusted.sharing.ShareData;
...@@ -20,12 +21,12 @@ import org.chromium.components.browser_ui.widget.TintedDrawable; ...@@ -20,12 +21,12 @@ import org.chromium.components.browser_ui.widget.TintedDrawable;
* Stores info about a web app. * Stores info about a web app.
*/ */
public class WebappIntentDataProvider extends BrowserServicesIntentDataProvider { public class WebappIntentDataProvider extends BrowserServicesIntentDataProvider {
private int mToolbarColor; private final int mToolbarColor;
private boolean mHasCustomToolbarColor; private final boolean mHasCustomToolbarColor;
private Drawable mCloseButtonIcon; private final Drawable mCloseButtonIcon;
private ShareData mShareData; private final ShareData mShareData;
private WebappExtras mWebappExtras; private final @NonNull WebappExtras mWebappExtras;
private WebApkExtras mWebApkExtras; private final @Nullable WebApkExtras mWebApkExtras;
/** /**
* Returns the toolbar color to use if a custom color is not specified by the webapp. * Returns the toolbar color to use if a custom color is not specified by the webapp.
...@@ -35,7 +36,7 @@ public class WebappIntentDataProvider extends BrowserServicesIntentDataProvider ...@@ -35,7 +36,7 @@ public class WebappIntentDataProvider extends BrowserServicesIntentDataProvider
} }
WebappIntentDataProvider(int toolbarColor, boolean hasCustomToolbarColor, ShareData shareData, WebappIntentDataProvider(int toolbarColor, boolean hasCustomToolbarColor, ShareData shareData,
WebappExtras webappExtras, WebApkExtras webApkExtras) { @NonNull WebappExtras webappExtras, @Nullable WebApkExtras webApkExtras) {
mToolbarColor = toolbarColor; mToolbarColor = toolbarColor;
mHasCustomToolbarColor = hasCustomToolbarColor; mHasCustomToolbarColor = hasCustomToolbarColor;
mCloseButtonIcon = TintedDrawable.constructTintedDrawable( mCloseButtonIcon = TintedDrawable.constructTintedDrawable(
...@@ -45,6 +46,12 @@ public class WebappIntentDataProvider extends BrowserServicesIntentDataProvider ...@@ -45,6 +46,12 @@ public class WebappIntentDataProvider extends BrowserServicesIntentDataProvider
mWebApkExtras = webApkExtras; mWebApkExtras = webApkExtras;
} }
@Override
@Nullable
public String getUrlToLoad() {
return mWebappExtras.url;
}
@Override @Override
public int getToolbarColor() { public int getToolbarColor() {
return mToolbarColor; return mToolbarColor;
......
// Copyright 2020 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.webapps;
import androidx.annotation.Nullable;
import org.chromium.base.Promise;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.Verifier;
/**
* Contains common implementation between {@link AddToHomescreenVerifier} and
* {@link WebApkVerifier}.
*/
public abstract class WebappVerifier implements Verifier {
@Override
public final Promise<Boolean> verify(String url) {
return Promise.fulfilled(isUrlInScope(url));
}
@Override
public final boolean wasPreviouslyVerified(String url) {
return isUrlInScope(url);
}
@Nullable
@Override
public final String getVerifiedScope(String url) {
if (isUrlInScope(url)) return getScope();
return url;
}
@Override
public boolean shouldIgnoreExternalIntentHandlers(String url) {
return isUrlInScope(url);
}
/**
* Returns the scope that the homscreen shortcut/WebAPK is valid for.
*/
protected abstract String getScope();
/**
* @return {@code true} if given {@code url} is in scope of the webapp.
*/
protected abstract boolean isUrlInScope(String url);
}
...@@ -4,11 +4,12 @@ ...@@ -4,11 +4,12 @@
package org.chromium.chrome.browser.webapps.dependency_injection; package org.chromium.chrome.browser.webapps.dependency_injection;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.TrustedWebActivityBrowserControlsVisibilityManager;
import org.chromium.chrome.browser.customtabs.dependency_injection.BaseCustomTabActivityComponent; import org.chromium.chrome.browser.customtabs.dependency_injection.BaseCustomTabActivityComponent;
import org.chromium.chrome.browser.dependency_injection.ActivityScope; import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule; import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule;
import org.chromium.chrome.browser.webapps.AddToHomescreenVerifier;
import org.chromium.chrome.browser.webapps.WebApkUpdateManager; import org.chromium.chrome.browser.webapps.WebApkUpdateManager;
import org.chromium.chrome.browser.webapps.WebApkVerifier;
import org.chromium.chrome.browser.webapps.WebappActivityTabController; import org.chromium.chrome.browser.webapps.WebappActivityTabController;
import dagger.Subcomponent; import dagger.Subcomponent;
...@@ -20,7 +21,8 @@ import dagger.Subcomponent; ...@@ -20,7 +21,8 @@ import dagger.Subcomponent;
@Subcomponent(modules = {ChromeActivityCommonsModule.class, WebappActivityModule.class}) @Subcomponent(modules = {ChromeActivityCommonsModule.class, WebappActivityModule.class})
@ActivityScope @ActivityScope
public interface WebappActivityComponent extends BaseCustomTabActivityComponent { public interface WebappActivityComponent extends BaseCustomTabActivityComponent {
TrustedWebActivityBrowserControlsVisibilityManager resolveBrowserControlsVisibilityManager(); AddToHomescreenVerifier resolveAddToHomescreenVerifier();
WebappActivityTabController resolveTabController(); WebappActivityTabController resolveTabController();
WebApkVerifier resolveWebApkVerifier();
WebApkUpdateManager resolveWebApkUpdateManager(); WebApkUpdateManager resolveWebApkUpdateManager();
} }
...@@ -8,10 +8,14 @@ import androidx.annotation.Nullable; ...@@ -8,10 +8,14 @@ import androidx.annotation.Nullable;
import org.chromium.chrome.browser.browserservices.BrowserServicesActivityTabController; import org.chromium.chrome.browser.browserservices.BrowserServicesActivityTabController;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.Verifier;
import org.chromium.chrome.browser.customtabs.CustomTabUmaRecorder; import org.chromium.chrome.browser.customtabs.CustomTabUmaRecorder;
import org.chromium.chrome.browser.init.StartupTabPreloader; import org.chromium.chrome.browser.init.StartupTabPreloader;
import org.chromium.chrome.browser.webapps.AddToHomescreenVerifier;
import org.chromium.chrome.browser.webapps.WebApkVerifier;
import org.chromium.chrome.browser.webapps.WebappActivityTabController; import org.chromium.chrome.browser.webapps.WebappActivityTabController;
import dagger.Lazy;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
...@@ -37,6 +41,13 @@ public final class WebappActivityModule { ...@@ -37,6 +41,13 @@ public final class WebappActivityModule {
return webappTabController; return webappTabController;
} }
@Provides
public Verifier provideVerifier(Lazy<AddToHomescreenVerifier> addToHomescreenVerifier,
Lazy<WebApkVerifier> webApkVerifier) {
return mIntentDataProvider.isWebApkActivity() ? webApkVerifier.get()
: addToHomescreenVerifier.get();
}
@Nullable @Nullable
@Provides @Provides
// TODO(crbug.com/1021201): Add bit to all metrics to record whether they are recorded from a // TODO(crbug.com/1021201): Add bit to all metrics to record whether they are recorded from a
......
// Copyright 2020 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.browserservices.trustedwebactivityui.controller;
import static org.junit.Assert.assertEquals;
import android.content.Intent;
import android.net.Uri;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import org.chromium.base.CommandLine;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.browser.browserservices.TrustedWebActivityTestUtil;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.CurrentPageVerifier.VerificationStatus;
import org.chromium.chrome.browser.customtabs.CustomTabActivity;
import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.test.MockCertVerifierRuleAndroid;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.content_public.browser.test.NativeLibraryTestRule;
import org.chromium.content_public.common.ContentSwitches;
import java.util.concurrent.TimeoutException;
/**
* Tests the {@link CurrentPageVerifier} integration with Trusted Web Activity Mode.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public final class TrustedWebActivityCurrentPageVerifierTest {
public final CustomTabActivityTestRule mActivityTestRule = new CustomTabActivityTestRule();
public final NativeLibraryTestRule mNativeLibraryTestRule = new NativeLibraryTestRule();
public MockCertVerifierRuleAndroid mCertVerifierRule =
new MockCertVerifierRuleAndroid(mNativeLibraryTestRule, 0 /* net::OK */);
@Rule
public RuleChain mRuleChain = RuleChain.emptyRuleChain()
.around(mActivityTestRule)
.around(mNativeLibraryTestRule)
.around(mCertVerifierRule);
@Before
public void setUp() {
mActivityTestRule.getEmbeddedTestServerRule().setServerUsesHttps(true);
Uri mapToUri =
Uri.parse(mActivityTestRule.getEmbeddedTestServerRule().getServer().getURL("/"));
CommandLine.getInstance().appendSwitchWithValue(
ContentSwitches.HOST_RESOLVER_RULES, "MAP * " + mapToUri.getAuthority());
}
private void launchTwa(String url) throws TimeoutException {
String packageName = InstrumentationRegistry.getTargetContext().getPackageName();
Intent intent = TrustedWebActivityTestUtil.createTrustedWebActivityIntent(url);
TrustedWebActivityTestUtil.spoofVerification(packageName, url);
TrustedWebActivityTestUtil.createSession(intent, packageName);
mActivityTestRule.startCustomTabActivityWithIntent(intent);
}
private @VerificationStatus int getCurrentPageVerifierStatus() {
CustomTabActivity customTabActivity = mActivityTestRule.getActivity();
return customTabActivity.getComponent().resolveCurrentPageVerifier().getState().status;
}
@Test
@LargeTest
public void testInScope() throws TimeoutException {
String page = "https://foo.com/chrome/test/data/android/customtabs/cct_header.html";
String otherPageInScope =
"https://foo.com/chrome/test/data/android/customtabs/cct_header_frame.html";
launchTwa(page);
mActivityTestRule.loadUrl(otherPageInScope);
TrustedWebActivityTestUtil.waitForCurrentPageVerifierToFinish(
mActivityTestRule.getActivity());
assertEquals(VerificationStatus.SUCCESS, getCurrentPageVerifierStatus());
}
@Test
@LargeTest
public void testOutsideScope() throws TimeoutException {
String page = "https://foo.com/chrome/test/data/android/simple.html";
String pageDifferentOrigin = "https://bar.com/chrome/test/data/android/simple.html";
launchTwa(page);
mActivityTestRule.loadUrl(pageDifferentOrigin, 10 /* secondsToWait */);
TrustedWebActivityTestUtil.waitForCurrentPageVerifierToFinish(
mActivityTestRule.getActivity());
assertEquals(VerificationStatus.FAILURE, getCurrentPageVerifierStatus());
}
}
// Copyright 2020 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.webapps;
import static org.junit.Assert.assertEquals;
import android.content.Intent;
import android.net.Uri;
import android.support.test.filters.LargeTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
import org.chromium.base.CommandLine;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.ShortcutHelper;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.CurrentPageVerifier.VerificationStatus;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.test.MockCertVerifierRuleAndroid;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.content_public.browser.test.NativeLibraryTestRule;
import org.chromium.content_public.common.ContentSwitches;
/**
* Tests the {@link CurrentPageVerifier} integration with PWAs added to the homescreen.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public final class AddToHomescreenCurrentPageVerifierTest {
public final WebappActivityTestRule mActivityTestRule = new WebappActivityTestRule();
public final NativeLibraryTestRule mNativeLibraryTestRule = new NativeLibraryTestRule();
public MockCertVerifierRuleAndroid mCertVerifierRule =
new MockCertVerifierRuleAndroid(mNativeLibraryTestRule, 0 /* net::OK */);
@Rule
public RuleChain mRuleChain = RuleChain.emptyRuleChain()
.around(mActivityTestRule)
.around(mNativeLibraryTestRule)
.around(mCertVerifierRule);
@Before
public void setUp() {
mActivityTestRule.getEmbeddedTestServerRule().setServerUsesHttps(true);
Uri mapToUri =
Uri.parse(mActivityTestRule.getEmbeddedTestServerRule().getServer().getURL("/"));
CommandLine.getInstance().appendSwitchWithValue(
ContentSwitches.HOST_RESOLVER_RULES, "MAP * " + mapToUri.getAuthority());
}
private void launchWebapp(String url) {
Intent launchIntent = mActivityTestRule.createIntent();
launchIntent.putExtra(ShortcutHelper.EXTRA_URL, url);
mActivityTestRule.startWebappActivity(launchIntent);
}
private @VerificationStatus int getCurrentPageVerifierStatus() {
WebappActivity webappActivity = mActivityTestRule.getActivity();
return webappActivity.getComponent().resolveCurrentPageVerifier().getState().status;
}
/**
* Tests that {@link CurrentPageVerifier} verification succeeds if the webapp navigates to a
* page within the webapp origin.
*/
@Test
@LargeTest
@Feature({"Webapps"})
public void testInScope() {
String page = "https://foo.com/chrome/test/data/android/customtabs/cct_header.html";
String otherPageInScope = "https://foo.com/chrome/test/data/android/simple.html";
launchWebapp(page);
mActivityTestRule.loadUrl(otherPageInScope);
assertEquals(VerificationStatus.SUCCESS, getCurrentPageVerifierStatus());
}
/**
* Tests that {@link CurrentPageVerifier} verification fails if the webapp navigates to a
* page with a different origin than the webapp.
*/
@Test
@LargeTest
@Feature({"Webapps"})
public void testDifferentOrigin() {
String page = "https://foo.com/chrome/test/data/android/simple.html";
String pageDifferentOrigin = "https://bar.com/chrome/test/data/android/simple.html";
launchWebapp(page);
mActivityTestRule.loadUrl(pageDifferentOrigin, 10 /* secondsToWait */);
assertEquals(VerificationStatus.FAILURE, getCurrentPageVerifierStatus());
}
}
// Copyright 2020 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.webapps;
import static org.junit.Assert.assertEquals;
import android.support.test.filters.LargeTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller.CurrentPageVerifier.VerificationStatus;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.util.browser.webapps.WebApkInfoBuilder;
import org.chromium.net.test.EmbeddedTestServer;
/**
* Tests the {@link CurrentPageVerifier} integration with {@link WebApkActivity}.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public final class WebApkCurrentPageVerifierTest {
@Rule
public final WebApkActivityTestRule mActivityTestRule = new WebApkActivityTestRule();
private EmbeddedTestServer mTestServer;
@Before
public void setUp() {
mTestServer = mActivityTestRule.getTestServer();
}
private WebApkActivity launchWebApk(String url) {
WebApkInfo webApkInfo = new WebApkInfoBuilder("org.chromium.webapk.random", url).build();
return mActivityTestRule.startWebApkActivity(webApkInfo);
}
private @VerificationStatus int getCurrentPageVerifierStatus() {
WebappActivity webappActivity = mActivityTestRule.getActivity();
return webappActivity.getComponent().resolveCurrentPageVerifier().getState().status;
}
/**
* Tests that {@link CurrentPageVerifier} verification succeeds if the page is within the
* WebAPK scope.
*/
@Test
@LargeTest
@Feature({"Webapps"})
public void testInScope() {
String page = mTestServer.getURL("/chrome/test/data/android/customtabs/cct_header.html");
String otherPageInScope =
mTestServer.getURL("/chrome/test/data/android/customtabs/cct_header_frame.html");
String expectedScope = mTestServer.getURL("/chrome/test/data/android/customtabs/");
WebappActivity webappActivity = launchWebApk(page);
assertEquals(expectedScope, webappActivity.getWebappInfo().scopeUrl());
mActivityTestRule.loadUrl(otherPageInScope);
assertEquals(VerificationStatus.SUCCESS, getCurrentPageVerifierStatus());
}
/**
* Tests that {@link CurrentPageVerifier} verification fails if the WebAPK navigates to a page
* which is outside the WebAPK scope.
*/
@Test
@LargeTest
@Feature({"Webapps"})
public void testOutsideScopeSameOrigin() {
String page = mTestServer.getURL("/chrome/test/data/android/customtabs/cct_header.html");
String pageOutsideScopeSameOrigin =
mTestServer.getURL("/chrome/test/data/android/simple.html");
String expectedScope = mTestServer.getURL("/chrome/test/data/android/customtabs/");
WebappActivity webappActivity = launchWebApk(page);
assertEquals(expectedScope, webappActivity.getWebappInfo().scopeUrl());
mActivityTestRule.loadUrl(pageOutsideScopeSameOrigin);
assertEquals(VerificationStatus.FAILURE, getCurrentPageVerifierStatus());
}
}
...@@ -14,6 +14,7 @@ import org.junit.rules.RuleChain; ...@@ -14,6 +14,7 @@ import org.junit.rules.RuleChain;
import org.junit.rules.TestRule; import org.junit.rules.TestRule;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule; import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule;
...@@ -118,5 +119,9 @@ public class WebApkInitializationTest { ...@@ -118,5 +119,9 @@ public class WebApkInitializationTest {
WebappDisclosureSnackbarController.class.getName())); WebappDisclosureSnackbarController.class.getName()));
assertTrue(registeredObserverClassNames.contains( assertTrue(registeredObserverClassNames.contains(
WebApkActivityLifecycleUmaTracker.class.getName())); WebApkActivityLifecycleUmaTracker.class.getName()));
// Test that WebappActiveTabUmaTracker is hooked up.
assertTrue(0 < RecordHistogram.getHistogramTotalCountForTesting(
WebappActiveTabUmaTracker.HISTOGRAM_NAVIGATION_STATUS));
} }
} }
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