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

Commit 156775e0 authored by Vadim Tryshev's avatar Vadim Tryshev Committed by Android (Google) Code Review
Browse files

Merge "Initial implementation for TAPL support for gestural navigation" into ub-launcher3-master

parents e790b217 8bba0187
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.launcher3.tapl;

import android.graphics.Point;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.widget.TextView;

@@ -41,10 +42,12 @@ public final class AppIcon extends Launchable {
     */
    public AppIconMenu openMenu() {
        final Point iconCenter = mObject.getVisibleCenter();
        mLauncher.sendPointer(MotionEvent.ACTION_DOWN, iconCenter);
        final long downTime = SystemClock.uptimeMillis();
        mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, iconCenter);
        final UiObject2 deepShortcutsContainer = mLauncher.waitForLauncherObject(
                "deep_shortcuts_container");
        mLauncher.sendPointer(MotionEvent.ACTION_UP, iconCenter);
        mLauncher.sendPointer(
                downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, iconCenter);
        return new AppIconMenu(mLauncher, deepShortcutsContainer);
    }
}
+42 −14
Original line number Diff line number Diff line
@@ -22,6 +22,10 @@ import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;

import static org.junit.Assert.assertTrue;

import android.graphics.Point;
import android.os.SystemClock;
import android.view.MotionEvent;

import androidx.annotation.NonNull;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.Until;
@@ -33,6 +37,8 @@ import com.android.launcher3.TestProtocol;
 * indicate Launcher as long as Launcher is not in Overview state.
 */
public class Background extends LauncherInstrumentation.VisibleContainer {
    private static final int ZERO_BUTTON_SWIPE_UP_GESTURE_DURATION = 500;
    private static final int ZERO_BUTTON_SWIPE_UP_HOLD_DURATION = 400;

    Background(LauncherInstrumentation launcher) {
        super(launcher);
@@ -59,19 +65,41 @@ public class Background extends LauncherInstrumentation.VisibleContainer {
    }

    protected void goToOverviewUnchecked(int expectedState) {
        if (mLauncher.isSwipeUpEnabled()) {
        switch (mLauncher.getNavigationModel()) {
            case ZERO_BUTTON: {
                final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
                final int startY = getSwipeStartY();
            final int swipeHeight = mLauncher.getTestInfo(
                    getSwipeHeightRequestName()).
                final int swipeHeight = mLauncher.getTestInfo(getSwipeHeightRequestName()).
                        getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
                final Point start = new Point(centerX, startY);
                final Point end =
                        new Point(centerX, startY - swipeHeight - mLauncher.getTouchSlop());

                final long downTime = SystemClock.uptimeMillis();
                mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start);
                mLauncher.movePointer(downTime, ZERO_BUTTON_SWIPE_UP_GESTURE_DURATION, start, end);
                LauncherInstrumentation.sleep(ZERO_BUTTON_SWIPE_UP_HOLD_DURATION);
                mLauncher.sendPointer(
                        downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, end);
                break;
            }

            case TWO_BUTTON: {
                final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
                final int startY = getSwipeStartY();
                final int swipeHeight = mLauncher.getTestInfo(getSwipeHeightRequestName()).
                        getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);

                mLauncher.swipe(
                        centerX, startY, centerX,
                        startY - swipeHeight - mLauncher.getTouchSlop(),
                        expectedState);
        } else {
                break;
            }

            case THREE_BUTTON:
                mLauncher.waitForSystemUiObject("recent_apps").click();
                break;
        }
    }

@@ -80,6 +108,6 @@ public class Background extends LauncherInstrumentation.VisibleContainer {
    }

