1 /*
2  * Copyright (C) 2024 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.popup;
18 
19 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
20 
21 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
22 import static com.android.launcher3.Flags.FLAG_ENABLE_PRIVATE_SPACE;
23 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
24 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
25 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
26 import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI;
27 
28 import static org.junit.Assert.assertFalse;
29 import static org.junit.Assert.assertNotNull;
30 import static org.junit.Assert.assertNull;
31 import static org.junit.Assert.assertTrue;
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.Mockito.atLeast;
34 import static org.mockito.Mockito.doReturn;
35 import static org.mockito.Mockito.times;
36 import static org.mockito.Mockito.verify;
37 import static org.mockito.Mockito.when;
38 
39 import android.content.ComponentName;
40 import android.content.Intent;
41 import android.content.pm.ApplicationInfo;
42 import android.content.pm.LauncherActivityInfo;
43 import android.content.pm.LauncherApps;
44 import android.os.Process;
45 import android.os.UserHandle;
46 import android.platform.test.annotations.DisableFlags;
47 import android.platform.test.annotations.EnableFlags;
48 import android.platform.test.flag.junit.SetFlagsRule;
49 import android.view.View;
50 
51 import androidx.test.annotation.UiThreadTest;
52 import androidx.test.filters.SmallTest;
53 
54 import com.android.launcher3.allapps.PrivateProfileManager;
55 import com.android.launcher3.model.data.AppInfo;
56 import com.android.launcher3.model.data.ItemInfo;
57 import com.android.launcher3.model.data.WorkspaceItemInfo;
58 import com.android.launcher3.pm.UserCache;
59 import com.android.launcher3.util.ApiWrapper;
60 import com.android.launcher3.util.ComponentKey;
61 import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
62 import com.android.launcher3.util.LauncherMultivalentJUnit;
63 import com.android.launcher3.util.TestSandboxModelContextWrapper;
64 import com.android.launcher3.util.UserIconInfo;
65 import com.android.launcher3.views.BaseDragLayer;
66 
67 import org.junit.After;
68 import org.junit.Assert;
69 import org.junit.Before;
70 import org.junit.Rule;
71 import org.junit.Test;
72 import org.junit.runner.RunWith;
73 import org.mockito.Mock;
74 import org.mockito.MockitoAnnotations;
75 
76 import java.util.ArrayList;
77 
78 @SmallTest
79 @RunWith(LauncherMultivalentJUnit.class)
80 public class SystemShortcutTest {
81     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
82     private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
83     private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
84     private View mView;
85     private ItemInfo mItemInfo;
86     private TestSandboxModelContextWrapper mTestContext;
87     private final SandboxModelContext mSandboxContext = new SandboxModelContext();
88     private PrivateProfileManager mPrivateProfileManager;
89     private PopupDataProvider mPopupDataProvider;
90     private AppInfo mAppInfo;
91     @Mock UserCache mUserCache;
92     @Mock ApiWrapper mApiWrapper;
93     @Mock BaseDragLayer mBaseDragLayer;
94     @Mock UserIconInfo mUserIconInfo;
95     @Mock LauncherActivityInfo mLauncherActivityInfo;
96     @Mock ApplicationInfo mApplicationInfo;
97     @Mock Intent mIntent;
98 
99     @Before
setUp()100     public void setUp() {
101         MockitoAnnotations.initMocks(this);
102         mSandboxContext.putObject(UserCache.INSTANCE, mUserCache);
103         mSandboxContext.putObject(ApiWrapper.INSTANCE, mApiWrapper);
104         mTestContext = new TestSandboxModelContextWrapper(mSandboxContext);
105         mView = new View(mSandboxContext);
106         spyOn(mTestContext);
107         spyOn(mSandboxContext);
108         doReturn(mBaseDragLayer).when(mTestContext).getDragLayer();
109 
110         mItemInfo = new ItemInfo();
111 
112         LauncherApps mLauncherApps = mSandboxContext.spyService(LauncherApps.class);
113         doReturn(mLauncherActivityInfo).when(mLauncherApps).resolveActivity(any(), any());
114         when(mLauncherActivityInfo.getApplicationInfo()).thenReturn(mApplicationInfo);
115 
116         when(mUserCache.getUserInfo(any())).thenReturn(mUserIconInfo);
117         when(mBaseDragLayer.getChildCount()).thenReturn(0);
118         mPrivateProfileManager = mTestContext.getAppsView().getPrivateProfileManager();
119         spyOn(mPrivateProfileManager);
120         when(mPrivateProfileManager.getProfileUser()).thenReturn(PRIVATE_HANDLE);
121 
122         mPopupDataProvider = mTestContext.getPopupDataProvider();
123         spyOn(mPopupDataProvider);
124     }
125 
126     @After
tearDown()127     public void tearDown() {
128         mSandboxContext.onDestroy();
129     }
130 
131     @Test
testWidgetsForNullComponentName()132     public void testWidgetsForNullComponentName() {
133         assertNull(mItemInfo.getTargetComponent());
134         SystemShortcut systemShortcut = SystemShortcut.WIDGETS
135                 .getShortcut(mTestContext, mItemInfo, mView);
136         assertNull(systemShortcut);
137     }
138 
139     @Test
testWidgetsForEmptyWidgetList()140     public void testWidgetsForEmptyWidgetList() {
141         mAppInfo = new AppInfo();
142         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
143         assertNotNull(mAppInfo.getTargetComponent());
144         doReturn(new ArrayList<>()).when(mPopupDataProvider).getWidgetsForPackageUser(any());
145         spyOn(mAppInfo);
146         SystemShortcut systemShortcut = SystemShortcut.WIDGETS
147                 .getShortcut(mTestContext, mAppInfo, mView);
148         verify(mAppInfo, times(2)).getTargetComponent();
149         assertNull(systemShortcut);
150     }
151 
152     @Test
testAppInfoShortcut()153     public void testAppInfoShortcut() {
154         mAppInfo = new AppInfo();
155         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
156         SystemShortcut systemShortcut = SystemShortcut.APP_INFO
157                 .getShortcut(mTestContext, mAppInfo, mView);
158         assertNotNull(systemShortcut);
159     }
160 
161 
162     @Test
testDontSuggestAppForNonPredictedItem()163     public void testDontSuggestAppForNonPredictedItem() {
164         assertFalse(mItemInfo.isPredictedItem());
165         SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
166                 .getShortcut(mTestContext, mItemInfo, mView);
167         assertNull(systemShortcut);
168     }
169 
170     @Test
testDontSuggestAppForPredictedItem()171     public void testDontSuggestAppForPredictedItem() {
172         mAppInfo = new AppInfo();
173         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
174         mAppInfo.container = CONTAINER_HOTSEAT_PREDICTION;
175         assertTrue(mAppInfo.isPredictedItem());
176         SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
177                 .getShortcut(mTestContext, mAppInfo, mView);
178         assertNotNull(systemShortcut);
179         systemShortcut.onClick(mView);
180     }
181 
182     @Test
testPrivateProfileInstallwithTargetComponentNull()183     public void testPrivateProfileInstallwithTargetComponentNull() {
184         assertNull(mItemInfo.getTargetComponent());
185         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
186                 .getShortcut(mTestContext, mItemInfo, mView);
187         assertNull(systemShortcut);
188     }
189 
190     @Test
testPrivateProfileInstallNotAllAppsContainer()191     public void testPrivateProfileInstallNotAllAppsContainer() {
192         mAppInfo = new AppInfo();
193         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
194         mAppInfo.container = CONTAINER_HOTSEAT_PREDICTION;
195 
196         assertNotNull(mAppInfo.getTargetComponent());
197         assertFalse(mAppInfo.getContainerInfo().hasAllAppsContainer());
198 
199         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
200                 .getShortcut(mTestContext, mAppInfo, mView);
201         assertNull(systemShortcut);
202     }
203 
204     @Test
testPrivateProfileInstallNullPrivateProfileManager()205     public void testPrivateProfileInstallNullPrivateProfileManager() {
206         mAppInfo = new AppInfo();
207         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
208         mAppInfo.container = CONTAINER_ALL_APPS;
209         mPrivateProfileManager = null;
210 
211         assertNotNull(mAppInfo.getTargetComponent());
212         assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
213         assertNull(mPrivateProfileManager);
214 
215         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
216                 .getShortcut(mTestContext, mAppInfo, mView);
217         assertNull(systemShortcut);
218     }
219 
220     @Test
testPrivateProfileInstallPrivateProfileManagerDisabled()221     public void testPrivateProfileInstallPrivateProfileManagerDisabled() {
222         mAppInfo = new AppInfo();
223         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
224         mAppInfo.container = CONTAINER_ALL_APPS;
225 
226         assertNotNull(mPrivateProfileManager);
227         assertNotNull(mAppInfo.getTargetComponent());
228         assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
229 
230         when(mPrivateProfileManager.isEnabled()).thenReturn(false);
231         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
232                 .getShortcut(mTestContext, mAppInfo, mView);
233         assertNull(systemShortcut);
234     }
235 
236     @Test
testPrivateProfileInstallNullPrivateProfileUser()237     public void testPrivateProfileInstallNullPrivateProfileUser() {
238         mAppInfo = new AppInfo();
239         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
240         mAppInfo.container = CONTAINER_ALL_APPS;
241         when(mPrivateProfileManager.getProfileUser()).thenReturn(null);
242 
243         assertNotNull(mPrivateProfileManager);
244         assertNotNull(mAppInfo.getTargetComponent());
245         assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
246         assertNull(mPrivateProfileManager.getProfileUser());
247 
248         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
249                 .getShortcut(mTestContext, mAppInfo, mView);
250 
251         assertNull(systemShortcut);
252     }
253 
254     @Test
testPrivateProfileInstallNonNullPrivateProfileUser()255     public void testPrivateProfileInstallNonNullPrivateProfileUser() {
256         mAppInfo = new AppInfo();
257         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
258         mAppInfo.container = CONTAINER_ALL_APPS;
259         when(mPrivateProfileManager.isEnabled()).thenReturn(true);
260         when(mPrivateProfileManager.getProfileUser()).thenReturn(PRIVATE_HANDLE);
261 
262         assertNotNull(mAppInfo.getTargetComponent());
263         assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
264         assertNotNull(mPrivateProfileManager);
265         assertNotNull(mPrivateProfileManager.getProfileUser());
266         assertNull(mTestContext.getAppsView().getAppsStore().getApp(
267                 new ComponentKey(mAppInfo.getTargetComponent(), PRIVATE_HANDLE)));
268 
269         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
270                 .getShortcut(mTestContext, mAppInfo, mView);
271 
272         verify(mPrivateProfileManager, atLeast(1)).isEnabled();
273         assertNotNull(systemShortcut);
274     }
275 
276     @Test
testInstallGetShortcutWithNonWorkSpaceItemInfo()277     public void testInstallGetShortcutWithNonWorkSpaceItemInfo() {
278         SystemShortcut systemShortcut = SystemShortcut.INSTALL.getShortcut(
279                 mTestContext, mItemInfo, mView);
280         Assert.assertNull(systemShortcut);
281     }
282 
283     @Test
284     @UiThreadTest
testInstallGetShortcutWithWorkSpaceItemInfo()285     public void testInstallGetShortcutWithWorkSpaceItemInfo() {
286         mAppInfo = new AppInfo();
287         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
288         mAppInfo.intent = mIntent;
289         WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(mAppInfo);
290         workspaceItemInfo.status = FLAG_SUPPORTS_WEB_UI;
291         SystemShortcut systemShortcut = SystemShortcut.INSTALL.getShortcut(
292                 mTestContext, workspaceItemInfo, mView);
293         Assert.assertNotNull(systemShortcut);
294     }
295 
296 
297     @Test
298     @DisableFlags(FLAG_ENABLE_PRIVATE_SPACE)
testUninstallGetShortcutWithPrivateSpaceOff()299     public void testUninstallGetShortcutWithPrivateSpaceOff() {
300         SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
301                 mTestContext, null, mView);
302         Assert.assertNull(systemShortcut);
303     }
304 
305     @Test
306     @EnableFlags(FLAG_ENABLE_PRIVATE_SPACE)
testUninstallGetShortcutWithNonPrivateItemInfo()307     public void testUninstallGetShortcutWithNonPrivateItemInfo() {
308         mAppInfo = new AppInfo();
309         mAppInfo.user = MAIN_HANDLE;
310         when(mUserIconInfo.isPrivate()).thenReturn(false);
311 
312         SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
313                 mTestContext, mAppInfo, mView);
314         verify(mUserIconInfo).isPrivate();
315         Assert.assertNull(systemShortcut);
316     }
317 
318     @Test
319     @EnableFlags(FLAG_ENABLE_PRIVATE_SPACE)
testUninstallGetShortcutWithSystemItemInfo()320     public void testUninstallGetShortcutWithSystemItemInfo() {
321         mAppInfo = new AppInfo();
322         mAppInfo.user = PRIVATE_HANDLE;
323         mAppInfo.itemType = ITEM_TYPE_APPLICATION;
324         mAppInfo.intent = mIntent;
325         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
326         when(mLauncherActivityInfo.getComponentName()).thenReturn(mAppInfo.componentName);
327         when(mUserIconInfo.isPrivate()).thenReturn(true);
328         // System App
329         mApplicationInfo.flags = 1;
330 
331         SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
332                 mTestContext, mAppInfo, mView);
333         verify(mLauncherActivityInfo, times(0)).getComponentName();
334         Assert.assertNull(systemShortcut);
335     }
336 
337     @Test
338     @EnableFlags(FLAG_ENABLE_PRIVATE_SPACE)
testUninstallGetShortcutWithPrivateItemInfo()339     public void testUninstallGetShortcutWithPrivateItemInfo() {
340         mAppInfo = new AppInfo();
341         mAppInfo.user = PRIVATE_HANDLE;
342         mAppInfo.itemType = ITEM_TYPE_APPLICATION;
343         mAppInfo.intent = mIntent;
344         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
345         when(mUserIconInfo.isPrivate()).thenReturn(true);
346         when(mLauncherActivityInfo.getComponentName()).thenReturn(mAppInfo.componentName);
347         // 3rd party app, not system app.
348         mApplicationInfo.flags = 0;
349 
350         SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
351                 mTestContext, mAppInfo, mView);
352 
353         verify(mLauncherActivityInfo).getComponentName();
354         Assert.assertNotNull(systemShortcut);
355 
356         systemShortcut.onClick(mView);
357         verify(mSandboxContext).startActivity(any());
358     }
359 }
360