Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6d4df87 authored by Sukesh Ram's avatar Sukesh Ram Committed by Brian Isganitis
Browse files

Added Tests for Secondary Display Launcher

These UIAutomator tests for secondary display launcher cover app drawer, drag-n-drop functionality, app predictions, pin/unpinning icons, and correct back press behavior.

We are deviating from  go/modify-tapl due to the time constraints of this project as outlined here (https://docs.google.com/document/d/1wLb2h8qCPGur-VsufCH4mLnnuLDLcmMq0FrCo7ichu8/edit#heading=h.brf6af3bno4g).

A preliminary design document has also been created to reference for future TAPL integration (https://docs.google.com/document/d/1H642SSu5DCM_zSXTsvTWumgm3OHIxsKEXvTlTeC4y54/edit?resourcekey=0-M9sTxdyQBi8bUy5cpjmJNA#heading=h.90f2s4sc5ic9).

Before TAPL integration, we need to follow up on test rewrite to eliminate antipatterns in the following bug: b/242776943.

Bug: 241166788
Test: Run Locally, on presubmit, and on a test on a cuttlefish emulator
Change-Id: I556a47b93a7ea3b2583dbc1efd2de7623d820e2a
Merged-In: I556a47b93a7ea3b2583dbc1efd2de7623d820e2a
parent 2bcc3f85
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -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
@@ -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()) {
+250 −16
Original line number Diff line number Diff line
@@ -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();
    }
}