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:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user