| Index: chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java
|
| diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..00b1caa68df8a563e0b364d97e23cc5faf5fd6ed
|
| --- /dev/null
|
| +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarTest2.java
|
| @@ -0,0 +1,450 @@
|
| +// Copyright 2015 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.infobar;
|
| +
|
| +import android.graphics.Rect;
|
| +import android.graphics.Region;
|
| +import android.test.FlakyTest;
|
| +import android.test.suitebuilder.annotation.MediumTest;
|
| +import android.view.ViewGroup;
|
| +import android.view.ViewTreeObserver;
|
| +
|
| +import org.chromium.base.ThreadUtils;
|
| +import org.chromium.base.test.util.Feature;
|
| +import org.chromium.chrome.browser.ChromeActivity;
|
| +import org.chromium.chrome.browser.Tab;
|
| +import org.chromium.chrome.browser.preferences.NetworkPredictionOptions;
|
| +import org.chromium.chrome.browser.preferences.PrefServiceBridge;
|
| +import org.chromium.chrome.test.ChromeActivityTestCaseBase;
|
| +import org.chromium.chrome.test.util.InfoBarTestAnimationListener;
|
| +import org.chromium.chrome.test.util.InfoBarUtil;
|
| +import org.chromium.chrome.test.util.TestHttpServerClient;
|
| +import org.chromium.content.browser.test.util.Criteria;
|
| +import org.chromium.content.browser.test.util.CriteriaHelper;
|
| +
|
| +import java.util.ArrayList;
|
| +import java.util.concurrent.Callable;
|
| +import java.util.concurrent.ExecutionException;
|
| +import java.util.concurrent.TimeoutException;
|
| +import java.util.concurrent.atomic.AtomicInteger;
|
| +
|
| +/**
|
| + * Tests for InfoBars.
|
| + *
|
| + * TODO(newt): merge this with InfoBarTest after upstreaming.
|
| + */
|
| +public class InfoBarTest2 extends ChromeActivityTestCaseBase<ChromeActivity> {
|
| + static class MutableBoolean {
|
| + public boolean mValue = false;
|
| + }
|
| +
|
| + private InfoBarTestAnimationListener mListener;
|
| +
|
| + public InfoBarTest2() {
|
| + super(ChromeActivity.class);
|
| + }
|
| +
|
| + @Override
|
| + protected void setUp() throws Exception {
|
| + super.setUp();
|
| +
|
| + // Register for animation notifications
|
| + InfoBarContainer container =
|
| + getActivity().getActivityTab().getInfoBarContainer();
|
| + mListener = new InfoBarTestAnimationListener();
|
| + container.setAnimationListener(mListener);
|
| + }
|
| +
|
| + // Adds an infobar to the currrent tab. Blocks until the infobar has been added.
|
| + protected void addInfoBarToCurrentTab(final InfoBar infoBar) throws InterruptedException {
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + Tab tab = getActivity().getActivityTab();
|
| + assertTrue("Failed to find tab.", tab != null);
|
| + tab.getInfoBarContainer().addInfoBar(infoBar);
|
| + }
|
| + });
|
| + assertTrue("InfoBar not added.", mListener.addInfoBarAnimationFinished());
|
| + getInstrumentation().waitForIdleSync();
|
| + }
|
| +
|
| + // Removes an infobar from the currrent tab. Blocks until the infobar has been removed.
|
| + protected void removeInfoBarFromCurrentTab(final InfoBar infoBar) throws InterruptedException {
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + Tab tab = getActivity().getActivityTab();
|
| + assertTrue("Failed to find tab.", tab != null);
|
| + tab.getInfoBarContainer().removeInfoBar(infoBar);
|
| + }
|
| + });
|
| + assertTrue("InfoBar not removed.", mListener.removeInfoBarAnimationFinished());
|
| + getInstrumentation().waitForIdleSync();
|
| + }
|
| +
|
| + // Dismisses the passed infobar. Blocks until the bar has been removed.
|
| + protected void dismissInfoBar(final InfoBar infoBar) throws InterruptedException {
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + infoBar.dismissJavaOnlyInfoBar();
|
| + }
|
| + });
|
| + assertTrue("InfoBar not removed.", mListener.removeInfoBarAnimationFinished());
|
| + getInstrumentation().waitForIdleSync();
|
| + }
|
| +
|
| + protected ArrayList<Integer> getInfoBarIdsForCurrentTab() {
|
| + final ArrayList<Integer> infoBarIds = new ArrayList<Integer>();
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + Tab tab = getActivity().getActivityTab();
|
| + assertTrue("Failed to find tab.", tab != null);
|
| + for (InfoBar infoBar : tab.getInfoBarContainer().getInfoBars()) {
|
| + infoBarIds.add(infoBar.getId());
|
| + }
|
| + }
|
| + });
|
| + return infoBarIds;
|
| + }
|
| +
|
| + /**
|
| + * Verifies that infobars added from Java expire or not as expected.
|
| + */
|
| + @MediumTest
|
| + @Feature({"Browser"})
|
| + public void testInfoBarExpiration() throws InterruptedException {
|
| + // First add an infobar that expires.
|
| + final MutableBoolean dismissed = new MutableBoolean();
|
| + MessageInfoBar expiringInfoBar = new MessageInfoBar("Hello!");
|
| + expiringInfoBar.setDismissedListener(new InfoBarListeners.Dismiss() {
|
| + @Override
|
| + public void onInfoBarDismissed(InfoBar infoBar) {
|
| + dismissed.mValue = true;
|
| + }
|
| + });
|
| + expiringInfoBar.setExpireOnNavigation(true);
|
| + addInfoBarToCurrentTab(expiringInfoBar);
|
| +
|
| + // Verify it's really there.
|
| + ArrayList<Integer> infoBarIds = getInfoBarIdsForCurrentTab();
|
| + assertEquals(1, infoBarIds.size());
|
| + assertEquals(expiringInfoBar.getId(), infoBarIds.get(0).intValue());
|
| +
|
| + // Now navigate, it should expire.
|
| + loadUrl(TestHttpServerClient.getUrl("chrome/test/data/android/google.html"));
|
| + assertTrue("InfoBar not removed.", mListener.removeInfoBarAnimationFinished());
|
| + assertTrue("InfoBar did not expire on navigation.", dismissed.mValue);
|
| + infoBarIds = getInfoBarIdsForCurrentTab();
|
| + assertTrue(infoBarIds.isEmpty());
|
| +
|
| + // Now test a non-expiring infobar.
|
| + MessageInfoBar persistentInfoBar = new MessageInfoBar("Hello!");
|
| + persistentInfoBar.setDismissedListener(new InfoBarListeners.Dismiss() {
|
| + @Override
|
| + public void onInfoBarDismissed(InfoBar infoBar) {
|
| + dismissed.mValue = true;
|
| + }
|
| + });
|
| + dismissed.mValue = false;
|
| + persistentInfoBar.setExpireOnNavigation(false);
|
| + addInfoBarToCurrentTab(persistentInfoBar);
|
| +
|
| + // Navigate, it should still be there.
|
| + loadUrl(TestHttpServerClient.getUrl("chrome/test/data/android/google.html"));
|
| + assertFalse("InfoBar did expire on navigation.", dismissed.mValue);
|
| + infoBarIds = getInfoBarIdsForCurrentTab();
|
| + assertEquals(1, infoBarIds.size());
|
| + assertEquals(persistentInfoBar.getId(), infoBarIds.get(0).intValue());
|
| +
|
| + // Close the infobar.
|
| + dismissInfoBar(persistentInfoBar);
|
| + }
|
| +
|
| + // Define function to pass parameter to Runnable to be used in testInfoBarExpirationNoPrerender.
|
| + private Runnable setNetworkPredictionOptions(
|
| + final NetworkPredictionOptions networkPredictionOptions) {
|
| + return new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + PrefServiceBridge.getInstance().setNetworkPredictionOptions(
|
| + networkPredictionOptions);
|
| + }
|
| + };
|
| + };
|
| +
|
| + /**
|
| + * Same as testInfoBarExpiration but with prerender turned-off.
|
| + * The behavior when prerender is on/off is different as in the prerender case the infobars are
|
| + * added when we swap tabs.
|
| + * @throws InterruptedException
|
| + */
|
| + @MediumTest
|
| + @Feature({"Browser"})
|
| + public void testInfoBarExpirationNoPrerender() throws InterruptedException, ExecutionException {
|
| + // Save prediction preference.
|
| + NetworkPredictionOptions networkPredictionOption =
|
| + ThreadUtils.runOnUiThreadBlocking(new Callable<NetworkPredictionOptions>() {
|
| + @Override
|
| + public NetworkPredictionOptions call() {
|
| + return PrefServiceBridge.getInstance().getNetworkPredictionOptions();
|
| + }
|
| + });
|
| + try {
|
| + ThreadUtils.runOnUiThreadBlocking(setNetworkPredictionOptions(
|
| + NetworkPredictionOptions.NETWORK_PREDICTION_NEVER));
|
| + testInfoBarExpiration();
|
| + } finally {
|
| + // Make sure we restore prediction preference.
|
| + ThreadUtils.runOnUiThreadBlocking(setNetworkPredictionOptions(networkPredictionOption));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Tests that adding and then immediately removing an infobar works as expected (and does not
|
| + * assert).
|
| + */
|
| + @MediumTest
|
| + @Feature({"Browser"})
|
| + public void testQuickAddOneAndRemove() throws InterruptedException {
|
| + final InfoBar infoBar = new MessageInfoBar("Hello");
|
| + addInfoBarToCurrentTab(infoBar);
|
| + removeInfoBarFromCurrentTab(infoBar);
|
| + assertTrue(getInfoBarIdsForCurrentTab().isEmpty());
|
| + }
|
| +
|
| + /**
|
| + * Tests that adding and then immediately dismissing an infobar works as expected (and does not
|
| + * assert).
|
| + */
|
| + @MediumTest
|
| + @Feature({"Browser"})
|
| + public void testQuickAddOneAndDismiss() throws InterruptedException {
|
| + final InfoBar infoBar = new MessageInfoBar("Hello");
|
| + addInfoBarToCurrentTab(infoBar);
|
| + dismissInfoBar(infoBar);
|
| + assertTrue(getInfoBarIdsForCurrentTab().isEmpty());
|
| + }
|
| +
|
| + /**
|
| + * Tests that adding 2 infobars and then immediately removing the last one works as expected.
|
| + * This scenario is special as the 2nd infobar does not even get added to the view hierarchy.
|
| + */
|
| + @MediumTest
|
| + @Feature({"Browser"})
|
| + public void testAddTwoAndRemoveOneQuick() throws InterruptedException {
|
| + final InfoBar infoBar1 = new MessageInfoBar("One");
|
| + final InfoBar infoBar2 = new MessageInfoBar("Two");
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + Tab tab = getActivity().getActivityTab();
|
| + assertTrue("Failed to find tab.", tab != null);
|
| + tab.getInfoBarContainer().addInfoBar(infoBar1);
|
| + tab.getInfoBarContainer().addInfoBar(infoBar2);
|
| + tab.getInfoBarContainer().removeInfoBar(infoBar2);
|
| + }
|
| + });
|
| +
|
| + // We should get an infobar added event for the first infobar.
|
| + assertTrue("InfoBar not added.", mListener.addInfoBarAnimationFinished());
|
| +
|
| + // But no infobar removed event as the 2nd infobar was removed before it got added.
|
| + assertFalse("InfoBar not removed.", mListener.removeInfoBarAnimationFinished());
|
| + ArrayList<Integer> infoBarIds = getInfoBarIdsForCurrentTab();
|
| + assertEquals(1, infoBarIds.size());
|
| + assertEquals(infoBar1.getId(), infoBarIds.get(0).intValue());
|
| + }
|
| +
|
| + /**
|
| + * Tests that adding 2 infobars and then immediately dismissing the last one works as expected
|
| + * This scenario is special as the 2nd infobar does not even get added to the view hierarchy.
|
| + */
|
| + @MediumTest
|
| + @Feature({"Browser"})
|
| + public void testAddTwoAndDismissOneQuick() throws InterruptedException {
|
| + final InfoBar infoBar1 = new MessageInfoBar("One");
|
| + final InfoBar infoBar2 = new MessageInfoBar("Two");
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + Tab tab = getActivity().getActivityTab();
|
| + assertTrue("Failed to find tab.", tab != null);
|
| + tab.getInfoBarContainer().addInfoBar(infoBar1);
|
| + tab.getInfoBarContainer().addInfoBar(infoBar2);
|
| + infoBar2.dismissJavaOnlyInfoBar();
|
| + }
|
| + });
|
| +
|
| + // We should get an infobar added event for the first infobar.
|
| + assertTrue("InfoBar not added.", mListener.addInfoBarAnimationFinished());
|
| +
|
| + // But no infobar removed event as the 2nd infobar was removed before it got added.
|
| + assertFalse("InfoBar not removed.", mListener.removeInfoBarAnimationFinished());
|
| + ArrayList<Integer> infoBarIds = getInfoBarIdsForCurrentTab();
|
| + assertEquals(1, infoBarIds.size());
|
| + assertEquals(infoBar1.getId(), infoBarIds.get(0).intValue());
|
| + }
|
| +
|
| + /**
|
| + * Tests that we don't assert when a tab is getting closed while an infobar is being shown and
|
| + * had been removed.
|
| + */
|
| + @MediumTest
|
| + @Feature({"Browser"})
|
| + public void testCloseTabOnAdd() throws InterruptedException {
|
| + loadUrl(TestHttpServerClient.getUrl(
|
| + "chrome/test/data/android/google.html"));
|
| +
|
| + final InfoBar infoBar = new MessageInfoBar("Hello");
|
| + addInfoBarToCurrentTab(infoBar);
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + Tab tab = getActivity().getActivityTab();
|
| + assertTrue("Failed to find tab.", tab != null);
|
| + tab.getInfoBarContainer().removeInfoBar(infoBar);
|
| + getActivity().getTabModelSelector().closeTab(tab);
|
| + }
|
| + });
|
| + }
|
| +
|
| + /**
|
| + * Tests that the x button in the infobar does close the infobar and that the event is not
|
| + * propagated to the ContentView.
|
| + * @MediumTest
|
| + * @Feature({"Browser"})
|
| + * Bug: http://crbug.com/172427
|
| + */
|
| + @FlakyTest
|
| + public void testCloseButton() throws InterruptedException, TimeoutException {
|
| + loadUrl(TestHttpServerClient.getUrl(
|
| + "chrome/test/data/android/click_listener.html"));
|
| + final InfoBar infoBar = new MessageInfoBar("Hello");
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + Tab tab = getActivity().getActivityTab();
|
| + assertTrue("Failed to find tab.", tab != null);
|
| + tab.getInfoBarContainer().addInfoBar(infoBar);
|
| + }
|
| + });
|
| + assertTrue("InfoBar not added", mListener.addInfoBarAnimationFinished());
|
| +
|
| + // Now press the close button.
|
| + assertTrue("Close button wasn't found", InfoBarUtil.clickCloseButton(infoBar));
|
| + assertTrue("Infobar not removed.", mListener.removeInfoBarAnimationFinished());
|
| +
|
| + // The page should not have received the click.
|
| + assertTrue("The page recieved the click.",
|
| + !Boolean.parseBoolean(runJavaScriptCodeInCurrentTab("wasClicked")));
|
| + }
|
| +
|
| + /**
|
| + * Tests that adding and removing correctly manages the transparent region, which allows for
|
| + * optimizations in SurfaceFlinger (less overlays).
|
| + */
|
| + @MediumTest
|
| + @Feature({"Browser"})
|
| + public void testAddAndDismissSurfaceFlingerOverlays() throws InterruptedException {
|
| + final ViewGroup decorView = (ViewGroup) getActivity().getWindow().getDecorView();
|
| + final InfoBarContainer infoBarContainer =
|
| + getActivity().getActivityTab().getInfoBarContainer();
|
| +
|
| + // Detect layouts. Note this doesn't actually need to be atomic (just final).
|
| + final AtomicInteger layoutCount = new AtomicInteger();
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + decorView.getViewTreeObserver().addOnGlobalLayoutListener(
|
| + new ViewTreeObserver.OnGlobalLayoutListener() {
|
| + @Override
|
| + public void onGlobalLayout() {
|
| + layoutCount.incrementAndGet();
|
| + }
|
| + });
|
| + }
|
| + });
|
| +
|
| + // First add an infobar.
|
| + final InfoBar infoBar = new MessageInfoBar("Hello");
|
| + addInfoBarToCurrentTab(infoBar);
|
| +
|
| + // A layout must occur to recalculate the transparent region.
|
| + boolean layoutOccured = CriteriaHelper.pollForUIThreadCriteria(
|
| + new Criteria() {
|
| + @Override
|
| + public boolean isSatisfied() {
|
| + return layoutCount.get() > 0;
|
| + }
|
| + });
|
| + assertTrue(layoutOccured);
|
| +
|
| + final Rect fullDisplayFrame = new Rect();
|
| + final Rect fullDisplayFrameMinusContainer = new Rect();
|
| + final Rect containerDisplayFrame = new Rect();
|
| +
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + decorView.getWindowVisibleDisplayFrame(fullDisplayFrame);
|
| + decorView.getWindowVisibleDisplayFrame(fullDisplayFrameMinusContainer);
|
| + fullDisplayFrameMinusContainer.bottom -= infoBarContainer.getHeight();
|
| + int windowLocation[] = new int[2];
|
| + infoBarContainer.getLocationInWindow(windowLocation);
|
| + containerDisplayFrame.set(
|
| + windowLocation[0],
|
| + windowLocation[1],
|
| + windowLocation[0] + infoBarContainer.getWidth(),
|
| + windowLocation[1] + infoBarContainer.getHeight());
|
| +
|
| + // The InfoBarContainer subtracts itself from the transparent region.
|
| + Region transparentRegion = new Region(fullDisplayFrame);
|
| + infoBarContainer.gatherTransparentRegion(transparentRegion);
|
| + assertEquals(transparentRegion.getBounds(), fullDisplayFrameMinusContainer);
|
| + }
|
| + });
|
| +
|
| + // Now remove the infobar.
|
| + layoutCount.set(0);
|
| + dismissInfoBar(infoBar);
|
| +
|
| + // A layout must occur to recalculate the transparent region.
|
| + layoutOccured = CriteriaHelper.pollForUIThreadCriteria(
|
| + new Criteria() {
|
| + @Override
|
| + public boolean isSatisfied() {
|
| + return layoutCount.get() > 0;
|
| + }
|
| + });
|
| + assertTrue(layoutOccured);
|
| +
|
| + getInstrumentation().runOnMainSync(new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + // The InfoBarContainer should no longer be subtracted from the transparent region.
|
| + // We really want assertTrue(transparentRegion.contains(containerDisplayFrame)),
|
| + // but region doesn't have 'contains(Rect)', so we invert the test. So, the old
|
| + // container rect can't touch the bounding rect of the non-transparent region).
|
| + Region transparentRegion = new Region();
|
| + decorView.gatherTransparentRegion(transparentRegion);
|
| + Region opaqueRegion = new Region(fullDisplayFrame);
|
| + opaqueRegion.op(transparentRegion, Region.Op.DIFFERENCE);
|
| + assertFalse(opaqueRegion.getBounds().intersect(containerDisplayFrame));
|
| + }
|
| + });
|
| +
|
| + // Additional manual test that this is working:
|
| + // - adb shell dumpsys SurfaceFlinger
|
| + // - Observe that Clank's overlay size changes (or disappears if URLbar is also gone).
|
| + }
|
| +
|
| + @Override
|
| + public void startMainActivity() throws InterruptedException {
|
| + startMainActivityOnBlankPage();
|
| + }
|
| +}
|
|
|