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

Commit 3471127e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "UNREVIEWED: TAPL prototype for in-lab flake test" into ub-launcher3-edmonton-polish

parents 0eb466ea 5a7d701d
Loading
Loading
Loading
Loading
+142 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.tapl;

import android.support.annotation.NonNull;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiObject2;

/**
 * Operations on AllApps opened from Home.
 */
public final class AllAppsFromHome {
    private static final int MAX_SCROLL_ATTEMPTS = 40;
    private static final int MIN_INTERACT_SIZE = 100;
    private static final int FLING_SPEED = 12000;

    private final Launcher mLauncher;
    private final int mHeight;

    AllAppsFromHome(Launcher launcher) {
        mLauncher = launcher;
        final UiObject2 allAppsContainer = assertState();
        mHeight = allAppsContainer.getVisibleBounds().height();
    }

    /**
     * Asserts that we are in all apps.
     *
     * @return All apps container.
     */
    @NonNull
    private UiObject2 assertState() {
        return mLauncher.assertState(Launcher.State.ALL_APPS);
    }

    /**
     * Finds an icon. Fails if the icon doesn't exist. Scrolls the app list when needed to make
     * sure the icon is visible.
     *
     * @param appName name of the app.
     * @return The app.
     */
    @NonNull
    public AppIcon getAppIcon(String appName) {
        final UiObject2 allAppsContainer = assertState();
        final BySelector appIconSelector = AppIcon.getAppIconSelector(appName);
        if (!allAppsContainer.hasObject(appIconSelector)) {
            scrollBackToBeginning();
            int attempts = 0;
            while (!allAppsContainer.hasObject(appIconSelector) &&
                    allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
                mLauncher.assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
                        ++attempts <= MAX_SCROLL_ATTEMPTS);
                assertState();
            }
        }
        assertState();

        final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer, appIconSelector);
        ensureIconVisible(appIcon, allAppsContainer);
        return new AppIcon(mLauncher, appIcon);
    }

    private void scrollBackToBeginning() {
        final UiObject2 allAppsContainer = assertState();

        int attempts = 0;
        allAppsContainer.setGestureMargins(5, 500, 5, 5);

        while (allAppsContainer.scroll(Direction.UP, 0.5f)) {
            mLauncher.waitForIdle();
            assertState();

            mLauncher.assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
                    ++attempts <= MAX_SCROLL_ATTEMPTS);
        }

        mLauncher.waitForIdle();
        assertState();
    }

    private void ensureIconVisible(UiObject2 appIcon, UiObject2 allAppsContainer) {
        final int appHeight = appIcon.getVisibleBounds().height();
        if (appHeight < MIN_INTERACT_SIZE) {
            // Try to figure out how much percentage of the container needs to be scrolled in order
            // to reveal the app icon to have the MIN_INTERACT_SIZE
            final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f);
            allAppsContainer.scroll(Direction.DOWN, pct);
            mLauncher.waitForIdle();
            assertState();
        }
    }

    /**
     * Flings forward (down) and waits the fling's end.
     */
    public void flingForward() {
        final UiObject2 allAppsContainer = assertState();
        // Start the gesture in the center to avoid starting at elements near the top.
        allAppsContainer.setGestureMargins(0, 0, 0, mHeight / 2);
        allAppsContainer.fling(Direction.DOWN, FLING_SPEED);
        assertState();
    }

    /**
     * Flings backward (up) and waits the fling's end.
     */
    public void flingBackward() {
        final UiObject2 allAppsContainer = assertState();
        // Start the gesture in the center, for symmetry with forward.
        allAppsContainer.setGestureMargins(0, mHeight / 2, 0, 0);
        allAppsContainer.fling(Direction.UP, FLING_SPEED);
        assertState();
    }

    /**
     * Gets the UI object for AllApps.
     * Used by NexusLauncherStrategy.openAllApps(). No one else should use it.
     *
     * @return container object.
     */
    @Deprecated
    @NonNull
    public UiObject2 getObjectDeprecated() {
        return assertState();
    }
}
+63 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.tapl;

import android.graphics.Point;
import android.support.annotation.NonNull;
import android.support.test.uiautomator.UiObject2;

/**
 * Operations on AllApps opened from Overview.
 * Scroll gestures that are OK for {@link AllAppsFromHome} may close it, so they are not supported.
 */
public final class AllAppsFromOverview {
    private final Launcher mLauncher;

    AllAppsFromOverview(Launcher launcher) {
        mLauncher = launcher;
        assertState();
    }

    /**
     * Asserts that we are in all apps.
     *
     * @return All apps container.
     */
    @NonNull
    private UiObject2 assertState() {
        return mLauncher.assertState(Launcher.State.ALL_APPS);
    }

    /**
     * Swipes down to switch back to Overview whence we came from.
     *
     * @return the overview panel.
     */
    @NonNull
    public Overview switchBackToOverview() {
        final UiObject2 allAppsContainer = assertState();
        // Swipe from the search box to the bottom.
        final UiObject2 qsb = mLauncher.waitForObjectInContainer(
                allAppsContainer, "search_container_all_apps");
        final Point start = qsb.getVisibleCenter();
        final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.6);
        mLauncher.swipe(start.x, start.y, start.x, endY, (endY - start.y) / 100);  // 100 px/step

        return new Overview(mLauncher);
    }

}
+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.tapl;

import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.widget.TextView;

/**
 * App icon, whether in all apps or in workspace/
 */
public final class AppIcon {
    private final Launcher mLauncher;
    private final UiObject2 mIcon;

