blob: 78301e48cde74c1d0869224c010ef1536bb9bab6 [file] [log] [blame]
/*
* 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.graphics.Rect;
import android.os.Bundle;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.StaleObjectException;
import androidx.test.uiautomator.UiObject2;
import com.android.launcher3.testing.TestProtocol;
import java.util.stream.Collectors;
/**
* Operations on AllApps opened from Home. Also a parent for All Apps opened from Overview.
*/
public class AllApps extends LauncherInstrumentation.VisibleContainer {
private static final int MAX_SCROLL_ATTEMPTS = 40;
private final int mHeight;
private final int mIconHeight;
AllApps(LauncherInstrumentation launcher) {
super(launcher);
final UiObject2 allAppsContainer = verifyActiveContainer();
mHeight = mLauncher.getVisibleBounds(allAppsContainer).height();
final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer,
"apps_list_view");
// Wait for the recycler to populate.
mLauncher.waitForObjectInContainer(appListRecycler, By.clazz(TextView.class));
verifyNotFrozen("All apps freeze flags upon opening all apps");
mIconHeight = mLauncher.getTestInfo(
TestProtocol.REQUEST_ICON_HEIGHT).
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
@Override
protected LauncherInstrumentation.ContainerType getContainerType() {
return LauncherInstrumentation.ContainerType.ALL_APPS;
}
private boolean hasClickableIcon(UiObject2 allAppsContainer, UiObject2 appListRecycler,
BySelector appIconSelector, int displayBottom) {
final UiObject2 icon;
try {
icon = appListRecycler.findObject(appIconSelector);
} catch (StaleObjectException e) {
mLauncher.fail("All apps recycler disappeared from screen");
return false;
}
if (icon == null) {
LauncherInstrumentation.log("hasClickableIcon: icon not visible");
return false;
}
final Rect iconBounds = mLauncher.getVisibleBounds(icon);
LauncherInstrumentation.log("hasClickableIcon: icon bounds: " + iconBounds);
if (iconBounds.height() < mIconHeight / 2) {
LauncherInstrumentation.log("hasClickableIcon: icon has insufficient height");
return false;
}
if (iconCenterInSearchBox(allAppsContainer, icon)) {
LauncherInstrumentation.log("hasClickableIcon: icon center is under search box");
return false;
}
if (iconBounds.bottom > displayBottom) {
LauncherInstrumentation.log("hasClickableIcon: icon bottom below bottom offset");
return false;
}
LauncherInstrumentation.log("hasClickableIcon: icon is clickable");
return true;
}
private boolean iconCenterInSearchBox(UiObject2 allAppsContainer, UiObject2 icon) {
final Point iconCenter = icon.getVisibleCenter();
return mLauncher.getVisibleBounds(getSearchBox(allAppsContainer)).contains(
iconCenter.x, iconCenter.y);
}
/**
* 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) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"getting app icon " + appName + " on all apps")) {
final UiObject2 allAppsContainer = verifyActiveContainer();
final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer,
"apps_list_view");
final UiObject2 searchBox = getSearchBox(allAppsContainer);
int deviceHeight = mLauncher.getRealDisplaySize().y;
int bottomGestureStartOnScreen = mLauncher.getBottomGestureStartOnScreen();
final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
if (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector,
bottomGestureStartOnScreen)) {
scrollBackToBeginning();
int attempts = 0;
int scroll = getAllAppsScroll();
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) {
while (!hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector,
bottomGestureStartOnScreen)) {
mLauncher.scrollToLastVisibleRow(
allAppsContainer,
mLauncher.getObjectsInContainer(allAppsContainer, "icon")
.stream()
.filter(icon ->
mLauncher.getVisibleBounds(icon).top
< bottomGestureStartOnScreen)
.collect(Collectors.toList()),
mLauncher.getVisibleBounds(searchBox).bottom
- mLauncher.getVisibleBounds(allAppsContainer).top);
verifyActiveContainer();
final int newScroll = getAllAppsScroll();
mLauncher.assertTrue(
"Scrolled in a wrong direction in AllApps: from " + scroll + " to "
+ newScroll, newScroll >= scroll);
if (newScroll == scroll) break;
mLauncher.assertTrue(
"Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
++attempts <= MAX_SCROLL_ATTEMPTS);
scroll = newScroll;
}
}
verifyActiveContainer();
}
// Ignore bottom offset selection here as there might not be any scroll more scroll
// region available.
mLauncher.assertTrue("Unable to scroll to a clickable icon: " + appName,
hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector,
deviceHeight));
final UiObject2 appIcon = mLauncher.waitForObjectInContainer(appListRecycler,
appIconSelector);
return new AppIcon(mLauncher, appIcon);
}
}
private void scrollBackToBeginning() {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to scroll back in all apps")) {
LauncherInstrumentation.log("Scrolling to the beginning");
final UiObject2 allAppsContainer = verifyActiveContainer();
final UiObject2 searchBox = getSearchBox(allAppsContainer);
int attempts = 0;
final Rect margins =
new Rect(0, mLauncher.getVisibleBounds(searchBox).bottom + 1, 0, 5);
for (int scroll = getAllAppsScroll();
scroll != 0;
scroll = getAllAppsScroll()) {
mLauncher.assertTrue("Negative scroll position", scroll > 0);
mLauncher.assertTrue(
"Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
++attempts <= MAX_SCROLL_ATTEMPTS);
mLauncher.scroll(
allAppsContainer, Direction.UP, margins, 12, false);
}
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) {
verifyActiveContainer();
}
}
}
private int getAllAppsScroll() {
return mLauncher.getTestInfo(
TestProtocol.REQUEST_APPS_LIST_SCROLL_Y)
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
private UiObject2 getSearchBox(UiObject2 allAppsContainer) {
return mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
}
/**
* Flings forward (down) and waits the fling's end.
*/
public void flingForward() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c =
mLauncher.addContextLayer("want to fling forward in all apps")) {
final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center to avoid starting at elements near the top.
mLauncher.scroll(
allAppsContainer, Direction.DOWN, new Rect(0, 0, 0, mHeight / 2), 10, false);
verifyActiveContainer();
}
}
/**
* Flings backward (up) and waits the fling's end.
*/
public void flingBackward() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c =
mLauncher.addContextLayer("want to fling backward in all apps")) {
final UiObject2 allAppsContainer = verifyActiveContainer();
// Start the gesture in the center, for symmetry with forward.
mLauncher.scroll(
allAppsContainer, Direction.UP, new Rect(0, mHeight / 2, 0, 0), 10, false);
verifyActiveContainer();
}
}
/**
* Freezes updating app list upon app install/uninstall/update.
*/
public void freeze() {
mLauncher.getTestInfo(TestProtocol.REQUEST_FREEZE_APP_LIST);
}
/**
* Resumes updating app list upon app install/uninstall/update.
*/
public void unfreeze() {
mLauncher.getTestInfo(TestProtocol.REQUEST_UNFREEZE_APP_LIST);
verifyNotFrozen("All apps freeze flags upon unfreezing");
}
private void verifyNotFrozen(String message) {
final Bundle testInfo = mLauncher.getTestInfo(TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS);
if (testInfo == null) return;
mLauncher.assertEquals(message, 0, testInfo.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD));
}
}