Merge "Added Tests for Secondary Display Launcher" into tm-qpr-dev am: 8a03be1880

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/19930975

Change-Id: I9fece672230da39cfeb3c5d3a8ee85e169b8b4f2
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
index 5eac01e..c8455b8 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -38,12 +38,14 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.util.ShortcutUtil;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
 
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 
 /**
  * DragLayer for Secondary launcher
@@ -194,15 +196,21 @@
             return false;
         }
 
+        List<SystemShortcut> systemShortcuts = new ArrayList<>();
+
+        // Hide redundant pin shortcut for app drawer icons if drag-n-drop is enabled.
+        if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
+            systemShortcuts.add(mPinnedAppsAdapter.getSystemShortcut(item, v));
+        }
+        systemShortcuts.add(APP_INFO.getShortcut(mActivity, item, v));
+
         final PopupContainerWithArrow container =
                 (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
                         R.layout.popup_container, mActivity.getDragLayer(), false);
 
         container.populateAndShow((BubbleTextView) v,
                 popupDataProvider.getShortcutCountForItem(item),
-                Collections.emptyList(),
-                Arrays.asList(mPinnedAppsAdapter.getSystemShortcut(item, v),
-                        APP_INFO.getShortcut(mActivity, item, v)));
+                Collections.emptyList(), systemShortcuts);
         container.requestFocus();
 
         if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
diff --git a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java b/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
index 93fa705..082e243 100644
--- a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
+++ b/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
@@ -15,39 +15,273 @@
  */
 package com.android.launcher3.secondarydisplay;
 
-import static androidx.test.core.app.ActivityScenario.launch;
+import static android.content.Context.MODE_PRIVATE;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.view.MotionEvent.ACTION_DOWN;
 
-import androidx.test.core.app.ActivityScenario;
-import androidx.test.espresso.intent.Intents;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Point;
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.widget.TextView;
+
 import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.MediumTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.util.LauncherModelHelper;
 
 import org.junit.After;
