• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.AbstractFloatingView.TYPE_SNACKBAR;
23 import static com.android.launcher3.Flags.FLAG_ENABLE_DISMISS_PREDICTION_UNDO;
24 import static com.android.launcher3.Flags.FLAG_ENABLE_PRIVATE_SPACE;
25 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
26 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
27 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
28 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO;
29 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP;
30 import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI;
31 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
32 
33 import static org.junit.Assert.assertFalse;
34 import static org.junit.Assert.assertNotNull;
35 import static org.junit.Assert.assertNull;
36 import static org.junit.Assert.assertTrue;
37 import static org.mockito.ArgumentMatchers.any;
38 import static org.mockito.ArgumentMatchers.eq;
39 import static org.mockito.Mockito.atLeast;
40 import static org.mockito.Mockito.doReturn;
41 import static org.mockito.Mockito.reset;
42 import static org.mockito.Mockito.times;
43 import static org.mockito.Mockito.verify;
44 import static org.mockito.Mockito.when;
45 
46 import android.content.ComponentName;
47 import android.content.Intent;
48 import android.content.pm.ApplicationInfo;
49 import android.content.pm.LauncherActivityInfo;
50 import android.content.pm.LauncherApps;
51 import android.os.Process;
52 import android.os.UserHandle;
53 import android.platform.test.annotations.DisableFlags;
54 import android.platform.test.annotations.EnableFlags;
55 import android.platform.test.flag.junit.SetFlagsRule;
56 import android.view.View;
57 
58 import androidx.test.annotation.UiThreadTest;
59 import androidx.test.filters.SmallTest;
60 import androidx.test.platform.app.InstrumentationRegistry;
61 
62 import com.android.launcher3.AbstractFloatingView;
63 import com.android.launcher3.R;
64 import com.android.launcher3.allapps.PrivateProfileManager;
65 import com.android.launcher3.dagger.LauncherAppComponent;
66 import com.android.launcher3.dagger.LauncherAppSingleton;
67 import com.android.launcher3.logging.StatsLogManager;
68 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
69 import com.android.launcher3.model.data.AppInfo;
70 import com.android.launcher3.model.data.ItemInfo;
71 import com.android.launcher3.model.data.WorkspaceItemInfo;
72 import com.android.launcher3.pm.UserCache;
73 import com.android.launcher3.util.AllModulesForTest;
74 import com.android.launcher3.util.ComponentKey;
75 import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
76 import com.android.launcher3.util.LauncherMultivalentJUnit;
77 import com.android.launcher3.util.TestSandboxModelContextWrapper;
78 import com.android.launcher3.util.TestUtil;
79 import com.android.launcher3.util.UserIconInfo;
80 import com.android.launcher3.views.Snackbar;
81 import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
82 import com.android.launcher3.widget.picker.model.data.WidgetPickerData;
83 
84 import org.junit.After;
85 import org.junit.Assert;
86 import org.junit.Before;
87 import org.junit.Rule;
88 import org.junit.Test;
89 import org.junit.runner.RunWith;
90 import org.mockito.Answers;
91 import org.mockito.Mock;
92 import org.mockito.MockitoAnnotations;
93 
94 import dagger.BindsInstance;
95 import dagger.Component;
96 
97 @SmallTest
98 @RunWith(LauncherMultivalentJUnit.class)
99 public class SystemShortcutTest {
100     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
101     private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
102     private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
103     private View mView;
104     private ItemInfo mItemInfo;
105     private TestSandboxModelContextWrapper mTestContext;
106     private final SandboxModelContext mSandboxContext = new SandboxModelContext();
107     private PrivateProfileManager mPrivateProfileManager;
108     private WidgetPickerDataProvider mWidgetPickerDataProvider;
109     private AppInfo mAppInfo;
110 
111     @Mock UserCache mUserCache;
112     @Mock UserIconInfo mUserIconInfo;
113     @Mock LauncherActivityInfo mLauncherActivityInfo;
114     @Mock ApplicationInfo mApplicationInfo;
115     @Mock Intent mIntent;
116     @Mock StatsLogManager mStatsLogManager;
117     @Mock(answer = Answers.RETURNS_SELF) StatsLogger mStatsLogger;
118 
119     @Before
setUp()120     public void setUp() {
121         MockitoAnnotations.initMocks(this);
122         mSandboxContext.initDaggerComponent(
123                 DaggerSystemShortcutTest_TestComponent.builder().bindUserCache(mUserCache)
124         );
125         mTestContext = new TestSandboxModelContextWrapper(mSandboxContext) {
126             @Override
127             public StatsLogManager getStatsLogManager() {
128                 return mStatsLogManager;
129             }
130         };
131         spyOn(mSandboxContext);
132         doReturn(mStatsLogger).when(mStatsLogManager).logger();
133 
134         mView = new View(mTestContext);
135         mItemInfo = new ItemInfo();
136 
137         LauncherApps mLauncherApps = mSandboxContext.spyService(LauncherApps.class);
138         doReturn(mLauncherActivityInfo).when(mLauncherApps).resolveActivity(any(), any());
139         when(mLauncherActivityInfo.getApplicationInfo()).thenReturn(mApplicationInfo);
140 
141         when(mUserCache.getUserInfo(any())).thenReturn(mUserIconInfo);
142         mPrivateProfileManager = mTestContext.getAppsView().getPrivateProfileManager();
143         spyOn(mPrivateProfileManager);
144         when(mPrivateProfileManager.getProfileUser()).thenReturn(PRIVATE_HANDLE);
145 
146         mWidgetPickerDataProvider = mTestContext.getWidgetPickerDataProvider();
147         spyOn(mWidgetPickerDataProvider);
148     }
149 
150     @After
tearDown()151     public void tearDown() {
152         mSandboxContext.onDestroy();
153     }
154 
155     @Test
testWidgetsForNullComponentName()156     public void testWidgetsForNullComponentName() {
157         assertNull(mItemInfo.getTargetComponent());
158         SystemShortcut systemShortcut = SystemShortcut.WIDGETS
159                 .getShortcut(mTestContext, mItemInfo, mView);
160         assertNull(systemShortcut);
161     }
162 
163     @Test
testWidgetsForEmptyWidgetList()164     public void testWidgetsForEmptyWidgetList() {
165         mAppInfo = new AppInfo();
166         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
167         assertNotNull(mAppInfo.getTargetComponent());
168         doReturn(new WidgetPickerData()).when(mWidgetPickerDataProvider).get();
169         spyOn(mAppInfo);
170         SystemShortcut systemShortcut = SystemShortcut.WIDGETS
171                 .getShortcut(mTestContext, mAppInfo, mView);
172         verify(mAppInfo, times(2)).getTargetComponent();
173         assertNull(systemShortcut);
174     }
175 
176     @Test
testAppInfoShortcut()177     public void testAppInfoShortcut() {
178         mAppInfo = new AppInfo();
179         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
180         SystemShortcut systemShortcut = SystemShortcut.APP_INFO
181                 .getShortcut(mTestContext, mAppInfo, mView);
182         assertNotNull(systemShortcut);
183     }
184 
185 
186     @Test
testDontSuggestAppForNonPredictedItem()187     public void testDontSuggestAppForNonPredictedItem() {
188         assertFalse(mItemInfo.isPredictedItem());
189         SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
190                 .getShortcut(mTestContext, mItemInfo, mView);
191         assertNull(systemShortcut);
192     }
193 
194     @Test
195     @DisableFlags(FLAG_ENABLE_DISMISS_PREDICTION_UNDO)
testDontSuggestAppForPredictedItem()196     public void testDontSuggestAppForPredictedItem() {
197         mAppInfo = new AppInfo();
198         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
199         mAppInfo.container = CONTAINER_HOTSEAT_PREDICTION;
200         assertTrue(mAppInfo.isPredictedItem());
201         SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
202                 .getShortcut(mTestContext, mAppInfo, mView);
203         assertNotNull(systemShortcut);
204 
205         TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () -> systemShortcut.onClick(mView));
206         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
207 
208         verify(mStatsLogger).log(eq(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP));
209         assertFalse(AbstractFloatingView.hasOpenView(mTestContext, TYPE_SNACKBAR));
210     }
211 
212     @Test
213     @EnableFlags(FLAG_ENABLE_DISMISS_PREDICTION_UNDO)
testDontSuggestAppForPredictedItemWithUndo()214     public void testDontSuggestAppForPredictedItemWithUndo() {
215         mAppInfo = new AppInfo();
216         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
217         mAppInfo.container = CONTAINER_HOTSEAT_PREDICTION;
218         assertTrue(mAppInfo.isPredictedItem());
219         SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
220                 .getShortcut(mTestContext, mAppInfo, mView);
221         assertNotNull(systemShortcut);
222 
223         TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () -> systemShortcut.onClick(mView));
224         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
225         verify(mStatsLogger).log(eq(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP));
226 
227         // Undo bar shown
228         Snackbar snackbar = AbstractFloatingView.getOpenView(mTestContext, TYPE_SNACKBAR);
229         assertNotNull(snackbar);
230         reset(mStatsLogger);
231         TestUtil.runOnExecutorSync(MAIN_EXECUTOR, snackbar.findViewById(
232                 R.id.action)::performClick);
233         verify(mStatsLogger).log(eq(LAUNCHER_DISMISS_PREDICTION_UNDO));
234     }
235 
236     @Test
testPrivateProfileInstallwithTargetComponentNull()237     public void testPrivateProfileInstallwithTargetComponentNull() {
238         assertNull(mItemInfo.getTargetComponent());
239         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
240                 .getShortcut(mTestContext, mItemInfo, mView);
241         assertNull(systemShortcut);
242     }
243 
244     @Test
testPrivateProfileInstallNotAllAppsContainer()245     public void testPrivateProfileInstallNotAllAppsContainer() {
246         mAppInfo = new AppInfo();
247         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
248         mAppInfo.container = CONTAINER_HOTSEAT_PREDICTION;
249 
250         assertNotNull(mAppInfo.getTargetComponent());
251         assertFalse(mAppInfo.getContainerInfo().hasAllAppsContainer());
252 
253         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
254                 .getShortcut(mTestContext, mAppInfo, mView);
255         assertNull(systemShortcut);
256     }
257 
258     @Test
testPrivateProfileInstallNullPrivateProfileManager()259     public void testPrivateProfileInstallNullPrivateProfileManager() {
260         mAppInfo = new AppInfo();
261         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
262         mAppInfo.container = CONTAINER_ALL_APPS;
263         mPrivateProfileManager = null;
264 
265         assertNotNull(mAppInfo.getTargetComponent());
266         assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
267         assertNull(mPrivateProfileManager);
268 
269         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
270                 .getShortcut(mTestContext, mAppInfo, mView);
271         assertNull(systemShortcut);
272     }
273 
274     @Test
testPrivateProfileInstallPrivateProfileManagerDisabled()275     public void testPrivateProfileInstallPrivateProfileManagerDisabled() {
276         mAppInfo = new AppInfo();
277         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
278         mAppInfo.container = CONTAINER_ALL_APPS;
279 
280         assertNotNull(mPrivateProfileManager);
281         assertNotNull(mAppInfo.getTargetComponent());
282         assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
283 
284         when(mPrivateProfileManager.isEnabled()).thenReturn(false);
285         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
286                 .getShortcut(mTestContext, mAppInfo, mView);
287         assertNull(systemShortcut);
288     }
289 
290     @Test
testPrivateProfileInstallNullPrivateProfileUser()291     public void testPrivateProfileInstallNullPrivateProfileUser() {
292         mAppInfo = new AppInfo();
293         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
294         mAppInfo.container = CONTAINER_ALL_APPS;
295         when(mPrivateProfileManager.getProfileUser()).thenReturn(null);
296 
297         assertNotNull(mPrivateProfileManager);
298         assertNotNull(mAppInfo.getTargetComponent());
299         assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
300         assertNull(mPrivateProfileManager.getProfileUser());
301 
302         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
303                 .getShortcut(mTestContext, mAppInfo, mView);
304 
305         assertNull(systemShortcut);
306     }
307 
308     @Test
testPrivateProfileInstallNonNullPrivateProfileUser()309     public void testPrivateProfileInstallNonNullPrivateProfileUser() {
310         mAppInfo = new AppInfo();
311         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
312         mAppInfo.container = CONTAINER_ALL_APPS;
313         when(mPrivateProfileManager.isEnabled()).thenReturn(true);
314         when(mPrivateProfileManager.getProfileUser()).thenReturn(PRIVATE_HANDLE);
315 
316         assertNotNull(mAppInfo.getTargetComponent());
317         assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
318         assertNotNull(mPrivateProfileManager);
319         assertNotNull(mPrivateProfileManager.getProfileUser());
320         assertNull(mTestContext.getAppsView().getAppsStore().getApp(
321                 new ComponentKey(mAppInfo.getTargetComponent(), PRIVATE_HANDLE)));
322 
323         SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
324                 .getShortcut(mTestContext, mAppInfo, mView);
325 
326         verify(mPrivateProfileManager, atLeast(1)).isEnabled();
327         assertNotNull(systemShortcut);
328     }
329 
330     @Test
testInstallGetShortcutWithNonWorkSpaceItemInfo()331     public void testInstallGetShortcutWithNonWorkSpaceItemInfo() {
332         SystemShortcut systemShortcut = SystemShortcut.INSTALL.getShortcut(
333                 mTestContext, mItemInfo, mView);
334         Assert.assertNull(systemShortcut);
335     }
336 
337     @Test
338     @UiThreadTest
testInstallGetShortcutWithWorkSpaceItemInfo()339     public void testInstallGetShortcutWithWorkSpaceItemInfo() {
340         mAppInfo = new AppInfo();
341         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
342         mAppInfo.intent = mIntent;
343         WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(mAppInfo);
344         workspaceItemInfo.status = FLAG_SUPPORTS_WEB_UI;
345         SystemShortcut systemShortcut = SystemShortcut.INSTALL.getShortcut(
346                 mTestContext, workspaceItemInfo, mView);
347         Assert.assertNotNull(systemShortcut);
348     }
349 
350 
351     @Test
352     @DisableFlags(FLAG_ENABLE_PRIVATE_SPACE)
testUninstallGetShortcutWithPrivateSpaceOff()353     public void testUninstallGetShortcutWithPrivateSpaceOff() {
354         SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
355                 mTestContext, null, mView);
356         Assert.assertNull(systemShortcut);
357     }
358 
359     @Test
360     @EnableFlags(FLAG_ENABLE_PRIVATE_SPACE)
testUninstallGetShortcutWithNonPrivateItemInfo()361     public void testUninstallGetShortcutWithNonPrivateItemInfo() {
362         mAppInfo = new AppInfo();
363         mAppInfo.user = MAIN_HANDLE;
364         when(mUserIconInfo.isPrivate()).thenReturn(false);
365 
366         SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
367                 mTestContext, mAppInfo, mView);
368         verify(mUserIconInfo).isPrivate();
369         Assert.assertNull(systemShortcut);
370     }
371 
372     @Test
373     @EnableFlags(FLAG_ENABLE_PRIVATE_SPACE)
testUninstallGetShortcutWithSystemItemInfo()374     public void testUninstallGetShortcutWithSystemItemInfo() {
375         mAppInfo = new AppInfo();
376         mAppInfo.user = PRIVATE_HANDLE;
377         mAppInfo.itemType = ITEM_TYPE_APPLICATION;
378         mAppInfo.intent = mIntent;
379         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
380         when(mLauncherActivityInfo.getComponentName()).thenReturn(mAppInfo.componentName);
381         when(mUserIconInfo.isPrivate()).thenReturn(true);
382         // System App
383         mApplicationInfo.flags = 1;
384 
385         SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
386                 mTestContext, mAppInfo, mView);
387         verify(mLauncherActivityInfo, times(0)).getComponentName();
388         Assert.assertNull(systemShortcut);
389     }
390 
391     @Test
392     @EnableFlags(FLAG_ENABLE_PRIVATE_SPACE)
testUninstallGetShortcutWithPrivateItemInfo()393     public void testUninstallGetShortcutWithPrivateItemInfo() {
394         mAppInfo = new AppInfo();
395         mAppInfo.user = PRIVATE_HANDLE;
396         mAppInfo.itemType = ITEM_TYPE_APPLICATION;
397         mAppInfo.intent = mIntent;
398         mAppInfo.componentName = new ComponentName(mTestContext, getClass());
399         when(mUserIconInfo.isPrivate()).thenReturn(true);
400         when(mLauncherActivityInfo.getComponentName()).thenReturn(mAppInfo.componentName);
401         // 3rd party app, not system app.
402         mApplicationInfo.flags = 0;
403 
404         SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
405                 mTestContext, mAppInfo, mView);
406 
407         verify(mLauncherActivityInfo).getComponentName();
408         Assert.assertNotNull(systemShortcut);
409 
410         systemShortcut.onClick(mView);
411         verify(mSandboxContext).startActivity(any());
412     }
413 
414     @LauncherAppSingleton
415     @Component(modules = { AllModulesForTest.class })
416     interface TestComponent extends LauncherAppComponent {
417         @Component.Builder
418         interface Builder extends LauncherAppComponent.Builder {
419             @BindsInstance
bindUserCache(UserCache userCache)420             SystemShortcutTest.TestComponent.Builder bindUserCache(UserCache userCache);
build()421             @Override LauncherAppComponent build();
422         }
423     }
424 }
425