Index: chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java |
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java |
index 3d060ec9ed3758f5c5f5e927c8153151314dbfa2..eb60b9bba08d397d5845471df871d3c9c2d1803b 100644 |
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java |
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java |
@@ -22,6 +22,7 @@ import org.chromium.chrome.test.util.ChromeRestriction; |
import org.chromium.chrome.test.util.ChromeTabUtils; |
import org.chromium.chrome.test.util.TabStripUtils; |
import org.chromium.content.browser.test.util.CallbackHelper; |
+import org.chromium.ui.base.LocalizationUtils; |
import java.util.concurrent.TimeoutException; |
@@ -466,6 +467,224 @@ public class TabStripTest extends ChromeTabbedActivityTestBase { |
} |
/** |
+ * Compares tab strips with models after switching between the ScrollingStripStacker and |
+ * CascadingStripStacker when an incognito tab is present. Also tests tapping the incognito |
+ * button while the strip is using the ScrollingStripStacker (other tests cover tapping |
+ * the button while using the CascadingStripStacker). |
+ */ |
+ @LargeTest |
+ @Restriction(ChromeRestriction.RESTRICTION_TYPE_TABLET) |
+ @Feature({"TabStrip"}) |
+ public void testSwitchStripStackersWithIncognito() throws InterruptedException { |
+ // Open an incognito tab. |
+ newIncognitoTabFromMenu(); |
+ |
+ // Switch to the ScrollingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(false); |
+ |
+ // Switch tab models. |
+ clickIncognitoToggleButton(); |
+ |
+ // Switch to the CascadingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(true); |
+ } |
+ |
+ /** |
+ * Compares tab strip with model after switching between the ScrollingStripStacker and |
+ * CascadingStripStacker when the last tab is selected. This also verifies that the strip |
+ * scrolls correctly and the correct index is selected after switching. |
+ */ |
+ @LargeTest |
+ @Restriction(ChromeRestriction.RESTRICTION_TYPE_TABLET) |
+ @Feature({"TabStrip"}) |
+ public void testSwitchStripStackersWithLastTabSelected() throws InterruptedException { |
+ // Open enough regular tabs to cause the tabs to cascade or the strip to scroll depending |
+ // on which stacker is being used. |
+ ChromeTabUtils.newTabsFromMenu(getInstrumentation(), getActivity(), 10); |
+ |
+ // Switch to the ScrollingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(false); |
+ |
+ // Switch to the CascadingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(true); |
+ } |
+ |
+ /** |
+ * Compares tab strip with model after switching between the ScrollingStripStacker and |
+ * CascadingStripStacker when the first tab is selected. This also verifies that the strip |
+ * scrolls correctly and the correct index is selected after switching. |
+ */ |
+ @LargeTest |
+ @Restriction(ChromeRestriction.RESTRICTION_TYPE_TABLET) |
+ @Feature({"TabStrip"}) |
+ public void testSwitchStripStackersWithFirstTabSelected() throws InterruptedException { |
+ // Open enough regular tabs to cause the tabs to cascade or the strip to scroll depending |
+ // on which stacker is being used. |
+ ChromeTabUtils.newTabsFromMenu(getInstrumentation(), getActivity(), 10); |
+ |
+ // Select the first tab by setting the index directly. It may not be visible, so don't |
+ // try to tap on it. |
+ ChromeTabUtils.switchTabInCurrentTabModel(getActivity(), 0); |
+ |
+ // Switch to the ScrollingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(false); |
+ |
+ // Scroll so the first tab is off screen to verify that switching to the |
+ // CascadingStripStacker makes it visible again. The selected tab should always be visible |
+ // when using the CascadingStripStacker but may not be visible when using the |
+ // ScrollingStripStacker. |
+ assertSetTabStripScrollOffset((int) TabStripUtils.getActiveStripLayoutHelper( |
+ getActivity()).getMinimumScrollOffset()); |
+ StripLayoutTab selectedLayoutTab = TabStripUtils.findStripLayoutTab( |
+ getActivity(), false, getActivity().getCurrentTabModel().getTabAt(0).getId()); |
+ assertTabVisibility(false, selectedLayoutTab); |
+ |
+ // Switch to the CascadingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(true); |
+ } |
+ |
+ /** |
+ * Compares tab strip with model after switching between the ScrollingStripStacker and |
+ * CascadingStripStacker when a middle tab is selected. This also verifies that the strip |
+ * scrolls correctly and the correct index is selected after switching. |
+ */ |
+ @LargeTest |
+ @Restriction(ChromeRestriction.RESTRICTION_TYPE_TABLET) |
+ @Feature({"TabStrip"}) |
+ public void testSwitchStripStackersWithMiddleTabSelected() throws InterruptedException { |
+ // Open enough regular tabs to cause the tabs to cascade or the strip to scroll depending |
+ // on which stacker is being used. |
+ ChromeTabUtils.newTabsFromMenu(getInstrumentation(), getActivity(), 10); |
+ |
+ // Select the sixth tab by setting the index directly. It may not be visible, so don't |
+ // try to tap on it. |
+ ChromeTabUtils.switchTabInCurrentTabModel(getActivity(), 5); |
+ |
+ // Switch to the ScrollingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(false); |
+ |
+ // Switch to the CascadingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(true); |
+ } |
+ |
+ /** |
+ * Test that the right and left tab strip fades are fully visible, partially visible or |
+ * hidden at various scroll positions. |
+ * TODO(twellington): Also test these expectations in RTL. |
+ */ |
+ @LargeTest |
+ @Restriction(ChromeRestriction.RESTRICTION_TYPE_TABLET) |
+ @Feature({"TabStrip"}) |
+ public void testScrollingStripStackerFadeOpacity() throws InterruptedException { |
+ // Switch to the ScrollingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(false); |
+ |
+ // Open enough regular tabs to cause the strip to scroll. |
+ ChromeTabUtils.newTabsFromMenu(getInstrumentation(), getActivity(), 10); |
+ |
+ // In RTL the expectation for left/right fade opacities is swapped. |
+ boolean isLeft = !LocalizationUtils.isLayoutRtl(); |
+ |
+ // Initially the right fade (in LTR) should be hidden and the left fade should be visible. |
+ assertTabStripFadeFullyHidden(!isLeft); |
+ assertTabStripFadeFullyVisible(isLeft); |
+ |
+ // Scroll a little below the minimum scroll offset causing the right fade (in LTR) to be |
+ // at partial opacity. |
+ assertSetTabStripScrollOffset((int) (TabStripUtils.getActiveStripLayoutHelper( |
+ getActivity()).getMinimumScrollOffset() |
+ + StripLayoutHelper.FADE_FULL_OPACITY_THRESHOLD_DP / 2)); |
+ assertTabStripFadePartiallyVisible(!isLeft); |
+ assertTabStripFadeFullyVisible(isLeft); |
+ |
+ // Scroll a little above 0 causing the left fade (in LTR) to be at partial opacity. |
+ assertSetTabStripScrollOffset( |
+ (int) (0 - StripLayoutHelper.FADE_FULL_OPACITY_THRESHOLD_DP / 2)); |
+ assertTabStripFadeFullyVisible(!isLeft); |
+ assertTabStripFadePartiallyVisible(isLeft); |
+ |
+ // Scroll to 0 causing the left fade (in LTR) to be hidden. |
+ assertSetTabStripScrollOffset(0); |
+ assertTabStripFadeFullyHidden(isLeft); |
+ assertTabStripFadeFullyVisible(!isLeft); |
+ } |
+ |
+ /** |
+ * Test that selecting a tab that isn't currently visible causes the ScrollingStripStacker |
+ * to scroll to make it visible. |
+ */ |
+ @LargeTest |
+ @Restriction(ChromeRestriction.RESTRICTION_TYPE_TABLET) |
+ @Feature({"TabStrip"}) |
+ public void testScrollingStripStackerScrollsToSelectedTab() throws InterruptedException { |
+ // Switch to the ScrollingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(false); |
+ |
+ // Open enough regular tabs to cause the strip to scroll. |
+ ChromeTabUtils.newTabsFromMenu(getInstrumentation(), getActivity(), 10); |
+ |
+ // Get tab at index 0 and assert it is not visible. |
+ TabModel model = getActivity().getTabModelSelector().getModel(false); |
+ StripLayoutTab tab = TabStripUtils.findStripLayoutTab(getActivity(), false, |
+ model.getTabAt(0).getId()); |
+ assertTabVisibility(false, tab); |
+ |
+ // Select tab 0. |
+ ChromeTabUtils.switchTabInCurrentTabModel(getActivity(), 0); |
+ getInstrumentation().waitForIdleSync(); |
+ |
+ // Tab should now be visible. |
+ assertTabVisibility(true, tab); |
+ } |
+ |
+ /** |
+ * Test that the draw positions for tabs match expectations at various scroll positions |
+ * when using the ScrollingStripStacker. |
+ */ |
+ @LargeTest |
+ @Restriction(ChromeRestriction.RESTRICTION_TYPE_TABLET) |
+ @Feature({"TabStrip"}) |
+ public void testScrollingStripStackerTabOffsets() throws InterruptedException { |
+ // Switch to the ScrollingStripStacker. |
+ setShouldCascadeTabsAndCheckTabStrips(false); |
+ |
+ // Open enough regular tabs to cause the strip to scroll and select the first tab. |
+ ChromeTabUtils.newTabsFromMenu(getInstrumentation(), getActivity(), 10); |
+ ChromeTabUtils.switchTabInCurrentTabModel(getActivity(), 0); |
+ getInstrumentation().waitForIdleSync(); |
+ |
+ // Check initial model validity. |
+ compareAllTabStripsWithModel(); |
+ |
+ // Set up some variables. |
+ StripLayoutHelper strip = TabStripUtils.getActiveStripLayoutHelper(getActivity()); |
+ StripLayoutTab[] tabs = strip.getStripLayoutTabs(); |
+ float tabDrawWidth = tabs[0].getWidth() - strip.getTabOverlapWidth(); |
+ |
+ // Assert getStripLayoutTabs() returns the expected number of tabs. |
+ assertEquals("Unexpected number of StripLayoutTabs.", 11, tabs.length); |
+ |
+ // Scroll tab strip to 0 and check tab positions. |
+ assertSetTabStripScrollOffset(0); |
+ for (int i = 0; i < tabs.length; i++) { |
+ assertTabDrawX(i * tabDrawWidth, tabs[i]); |
+ } |
+ |
+ // Scroll tab strip a little and check tab draw positions. |
+ assertSetTabStripScrollOffset(-25); |
+ for (int i = 0; i < tabs.length; i++) { |
+ assertTabDrawX(i * tabDrawWidth - 25.f, tabs[i]); |
+ } |
+ |
+ // Scroll tab strip a lot and check tab draw positions. |
+ assertSetTabStripScrollOffset(-500); |
+ for (int i = 0; i < tabs.length; i++) { |
+ assertTabDrawX(i * tabDrawWidth - 500.f, tabs[i]); |
+ } |
+ assertTabVisibility(false, tabs[0]); |
+ } |
+ |
+ /** |
* Take a model index and figure out which index it will be in the TabStrip's view hierarchy. |
* @param tabCount The number of tabs. |
* @param selectedIndex The index of the selected tab. |
@@ -584,15 +803,22 @@ public class TabStripTest extends ChromeTabbedActivityTestBase { |
&& getActivity().getTabModelSelector().isIncognitoSelected() == incognito) { |
assertTrue("ChromeTab is not in the proper selection state", |
tabStrip.isForegroundTab(tabView)); |
- assertEquals("ChromeTab is not completely visible, but is selected", |
- tabView.getVisiblePercentage(), 1.0f); |
+ if (tabStrip.shouldCascadeTabs()) { |
+ assertEquals("ChromeTab is not completely visible, but is selected. The selected " |
+ + "tab should be visible when the CascadingStripStacker is in use.", |
+ tabView.getVisiblePercentage(), 1.0f); |
+ } |
+ } |
+ |
+ if (!tabStrip.shouldCascadeTabs()) { |
+ assertTabVisibilityForScrollingStripStacker(tabStrip, tabView); |
} |
// TODO(dtrainor): Compare favicon bitmaps? Only compare a few pixels. |
} |
/** |
- * Compares an entire TabStrip with the corresponding TabModel. This tries to compare |
+ * Compares an entire TabStrip with the corresponding TabModel. This tries to compare |
* as many features as possible, including checking all of the tabs through |
* compareTabViewWithModel. It also checks that the incognito indicator is visible if the |
* incognito tab is showing. |
@@ -636,4 +862,150 @@ public class TabStripTest extends ChromeTabbedActivityTestBase { |
compareTabStripWithModel(true); |
compareTabStripWithModel(false); |
} |
+ |
+ /** |
+ * Sets whether the strip should cascade tabs and checks for validity. |
+ * |
+ * @param shouldCascadeTabs Whether the {@link CascadingStripStacker} should be used. If false, |
+ * the {@link ScrollingStripStacker} will be used instead. |
+ */ |
+ private void setShouldCascadeTabsAndCheckTabStrips(final boolean shouldCascadeTabs) { |
+ TabModel model = getActivity().getCurrentTabModel(); |
+ int selectedTabIndex = model.index(); |
+ |
+ ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
+ @Override |
+ public void run() { |
+ TabStripUtils.getStripLayoutHelper(getActivity(), true).setShouldCascadeTabs( |
+ shouldCascadeTabs); |
+ TabStripUtils.getStripLayoutHelper(getActivity(), false).setShouldCascadeTabs( |
+ shouldCascadeTabs); |
+ } |
+ }); |
+ |
+ // Assert that the correct StripStacker is being used. |
+ assertEquals(shouldCascadeTabs |
+ ? "Expected CascadingStripStacker but was ScrollingStripStacker." |
+ : "Expected ScrollingStripStacker but was CascadingStripStacker.", |
+ shouldCascadeTabs, |
+ TabStripUtils.getActiveStripLayoutHelper(getActivity()).shouldCascadeTabs()); |
+ |
+ // Assert that the same tab is still selected. |
+ assertEquals("The correct tab is not selected.", selectedTabIndex, model.index()); |
+ |
+ // Compare all TabStrips with corresponding TabModels. |
+ compareAllTabStripsWithModel(); |
+ |
+ // The selected tab should always be visible in the CascadingStripStacker and switching to |
+ // the ScrollingStripStacker should auto-scroll to make the selected tab visible. |
+ StripLayoutTab selectedLayoutTab = TabStripUtils.findStripLayoutTab( |
+ getActivity(), model.isIncognito(), model.getTabAt(selectedTabIndex).getId()); |
+ assertTabVisibility(true, selectedLayoutTab); |
+ } |
+ |
+ /** |
+ * Scrolls the tab strip to the desired position and checks for validity. |
+ * |
+ * @param scrollOffset The end scroll position for the tab strip. |
+ */ |
+ private void assertSetTabStripScrollOffset(final int scrollOffset) { |
+ final StripLayoutHelper strip = TabStripUtils.getActiveStripLayoutHelper(getActivity()); |
+ ThreadUtils.runOnUiThreadBlocking(new Runnable() { |
+ @Override |
+ public void run() { |
+ strip.setScrollOffsetForTesting(scrollOffset); |
+ } |
+ }); |
+ |
+ assertEquals("Tab strip scroll incorrect.", scrollOffset, strip.getScrollOffset()); |
+ compareAllTabStripsWithModel(); |
+ } |
+ |
+ /** |
+ * Asserts that the left or right fade is fully hidden. |
+ * @param isLeft Whether the left fade should be checked. |
+ */ |
+ private void assertTabStripFadeFullyHidden(boolean isLeft) { |
+ StripLayoutHelper strip = TabStripUtils.getActiveStripLayoutHelper(getActivity()); |
+ if (isLeft) { |
+ assertEquals("Left tab strip fade visibility is incorrect.", 0.f, |
+ strip.getLeftFadeOpacity()); |
+ } else { |
+ assertEquals("Right tab strip fade visibility is incorrect.", 0.f, |
+ strip.getRightFadeOpacity()); |
+ } |
+ } |
+ |
+ /** |
+ * Asserts that the left or right fade is fully visible. |
+ * @param isLeft Whether the left fade should be checked. |
+ */ |
+ private void assertTabStripFadeFullyVisible(boolean isLeft) { |
+ StripLayoutHelper strip = TabStripUtils.getActiveStripLayoutHelper(getActivity()); |
+ if (isLeft) { |
+ assertEquals("Left tab strip fade visibility is incorrect.", 1.f, |
+ strip.getLeftFadeOpacity()); |
+ } else { |
+ assertEquals("Right tab strip fade visibility is incorrect.", 1.f, |
+ strip.getRightFadeOpacity()); |
+ } |
+ } |
+ |
+ /** |
+ * Asserts that the left or right fade is partially visible. |
+ * @param isLeft Whether the left fade should be checked. |
+ */ |
+ private void assertTabStripFadePartiallyVisible(boolean isLeft) { |
+ StripLayoutHelper strip = TabStripUtils.getActiveStripLayoutHelper(getActivity()); |
+ if (isLeft) { |
+ boolean isPartiallyVisible = strip.getLeftFadeOpacity() > 0.f |
+ && strip.getLeftFadeOpacity() < 1.f; |
+ assertEquals("Left tab strip fade expected to be partially visible.", true, |
+ isPartiallyVisible); |
+ } else { |
+ boolean isPartiallyVisible = strip.getRightFadeOpacity() > 0.f |
+ && strip.getRightFadeOpacity() < 1.f; |
+ assertEquals("Right tab strip fade expected to be partially visible.", true, |
+ isPartiallyVisible); |
+ } |
+ } |
+ |
+ /** |
+ * Checks visible percentage and visibility for the given tab. Should only be called when the |
+ * ScrollingStripStacker is in use. |
+ * |
+ * @param tabStrip The StripLayoutHelper that owns the tab. |
+ * @param tabView The StripLayoutTab associated with the tab to check. |
+ */ |
+ private void assertTabVisibilityForScrollingStripStacker(StripLayoutHelper tabStrip, |
+ StripLayoutTab tabView) { |
+ // The visible percent for all tabs is 1.0 in the ScrollingStripStacker. |
+ assertEquals("ChromeTab is not completely visible. All tabs should be visible when " |
+ + "the ScrollingStripStacker is in use.", |
+ tabView.getVisiblePercentage(), 1.0f); |
+ |
+ // Only tabs that can currently be seen on the screen should be visible. |
+ boolean shouldBeVisible = (tabView.getDrawX() + tabView.getWidth()) >= 0 |
+ && tabView.getDrawX() <= tabStrip.getWidth(); |
+ assertTabVisibility(shouldBeVisible, tabView); |
+ } |
+ |
+ /** |
+ * Asserts whether a tab should be visible. |
+ * @param shouldBeVisible Whether the tab should be visible. |
+ * @param tabView The StripLayoutTab associated with the tab to check. |
+ */ |
+ private void assertTabVisibility(boolean shouldBeVisible, StripLayoutTab tabView) { |
+ assertEquals("ChromeTab " + (shouldBeVisible ? "should" : "should not") + " be visible.", |
+ shouldBeVisible, tabView.isVisible()); |
+ } |
+ |
+ /** |
+ * Asserts that the tab has the expected draw X position. |
+ * @param expectedDrawX The expected draw X position. |
+ * @param tabView The StripLayoutTab associated with the tab to check. |
+ */ |
+ private void assertTabDrawX(float expectedDrawX, StripLayoutTab tabView) { |
+ assertEquals("Incorrect draw position for tab.", expectedDrawX, tabView.getDrawX()); |
+ } |
} |