• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 package com.android.launcher3.dragging;
17 
18 import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
19 import static com.android.launcher3.util.TestConstants.AppNames.DUMMY_APP_NAME;
20 import static com.android.launcher3.util.TestConstants.AppNames.GMAIL_APP_NAME;
21 import static com.android.launcher3.util.TestConstants.AppNames.MAPS_APP_NAME;
22 import static com.android.launcher3.util.TestConstants.AppNames.STORE_APP_NAME;
23 import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import android.graphics.Point;
28 import android.platform.test.annotations.PlatinumTest;
29 import android.platform.test.rule.ScreenRecordRule;
30 import android.util.Log;
31 
32 import com.android.launcher3.Launcher;
33 import com.android.launcher3.tapl.HomeAllApps;
34 import com.android.launcher3.tapl.HomeAppIcon;
35 import com.android.launcher3.tapl.Workspace;
36 import com.android.launcher3.ui.AbstractLauncherUiTest;
37 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
38 import com.android.launcher3.util.TestUtil;
39 import com.android.launcher3.util.Wait;
40 
41 import org.junit.Test;
42 
43 import java.io.IOException;
44 import java.util.Arrays;
45 
46 /**
47  * Test runs in Out of process (Oop) and In process (Ipc)
48  * Test the behaviour of uninstalling and removing apps both from AllApps, Workspace and Hotseat.
49  */
50 public class TaplUninstallRemoveTest extends AbstractLauncherUiTest<Launcher> {
51 
52     /**
53      * Deletes app both built-in and user-installed from the Workspace and makes sure it's no longer
54      * in the Workspace.
55      */
56     @Test
57     @PortraitLandscape
testDeleteFromWorkspace()58     public void testDeleteFromWorkspace() {
59         for (String appName : new String[]{GMAIL_APP_NAME, STORE_APP_NAME, TEST_APP_NAME}) {
60             final HomeAppIcon homeAppIcon = createShortcutInCenterIfNotExist(appName);
61             Workspace workspace = mLauncher.getWorkspace().deleteAppIcon(homeAppIcon);
62             workspace.verifyWorkspaceAppIconIsGone(
63                     appName + " app was found after being deleted from workspace",
64                     appName);
65         }
66     }
67 
verifyAppUninstalledFromAllApps(Workspace workspace, String appName)68     private void verifyAppUninstalledFromAllApps(Workspace workspace, String appName) {
69         final HomeAllApps allApps = workspace.switchToAllApps();
70         Wait.atMost(appName + " app was found on all apps after being uninstalled",
71                 () -> allApps.tryGetAppIcon(appName) == null, mLauncher);
72     }
73 
installDummyAppAndWaitForUIUpdate()74     private void installDummyAppAndWaitForUIUpdate() throws IOException {
75         TestUtil.installDummyApp();
76         waitForLauncherUIUpdate();
77     }
78 
waitForLauncherUIUpdate()79     private void waitForLauncherUIUpdate() {
80         // Wait for model thread completion as it may be processing
81         // the install event from the SystemService
82         mLauncher.waitForModelQueueCleared();
83         // Wait for Launcher UI thread completion, as it may be processing updating the UI in
84         // response to the model update. Not that `waitForLauncherInitialized` is just a proxy
85         // method, we can use any method which touches Launcher UI thread,
86         mLauncher.waitForLauncherInitialized();
87     }
88 
89     /**
90      * Makes sure you can uninstall an app from the Workspace.
91      */
92     @Test
93     @PortraitLandscape
94     @PlatinumTest(focusArea = "launcher")
testUninstallFromWorkspace()95     public void testUninstallFromWorkspace() throws Exception {
96         installDummyAppAndWaitForUIUpdate();
97         try {
98             verifyAppUninstalledFromAllApps(
99                     createShortcutInCenterIfNotExist(DUMMY_APP_NAME).uninstall(), DUMMY_APP_NAME);
100         } finally {
101             TestUtil.uninstallDummyApp();
102         }
103     }
104 
105     /**
106      * Makes sure you can uninstall an app from AllApps.
107      */
108     @Test
109     @PortraitLandscape
110     @PlatinumTest(focusArea = "launcher")
111     @ScreenRecordRule.ScreenRecord // b/386231522
testUninstallFromAllApps()112     public void testUninstallFromAllApps() throws Exception {
113         // Ensure no existing app icons on the workspace cause scroll to all apps interruptions
114         mLauncher.clearLauncherData();
115 
116         installDummyAppAndWaitForUIUpdate();
117         try {
118             Workspace workspace = mLauncher.getWorkspace();
119             final HomeAllApps allApps = workspace.switchToAllApps();
120             workspace = allApps.getAppIcon(DUMMY_APP_NAME).uninstall();
121             verifyAppUninstalledFromAllApps(workspace, DUMMY_APP_NAME);
122         } finally {
123             TestUtil.uninstallDummyApp();
124         }
125     }
126 
127     /**
128      * Adds three icons to the workspace and removes one of them by dragging to uninstall.
129      */
130     @Test
131     @PlatinumTest(focusArea = "launcher")
uninstallWorkspaceIcon()132     public void uninstallWorkspaceIcon() throws IOException {
133         Point[] gridPositions = TestUtil.getCornersAndCenterPositions(mLauncher);
134         StringBuilder sb = new StringBuilder();
135         for (Point p : gridPositions) {
136             sb.append(p).append(", ");
137         }
138         Log.d(ICON_MISSING, "allGridPositions: " + sb);
139         try {
140             installDummyAppAndWaitForUIUpdate();
141 
142             final String[] appNameCandidates = {DUMMY_APP_NAME, MAPS_APP_NAME, STORE_APP_NAME};
143 
144             // List of test apps trimmed down to the length of grid positions.
145             final String[] appNames = Arrays.copyOfRange(
146                     appNameCandidates,
147                     0, Math.min(gridPositions.length, appNameCandidates.length));
148 
149             for (int i = 0; i < appNames.length; ++i) {
150                 createShortcutIfNotExist(appNames[i], gridPositions[i]);
151             }
152 
153             Point initialPosition =
154                     mLauncher.getWorkspace().getWorkspaceIconPosition(DUMMY_APP_NAME);
155             assertThat(initialPosition).isNotNull();
156 
157             final Workspace workspace = mLauncher.getWorkspace().getWorkspaceAppIcon(
158                     DUMMY_APP_NAME).uninstall();
159             workspace.verifyWorkspaceAppIconIsGone(
160                     DUMMY_APP_NAME + " was expected to disappear after uninstall.", DUMMY_APP_NAME);
161         } finally {
162             TestUtil.uninstallDummyApp();
163         }
164     }
165 
166     /**
167      * Drag icon from the Hotseat to the delete drop target
168      */
169     @Test
170     @PortraitLandscape
testAddDeleteShortcutOnHotseat()171     public void testAddDeleteShortcutOnHotseat() {
172         mLauncher.getWorkspace()
173                 .deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
174                 .switchToAllApps()
175                 .getAppIcon(TEST_APP_NAME)
176                 .dragToHotseat(0);
177         mLauncher.getWorkspace().deleteAppIcon(
178                 mLauncher.getWorkspace().getHotseatAppIcon(TEST_APP_NAME));
179     }
180 }
181