Adding Jank tests for watch face picker

The following test cases will be added:
1. Removing watch face from favorites.
2. Adding watch face from full list to favorites.
3. Fling on favorites list.
4. Fling on watch face full list.

In addition, there are few refactoring:
1. Modulerizing transitions between screens into method (step).
2. Introducing flingLeft() and flingRight() for flinging picker.

Change-Id: Idccb07548b1258bba451cbecdfb2b20a3e2afb55
diff --git a/tests/jank/sysapp_wear/src/com/android/wearable/sysapp/janktests/SysAppTestHelper.java b/tests/jank/sysapp_wear/src/com/android/wearable/sysapp/janktests/SysAppTestHelper.java
index c3daf72..8e6ba1d 100644
--- a/tests/jank/sysapp_wear/src/com/android/wearable/sysapp/janktests/SysAppTestHelper.java
+++ b/tests/jank/sysapp_wear/src/com/android/wearable/sysapp/janktests/SysAppTestHelper.java
@@ -31,20 +31,18 @@
 
 import junit.framework.Assert;
 
-import java.util.concurrent.TimeoutException;
-
 /**
  * Helper for all the system apps jank tests
  */
 public class SysAppTestHelper {
 
-    private static final String LOG_TAG = SysAppTestHelper.class.getSimpleName();
     public static final int EXPECTED_FRAMES_CARDS_TEST = 20;
     public static final int EXPECTED_FRAMES_WATCHFACE_PICKER_TEST = 20;
     public static final int EXPECTED_FRAMES = 100;
     public static final int LONG_TIMEOUT = 5000;
     public static final int SHORT_TIMEOUT = 500;
     public static final int FLING_SPEED = 5000;
+    private static final String LOG_TAG = SysAppTestHelper.class.getSimpleName();
     private static final long NEW_CARD_TIMEOUT_MS = 5 * 1000; // 5s
     private static final String RELOAD_NOTIFICATION_CARD_INTENT = "com.google.android.wearable."
             + "support.wearnotificationgenerator.SHOW_NOTIFICATION";
@@ -67,21 +65,18 @@
             .resourceId("com.google.android.wearable.app:id/text");
     private static final UiSelector STATUS_BAR_SELECTOR = new UiSelector()
             .resourceId("com.google.android.wearable.app:id/status_bar_icons");
-
+    private static SysAppTestHelper sysAppTestHelperInstance;
     private UiDevice mDevice = null;
     private Instrumentation instrumentation = null;
     private UiObject mCard = null;
     private UiObject mTitle = null;
-    private UiObject mClock = null;
     private UiObject mIcon = null;
     private UiObject mText = null;
-    private UiObject mStatus = null;
     private Intent mIntent = null;
-    private static SysAppTestHelper sysAppTestHelperInstance;
 
     /**
-     * @param mDevice
-     * @param instrumentation
+     * @param mDevice Instance to represent the current device.
+     * @param instrumentation Instance for instrumentation.
      */
     private SysAppTestHelper(UiDevice mDevice, Instrumentation instrumentation) {
         super();
@@ -90,10 +85,8 @@
         mIntent = new Intent();
         mCard = mDevice.findObject(CARD_SELECTOR);
         mTitle = mDevice.findObject(TITLE_SELECTOR);
-        mClock = mDevice.findObject(CLOCK_SELECTOR);
         mIcon = mDevice.findObject(ICON_SELECTOR);
         mText = mDevice.findObject(TEXT_SELECTOR);
-        mStatus = mDevice.findObject(STATUS_BAR_SELECTOR);
     }
 
     public static SysAppTestHelper getInstance(UiDevice device, Instrumentation instrumentation) {
@@ -103,6 +96,7 @@
         return sysAppTestHelperInstance;
     }
 
+    // TODO: Cleanup confusion between swipe and fling.
     public void swipeRight() {
         mDevice.swipe(50,
                 mDevice.getDisplayHeight() / 2, mDevice.getDisplayWidth() - 25,
@@ -128,6 +122,19 @@
         SystemClock.sleep(SHORT_TIMEOUT);
     }
 
+    // TODO: Cleanup confusion between swipe and fling.
+    public void flingLeft() {
+        mDevice.swipe(mDevice.getDisplayWidth() - 50, mDevice.getDisplayHeight() / 2,
+                50, mDevice.getDisplayHeight() / 2, 5); // fast speed
+        SystemClock.sleep(SHORT_TIMEOUT);
+    }
+
+    public void flingRight() {
+        mDevice.swipe(50, mDevice.getDisplayHeight() / 2,
+                mDevice.getDisplayWidth() - 50, mDevice.getDisplayHeight() / 2, 5); // fast speed
+        SystemClock.sleep(SHORT_TIMEOUT);
+    }
+
     public void flingUp() {
         mDevice.swipe(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() / 2 + 50,
                 mDevice.getDisplayWidth() / 2, 0, 5); // fast speed
@@ -142,34 +149,31 @@
 
     // Helper method to go back to home screen
     public void goBackHome() {
-        String launcherPackage = mDevice.getLauncherPackageName();
-        UiObject2 homeScreen = mDevice.findObject(By.res(launcherPackage, HOME_INDICATOR));
         int count = 0;
-        while (homeScreen == null && count < 5) {
+        do {
+            UiObject2 homeScreen = waitForSysAppUiObject2(HOME_INDICATOR);
+            if (homeScreen != null) {
+                break;
+            }
             mDevice.pressBack();
-            homeScreen = mDevice.findObject(By.res(launcherPackage, HOME_INDICATOR));
-            count ++;
-        }
+            count++;
+        } while (count < 5);
 
         // TODO (yuanlang@) Delete the following hacky codes after charging icon issue fixed
         // Make sure we're not in the launcher
-        homeScreen = mDevice.findObject(By.res(launcherPackage, LAUNCHER_VIEW_NAME));
-        if (homeScreen != null) {
+        if (waitForSysAppUiObject2(LAUNCHER_VIEW_NAME) != null) {
             mDevice.pressBack();
         }
         // Make sure we're not in cards view
-        homeScreen = mDevice.findObject(By.res(launcherPackage, CARD_VIEW_NAME));
-        if (homeScreen != null) {
+        if (waitForSysAppUiObject2(CARD_VIEW_NAME) != null) {
             mDevice.pressBack();
         }
         // Make sure we're not in the quick settings
-        homeScreen = mDevice.findObject(By.res(launcherPackage, QUICKSETTING_VIEW_NAME));
-        if (homeScreen != null) {
+        if (waitForSysAppUiObject2(QUICKSETTING_VIEW_NAME) != null) {
             mDevice.pressBack();
         }
         // Make sure we're not in watch face picker
-        homeScreen = mDevice.findObject(By.res(launcherPackage, WATCHFACE_PREVIEW_NAME));
-        if (homeScreen != null) {
+        if (waitForSysAppUiObject2(WATCHFACE_PREVIEW_NAME) != null) {
             mDevice.pressBack();
         }
         SystemClock.sleep(LONG_TIMEOUT);
@@ -179,7 +183,7 @@
 
     // TODO: Allow user to pass in how many cards are expected to find cause some tests may require
     // more than one card.
-    public void hasDemoCards() throws Exception {
+    public void hasDemoCards() {
         // Device should be pre-loaded with demo cards.
 
         goBackHome(); // Start by going to Home.
@@ -228,11 +232,18 @@
     }
 
     // Helper method to goto app launcher and verifies you are there.
-    public void gotoAppLauncher() throws TimeoutException {
+    public void gotoAppLauncher() {
         goBackHome();
         mDevice.pressKeyCode(KeyEvent.KEYCODE_BACK);
         UiObject2 appLauncher = mDevice.wait(Until.findObject(By.text("Agenda")),
                 SysAppTestHelper.LONG_TIMEOUT);
         Assert.assertNotNull("App launcher not launched", appLauncher);
     }
+
+    public UiObject2 waitForSysAppUiObject2(String resourceId) {
+        String launcherPackageName = mDevice.getLauncherPackageName();
+        return mDevice.wait(
+                Until.findObject(By.res(launcherPackageName, resourceId)),
+                SHORT_TIMEOUT);
+    }
 }
diff --git a/tests/jank/sysapp_wear/src/com/android/wearable/sysapp/janktests/WatchFacePickerJankTest.java b/tests/jank/sysapp_wear/src/com/android/wearable/sysapp/janktests/WatchFacePickerJankTest.java
index c800cbb..7ca40bc 100644
--- a/tests/jank/sysapp_wear/src/com/android/wearable/sysapp/janktests/WatchFacePickerJankTest.java
+++ b/tests/jank/sysapp_wear/src/com/android/wearable/sysapp/janktests/WatchFacePickerJankTest.java
@@ -20,25 +20,28 @@
 import android.support.test.jank.GfxMonitor;
 import android.support.test.jank.JankTest;
 import android.support.test.jank.JankTestBase;
-import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.Direction;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
-import android.support.test.uiautomator.Until;
+import android.util.Log;
 
 import junit.framework.Assert;
 
-import java.util.concurrent.TimeoutException;
+import java.util.List;
 
 /**
  * Jank tests for watchFace picker on clockwork device
  */
 public class WatchFacePickerJankTest extends JankTestBase {
 
-    private UiDevice mDevice;
-    private SysAppTestHelper mHelper;
-
     private static final String WEARABLE_APP_PACKAGE = "com.google.android.wearable.app";
     private static final String WATCHFACE_PREVIEW_NAME = "preview_image";
+    private static final String WATCHFACE_SHOW_ALL_BTN_NAME = "show_all_btn";
+    private static final String WATCHFACE_PICKER_ALL_LIST_NAME = "watch_face_picker_all_list";
+    private static final String WATCHFACE_PICKER_FAVORITE_LIST_NAME = "watch_face_picker_list";
+    private static final String TAG = "WatchFacePickerJankTest";
+    private UiDevice mDevice;
+    private SysAppTestHelper mHelper;
 
     /*
      * (non-Javadoc)
@@ -53,35 +56,219 @@
     }
 
     /**
-     * Test the jank by open watchface picker
+     * Test the jank by open watchface picker (favorites)
      */
     @JankTest(beforeLoop = "startFromHome", afterTest = "goBackHome",
             expectedFrames = SysAppTestHelper.EXPECTED_FRAMES_WATCHFACE_PICKER_TEST)
     @GfxMonitor(processName = WEARABLE_APP_PACKAGE)
-    public void testOpenWatchFacePicker() throws TimeoutException {
-        mHelper.swipeLeft();
-        UiObject2 previewImage = mDevice.wait(
-                Until.findObject(By.res(WEARABLE_APP_PACKAGE, WATCHFACE_PREVIEW_NAME)),
-                SysAppTestHelper.SHORT_TIMEOUT);
-        Assert.assertNotNull(previewImage);
+    public void testOpenWatchFacePicker() {
+        openPicker();
+    }
+
+    /**
+     * Test the jank by adding watch face to favorites.
+     */
+    @JankTest(beforeLoop = "startFromWatchFacePickerFull",
+            afterLoop = "resetToWatchFacePickerFull",
+            afterTest = "removeAllButOneWatchFace",
+            expectedFrames = SysAppTestHelper.EXPECTED_FRAMES_WATCHFACE_PICKER_TEST)
+    @GfxMonitor(processName = WEARABLE_APP_PACKAGE)
+    public void testSelectWatchFaceFromFullList() {
+        selectWatchFaceFromFullList(0);
+    }
+
+    /**
+     * Test the jank by removing watch face from favorites.
+     */
+    @JankTest(beforeLoop = "startWithTwoWatchFaces", afterLoop = "resetToTwoWatchFaces",
+            afterTest = "removeAllButOneWatchFace",
+            expectedFrames = SysAppTestHelper.EXPECTED_FRAMES_WATCHFACE_PICKER_TEST)
+    @GfxMonitor(processName = WEARABLE_APP_PACKAGE)
+    public void testRemoveWatchFaceFromFavorites() {
+        removeWatchFaceFromFavorites();
+    }
+
+    /**
+     * Test the jank on flinging watch face picker.
+     */
+    @JankTest(beforeLoop = "startWithFourWatchFaces", afterLoop = "resetToWatchFacePicker",
+            afterTest = "removeAllButOneWatchFace",
+            expectedFrames = SysAppTestHelper.EXPECTED_FRAMES_WATCHFACE_PICKER_TEST)
+    @GfxMonitor(processName = WEARABLE_APP_PACKAGE)
+    public void testWatchFacePickerFling() {
+        flingWatchFacePicker(5);
+    }
+
+    /**
+     * Test the jank of flinging watch face full list picker.
+     */
+    @JankTest(beforeLoop = "startFromWatchFacePickerFull",
+            afterLoop = "resetToWatchFacePickerFull",
+            afterTest = "removeAllButOneWatchFace",
+            expectedFrames = SysAppTestHelper.EXPECTED_FRAMES_WATCHFACE_PICKER_TEST)
+    @GfxMonitor(processName = WEARABLE_APP_PACKAGE)
+    public void testWatchFacePickerFullListFling() {
+        flingWatchFacePickerFullList(5);
     }
 
     public void startFromHome() {
         mHelper.goBackHome();
     }
 
+    public void startFromWatchFacePicker() {
+        Log.v(TAG, "Starting from watchface picker ...");
+        startFromHome();
+        openPicker();
+    }
+
+    public void startFromWatchFacePickerFull() {
+        Log.v(TAG, "Starting from watchface picker full list ...");
+        startFromHome();
+        openPicker();
+        openPickerAllList();
+    }
+
+    public void startWithTwoWatchFaces() {
+        Log.v(TAG, "Starting with two watchfaces ...");
+        for (int i = 0; i < 2; ++i) {
+            startFromHome();
+            openPicker();
+            openPickerAllList();
+            selectWatchFaceFromFullList(i);
+        }
+    }
+
+    public void startWithFourWatchFaces() {
+        Log.v(TAG, "Starting with four watchfaces ...");
+        for (int i = 0; i < 4; ++i) {
+            startFromHome();
+            openPicker();
+            openPickerAllList();
+            selectWatchFaceFromFullList(i);
+        }
+    }
+
     // Ensuring that we head back to the first screen before launching the app again
     public void goBackHome(Bundle metrics) {
-        mHelper.goBackHome();
+        Log.v(TAG, "Going back Home ...");
+        startFromHome();
         super.afterTest(metrics);
     }
 
-    /*
-     * (non-Javadoc)
-     * @see android.test.InstrumentationTestCase#tearDown()
+    public void removeAllButOneWatchFace(Bundle metrics) {
+        int count = 0;
+        do {
+            Log.v(TAG, "Removing all but one watch faces ...");
+            startFromWatchFacePicker();
+            removeWatchFaceFromFavorites();
+        } while (isOnlyOneWatchFaceInFavorites() && count++ < 5);
+        super.afterTest(metrics);
+    }
+
+    public void resetToWatchFacePicker() {
+        Log.v(TAG, "Resetting to watchface picker screen ...");
+        startFromWatchFacePicker();
+    }
+
+    public void resetToWatchFacePickerFull() {
+        Log.v(TAG, "Resetting to watchface picker full list screen ...");
+        startFromWatchFacePickerFull();
+    }
+
+    public void resetToTwoWatchFaces() {
+        Log.v(TAG, "Resetting to two watchfaces in favorites ...");
+        startWithTwoWatchFaces();
+    }
+
+    /**
+     * Check if there is only one watch face in favorites list.
+     *
+     * @return True is +id/show_all_btn is on the screen. False otherwise.
      */
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
+    private boolean isOnlyOneWatchFaceInFavorites() {
+        // Make sure we are not at the last watch face.
+        mHelper.swipeRight();
+        return mHelper.waitForSysAppUiObject2(WATCHFACE_SHOW_ALL_BTN_NAME) != null;
+    }
+
+    private void openPicker() {
+        mHelper.swipeLeft();
+        Assert.assertNotNull(mHelper.waitForSysAppUiObject2(WATCHFACE_PREVIEW_NAME));
+    }
+
+    private void openPickerAllList() {
+        // Assume the screen is on WatchFace picker for favorites.
+        // Swipe to the end of the list.
+        while (mHelper.waitForSysAppUiObject2(WATCHFACE_SHOW_ALL_BTN_NAME) == null) {
+            Log.v(TAG, "Swiping to the end of favorites list ...");
+            mHelper.flingLeft();
+        }
+
+        UiObject2 showAllButton = mHelper.waitForSysAppUiObject2(WATCHFACE_SHOW_ALL_BTN_NAME);
+        Assert.assertNotNull(showAllButton);
+        Log.v(TAG, "Tapping to show all watchfaces ...");
+        showAllButton.click();
+        UiObject2 watchFacePickerAllList =
+                mHelper.waitForSysAppUiObject2(WATCHFACE_PICKER_ALL_LIST_NAME);
+        Assert.assertNotNull(watchFacePickerAllList);
+    }
+
+    private void selectWatchFaceFromFullList(int index) {
+        // Assume the screen is on watch face picker for all faces.
+        UiObject2 watchFacePickerAllList = mHelper.waitForSysAppUiObject2(
+                WATCHFACE_PICKER_ALL_LIST_NAME);
+        Assert.assertNotNull(watchFacePickerAllList);
+        int swipes = index / 4; // Showing 4 for each scroll.
+        for (int i = 0; i < swipes; ++i) {
+            mHelper.swipeDown();
+        }
+        List<UiObject2> watchFaces = watchFacePickerAllList.getChildren();
+        Assert.assertNotNull(watchFaces);
+        int localIndex = index % 4;
+        if (watchFaces.size() <= localIndex) return;
+
+        Log.v(TAG, "Tapping the " + localIndex + " watchface on screen ...");
+        watchFaces.get(localIndex).click();
+        // Verify the watchface is selected properly.
+        UiObject2 watchFacePickerList =
+                mHelper.waitForSysAppUiObject2(WATCHFACE_PICKER_FAVORITE_LIST_NAME);
+        Assert.assertNotNull(watchFacePickerList);
+    }
+
+    private void removeWatchFaceFromFavorites() {
+        mHelper.flingRight();
+
+        // Assume the favorites list has at least 2 watch faces.
+        UiObject2 watchFacePicker =
+                mHelper.waitForSysAppUiObject2(WATCHFACE_PICKER_FAVORITE_LIST_NAME);
+        Assert.assertNotNull(watchFacePicker);
+        List<UiObject2> watchFaces = watchFacePicker.getChildren();
+        Assert.assertNotNull(watchFaces);
+        if (isOnlyOneWatchFaceInFavorites()) return;
+
+        Log.v(TAG, "Removing first watch face from favorites ...");
+        watchFaces.get(0).swipe(Direction.DOWN, 1.0f);
+    }
+
+    private void flingWatchFacePicker(int iterations) {
+        for (int i = 0; i < iterations; ++i) {
+            // Start fling to right, then left, alternatively.
+            if (i % 2 == 0) {
+                mHelper.flingRight();
+            } else {
+                mHelper.flingLeft();
+            }
+        }
+    }
+
+    private void flingWatchFacePickerFullList(int iterations) {
+        for (int i = 0; i < iterations; ++i) {
+            // Start fling up, then down, alternatively.
+            if (i % 2 == 0) {
+                mHelper.flingUp();
+            } else {
+                mHelper.flingDown();
+            }
+        }
     }
 }