Add TAPL API for adding app icon to hotseat

Please refer to go/tapl-add-icon-to-hotseat for more details.

Bug: 231400119
Test: atest NexusLauncherTests:TaplTestsQuickstep#testAddDeleteShortcutOnHotseat
Change-Id: I8cadecbe742413e3ce35ff269c0f78057331532c
This commit is contained in:
Chilun Huang
2022-05-19 16:45:29 +08:00
parent 9a0ab1c4de
commit a518e034f7
6 changed files with 212 additions and 1 deletions
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2022 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.testing;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Request object for querying a hotseat cell region in Rect.
*/
public class HotseatCellCenterRequest implements TestInformationRequest {
public final int cellInd;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(cellInd);
}
@Override
public String getRequestName() {
return TestProtocol.REQUEST_HOTSEAT_CELL_CENTER;
}
public static final Parcelable.Creator<HotseatCellCenterRequest> CREATOR =
new Parcelable.Creator<HotseatCellCenterRequest>() {
@Override
public HotseatCellCenterRequest createFromParcel(Parcel source) {
return new HotseatCellCenterRequest(source);
}
@Override
public HotseatCellCenterRequest[] newArray(int size) {
return new HotseatCellCenterRequest[size];
}
};
private HotseatCellCenterRequest(int cellInd) {
this.cellInd = cellInd;
}
private HotseatCellCenterRequest(Parcel in) {
this(in.readInt());
}
/**
* Create a builder for HotseatCellCenterRequest.
*
* @return HotseatCellCenterRequest builder.
*/
public static HotseatCellCenterRequest.Builder builder() {
return new HotseatCellCenterRequest.Builder();
}
/**
* HotseatCellCenterRequest Builder.
*/
public static final class Builder {
private int mCellInd;
private Builder() {
mCellInd = 0;
}
/**
* Set the index of hotseat cells.
*/
public HotseatCellCenterRequest.Builder setCellInd(int i) {
this.mCellInd = i;
return this;
}
/**
* build the HotseatCellCenterRequest.
*/
public HotseatCellCenterRequest build() {
return new HotseatCellCenterRequest(mCellInd);
}
}
}
@@ -33,6 +33,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Hotseat;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
@@ -185,7 +186,7 @@ public class TestInformationHandler implements ResourceBasedOverride {
return new int[]{cellLayout.getCountX(), cellLayout.getCountY()};
});
case TestProtocol.REQUEST_WORKSPACE_CELL_CENTER:
case TestProtocol.REQUEST_WORKSPACE_CELL_CENTER: {
final WorkspaceCellCenterRequest request = extra.getParcelable(
TestProtocol.TEST_INFO_REQUEST_FIELD);
return getLauncherUIProperty(Bundle::putParcelable, launcher -> {
@@ -197,6 +198,21 @@ public class TestInformationHandler implements ResourceBasedOverride {
cellLayout, request.cellX, request.cellY, request.spanX, request.spanY);
return new Point(cellRect.centerX(), cellRect.centerY());
});
}
case TestProtocol.REQUEST_HOTSEAT_CELL_CENTER: {
final HotseatCellCenterRequest request = extra.getParcelable(
TestProtocol.TEST_INFO_REQUEST_FIELD);
return getLauncherUIProperty(Bundle::putParcelable, launcher -> {
final Hotseat hotseat = launcher.getHotseat();
final Rect cellRect = getDescendantRectRelativeToDragLayerForCell(launcher,
hotseat, request.cellInd, /* cellY= */ 0,
/* spanX= */ 1, /* spanY= */ 1);
// TODO(b/234322284): return the real center point.
return new Point(cellRect.left + (cellRect.right - cellRect.left) / 3,
cellRect.centerY());
});
}
case TestProtocol.REQUEST_HAS_TIS: {
response.putBoolean(
@@ -115,6 +115,8 @@ public final class TestProtocol {
public static final String REQUEST_WORKSPACE_CELL_LAYOUT_SIZE = "workspace-cell-layout-size";
public static final String REQUEST_WORKSPACE_CELL_CENTER = "workspace-cell-center";
public static final String REQUEST_HOTSEAT_CELL_CENTER = "hotseat-cell-center";
public static final String REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET =
"get-focused-task-height-for-tablet";
public static final String REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET =
@@ -540,6 +540,18 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
}
}
@Test
@PortraitLandscape
public void testAddDeleteShortcutOnHotseat() {
mLauncher.getWorkspace()
.deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
.switchToAllApps()
.getAppIcon(APP_NAME)
.dragToHotseat(0);
mLauncher.getWorkspace().deleteAppIcon(
mLauncher.getWorkspace().getHotseatAppIcon(APP_NAME));
}
/**
* @return List of workspace grid coordinates. Those are not pixels. See {@link
* Workspace#getIconGridDimensions()}
@@ -22,6 +22,8 @@ import android.graphics.Rect;
import androidx.annotation.NonNull;
import androidx.test.uiautomator.UiObject2;
import java.util.function.Supplier;
/**
* App icon on the workspace or all apps.
*/
@@ -100,9 +102,46 @@ public abstract class HomeAppIcon extends AppIcon implements FolderDragTarget, W
}
}
/**
* Drag an object to the given cell in hotseat. The target cell should be expected to be empty.
*
* @param cellInd zero based index number of the hotseat cells.
* @return the workspace app icon.
*/
@NonNull
public WorkspaceAppIcon dragToHotseat(int cellInd) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
String.format("want to drag the icon to hotseat cell %d", cellInd))
) {
final Supplier<Point> dest = () -> Workspace.getHotseatCellCenter(mLauncher, cellInd);
Workspace.dragIconToHotseat(
mLauncher,
this,
dest,
() -> addExpectedEventsForLongClick(),
/*expectDropEvents= */ null);
try (LauncherInstrumentation.Closable ignore = mLauncher.addContextLayer("dragged")) {
WorkspaceAppIcon appIcon =
(WorkspaceAppIcon) mLauncher.getWorkspace().getHotseatAppIcon(mAppName);
mLauncher.assertTrue(
String.format("The %s icon should be in the hotseat cell %d.", mAppName,
cellInd),
appIcon.isInHotseatCell(cellInd));
return appIcon;
}
}
}
/** This method requires public access, however should not be called in tests. */
@Override
public Launchable getLaunchable() {
return this;
}
boolean isInHotseatCell(int cellInd) {
final Point center = Workspace.getHotseatCellCenter(mLauncher, cellInd);
return mObject.getVisibleBounds().contains(center.x, center.y);
}
}
@@ -39,6 +39,7 @@ import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
import com.android.launcher3.testing.HotseatCellCenterRequest;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.testing.WorkspaceCellCenterRequest;
@@ -250,6 +251,24 @@ public final class Workspace extends Home {
mHotseat, AppIcon.getAppIconSelector(appName, mLauncher)));
}
/**
* Returns an icon for the given cell; fails if the icon doesn't exist.
*
* @param cellInd zero based index number of the hotseat cells.
* @return app icon.
*/
@NonNull
public HomeAppIcon getHotseatAppIcon(int cellInd) {
List<UiObject2> icons = mHotseat.findObjects(AppIcon.getAnyAppIconSelector());
final Point center = getHotseatCellCenter(mLauncher, cellInd);
return icons.stream()
.filter(icon -> icon.getVisibleBounds().contains(center.x, center.y))
.findFirst()
.map(icon -> new WorkspaceAppIcon(mLauncher, icon))
.orElseThrow(() ->
new AssertionError("Unable to get a hotseat icon on " + cellInd));
}
/**
* @return map of text -> center of the view. In case of icons with the same name, the one with
* lower x coordinate is selected.
@@ -360,6 +379,11 @@ public final class Workspace extends Home {
TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
static Point getHotseatCellCenter(LauncherInstrumentation launcher, int cellInd) {
return launcher.getTestInfo(HotseatCellCenterRequest.builder()
.setCellInd(cellInd).build()).getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
/**
* Finds folder icons in the current workspace.
*
@@ -471,6 +495,25 @@ public final class Workspace extends Home {
() -> "Page scroll didn't happen", "Scrolling page");
}
static void dragIconToHotseat(
LauncherInstrumentation launcher,
Launchable launchable,
Supplier<Point> dest,
Runnable expectLongClickEvents,
@Nullable Runnable expectDropEvents) {
final long downTime = SystemClock.uptimeMillis();
Point dragStart = launchable.startDrag(
downTime,
expectLongClickEvents,
/* runToSpringLoadedState= */ true);
Point targetDest = dest.get();
launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, true,
downTime, SystemClock.uptimeMillis(), false,
LauncherInstrumentation.GestureScope.INSIDE);
dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
}
/**
* Flings to get to screens on the right. Waits for scrolling and a possible overscroll
* recoil to complete.