    AppIcon(Launcher launcher, UiObject2 icon) {
        mLauncher = launcher;
        mIcon = icon;
    }

    static BySelector getAppIconSelector(String appName) {
        return By.clazz(TextView.class).text(appName).pkg(Launcher.LAUNCHER_PKG);
    }

    /**
     * Clicks the icon to launch its app.
     */
    public void launch() {
        mLauncher.assertTrue("Launching an app didn't open a new window: " + mIcon.getText(),
                mIcon.clickAndWait(Until.newWindow(), Launcher.APP_LAUNCH_TIMEOUT_MS));
        mLauncher.assertState(Launcher.State.BACKGROUND);
    }

    UiObject2 getIcon() {
        return mIcon;
    }
}
+187 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3.tapl;

import static junit.framework.TestCase.assertTrue;

import android.graphics.Point;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiObject2;
import android.view.KeyEvent;

/**
 * Operations on the home screen.
 */
public final class Home {

    private final Launcher mLauncher;
    private final UiObject2 mHotseat;
    private final int ICON_DRAG_SPEED = 2000;

    Home(Launcher launcher) {
        mLauncher = launcher;
        assertState();
        mHotseat = launcher.waitForLauncherObject("hotseat");
    }

    /**
     * Asserts that we are in home.
     *
     * @return Workspace.
     */
    @NonNull
    private UiObject2 assertState() {
        return mLauncher.assertState(Launcher.State.HOME);
    }

    /**
     * Swipes up or presses the square button to switch to Overview.
     *
     * @return the Overview panel object.
     */
    @NonNull
    public Overview switchToOverview() {
        assertState();
        if (mLauncher.isSwipeUpEnabled()) {
            final int height = mLauncher.getDevice().getDisplayHeight();
            final UiObject2 navBar = mLauncher.getSystemUiObject("navigation_bar_frame");

            // Swipe from nav bar to 2/3rd down the screen.
            mLauncher.swipe(
                    navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
                    navBar.getVisibleBounds().centerX(), height * 2 / 3,
                    (navBar.getVisibleBounds().centerY() - height * 2 / 3) / 100); // 100 px/step
        } else {
            mLauncher.getSystemUiObject("recent_apps").click();
        }

        return new Overview(mLauncher);
    }

    /**
     * Swipes up to All Apps.
     *
     * @return the App Apps object.
     */
    @NonNull
    public AllAppsFromHome switchToAllApps() {
        assertState();
        if (mLauncher.isSwipeUpEnabled()) {
            int midX = mLauncher.getDevice().getDisplayWidth() / 2;
            int height = mLauncher.getDevice().getDisplayHeight();
            // Swipe from 6/7ths down the screen to 1/7th down the screen.
            mLauncher.swipe(
                    midX,
                    height * 6 / 7,
                    midX,
                    height / 7,
                    (height * 2 / 3) / 100); // 100 px/step
        } else {
            // Swipe from the hotseat to near the top, e.g. 10% of the screen.
            final UiObject2 hotseat = mHotseat;
            final Point start = hotseat.getVisibleCenter();
            final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
            mLauncher.swipe(
                    start.x,
                    start.y,
                    start.x,
                    endY,
                    (start.y - endY) / 100); // 100 px/step
        }

        return new AllAppsFromHome(mLauncher);
    }

    /**
     * Returns an icon for the app, if currently visible.
     *
     * @param appName name of the app
     * @return app icon, if found, null otherwise.
     */
    @Nullable
    public AppIcon tryGetWorkspaceAppIcon(String appName) {
        final UiObject2 workspace = assertState();
        final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName));
        return icon != null ? new AppIcon(mLauncher, icon) : null;
    }

    /**
     * Ensures that workspace is scrollable. If it's not, drags an icon icons from hotseat to the
     * second screen.
     */
    public void ensureWorkspaceIsScrollable() {
        final UiObject2 workspace = assertState();
        if (!isWorkspaceScrollable(workspace)) {
            dragIconToNextScreen(getHotseatAppIcon("Messages"), workspace);
        }
        assertTrue("Home screen workspace didn't become scrollable",
                isWorkspaceScrollable(workspace));
    }

    private boolean isWorkspaceScrollable(UiObject2 workspace) {
        return workspace.isScrollable();
    }

    @NonNull
    private AppIcon getHotseatAppIcon(String appName) {
        return new AppIcon(mLauncher, mLauncher.getObjectInContainer(
                mHotseat, AppIcon.getAppIconSelector(appName)));
    }

    private void dragIconToNextScreen(AppIcon app, UiObject2 workspace) {
        final Point dest = new Point(
                mLauncher.getDevice().getDisplayWidth(), workspace.getVisibleBounds().centerY());
        app.getIcon().drag(dest, ICON_DRAG_SPEED);
        assertState();
    }

    /**
     * Flings to get to screens on the right. Waits for scrolling and a possible overscroll
     * recoil to complete.
     */
    public void flingForward() {
        final UiObject2 workspace = assertState();
        workspace.fling(Direction.RIGHT);
        mLauncher.waitForIdle();
        assertState();
    }

    /**
     * Flings to get to screens on the left.  Waits for scrolling and a possible overscroll
     * recoil to complete.
     */
    public void flingBackward() {
        final UiObject2 workspace = assertState();
        workspace.fling(Direction.LEFT);
        mLauncher.waitForIdle();
        assertState();
    }

    /**
     * Opens widgets container by pressing Ctrl+W.
     *
     * @return the widgets container.
     */
    @NonNull
    public Widgets openAllWidgets() {
        assertState();
        mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
        return new Widgets(mLauncher);
    }
}
 No newline at end of file
+303 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading