michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.tests; michael@0: michael@0: import java.util.ArrayList; michael@0: michael@0: import org.mozilla.gecko.Actions; michael@0: michael@0: import android.support.v4.view.ViewPager; michael@0: import android.text.TextUtils; michael@0: import android.view.View; michael@0: import android.view.ViewGroup; michael@0: import android.widget.ListAdapter; michael@0: import android.widget.ListView; michael@0: import android.widget.TabWidget; michael@0: import android.widget.TextView; michael@0: michael@0: import com.jayway.android.robotium.solo.Condition; michael@0: michael@0: /** michael@0: * This class is an extension of BaseTest that helps with interaction with about:home michael@0: * This class contains methods that access the different tabs from about:home, methods that get information like history and bookmarks from the database, edit and remove bookmarks and history items michael@0: * The purpose of this class is to collect all the logically connected methods that deal with about:home michael@0: * To use any of these methods in your test make sure it extends AboutHomeTest instead of BaseTest michael@0: */ michael@0: abstract class AboutHomeTest extends PixelTest { michael@0: protected enum AboutHomeTabs {HISTORY, MOST_RECENT, TABS_FROM_LAST_TIME, TOP_SITES, BOOKMARKS, READING_LIST}; michael@0: private ArrayList aboutHomeTabs = new ArrayList() {{ michael@0: add("TOP_SITES"); michael@0: add("BOOKMARKS"); michael@0: add("READING_LIST"); michael@0: }}; michael@0: michael@0: michael@0: @Override michael@0: public void setUp() throws Exception { michael@0: super.setUp(); michael@0: michael@0: if (aboutHomeTabs.size() < 4) { michael@0: // Update it for tablets vs. phones. michael@0: if (mDevice.type.equals("phone")) { michael@0: aboutHomeTabs.add(0, AboutHomeTabs.HISTORY.toString()); michael@0: } else { michael@0: aboutHomeTabs.add(AboutHomeTabs.HISTORY.toString()); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * FIXME: Write new versions of these methods and update their consumers to use the new about:home pages. michael@0: */ michael@0: protected ListView getHistoryList(String waitText, int expectedChildCount) { michael@0: return null; michael@0: } michael@0: protected ListView getHistoryList(String waitText) { michael@0: return null; michael@0: } michael@0: michael@0: // Returns true if the bookmark is displayed in the bookmarks tab, false otherwise - does not check in folders michael@0: protected void isBookmarkDisplayed(final String url) { michael@0: boolean isCorrect = waitForTest(new BooleanTest() { michael@0: @Override michael@0: public boolean test() { michael@0: View bookmark = getDisplayedBookmark(url); michael@0: return bookmark != null; michael@0: } michael@0: }, MAX_WAIT_MS); michael@0: michael@0: mAsserter.ok(isCorrect, "Checking that " + url + " displayed as a bookmark", url + " displayed"); michael@0: } michael@0: michael@0: // Loads a bookmark by tapping on the bookmark view in the Bookmarks tab michael@0: protected void loadBookmark(String url) { michael@0: View bookmark = getDisplayedBookmark(url); michael@0: if (bookmark != null) { michael@0: Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded"); michael@0: mSolo.clickOnView(bookmark); michael@0: contentEventExpecter.blockForEvent(); michael@0: contentEventExpecter.unregisterListener(); michael@0: } else { michael@0: mAsserter.ok(false, url + " is not one of the displayed bookmarks", "Please make sure the url provided is bookmarked"); michael@0: } michael@0: } michael@0: michael@0: // Opens the bookmark context menu by long-tapping on it michael@0: protected void openBookmarkContextMenu(String url) { michael@0: View bookmark = getDisplayedBookmark(url); michael@0: if (bookmark != null) { michael@0: mSolo.waitForView(bookmark); michael@0: mSolo.clickLongOnView(bookmark, LONG_PRESS_TIME); michael@0: mSolo.waitForDialogToOpen(); michael@0: } else { michael@0: mAsserter.ok(false, url + " is not one of the displayed bookmarks", "Please make sure the url provided is bookmarked"); michael@0: } michael@0: } michael@0: michael@0: // @return the View associated with bookmark for the provided url or null if the link is not bookmarked michael@0: protected View getDisplayedBookmark(String url) { michael@0: openAboutHomeTab(AboutHomeTabs.BOOKMARKS); michael@0: mSolo.hideSoftKeyboard(); michael@0: getInstrumentation().waitForIdleSync(); michael@0: ListView bookmarksTabList = findListViewWithTag("bookmarks"); michael@0: waitForNonEmptyListToLoad(bookmarksTabList); michael@0: ListAdapter adapter = bookmarksTabList.getAdapter(); michael@0: if (adapter != null) { michael@0: for (int i = 0; i < adapter.getCount(); i++ ) { michael@0: // I am unable to click the view taken with getView for some reason so getting the child at i michael@0: bookmarksTabList.smoothScrollToPosition(i); michael@0: View bookmarkView = bookmarksTabList.getChildAt(i); michael@0: if (bookmarkView instanceof android.widget.LinearLayout) { michael@0: ViewGroup bookmarkItemView = (ViewGroup) bookmarkView; michael@0: for (int j = 0 ; j < bookmarkItemView.getChildCount(); j++) { michael@0: View bookmarkContent = bookmarkItemView.getChildAt(j); michael@0: if (bookmarkContent instanceof android.widget.LinearLayout) { michael@0: ViewGroup bookmarkItemLayout = (ViewGroup) bookmarkContent; michael@0: for (int k = 0 ; k < bookmarkItemLayout.getChildCount(); k++) { michael@0: // Both the title and url are represented as text views so we can cast the view without any issues michael@0: TextView bookmarkTextContent = (TextView)bookmarkItemLayout.getChildAt(k); michael@0: if (url.equals(bookmarkTextContent.getText().toString())) { michael@0: return bookmarkView; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return null; michael@0: } michael@0: michael@0: /** michael@0: * Waits for the given ListView to have a non-empty adapter and be populated michael@0: * with a minimum number of items. michael@0: * michael@0: * This method will return false if the given ListView or its adapter is null, michael@0: * or if the ListView does not have the minimum number of items. michael@0: */ michael@0: protected boolean waitForListToLoad(final ListView listView, final int minSize) { michael@0: Condition listWaitCondition = new Condition() { michael@0: @Override michael@0: public boolean isSatisfied() { michael@0: if (listView == null) { michael@0: return false; michael@0: } michael@0: michael@0: final ListAdapter adapter = listView.getAdapter(); michael@0: if (adapter == null) { michael@0: return false; michael@0: } michael@0: michael@0: return (listView.getCount() - listView.getHeaderViewsCount() >= minSize); michael@0: } michael@0: }; michael@0: return waitForCondition(listWaitCondition, MAX_WAIT_MS); michael@0: } michael@0: michael@0: protected boolean waitForNonEmptyListToLoad(final ListView listView) { michael@0: return waitForListToLoad(listView, 1); michael@0: } michael@0: michael@0: /** michael@0: * Get an active ListView with the specified tag . michael@0: * michael@0: * This method uses the predefined tags in HomePager. michael@0: */ michael@0: protected final ListView findListViewWithTag(String tag) { michael@0: for (ListView listView : mSolo.getCurrentViews(ListView.class)) { michael@0: final String listTag = (String) listView.getTag(); michael@0: if (TextUtils.isEmpty(listTag)) { michael@0: continue; michael@0: } michael@0: michael@0: if (TextUtils.equals(listTag, tag)) { michael@0: return listView; michael@0: } michael@0: } michael@0: michael@0: return null; michael@0: } michael@0: michael@0: // A wait in order for the about:home tab to be rendered after drag/tab selection michael@0: private void waitForAboutHomeTab(final int tabIndex) { michael@0: boolean correctTab = waitForCondition(new Condition() { michael@0: @Override michael@0: public boolean isSatisfied() { michael@0: ViewPager pager = (ViewPager)mSolo.getView(ViewPager.class, 0); michael@0: return (pager.getCurrentItem() == tabIndex); michael@0: } michael@0: }, MAX_WAIT_MS); michael@0: mAsserter.ok(correctTab, "Checking that the correct tab is displayed", "The " + aboutHomeTabs.get(tabIndex) + " tab is displayed"); michael@0: } michael@0: michael@0: private void clickAboutHomeTab(AboutHomeTabs tab) { michael@0: mSolo.clickOnText(tab.toString().replace("_", " ")); michael@0: } michael@0: michael@0: /** michael@0: * Swipes to an about:home tab. michael@0: * @param int swipeVector Value and direction to swipe (go left for negative, right for positive). michael@0: */ michael@0: private void swipeAboutHome(int swipeVector) { michael@0: // Increase swipe width, which will especially impact tablets. michael@0: int swipeWidth = mDriver.getGeckoWidth() - 1; michael@0: int swipeHeight = mDriver.getGeckoHeight() / 2; michael@0: michael@0: if (swipeVector >= 0) { michael@0: // Emulate swipe motion from right to left. michael@0: for (int i = 0; i < swipeVector; i++) { michael@0: mActions.drag(swipeWidth, 0, swipeHeight, swipeHeight); michael@0: mSolo.sleep(100); michael@0: } michael@0: } else { michael@0: // Emulate swipe motion from left to right. michael@0: for (int i = 0; i > swipeVector; i--) { michael@0: mActions.drag(0, swipeWidth, swipeHeight, swipeHeight); michael@0: mSolo.sleep(100); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * This method can be used to open the different tabs of about:home. michael@0: * michael@0: * @param AboutHomeTabs enum item {MOST_RECENT, TABS_FROM_LAST_TIME, TOP_SITES, BOOKMARKS, READING_LIST} michael@0: */ michael@0: protected void openAboutHomeTab(AboutHomeTabs tab) { michael@0: focusUrlBar(); michael@0: ViewPager pager = (ViewPager)mSolo.getView(ViewPager.class, 0); michael@0: final int currentTabIndex = pager.getCurrentItem(); michael@0: int tabOffset; michael@0: michael@0: // Handle tablets by just clicking the visible tab title. michael@0: if (mDevice.type.equals("tablet")) { michael@0: if (AboutHomeTabs.MOST_RECENT == tab || AboutHomeTabs.TABS_FROM_LAST_TIME == tab) { michael@0: tabOffset = aboutHomeTabs.indexOf(AboutHomeTabs.HISTORY.toString()) - currentTabIndex; michael@0: swipeAboutHome(tabOffset); michael@0: waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.HISTORY_LABEL)); michael@0: TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0); michael@0: michael@0: switch (tab) { michael@0: case MOST_RECENT: { michael@0: mSolo.clickOnView(tabwidget.getChildAt(0)); michael@0: // We can determine if we are on the MOST_RECENT tab only if pages were first visited during the test michael@0: mAsserter.ok(waitForText(StringHelper.TODAY_LABEL), "Checking that we are in the most recent tab of about:home", "We are in the most recent tab"); michael@0: break; michael@0: } michael@0: case TABS_FROM_LAST_TIME: { michael@0: mSolo.clickOnView(tabwidget.getChildAt(1)); michael@0: mAsserter.ok(waitForText(StringHelper.TABS_FROM_LAST_TIME_LABEL), "Checking that we are in the Tabs from last time tab of about:home", "We are in the Tabs from last time tab"); michael@0: break; michael@0: } michael@0: } michael@0: } else { michael@0: clickAboutHomeTab(tab); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: // Handle phones (non-tablets). michael@0: tabOffset = aboutHomeTabs.indexOf(tab.toString()) - currentTabIndex; michael@0: switch (tab) { michael@0: case TOP_SITES : { michael@0: swipeAboutHome(tabOffset); michael@0: waitForAboutHomeTab(aboutHomeTabs.indexOf(tab.toString())); michael@0: break; michael@0: } michael@0: case BOOKMARKS : { michael@0: swipeAboutHome(tabOffset); michael@0: waitForAboutHomeTab(aboutHomeTabs.indexOf(tab.toString())); michael@0: break; michael@0: } michael@0: case MOST_RECENT: { michael@0: // MOST_RECENT is contained in the HISTORY tab. michael@0: tabOffset = aboutHomeTabs.indexOf(AboutHomeTabs.HISTORY.toString()) - currentTabIndex; michael@0: swipeAboutHome(tabOffset); michael@0: waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.HISTORY_LABEL)); michael@0: TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0); michael@0: mSolo.clickOnView(tabwidget.getChildAt(0)); michael@0: // We can determine if we are on the MOST_RECENT tab only if pages were first visited during the test michael@0: mAsserter.ok(waitForText(StringHelper.TODAY_LABEL), "Checking that we are in the most recent tab of about:home", "We are in the most recent tab"); michael@0: break; michael@0: } michael@0: case TABS_FROM_LAST_TIME: { michael@0: // TABS_FROM_LAST_TIME is contained in the HISTORY tab. michael@0: tabOffset = aboutHomeTabs.indexOf(AboutHomeTabs.HISTORY.toString()) - currentTabIndex; michael@0: swipeAboutHome(tabOffset); michael@0: waitForAboutHomeTab(aboutHomeTabs.indexOf(StringHelper.HISTORY_LABEL)); michael@0: TabWidget tabwidget = (TabWidget)mSolo.getView(TabWidget.class, 0); michael@0: mSolo.clickOnView(tabwidget.getChildAt(1)); michael@0: mAsserter.ok(waitForText(StringHelper.TABS_FROM_LAST_TIME_LABEL), "Checking that we are in the Tabs from last time tab of about:home", "We are in the Tabs from last time tab"); michael@0: break; michael@0: } michael@0: case READING_LIST: { michael@0: swipeAboutHome(tabOffset); michael@0: waitForAboutHomeTab(aboutHomeTabs.indexOf(tab.toString())); michael@0: break; michael@0: } michael@0: michael@0: } michael@0: } michael@0: }