Loading src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java +12 −4 Original line number Diff line number Diff line Loading @@ -38,12 +38,14 @@ import com.android.launcher3.dragndrop.DragView; 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 Loading Loading @@ -194,15 +196,21 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> 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()) { Loading tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java +250 −16 Original line number Diff line number Diff line Loading @@ -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 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.core.app.ActivityScenario; import androidx.test.espresso.intent.Intents; 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; private static final String PINNED_APPS_KEY = "pinned_apps"; @Before public void setUp() { Intents.init(); // 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 @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 public void testAllAppsListOpens() { ActivityScenario<SecondaryDisplayLauncher> launcher = launch(SecondaryDisplayLauncher.class); launcher.onActivity(l -> l.showAppDrawer(true)); @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(); } } Loading
src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java +12 −4 Original line number Diff line number Diff line Loading @@ -38,12 +38,14 @@ import com.android.launcher3.dragndrop.DragView; 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 Loading Loading @@ -194,15 +196,21 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> 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()) { Loading
tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java +250 −16 Original line number Diff line number Diff line Loading @@ -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 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.core.app.ActivityScenario; import androidx.test.espresso.intent.Intents; 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; private static final String PINNED_APPS_KEY = "pinned_apps"; @Before public void setUp() { Intents.init(); // 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 @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 public void testAllAppsListOpens() { ActivityScenario<SecondaryDisplayLauncher> launcher = launch(SecondaryDisplayLauncher.class); launcher.onActivity(l -> l.showAppDrawer(true)); @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(); } }