-import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 /**
- * Tests for {@link SecondaryDisplayLauncher}
+ * Tests for {@link SecondaryDisplayLauncher}.
+ * TODO (b/242776943): Remove anti-patterns & migrate prediction row tests to Quickstep directory
  */
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
-public class SecondaryDisplayLauncherTest {
+public final class SecondaryDisplayLauncherTest extends AbstractLauncherUiTest {
+    private static final int WAIT_TIME_MS = 5000;
+    private static final int LONG_PRESS_DURATION_MS = 1000;
+    private static final int DRAG_TIME_MS = 160;
 
-    @Before
-    public void setUp() {
-        Intents.init();
+    private static final String PINNED_APPS_KEY = "pinned_apps";
+
+    // Variables required to coordinate drag steps.
+    private Point mStartPoint;
+    private Point mEndPoint;
+    private long mDownTime;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        setDragNDropFlag(true);
     }
 
     @After
     public void tearDown() {
-        Intents.release();
+        mTargetContext.getSharedPreferences(PINNED_APPS_KEY, MODE_PRIVATE)
+                .edit().clear().commit();
     }
 
     @Test
-    public void testAllAppsListOpens() {
-        ActivityScenario<SecondaryDisplayLauncher> launcher =
-                launch(SecondaryDisplayLauncher.class);
-        launcher.onActivity(l -> l.showAppDrawer(true));
+    @Ignore
+    public void initializeSecondaryDisplayLauncher_allAppsButtonVisible() {
+        assertThat(findObjectByResourceName("all_apps_button")).isNotNull();
+    }
+
+    @Test
+    @Ignore
+    public void allAppsButtonTap_opensAppDrawer() {
+        openAppDrawer();
+        assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull();
+    }
+
+    @Test
+    @Ignore("Launcher3 without quickstep doesn't have a predictions row.")
+    public void appDrawerOpened_predictionRowAppDividerVisible() {
+        openAppDrawer();
+        assertThat(findObjectByResourceName("apps_divider_view")).isNotNull();
+    }
+
+    @Test
+    @Ignore
+    public void dragNDropDisabled_pinIconAddsToWorkspace() {
+        setDragNDropFlag(false);
+        openAppDrawer();
+        UiObject2 app = findDescendantByResourceName(
+                findObjectByResourceName("apps_list_view"), "icon");
+        app.click(LONG_PRESS_DURATION_MS);
+        UiObject2 popupContainer = findObjectByResourceName("popup_container");
+        assertThat(popupContainer).isNotNull();
+        UiObject2 pinIcon = findDescendantByTextOrDesc(popupContainer, "Add to home screen");
+        assertThat(pinIcon).isNotNull();
+        pinIcon.click();
+        String appName = app.getContentDescription();
+        assertThat(findAppInWorkspace(appName)).isNotNull();
+    }
+
+    @Test
+    @Ignore
+    public void pressBackFromAllApps_popupMenuOpen_returnsToWorkspace() {
+        openAppDrawer();
+        assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull();
+
+        findDescendantByResourceName(findObjectByResourceName("apps_list_view"), "icon")
+                .click(LONG_PRESS_DURATION_MS);
+        assertThat(findObjectByResourceName("popup_container")).isNotNull();
+
+        // First back press should close only popup menu.
+        mDevice.pressBack();
+        assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull();
+        assertThat(findObjectByResourceName("popup_container")).isNull();
+
+        // Second back press should close app drawer.
+        mDevice.pressBack();
+        assertThat(findObjectByResourceName("popup_container")).isNull();
+        assertThat(findObjectByResourceName("search_container_all_apps")).isNull();
+    }
+
+    @Test
+    @Ignore("Launcher3 without quickstep doesn't have a predictions row.")
+    public void dragNDropFromPredictionsRow_pinToGrid() {
+        openAppDrawer();
+        assertThat(findObjectByResourceName("prediction_row")).isNotNull();
+        String appName = startDragFromPredictionRow();
+        moveAppToCenterOfScreen();
+        dropApp();
+
+        // Ensure app was added.
+        assertThat(findAppInWorkspace(appName)).isNotNull();
+    }
+
+    @Test
+    @Ignore
+    public void dragNDropFromAppDrawer_pinToGrid() {
+        openAppDrawer();
+        String draggedAppName = startDragFromAllApps();
+        moveAppToCenterOfScreen();
+        dropApp();
+
+        // Ensure app was added.
+        assertThat(findAppInWorkspace(draggedAppName)).isNotNull();
+    }
+
+    @Test
+    @Ignore
+    public void tapRemoveButton_unpinApp() {
+        openAppDrawer();
+        String draggedAppName = startDragFromAllApps();
+        moveAppToCenterOfScreen();
+        dropApp();
+        removeAppByName(draggedAppName);
+        assertThat(findAppInWorkspace(draggedAppName)).isNull();
+    }
+
+    private void openAppDrawer() {
+        UiObject2 allAppsButton = findObjectByResourceName("all_apps_button");
+        assertThat(allAppsButton).isNotNull();
+        allAppsButton.click();
+    }
+
+    private String startDragFromAllApps() {
+        // Find app from app drawer.
+        UiObject2 allApps = findObjectByResourceName("apps_list_view");
+        assertThat(allApps).isNotNull();
+        UiObject2 icon = findDescendantByResourceName(allApps, "icon");
+        assertThat(icon).isNotNull();
+        String appName = icon.getContentDescription();
+
+        // Start drag action.
+        mDownTime = SystemClock.uptimeMillis();
+        mStartPoint = icon.getVisibleCenter();
+        mEndPoint = new Point(mStartPoint.x, mStartPoint.y);
+        mLauncher.sendPointer(mDownTime, mDownTime, ACTION_DOWN, mStartPoint,
+                LauncherInstrumentation.GestureScope.INSIDE);
+        assertThat(findObjectByResourceName("popup_container")).isNotNull();
+        return appName;
+    }
+
+    private String startDragFromPredictionRow() {
+        // Find app from predictions.
+        UiObject2 predictionRow = findObjectByResourceName("prediction_row");
+        assertThat(predictionRow).isNotNull();
+
+        UiObject2 icon = findDescendantByResourceName(predictionRow, "icon");
+        assertThat(icon).isNotNull();
+
+        String appName = icon.getContentDescription();
+        UiObject2 app = findDescendantByAppName(predictionRow, appName);
+        assertThat(app).isNotNull();
+
+        // Start drag action.
+        mDownTime = SystemClock.uptimeMillis();
+        mStartPoint = icon.getVisibleCenter();
+        mEndPoint = new Point(mStartPoint.x, mStartPoint.y);
+        mLauncher.sendPointer(mDownTime, mDownTime, ACTION_DOWN, mStartPoint,
+                LauncherInstrumentation.GestureScope.INSIDE);
+        assertThat(findObjectByResourceName("popup_container")).isNotNull();
+        return appName;
+    }
+
+    private void moveAppToCenterOfScreen() {
+        mEndPoint.set(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() / 2);
+        mLauncher.movePointer(mDownTime, SystemClock.uptimeMillis(), DRAG_TIME_MS, true,
+                mStartPoint, mEndPoint, LauncherInstrumentation.GestureScope.INSIDE);
+    }
+
+    private void dropApp() {
+        mLauncher.sendPointer(mDownTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP,
+                mEndPoint, LauncherInstrumentation.GestureScope.INSIDE);
+    }
+
+    private void removeAppByName(String appName) {
+        // Find app within home screen.
+        UiObject2 app = findDescendantByAppName(findObjectByResourceName("workspace_grid"),
+                appName);
+        if (app == null) return;
+
+        // Open app's popup container.
+        app.click(LONG_PRESS_DURATION_MS);
+        UiObject2 popupContainer = findObjectByResourceName("popup_container");
+        assertThat(popupContainer).isNotNull();
+
+        // Grab & click remove button.
+        UiObject2 removeButton = findDescendantByTextOrDesc(popupContainer, "Remove");
+        assertThat(removeButton).isNotNull();
+        removeButton.click();
+    }
+
+    private UiObject2 findAppInWorkspace(String appName) {
+        UiObject2 workspace = findObjectByResourceName("workspace_grid");
+        return findDescendantByAppName(workspace, appName);
+    }
+
+    private UiObject2 findObjectByResourceName(String resourceName) {
+        return mDevice.wait(Until.findObject(By.res(mTargetPackage, resourceName)), WAIT_TIME_MS);
+    }
+
+    private UiObject2 findDescendantByResourceName(UiObject2 outerObject,
+            String resourceName) {
+        assertThat(outerObject).isNotNull();
+        return outerObject.findObject(By.res(mTargetPackage, resourceName));
+    }
+
+    private UiObject2 findDescendantByAppName(UiObject2 outerObject, String appName) {
+        assertThat(outerObject).isNotNull();
+        return outerObject.findObject(By.clazz(TextView.class).text(appName)
+                .pkg(mDevice.getLauncherPackageName()));
+    }
+
+    private UiObject2 findDescendantByTextOrDesc(UiObject2 outerObject, String content) {
+        assertThat(outerObject).isNotNull();
+        UiObject2 innerObject = outerObject.findObject(By.desc(content));
+        if (innerObject == null) innerObject = outerObject.findObject(By.text(content));
+        return innerObject;
+    }
+
+    private void startSecondaryDisplayActivity() {
+        mTargetContext.startActivity((
+                new Intent(mTargetContext, SecondaryDisplayLauncher.class).addFlags(
+                        FLAG_ACTIVITY_NEW_TASK)));
+    }
+
+    private void setDragNDropFlag(Boolean status) {
+        Context context = new LauncherModelHelper().sandboxContext;
+        context.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE).edit()
+                .putBoolean(FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.key, status)
+                .commit();
+        FeatureFlags.initialize(context);
+        startSecondaryDisplayActivity();
     }
 }