1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3.tapl;
18 
19 import android.graphics.Point;
20 import android.graphics.Rect;
21 
22 import androidx.annotation.NonNull;
23 import androidx.test.uiautomator.UiObject2;
24 
25 import java.util.function.Supplier;
26 
27 /**
28  * App icon on the workspace or all apps.
29  */
30 public abstract class HomeAppIcon extends AppIcon implements IconDragTarget, WorkspaceDragSource {
31 
32     private final String mAppName;
33 
HomeAppIcon(LauncherInstrumentation launcher, UiObject2 icon)34     HomeAppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
35         super(launcher, icon);
36         mAppName = icon.getText();
37     }
38 
39     /**
40      * Drag the AppIcon to the given position of other icon. The drag must result in a folder.
41      *
42      * @param target the destination icon.
43      */
44     @NonNull
dragToIcon(IconDragTarget target)45     public FolderIcon dragToIcon(IconDragTarget target) {
46         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
47              LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to drag icon")) {
48             final Rect dropBounds = target.getDropLocationBounds();
49             Workspace.dragIconToWorkspace(
50                     mLauncher, this,
51                     () -> {
52                         final Rect bounds = target.getDropLocationBounds();
53                         return new Point(bounds.centerX(), bounds.centerY());
54                     }, false);
55             FolderIcon result = target.getTargetIcon(dropBounds);
56             mLauncher.assertTrue("Can't find the target folder.", result != null);
57             return result;
58         }
59     }
60 
61     /**
62      * Drag the AppIcon to the given position of a folder icon, and then inside that folder.
63      *
64      * @param target the destination folder.
65      */
66     @NonNull
dragToFolder(IconDragTarget target)67     public Folder dragToFolder(IconDragTarget target) {
68         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
69              LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to drag icon")) {
70             Workspace.dragIconToWorkspace(
71                     mLauncher, this,
72                     () -> {
73                         final Rect bounds = target.getDropLocationBounds();
74                         return new Point(bounds.centerX(), bounds.centerY());
75                     }, /* isDraggingToFolder */ true);
76         }
77         return new Folder(mLauncher);
78     }
79 
80 
81     /** This method requires public access, however should not be called in tests. */
82     @Override
getDropLocationBounds()83     public Rect getDropLocationBounds() {
84         return mLauncher.getVisibleBounds(mObject);
85     }
86 
87     /** This method requires public access, however should not be called in tests. */
88     @Override
getTargetIcon(Rect bounds)89     public FolderIcon getTargetIcon(Rect bounds) {
90         for (FolderIcon folderIcon : mLauncher.getWorkspace().getFolderIcons()) {
91             final Rect folderIconBounds = folderIcon.getDropLocationBounds();
92             if (bounds.contains(folderIconBounds.centerX(), folderIconBounds.centerY())) {
93                 return folderIcon;
94             }
95         }
96         return null;
97     }
98 
99     @Override
openDeepShortcutMenu()100     public HomeAppIconMenu openDeepShortcutMenu() {
101         return (HomeAppIconMenu) super.openDeepShortcutMenu();
102     }
103 
104     @Override
createMenu(UiObject2 menu)105     protected HomeAppIconMenu createMenu(UiObject2 menu) {
106         return new HomeAppIconMenu(mLauncher, menu);
107     }
108 
109     /**
110      * Uninstall the appIcon by dragging it to the 'uninstall' drop point of the drop_target_bar.
111      *
112      * @return validated workspace after the existing appIcon being uninstalled.
113      */
uninstall()114     public Workspace uninstall() {
115         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
116              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
117                      "uninstalling app icon")) {
118             return Workspace.uninstallAppIcon(
119                     mLauncher, this,
120                     this::addExpectedEventsForLongClick
121             );
122         }
123     }
124 
125     /**
126      * Drag an object to the given cell in hotseat. The target cell should be expected to be empty.
127      *
128      * @param cellInd zero based index number of the hotseat cells.
129      * @return the workspace app icon.
130      */
131     @NonNull
dragToHotseat(int cellInd)132     public WorkspaceAppIcon dragToHotseat(int cellInd) {
133         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
134              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
135                      String.format("want to drag the icon to hotseat cell %d", cellInd))
136         ) {
137             final Supplier<Point> dest = () -> Workspace.getHotseatCellCenter(mLauncher, cellInd);
138 
139             Workspace.dragIconToHotseat(
140                     mLauncher,
141                     this,
142                     dest,
143                     () -> addExpectedEventsForLongClick(),
144                     /*expectDropEvents= */ null);
145             try (LauncherInstrumentation.Closable ignore = mLauncher.addContextLayer("dragged")) {
146                 WorkspaceAppIcon appIcon =
147                         (WorkspaceAppIcon) mLauncher.getWorkspace().getHotseatAppIcon(mAppName);
148                 mLauncher.assertTrue(
149                         String.format("The %s icon should be in the hotseat cell %d.", mAppName,
150                                 cellInd),
151                         appIcon.isInHotseatCell(cellInd));
152                 return appIcon;
153             }
154         }
155     }
156 
157     /** This method requires public access, however should not be called in tests. */
158     @Override
getLaunchable()159     public Launchable getLaunchable() {
160         return this;
161     }
162 
isInHotseatCell(int cellInd)163     boolean isInHotseatCell(int cellInd) {
164         final Point center = Workspace.getHotseatCellCenter(mLauncher, cellInd);
165         return mObject.getVisibleBounds().contains(center.x, center.y);
166     }
167 }
168