1 package com.android.launcher3.model;
2 
3 import static android.os.Process.myUserHandle;
4 
5 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
6 import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
7 import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY2;
8 import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY3;
9 import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
10 import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
11 
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertFalse;
14 import static org.junit.Assert.assertTrue;
15 
16 import android.content.Context;
17 
18 import androidx.test.ext.junit.runners.AndroidJUnit4;
19 import androidx.test.filters.SmallTest;
20 
21 import com.android.launcher3.LauncherAppState;
22 import com.android.launcher3.icons.BitmapInfo;
23 import com.android.launcher3.model.data.FolderInfo;
24 import com.android.launcher3.model.data.WorkspaceItemInfo;
25 import com.android.launcher3.util.IntSet;
26 import com.android.launcher3.util.LauncherLayoutBuilder;
27 import com.android.launcher3.util.LauncherModelHelper;
28 import com.android.launcher3.util.PackageUserKey;
29 import com.android.launcher3.util.rule.TestStabilityRule;
30 
31 import org.junit.After;
32 import org.junit.Before;
33 import org.junit.Rule;
34 import org.junit.Test;
35 import org.junit.rules.TestRule;
36 import org.junit.runner.RunWith;
37 
38 import java.util.Arrays;
39 import java.util.HashSet;
40 import java.util.List;
41 
42 /**
43  * Tests for {@link CacheDataUpdatedTask}
44  */
45 @SmallTest
46 @RunWith(AndroidJUnit4.class)
47 public class CacheDataUpdatedTaskTest {
48 
49     @Rule(order = 0)
50     public TestRule testStabilityRule = new TestStabilityRule();
51 
52     private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
53     private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
54 
55     private LauncherModelHelper mModelHelper;
56     private Context mContext;
57 
58     private int mSession1;
59 
60     @Before
setup()61     public void setup() throws Exception {
62         mModelHelper = new LauncherModelHelper();
63         mContext = mModelHelper.sandboxContext;
64         mSession1 = mModelHelper.createInstallerSession(PENDING_APP_1);
65         mModelHelper.createInstallerSession(PENDING_APP_2);
66 
67         LauncherLayoutBuilder builder = new LauncherLayoutBuilder()
68                 .atHotseat(1).putFolder("MyFolder")
69                 .addApp(TEST_PACKAGE, TEST_ACTIVITY)    // 2
70                 .addApp(TEST_PACKAGE, TEST_ACTIVITY2)   // 3
71                 .addApp(TEST_PACKAGE, TEST_ACTIVITY3)   // 4
72 
73                 // Pending App 1
74                 .addApp(PENDING_APP_1, TEST_ACTIVITY)   // 5
75                 .addApp(PENDING_APP_1, TEST_ACTIVITY2)  // 6
76                 .addApp(PENDING_APP_1, TEST_ACTIVITY3)  // 7
77 
78                 // Pending App 2
79                 .addApp(PENDING_APP_2, TEST_ACTIVITY)   // 8
80                 .addApp(PENDING_APP_2, TEST_ACTIVITY2)  // 9
81                 .addApp(PENDING_APP_2, TEST_ACTIVITY3)  // 10
82                 .build();
83         mModelHelper.setupDefaultLayoutProvider(builder);
84         mModelHelper.loadModelSync();
85         assertEquals(10, mModelHelper.getBgDataModel().itemsIdMap.size());
86     }
87 
88     @After
tearDown()89     public void tearDown() {
90         mModelHelper.destroy();
91     }
92 
newTask(int op, String... pkg)93     private CacheDataUpdatedTask newTask(int op, String... pkg) {
94         return new CacheDataUpdatedTask(op, myUserHandle(),
95                 new HashSet<>(Arrays.asList(pkg)));
96     }
97 
98     @Test
testCacheUpdate_update_apps()99     public void testCacheUpdate_update_apps() {
100         // Run on model executor so that no other task runs in the middle.
101         runOnExecutorSync(MODEL_EXECUTOR, () -> {
102             // Clear all icons from apps list so that its easy to check what was updated
103             allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
104 
105             mModelHelper.getModel().enqueueModelUpdateTask(
106                     newTask(CacheDataUpdatedTask.OP_CACHE_UPDATE, TEST_PACKAGE));
107 
108             // Verify that only the app icons of TEST_PACKAGE (id 2, 3, 4) are updated.
109             verifyUpdate(2, 3, 4);
110         });
111     }
112 
113     @Test
testSessionUpdate_ignores_normal_apps()114     public void testSessionUpdate_ignores_normal_apps() {
115         // Run on model executor so that no other task runs in the middle.
116         runOnExecutorSync(MODEL_EXECUTOR, () -> {
117             // Clear all icons from apps list so that its easy to check what was updated
118             allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
119 
120             mModelHelper.getModel().enqueueModelUpdateTask(
121                     newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, TEST_PACKAGE));
122 
123             // TEST_PACKAGE has no restored shortcuts. Verify that nothing was updated.
124             verifyUpdate();
125         });
126     }
127 
128     @Test
testSessionUpdate_updates_pending_apps()129     public void testSessionUpdate_updates_pending_apps() {
130         // Run on model executor so that no other task runs in the middle.
131         runOnExecutorSync(MODEL_EXECUTOR, () -> {
132             LauncherAppState.getInstance(mContext).getIconCache().updateSessionCache(
133                     new PackageUserKey(PENDING_APP_1, myUserHandle()),
134                     mContext.getPackageManager().getPackageInstaller().getSessionInfo(mSession1));
135 
136             // Clear all icons from apps list so that its easy to check what was updated
137             allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
138 
139             mModelHelper.getModel().enqueueModelUpdateTask(
140                     newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, PENDING_APP_1));
141 
142             // Only restored apps from PENDING_APP_1 (id 5, 6, 7) are updated
143             verifyUpdate(5, 6, 7);
144         });
145     }
146 
verifyUpdate(int... idsUpdated)147     private void verifyUpdate(int... idsUpdated) {
148         IntSet updates = IntSet.wrap(idsUpdated);
149         for (WorkspaceItemInfo info : allItems()) {
150             if (updates.contains(info.id)) {
151                 assertFalse(info.bitmap.isNullOrLowRes());
152             } else {
153                 assertTrue(info.bitmap.isNullOrLowRes());
154             }
155         }
156     }
157 
allItems()158     private List<WorkspaceItemInfo> allItems() {
159         return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).getAppContents();
160     }
161 }
162