Commit 06db5b4e authored by Anna Malova's avatar Anna Malova Committed by Commit Bot

Update X button behaviour if a dynamic module exists.

This CL is reupload of CL:1329797 which was reverted in CL:1343260 due to test flakiness.

The test flakiness comes from waiting of "https://www.google.com/..." URLs to be loaded.
Replacing these URLs with local URLs generated by EmbeddedTestServer fixed the problem.

Bug: 906834
Bug: 889916
Change-Id: I3e9981b4a4ca5a0bd64dff217e44bfd89ca10b9c
Reviewed-on: https://chromium-review.googlesource.com/c/1344132Reviewed-by: default avatarMichael van Ouwerkerk <mvanouwerkerk@chromium.org>
Reviewed-by: default avatarPeter Conn <peconn@chromium.org>
Commit-Queue: Anna Malova <amalova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610006}
parent 448a6987
...@@ -110,7 +110,9 @@ import org.chromium.chrome.browser.util.UrlUtilities; ...@@ -110,7 +110,9 @@ import org.chromium.chrome.browser.util.UrlUtilities;
import org.chromium.chrome.browser.webapps.WebappCustomTabTimeSpentLogger; import org.chromium.chrome.browser.webapps.WebappCustomTabTimeSpentLogger;
import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils; import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.NavigationController;
import org.chromium.content_public.browser.NavigationEntry; import org.chromium.content_public.browser.NavigationEntry;
import org.chromium.content_public.browser.NavigationHistory;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.PageTransition; import org.chromium.ui.base.PageTransition;
...@@ -370,6 +372,32 @@ public class CustomTabActivity extends ChromeActivity<CustomTabActivityComponent ...@@ -370,6 +372,32 @@ public class CustomTabActivity extends ChromeActivity<CustomTabActivityComponent
} }
} }
/**
* @return The index of the previous navigation history entry managed by a dynamic module
* or -1 if there is no such entry.
*/
private boolean goToModuleManagedNavigationIndex() {
if (mModuleActivityDelegate == null && mModuleCallback == null) return false;
NavigationController navigationController = getNavigationController();
if (navigationController == null) return false;
NavigationHistory history = navigationController.getNavigationHistory();
for (int i = history.getCurrentEntryIndex() - 1; i >= 0; i--) {
if (isModuleManagedUrl(history.getEntryAtIndex(i).getUrl())) {
navigationController.goToNavigationIndex(i);
return true;
}
}
return false;
}
@Nullable
private NavigationController getNavigationController() {
WebContents webContents = getActivityTab().getWebContents();
return webContents == null ? null : webContents.getNavigationController();
}
@VisibleForTesting @VisibleForTesting
void maybeInitialiseDynamicModulePostMessageHandler(PostMessageBackend backend) { void maybeInitialiseDynamicModulePostMessageHandler(PostMessageBackend backend) {
// Only initialise the handler if the feature is enabled. // Only initialise the handler if the feature is enabled.
...@@ -596,6 +624,11 @@ public class CustomTabActivity extends ChromeActivity<CustomTabActivityComponent ...@@ -596,6 +624,11 @@ public class CustomTabActivity extends ChromeActivity<CustomTabActivityComponent
if (mIntentDataProvider.shouldEnableEmbeddedMediaExperience()) { if (mIntentDataProvider.shouldEnableEmbeddedMediaExperience()) {
RecordUserAction.record("CustomTabs.CloseButtonClicked.DownloadsUI"); RecordUserAction.record("CustomTabs.CloseButtonClicked.DownloadsUI");
} }
if (goToModuleManagedNavigationIndex()) {
RecordUserAction.record(
"CustomTabs.CloseButtonClicked.GoToModuleManagedUrl");
return;
}
recordClientConnectionStatus(); recordClientConnectionStatus();
finishAndClose(false); finishAndClose(false);
} }
......
...@@ -134,10 +134,12 @@ public class CustomTabIntentDataProvider extends BrowserSessionDataProvider { ...@@ -134,10 +134,12 @@ public class CustomTabIntentDataProvider extends BrowserSessionDataProvider {
"org.chromium.chrome.browser.customtabs.EXTRA_MODULE_MANAGED_URLS_REGEX"; "org.chromium.chrome.browser.customtabs.EXTRA_MODULE_MANAGED_URLS_REGEX";
/** The APK package to load the module from. */ /** The APK package to load the module from. */
@VisibleForTesting
/* package */ static final String EXTRA_MODULE_PACKAGE_NAME = /* package */ static final String EXTRA_MODULE_PACKAGE_NAME =
"org.chromium.chrome.browser.customtabs.EXTRA_MODULE_PACKAGE_NAME"; "org.chromium.chrome.browser.customtabs.EXTRA_MODULE_PACKAGE_NAME";
/** The class name of the module entry point. */ /** The class name of the module entry point. */
@VisibleForTesting
/* package */ static final String EXTRA_MODULE_CLASS_NAME = /* package */ static final String EXTRA_MODULE_CLASS_NAME =
"org.chromium.chrome.browser.customtabs.EXTRA_MODULE_CLASS_NAME"; "org.chromium.chrome.browser.customtabs.EXTRA_MODULE_CLASS_NAME";
......
...@@ -42,6 +42,7 @@ import android.support.customtabs.PostMessageBackend; ...@@ -42,6 +42,7 @@ import android.support.customtabs.PostMessageBackend;
import android.support.test.InstrumentationRegistry; import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest; import android.support.test.filters.MediumTest;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
import android.support.test.uiautomator.UiDevice;
import android.support.v7.content.res.AppCompatResources; import android.support.v7.content.res.AppCompatResources;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.Menu; import android.view.Menu;
...@@ -77,6 +78,7 @@ import org.chromium.base.test.util.Feature; ...@@ -77,6 +78,7 @@ import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.Restriction; import org.chromium.base.test.util.Restriction;
import org.chromium.base.test.util.RetryOnFailure; import org.chromium.base.test.util.RetryOnFailure;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.AppHooksModule;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.ChromeSwitches;
...@@ -88,6 +90,7 @@ import org.chromium.chrome.browser.appmenu.AppMenuHandler; ...@@ -88,6 +90,7 @@ import org.chromium.chrome.browser.appmenu.AppMenuHandler;
import org.chromium.chrome.browser.browserservices.BrowserSessionContentUtils; import org.chromium.chrome.browser.browserservices.BrowserSessionContentUtils;
import org.chromium.chrome.browser.browserservices.Origin; import org.chromium.chrome.browser.browserservices.Origin;
import org.chromium.chrome.browser.browserservices.OriginVerifier; import org.chromium.chrome.browser.browserservices.OriginVerifier;
import org.chromium.chrome.browser.dependency_injection.ModuleFactoryOverrides;
import org.chromium.chrome.browser.document.ChromeLauncherActivity; import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.chrome.browser.firstrun.FirstRunStatus; import org.chromium.chrome.browser.firstrun.FirstRunStatus;
import org.chromium.chrome.browser.history.BrowsingHistoryBridge; import org.chromium.chrome.browser.history.BrowsingHistoryBridge;
...@@ -117,6 +120,7 @@ import org.chromium.chrome.test.util.browser.TabTitleObserver; ...@@ -117,6 +120,7 @@ import org.chromium.chrome.test.util.browser.TabTitleObserver;
import org.chromium.chrome.test.util.browser.contextmenu.ContextMenuUtils; import org.chromium.chrome.test.util.browser.contextmenu.ContextMenuUtils;
import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContentsObserver; import org.chromium.content_public.browser.WebContentsObserver;
import org.chromium.content_public.browser.test.util.ClickUtils;
import org.chromium.content_public.browser.test.util.Criteria; import org.chromium.content_public.browser.test.util.Criteria;
import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.test.util.DOMUtils; import org.chromium.content_public.browser.test.util.DOMUtils;
...@@ -124,12 +128,14 @@ import org.chromium.content_public.browser.test.util.JavaScriptUtils; ...@@ -124,12 +128,14 @@ import org.chromium.content_public.browser.test.util.JavaScriptUtils;
import org.chromium.content_public.browser.test.util.WebContentsUtils; import org.chromium.content_public.browser.test.util.WebContentsUtils;
import org.chromium.net.test.EmbeddedTestServer; import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.net.test.util.TestWebServer; import org.chromium.net.test.util.TestWebServer;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.mojom.WindowOpenDisposition; import org.chromium.ui.mojom.WindowOpenDisposition;
import org.chromium.ui.test.util.UiRestriction; import org.chromium.ui.test.util.UiRestriction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
...@@ -220,6 +226,9 @@ public class CustomTabActivityTest { ...@@ -220,6 +226,9 @@ public class CustomTabActivityTest {
PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX); PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
LibraryLoader.getInstance().ensureInitialized(LibraryProcessType.PROCESS_BROWSER); LibraryLoader.getInstance().ensureInitialized(LibraryProcessType.PROCESS_BROWSER);
mWebServer = TestWebServer.start(); mWebServer = TestWebServer.start();
ModuleFactoryOverrides.setOverride(AppHooksModule.Factory.class,
CustomTabsDynamicModuleTestUtils.AppHooksModuleForTest::new);
} }
@After @After
...@@ -236,6 +245,8 @@ public class CustomTabActivityTest { ...@@ -236,6 +245,8 @@ public class CustomTabActivityTest {
if (handler != null) handler.hideAppMenu(); if (handler != null) handler.hideAppMenu();
}); });
mWebServer.shutdown(); mWebServer.shutdown();
ModuleFactoryOverrides.clearOverrides();
} }
private CustomTabActivity getActivity() { private CustomTabActivity getActivity() {
...@@ -1110,6 +1121,123 @@ public class CustomTabActivityTest { ...@@ -1110,6 +1121,123 @@ public class CustomTabActivityTest {
} }
} }
private void runAndWaitForActivityStopped(Runnable runnable)
throws TimeoutException, InterruptedException {
CallbackHelper cctHiddenCallback = new CallbackHelper();
ActivityStateListener listener = (activity, newState) -> {
if (activity == mCustomTabActivityTestRule.getActivity()
&& (newState == ActivityState.STOPPED || newState == ActivityState.DESTROYED)) {
cctHiddenCallback.notifyCalled();
}
};
ApplicationStatus.registerStateListenerForAllActivities(listener);
runnable.run();
cctHiddenCallback.waitForCallback("Hide cct", 0);
ApplicationStatus.unregisterActivityStateListener(listener);
}
/**
This test executes the following workflow assuming dynamic module has been loaded succesfully:
- moduleManagedUrl1 -> nav1.1 -> nav1.2 -> modulemanagedUrl2 -> nav2.1 -> nav2.2
- User hits the "close button", therefore goes back to modulemanagedUrl2
- User hits the Android back button, going returning to nav1.2
- User hits the "close button" again, going return to moduleManagedUrl1
- User hits the Android back button thereby closes CCT.
*/
@Test
@SmallTest
@EnableFeatures(ChromeFeatureList.CCT_MODULE)
public void testCloseButtonBehaviourWithDynamicModule()
throws InterruptedException, ExecutionException, TimeoutException {
String moduleManagedUrl1 = mTestServer.getURL(
"/chrome/test/data/android/about.html");
String moduleManagedUrl2 = mTestServer.getURL(
"/chrome/test/data/android/simple.html");
Intent intent = CustomTabsDynamicModuleTestUtils.makeDynamicModuleIntent(moduleManagedUrl1,
"^(" + moduleManagedUrl1 + "|" + moduleManagedUrl2 + ")$");
// Open CCT with moduleManagedUrl1 and navigate
// moduleManagedUrl1 -> nav1.1 - nav1.2 -> modulemanagedUrl2 -> nav2.1 -> nav2.2
mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
CustomTabActivity cctActivity = mCustomTabActivityTestRule.getActivity();
mCustomTabActivityTestRule.loadUrlInTab(mTestPage, PageTransition.LINK,
cctActivity.getActivityTab());
mCustomTabActivityTestRule.loadUrlInTab(mTestPage2, PageTransition.LINK,
cctActivity.getActivityTab());
mCustomTabActivityTestRule.loadUrlInTab(moduleManagedUrl2, PageTransition.TYPED,
cctActivity.getActivityTab());
mCustomTabActivityTestRule.loadUrlInTab(mTestPage, PageTransition.LINK,
cctActivity.getActivityTab());
mCustomTabActivityTestRule.loadUrlInTab(mTestPage2, PageTransition.LINK,
cctActivity.getActivityTab());
// click the close button and wait while tab page loaded
ClickUtils.clickButton(cctActivity.findViewById(R.id.close_button));
ChromeTabUtils.waitForTabPageLoaded(cctActivity.getActivityTab(), (String) null);
// close button returns back to moduleManagedUrl2
Assert.assertEquals(moduleManagedUrl2, cctActivity.getActivityTab().getUrl());
// press the back button and wait while tab page loaded
UiDevice mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mDevice.pressBack();
ChromeTabUtils.waitForTabPageLoaded(cctActivity.getActivityTab(), (String) null);
// the back button returns to nav1.2
Assert.assertEquals(mTestPage2, cctActivity.getActivityTab().getUrl());
// click the close button and wait while tab page loaded
ClickUtils.clickButton(cctActivity.findViewById(R.id.close_button));
ChromeTabUtils.waitForTabPageLoaded(cctActivity.getActivityTab(), (String) null);
// close button returns back to moduleManagedUrl1
Assert.assertEquals(moduleManagedUrl1, cctActivity.getActivityTab().getUrl());
// press back button and while cct is hidden
runAndWaitForActivityStopped(mDevice::pressBack);
}
/**
This test executes the following workflow assuming dynamic module has not been loaded:
- moduleManagedUrl1 -> nav1.1 - nav1.2 -> modulemanagedUrl2 -> nav2.1 -> nav2.2
- User hits the close button, thereby closes CCT
*/
@Test
@SmallTest
public void testCloseButtonBehaviourWithoutDynamicModule()
throws InterruptedException, ExecutionException, TimeoutException {
String moduleManagedUrl1 = mTestServer.getURL(
"/chrome/test/data/android/about.html");
String moduleManagedUrl2 = mTestServer.getURL(
"/chrome/test/data/android/simple.html");
// Open CCT with moduleManagedUrl1 and navigate
// moduleManagedUrl1 -> nav1.1 - nav1.2 -> modulemanagedUrl2 -> nav2.1 -> nav2.2
Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(
InstrumentationRegistry.getTargetContext(), moduleManagedUrl1);
mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
CustomTabActivity cctActivity = mCustomTabActivityTestRule.getActivity();
mCustomTabActivityTestRule.loadUrlInTab(mTestPage, PageTransition.LINK,
cctActivity.getActivityTab());
mCustomTabActivityTestRule.loadUrlInTab(mTestPage2, PageTransition.LINK,
cctActivity.getActivityTab());
mCustomTabActivityTestRule.loadUrlInTab(moduleManagedUrl2, PageTransition.LINK,
cctActivity.getActivityTab());
mCustomTabActivityTestRule.loadUrlInTab(mTestPage, PageTransition.LINK,
cctActivity.getActivityTab());
mCustomTabActivityTestRule.loadUrlInTab(mTestPage2, PageTransition.LINK,
cctActivity.getActivityTab());
// click close button and wait while cct is hidden
runAndWaitForActivityStopped(() ->
ClickUtils.clickButton(cctActivity.findViewById(R.id.close_button)));
}
@Test @Test
@SmallTest @SmallTest
@RetryOnFailure @RetryOnFailure
......
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