Upstream oodles of Chrome for Android code into Chromium.
[chromium-blink-merge.git] / chrome / android / javatests / src / org / chromium / chrome / browser / infobar / InfoBarTest2.java
blob00b1caa68df8a563e0b364d97e23cc5faf5fd6ed
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.chrome.browser.infobar;
7 import android.graphics.Rect;
8 import android.graphics.Region;
9 import android.test.FlakyTest;
10 import android.test.suitebuilder.annotation.MediumTest;
11 import android.view.ViewGroup;
12 import android.view.ViewTreeObserver;
14 import org.chromium.base.ThreadUtils;
15 import org.chromium.base.test.util.Feature;
16 import org.chromium.chrome.browser.ChromeActivity;
17 import org.chromium.chrome.browser.Tab;
18 import org.chromium.chrome.browser.preferences.NetworkPredictionOptions;
19 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
20 import org.chromium.chrome.test.ChromeActivityTestCaseBase;
21 import org.chromium.chrome.test.util.InfoBarTestAnimationListener;
22 import org.chromium.chrome.test.util.InfoBarUtil;
23 import org.chromium.chrome.test.util.TestHttpServerClient;
24 import org.chromium.content.browser.test.util.Criteria;
25 import org.chromium.content.browser.test.util.CriteriaHelper;
27 import java.util.ArrayList;
28 import java.util.concurrent.Callable;
29 import java.util.concurrent.ExecutionException;
30 import java.util.concurrent.TimeoutException;
31 import java.util.concurrent.atomic.AtomicInteger;
33 /**
34 * Tests for InfoBars.
36 * TODO(newt): merge this with InfoBarTest after upstreaming.
38 public class InfoBarTest2 extends ChromeActivityTestCaseBase<ChromeActivity> {
39 static class MutableBoolean {
40 public boolean mValue = false;
43 private InfoBarTestAnimationListener mListener;
45 public InfoBarTest2() {
46 super(ChromeActivity.class);
49 @Override
50 protected void setUp() throws Exception {
51 super.setUp();
53 // Register for animation notifications
54 InfoBarContainer container =
55 getActivity().getActivityTab().getInfoBarContainer();
56 mListener = new InfoBarTestAnimationListener();
57 container.setAnimationListener(mListener);
60 // Adds an infobar to the currrent tab. Blocks until the infobar has been added.
61 protected void addInfoBarToCurrentTab(final InfoBar infoBar) throws InterruptedException {
62 getInstrumentation().runOnMainSync(new Runnable() {
63 @Override
64 public void run() {
65 Tab tab = getActivity().getActivityTab();
66 assertTrue("Failed to find tab.", tab != null);
67 tab.getInfoBarContainer().addInfoBar(infoBar);
69 });
70 assertTrue("InfoBar not added.", mListener.addInfoBarAnimationFinished());
71 getInstrumentation().waitForIdleSync();
74 // Removes an infobar from the currrent tab. Blocks until the infobar has been removed.
75 protected void removeInfoBarFromCurrentTab(final InfoBar infoBar) throws InterruptedException {
76 getInstrumentation().runOnMainSync(new Runnable() {
77 @Override
78 public void run() {
79 Tab tab = getActivity().getActivityTab();
80 assertTrue("Failed to find tab.", tab != null);
81 tab.getInfoBarContainer().removeInfoBar(infoBar);
83 });
84 assertTrue("InfoBar not removed.", mListener.removeInfoBarAnimationFinished());
85 getInstrumentation().waitForIdleSync();
88 // Dismisses the passed infobar. Blocks until the bar has been removed.
89 protected void dismissInfoBar(final InfoBar infoBar) throws InterruptedException {
90 getInstrumentation().runOnMainSync(new Runnable() {
91 @Override
92 public void run() {
93 infoBar.dismissJavaOnlyInfoBar();
95 });
96 assertTrue("InfoBar not removed.", mListener.removeInfoBarAnimationFinished());
97 getInstrumentation().waitForIdleSync();
100 protected ArrayList<Integer> getInfoBarIdsForCurrentTab() {
101 final ArrayList<Integer> infoBarIds = new ArrayList<Integer>();
102 getInstrumentation().runOnMainSync(new Runnable() {
103 @Override
104 public void run() {
105 Tab tab = getActivity().getActivityTab();
106 assertTrue("Failed to find tab.", tab != null);
107 for (InfoBar infoBar : tab.getInfoBarContainer().getInfoBars()) {
108 infoBarIds.add(infoBar.getId());
112 return infoBarIds;
116 * Verifies that infobars added from Java expire or not as expected.
118 @MediumTest
119 @Feature({"Browser"})
120 public void testInfoBarExpiration() throws InterruptedException {
121 // First add an infobar that expires.
122 final MutableBoolean dismissed = new MutableBoolean();
123 MessageInfoBar expiringInfoBar = new MessageInfoBar("Hello!");
124 expiringInfoBar.setDismissedListener(new InfoBarListeners.Dismiss() {
125 @Override
126 public void onInfoBarDismissed(InfoBar infoBar) {
127 dismissed.mValue = true;
130 expiringInfoBar.setExpireOnNavigation(true);
131 addInfoBarToCurrentTab(expiringInfoBar);
133 // Verify it's really there.
134 ArrayList<Integer> infoBarIds = getInfoBarIdsForCurrentTab();
135 assertEquals(1, infoBarIds.size());
136 assertEquals(expiringInfoBar.getId(), infoBarIds.get(0).intValue());
138 // Now navigate, it should expire.
139 loadUrl(TestHttpServerClient.getUrl("chrome/test/data/android/google.html"));
140 assertTrue("InfoBar not removed.", mListener.removeInfoBarAnimationFinished());
141 assertTrue("InfoBar did not expire on navigation.", dismissed.mValue);
142 infoBarIds = getInfoBarIdsForCurrentTab();
143 assertTrue(infoBarIds.isEmpty());
145 // Now test a non-expiring infobar.
146 MessageInfoBar persistentInfoBar = new MessageInfoBar("Hello!");
147 persistentInfoBar.setDismissedListener(new InfoBarListeners.Dismiss() {
148 @Override
149 public void onInfoBarDismissed(InfoBar infoBar) {
150 dismissed.mValue = true;
153 dismissed.mValue = false;
154 persistentInfoBar.setExpireOnNavigation(false);
155 addInfoBarToCurrentTab(persistentInfoBar);
157 // Navigate, it should still be there.
158 loadUrl(TestHttpServerClient.getUrl("chrome/test/data/android/google.html"));
159 assertFalse("InfoBar did expire on navigation.", dismissed.mValue);
160 infoBarIds = getInfoBarIdsForCurrentTab();
161 assertEquals(1, infoBarIds.size());
162 assertEquals(persistentInfoBar.getId(), infoBarIds.get(0).intValue());
164 // Close the infobar.
165 dismissInfoBar(persistentInfoBar);
168 // Define function to pass parameter to Runnable to be used in testInfoBarExpirationNoPrerender.
169 private Runnable setNetworkPredictionOptions(
170 final NetworkPredictionOptions networkPredictionOptions) {
171 return new Runnable() {
172 @Override
173 public void run() {
174 PrefServiceBridge.getInstance().setNetworkPredictionOptions(
175 networkPredictionOptions);
181 * Same as testInfoBarExpiration but with prerender turned-off.
182 * The behavior when prerender is on/off is different as in the prerender case the infobars are
183 * added when we swap tabs.
184 * @throws InterruptedException
186 @MediumTest
187 @Feature({"Browser"})
188 public void testInfoBarExpirationNoPrerender() throws InterruptedException, ExecutionException {
189 // Save prediction preference.
190 NetworkPredictionOptions networkPredictionOption =
191 ThreadUtils.runOnUiThreadBlocking(new Callable<NetworkPredictionOptions>() {
192 @Override
193 public NetworkPredictionOptions call() {
194 return PrefServiceBridge.getInstance().getNetworkPredictionOptions();
197 try {
198 ThreadUtils.runOnUiThreadBlocking(setNetworkPredictionOptions(
199 NetworkPredictionOptions.NETWORK_PREDICTION_NEVER));
200 testInfoBarExpiration();
201 } finally {
202 // Make sure we restore prediction preference.
203 ThreadUtils.runOnUiThreadBlocking(setNetworkPredictionOptions(networkPredictionOption));
208 * Tests that adding and then immediately removing an infobar works as expected (and does not
209 * assert).
211 @MediumTest
212 @Feature({"Browser"})
213 public void testQuickAddOneAndRemove() throws InterruptedException {
214 final InfoBar infoBar = new MessageInfoBar("Hello");
215 addInfoBarToCurrentTab(infoBar);
216 removeInfoBarFromCurrentTab(infoBar);
217 assertTrue(getInfoBarIdsForCurrentTab().isEmpty());
221 * Tests that adding and then immediately dismissing an infobar works as expected (and does not
222 * assert).
224 @MediumTest
225 @Feature({"Browser"})
226 public void testQuickAddOneAndDismiss() throws InterruptedException {
227 final InfoBar infoBar = new MessageInfoBar("Hello");
228 addInfoBarToCurrentTab(infoBar);
229 dismissInfoBar(infoBar);
230 assertTrue(getInfoBarIdsForCurrentTab().isEmpty());
234 * Tests that adding 2 infobars and then immediately removing the last one works as expected.
235 * This scenario is special as the 2nd infobar does not even get added to the view hierarchy.
237 @MediumTest
238 @Feature({"Browser"})
239 public void testAddTwoAndRemoveOneQuick() throws InterruptedException {
240 final InfoBar infoBar1 = new MessageInfoBar("One");
241 final InfoBar infoBar2 = new MessageInfoBar("Two");
242 getInstrumentation().runOnMainSync(new Runnable() {
243 @Override
244 public void run() {
245 Tab tab = getActivity().getActivityTab();
246 assertTrue("Failed to find tab.", tab != null);
247 tab.getInfoBarContainer().addInfoBar(infoBar1);
248 tab.getInfoBarContainer().addInfoBar(infoBar2);
249 tab.getInfoBarContainer().removeInfoBar(infoBar2);
253 // We should get an infobar added event for the first infobar.
254 assertTrue("InfoBar not added.", mListener.addInfoBarAnimationFinished());
256 // But no infobar removed event as the 2nd infobar was removed before it got added.
257 assertFalse("InfoBar not removed.", mListener.removeInfoBarAnimationFinished());
258 ArrayList<Integer> infoBarIds = getInfoBarIdsForCurrentTab();
259 assertEquals(1, infoBarIds.size());
260 assertEquals(infoBar1.getId(), infoBarIds.get(0).intValue());
264 * Tests that adding 2 infobars and then immediately dismissing the last one works as expected
265 * This scenario is special as the 2nd infobar does not even get added to the view hierarchy.
267 @MediumTest
268 @Feature({"Browser"})
269 public void testAddTwoAndDismissOneQuick() throws InterruptedException {
270 final InfoBar infoBar1 = new MessageInfoBar("One");
271 final InfoBar infoBar2 = new MessageInfoBar("Two");
272 getInstrumentation().runOnMainSync(new Runnable() {
273 @Override
274 public void run() {
275 Tab tab = getActivity().getActivityTab();
276 assertTrue("Failed to find tab.", tab != null);
277 tab.getInfoBarContainer().addInfoBar(infoBar1);
278 tab.getInfoBarContainer().addInfoBar(infoBar2);
279 infoBar2.dismissJavaOnlyInfoBar();
283 // We should get an infobar added event for the first infobar.
284 assertTrue("InfoBar not added.", mListener.addInfoBarAnimationFinished());
286 // But no infobar removed event as the 2nd infobar was removed before it got added.
287 assertFalse("InfoBar not removed.", mListener.removeInfoBarAnimationFinished());
288 ArrayList<Integer> infoBarIds = getInfoBarIdsForCurrentTab();
289 assertEquals(1, infoBarIds.size());
290 assertEquals(infoBar1.getId(), infoBarIds.get(0).intValue());
294 * Tests that we don't assert when a tab is getting closed while an infobar is being shown and
295 * had been removed.
297 @MediumTest
298 @Feature({"Browser"})
299 public void testCloseTabOnAdd() throws InterruptedException {
300 loadUrl(TestHttpServerClient.getUrl(
301 "chrome/test/data/android/google.html"));
303 final InfoBar infoBar = new MessageInfoBar("Hello");
304 addInfoBarToCurrentTab(infoBar);
305 getInstrumentation().runOnMainSync(new Runnable() {
306 @Override
307 public void run() {
308 Tab tab = getActivity().getActivityTab();
309 assertTrue("Failed to find tab.", tab != null);
310 tab.getInfoBarContainer().removeInfoBar(infoBar);
311 getActivity().getTabModelSelector().closeTab(tab);
317 * Tests that the x button in the infobar does close the infobar and that the event is not
318 * propagated to the ContentView.
319 * @MediumTest
320 * @Feature({"Browser"})
321 * Bug: http://crbug.com/172427
323 @FlakyTest
324 public void testCloseButton() throws InterruptedException, TimeoutException {
325 loadUrl(TestHttpServerClient.getUrl(
326 "chrome/test/data/android/click_listener.html"));
327 final InfoBar infoBar = new MessageInfoBar("Hello");
328 getInstrumentation().runOnMainSync(new Runnable() {
329 @Override
330 public void run() {
331 Tab tab = getActivity().getActivityTab();
332 assertTrue("Failed to find tab.", tab != null);
333 tab.getInfoBarContainer().addInfoBar(infoBar);
336 assertTrue("InfoBar not added", mListener.addInfoBarAnimationFinished());
338 // Now press the close button.
339 assertTrue("Close button wasn't found", InfoBarUtil.clickCloseButton(infoBar));
340 assertTrue("Infobar not removed.", mListener.removeInfoBarAnimationFinished());
342 // The page should not have received the click.
343 assertTrue("The page recieved the click.",
344 !Boolean.parseBoolean(runJavaScriptCodeInCurrentTab("wasClicked")));
348 * Tests that adding and removing correctly manages the transparent region, which allows for
349 * optimizations in SurfaceFlinger (less overlays).
351 @MediumTest
352 @Feature({"Browser"})
353 public void testAddAndDismissSurfaceFlingerOverlays() throws InterruptedException {
354 final ViewGroup decorView = (ViewGroup) getActivity().getWindow().getDecorView();
355 final InfoBarContainer infoBarContainer =
356 getActivity().getActivityTab().getInfoBarContainer();
358 // Detect layouts. Note this doesn't actually need to be atomic (just final).
359 final AtomicInteger layoutCount = new AtomicInteger();
360 getInstrumentation().runOnMainSync(new Runnable() {
361 @Override
362 public void run() {
363 decorView.getViewTreeObserver().addOnGlobalLayoutListener(
364 new ViewTreeObserver.OnGlobalLayoutListener() {
365 @Override
366 public void onGlobalLayout() {
367 layoutCount.incrementAndGet();
373 // First add an infobar.
374 final InfoBar infoBar = new MessageInfoBar("Hello");
375 addInfoBarToCurrentTab(infoBar);
377 // A layout must occur to recalculate the transparent region.
378 boolean layoutOccured = CriteriaHelper.pollForUIThreadCriteria(
379 new Criteria() {
380 @Override
381 public boolean isSatisfied() {
382 return layoutCount.get() > 0;
385 assertTrue(layoutOccured);
387 final Rect fullDisplayFrame = new Rect();
388 final Rect fullDisplayFrameMinusContainer = new Rect();
389 final Rect containerDisplayFrame = new Rect();
391 getInstrumentation().runOnMainSync(new Runnable() {
392 @Override
393 public void run() {
394 decorView.getWindowVisibleDisplayFrame(fullDisplayFrame);
395 decorView.getWindowVisibleDisplayFrame(fullDisplayFrameMinusContainer);
396 fullDisplayFrameMinusContainer.bottom -= infoBarContainer.getHeight();
397 int windowLocation[] = new int[2];
398 infoBarContainer.getLocationInWindow(windowLocation);
399 containerDisplayFrame.set(
400 windowLocation[0],
401 windowLocation[1],
402 windowLocation[0] + infoBarContainer.getWidth(),
403 windowLocation[1] + infoBarContainer.getHeight());
405 // The InfoBarContainer subtracts itself from the transparent region.
406 Region transparentRegion = new Region(fullDisplayFrame);
407 infoBarContainer.gatherTransparentRegion(transparentRegion);
408 assertEquals(transparentRegion.getBounds(), fullDisplayFrameMinusContainer);
412 // Now remove the infobar.
413 layoutCount.set(0);
414 dismissInfoBar(infoBar);
416 // A layout must occur to recalculate the transparent region.
417 layoutOccured = CriteriaHelper.pollForUIThreadCriteria(
418 new Criteria() {
419 @Override
420 public boolean isSatisfied() {
421 return layoutCount.get() > 0;
424 assertTrue(layoutOccured);
426 getInstrumentation().runOnMainSync(new Runnable() {
427 @Override
428 public void run() {
429 // The InfoBarContainer should no longer be subtracted from the transparent region.
430 // We really want assertTrue(transparentRegion.contains(containerDisplayFrame)),
431 // but region doesn't have 'contains(Rect)', so we invert the test. So, the old
432 // container rect can't touch the bounding rect of the non-transparent region).
433 Region transparentRegion = new Region();
434 decorView.gatherTransparentRegion(transparentRegion);
435 Region opaqueRegion = new Region(fullDisplayFrame);
436 opaqueRegion.op(transparentRegion, Region.Op.DIFFERENCE);
437 assertFalse(opaqueRegion.getBounds().intersect(containerDisplayFrame));
441 // Additional manual test that this is working:
442 // - adb shell dumpsys SurfaceFlinger
443 // - Observe that Clank's overlay size changes (or disappears if URLbar is also gone).
446 @Override
447 public void startMainActivity() throws InterruptedException {
448 startMainActivityOnBlankPage();