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