    protected int getSwipeStartY() {
        return mLauncher.waitForSystemUiObject("home").getVisibleBounds().centerY();
        return mLauncher.waitForSystemUiObject("navigation_bar_frame").getVisibleBounds().centerY();
    }
}
+6 −2
Original line number Diff line number Diff line
@@ -44,8 +44,10 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
     * Flings forward (left) and waits the fling's end.
     */
    public void flingForward() {
        final UiObject2 overview = verifyActiveContainer();
        LauncherInstrumentation.log("Overview.flingForward before fling");
        final UiObject2 overview = verifyActiveContainer();
        final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
        overview.setGestureMargins(margin, 0, 0, 0);
        overview.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
        mLauncher.waitForIdle();
        verifyActiveContainer();
@@ -71,8 +73,10 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
     * Flings backward (right) and waits the fling's end.
     */
    public void flingBackward() {
        final UiObject2 overview = verifyActiveContainer();
        LauncherInstrumentation.log("Overview.flingBackward before fling");
        final UiObject2 overview = verifyActiveContainer();
        final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
        overview.setGestureMargins(0, 0, margin, 0);
        overview.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
        mLauncher.waitForIdle();
        verifyActiveContainer();
+112 −27
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.launcher3.tapl;

import static com.android.launcher3.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
import static com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME;

import android.app.ActivityManager;
@@ -30,14 +31,17 @@ import android.os.Parcelable;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.Configurator;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
@@ -59,6 +63,7 @@ import java.util.concurrent.TimeoutException;
public final class LauncherInstrumentation {

    private static final String TAG = "Tapl";
    private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20;

    // Types for launcher containers that the user is interacting with. "Background" is a
    // pseudo-container corresponding to inactive launcher covered by another app.
@@ -66,6 +71,8 @@ public final class LauncherInstrumentation {
        WORKSPACE, ALL_APPS, OVERVIEW, WIDGETS, BACKGROUND, BASE_OVERVIEW
    }

    public enum NavigationModel {ZERO_BUTTON, TWO_BUTTON, THREE_BUTTON}

    // Base class for launcher containers.
    static abstract class VisibleContainer {
        protected final LauncherInstrumentation mLauncher;
@@ -150,7 +157,11 @@ public final class LauncherInstrumentation {
        sActiveContainer = new WeakReference<>(container);
    }

    public boolean isSwipeUpEnabled() {
    public NavigationModel getNavigationModel() {
        return isSwipeUpEnabled() ? NavigationModel.TWO_BUTTON : NavigationModel.THREE_BUTTON;
    }

    private boolean isSwipeUpEnabled() {
        final boolean swipeUpEnabledDefaultValue = SwipeUpSetting.isSwipeUpEnabledDefaultValue();
        return SwipeUpSetting.isSwipeUpSettingAvailable() ?
                Settings.Secure.getInt(
@@ -286,6 +297,30 @@ public final class LauncherInstrumentation {
        // We need waiting for any accessibility event generated after pressing Home because
        // otherwise waitForIdle may return immediately in case when there was a big enough pause in
        // accessibility events prior to pressing Home.
        if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
            if (hasLauncherObject(WORKSPACE_RES_ID)) {
                log("0-button pressHome: already in workspace");
            } else if (hasLauncherObject(OVERVIEW_RES_ID)) {
                log("0-button pressHome: overview");
                mDevice.pressHome();
            } else if (hasLauncherObject(WIDGETS_RES_ID)) {
                log("0-button pressHome: widgets");
                mDevice.pressHome();
            } else if (hasLauncherObject(APPS_RES_ID)) {
                log("0-button pressHome: all apps");
                mDevice.pressHome();
            } else {
                log("0-button pressHome: another app");
                assertTrue("Launcher is visible, don't know how to go home",
                        !mDevice.hasObject(By.pkg(getLauncherPackageName())));
                final UiObject2 navBar = waitForSystemUiObject("navigation_bar_frame");

                swipe(
                        navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
                        navBar.getVisibleBounds().centerX(), 0,
                        BACKGROUND_APP_STATE_ORDINAL, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME);
            }
        } else {
            executeAndWaitForEvent(
                    () -> {
                        log("LauncherInstrumentation.pressHome before clicking");
@@ -304,6 +339,7 @@ public final class LauncherInstrumentation {
                    event -> true,
                    "Pressing Home didn't produce any events");
            mDevice.waitForIdle();
        }
        return getWorkspace();
    }

@@ -424,6 +460,11 @@ public final class LauncherInstrumentation {
        return object;
    }

    @Nullable
    private boolean hasLauncherObject(String resId) {
        return mDevice.hasObject(getLauncherObjectSelector(resId));
    }

    @NonNull
    UiObject2 waitForLauncherObject(String resName) {
        final BySelector selector = getLauncherObjectSelector(resName);
@@ -446,8 +487,12 @@ public final class LauncherInstrumentation {
    }

    void swipe(int startX, int startY, int endX, int endY, int expectedState) {
        swipe(startX, startY, endX, endY, expectedState, 60);
    }

    void swipe(int startX, int startY, int endX, int endY, int expectedState, int steps) {
        final Bundle parcel = (Bundle) executeAndWaitForEvent(
                () -> mDevice.swipe(startX, startY, endX, endY, 60),
                () -> mDevice.swipe(startX, startY, endX, endY, steps),
                event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()),
                "Swipe failed to receive an event for the swipe end: " + startX + ", " + startY
                        + ", " + endX + ", " + endY);
@@ -459,13 +504,6 @@ public final class LauncherInstrumentation {
        mDevice.waitForIdle();
    }

    void sendPointer(int action, Point point) {
        final MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(),
                SystemClock.uptimeMillis(), action, point.x, point.y, 0);
        mInstrumentation.sendPointerSync(event);
        event.recycle();
    }

    float getDisplayDensity() {
        return mInstrumentation.getTargetContext().getResources().getDisplayMetrics().density;
    }
@@ -473,4 +511,51 @@ public final class LauncherInstrumentation {
    int getTouchSlop() {
        return ViewConfiguration.get(getContext()).getScaledTouchSlop();
    }

    private static MotionEvent getMotionEvent(long downTime, long eventTime, int action,
            float x, float y) {
        MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
        properties.id = 0;
        properties.toolType = Configurator.getInstance().getToolType();

        MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
        coords.pressure = 1;
        coords.size = 1;
        coords.x = x;
        coords.y = y;

        return MotionEvent.obtain(downTime, eventTime, action, 1,
                new MotionEvent.PointerProperties[]{properties},
                new MotionEvent.PointerCoords[]{coords},
                0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
    }

    void sendPointer(long downTime, long currentTime, int action, Point point) {
        final MotionEvent event = getMotionEvent(downTime, currentTime, action, point.x, point.y);
        mInstrumentation.getUiAutomation().injectInputEvent(event, true);
        event.recycle();
    }

    void movePointer(long downTime, long duration, Point from, Point to) {
        final Point point = new Point();
        for (; ; ) {
            sleep(16);

            final long currentTime = SystemClock.uptimeMillis();
            final float progress = (currentTime - downTime) / (float) duration;
            if (progress > 1) return;

            point.x = from.x + (int) (progress * (to.x - from.x));
            point.y = from.y + (int) (progress * (to.y - from.y));

            sendPointer(downTime, currentTime, MotionEvent.ACTION_MOVE, point);
        }
    }

    static void sleep(int duration) {
        try {
            Thread.sleep(duration);
        } catch (InterruptedException e) {
        }
    }
}
 No newline at end of file
+4 −0
Original line number Diff line number Diff line
@@ -136,6 +136,8 @@ public final class Workspace extends Home {
     */
    public void flingForward() {
        final UiObject2 workspace = verifyActiveContainer();
        final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
        workspace.setGestureMargins(0, 0, margin, 0);
        workspace.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
        mLauncher.waitForIdle();
        verifyActiveContainer();
@@ -147,6 +149,8 @@ public final class Workspace extends Home {
     */
    public void flingBackward() {
        final UiObject2 workspace = verifyActiveContainer();
        final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
        workspace.setGestureMargins(margin, 0, 0, 0);
        workspace.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
        mLauncher.waitForIdle();
        verifyActiveContainer();