Converting some caching logic booleans to lookup flags

Bug: 366237794
Test: atest IconCacheTest
Flag: EXEMPT refactor

Change-Id: I0d25996181954df22e1cb61596be0a2694ee7068
This commit is contained in:
Sunny Goyal
2024-09-27 12:45:27 -07:00
parent 1b1ce734f0
commit e978f6cedb
5 changed files with 160 additions and 22 deletions
@@ -110,8 +110,6 @@ object CacheableShortcutCachingLogic : CachingLogic<CacheableShortcutInfo> {
info?.let { max(info.shortcutInfo.lastChangedTimestamp, packageInfo.lastUpdateTime) }
?: packageInfo.lastUpdateTime
override fun addToMemCache() = false
override fun getApplicationInfo(info: CacheableShortcutInfo) = info.appInfo.getInfo()
override fun loadIcon(context: Context, cache: BaseIconCache, info: CacheableShortcutInfo) =
@@ -110,8 +110,7 @@ public class IconCache extends BaseIconCache {
IconProvider iconProvider) {
super(context, dbFileName, MODEL_EXECUTOR.getLooper(),
idp.fillResIconDpi, idp.iconBitmapSize, true /* inMemoryCache */, iconProvider);
mComponentWithLabelCachingLogic = new CachedObjectCachingLogic(
context, false /* loadIcons */, false /* addToMemCache */);
mComponentWithLabelCachingLogic = new CachedObjectCachingLogic(context);
mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.INSTANCE;
mLauncherApps = mContext.getSystemService(LauncherApps.class);
mUserManager = UserCache.INSTANCE.get(mContext);
@@ -149,8 +148,7 @@ public class IconCache extends BaseIconCache {
PackageManager.GET_UNINSTALLED_PACKAGES);
long userSerial = mUserManager.getSerialNumberForUser(user);
for (LauncherActivityInfo app : mLauncherApps.getActivityList(packageName, user)) {
addIconToDBAndMemCache(app, mLauncherActivityInfoCachingLogic, info, userSerial,
false /*replace existing*/);
addIconToDBAndMemCache(app, mLauncherActivityInfoCachingLogic, info, userSerial);
}
} catch (NameNotFoundException e) {
Log.d(TAG, "Package not found", e);
@@ -205,7 +203,7 @@ public class IconCache extends BaseIconCache {
CancellableTask<ItemInfoWithIcon> request = new CancellableTask<>(
task, MAIN_EXECUTOR, caller::reapplyItemInfo, endRunnable);
Utilities.postAsyncCallback(mWorkerHandler, request);
Utilities.postAsyncCallback(workerHandler, request);
return request;
}
@@ -257,6 +255,7 @@ public class IconCache extends BaseIconCache {
/**
* Fill in {@code info} with the icon and label for {@code si}. If the icon is not
* available, and fallback check returns true, it keeps the old icon.
* Shortcut entries are not kept in memory since they are not frequently used
*/
public <T extends ItemInfoWithIcon> void getShortcutIcon(T info, CacheableShortcutInfo si,
@NonNull Predicate<T> fallbackIconCheck) {
@@ -266,7 +265,7 @@ public class IconCache extends BaseIconCache {
user,
() -> si,
CacheableShortcutCachingLogic.INSTANCE,
LookupFlag.DEFAULT).bitmap;
LookupFlag.SKIP_ADD_TO_MEM_CACHE).bitmap;
if (bitmapInfo.isNullOrLowRes()) {
bitmapInfo = getDefaultIcon(user);
}
@@ -337,7 +336,8 @@ public class IconCache extends BaseIconCache {
*/
public synchronized String getTitleNoCache(ComponentWithLabel info) {
CacheEntry entry = cacheLocked(info.getComponent(), info.getUser(), () -> info,
mComponentWithLabelCachingLogic, LookupFlag.USE_LOW_RES);
mComponentWithLabelCachingLogic,
LookupFlag.USE_LOW_RES | LookupFlag.SKIP_ADD_TO_MEM_CACHE);
return Utilities.trim(entry.title);
}
@@ -15,21 +15,39 @@
*/
package com.android.launcher3.icons;
import static android.os.Process.myUserHandle;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE;
import static com.android.launcher3.icons.IconCacheUpdateHandlerTestKt.waitForUpdateHandlerToFinish;
import static com.android.launcher3.model.data.AppInfo.makeLaunchIntent;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutInfo.Builder;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.drawable.Icon;
import android.os.PersistableBundle;
import android.os.UserHandle;
import android.text.TextUtils;
import androidx.annotation.Nullable;
@@ -37,15 +55,30 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.icons.cache.CachingLogic;
import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
import com.android.launcher3.icons.cache.LauncherActivityCachingLogic;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.settings.SettingsActivity;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.RoboApiWrapper;
import com.google.common.truth.Truth;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class IconCacheTest {
@@ -112,6 +145,102 @@ public class IconCacheTest {
assertEquals(((PackageItemInfo) item).packageName, otherPackage);
}
@Test
public void launcherActivityInfo_cached_in_memory() {
RoboApiWrapper.INSTANCE.initialize();
ComponentName cn = new ComponentName(TEST_PACKAGE, TEST_ACTIVITY);
UserHandle user = myUserHandle();
ComponentKey cacheKey = new ComponentKey(cn, user);
LauncherActivityInfo lai = mContext.getSystemService(LauncherApps.class)
.resolveActivity(makeLaunchIntent(cn), user);
assertNotNull(lai);
WorkspaceItemInfo info = new WorkspaceItemInfo();
info.intent = makeLaunchIntent(cn);
runOnExecutorSync(MODEL_EXECUTOR,
() -> mIconCache.getTitleAndIcon(info, lai, false));
assertNotNull(info.bitmap);
assertFalse(info.bitmap.isLowRes());
// Verify that icon is in memory cache
runOnExecutorSync(MODEL_EXECUTOR,
() -> assertNotNull(mIconCache.getInMemoryEntryLocked(cacheKey)));
// Schedule async update and wait for it to complete
Set<PackageUserKey> updates =
executeIconUpdate(lai, LauncherActivityCachingLogic.INSTANCE);
// Verify that the icon was not updated and is still in memory cache
Truth.assertThat(updates).isEmpty();
runOnExecutorSync(MODEL_EXECUTOR,
() -> assertNotNull(mIconCache.getInMemoryEntryLocked(cacheKey)));
}
@Test
public void shortcutInfo_not_cached_in_memory() {
CacheableShortcutInfo si = mockShortcutInfo(0);
ShortcutKey cacheKey = ShortcutKey.fromInfo(si.getShortcutInfo());
WorkspaceItemInfo info = new WorkspaceItemInfo();
runOnExecutorSync(MODEL_EXECUTOR, () -> mIconCache.getShortcutIcon(info, si));
assertNotNull(info.bitmap);
assertFalse(info.bitmap.isLowRes());
// Verify that icon is in memory cache
runOnExecutorSync(MODEL_EXECUTOR,
() -> assertNull(mIconCache.getInMemoryEntryLocked(cacheKey)));
Set<PackageUserKey> updates =
executeIconUpdate(si, CacheableShortcutCachingLogic.INSTANCE);
// Verify that the icon was not updated and is still in memory cache
Truth.assertThat(updates).isEmpty();
runOnExecutorSync(MODEL_EXECUTOR,
() -> assertNull(mIconCache.getInMemoryEntryLocked(cacheKey)));
// Now update the shortcut with a newer version
updates = executeIconUpdate(
mockShortcutInfo(System.currentTimeMillis() + 2000),
CacheableShortcutCachingLogic.INSTANCE);
// Verify that icon was updated but it is still not in mem-cache
Truth.assertThat(updates).containsExactly(
new PackageUserKey(cacheKey.getPackageName(), cacheKey.user));
runOnExecutorSync(MODEL_EXECUTOR,
() -> assertNull(mIconCache.getInMemoryEntryLocked(cacheKey)));
}
/**
* Executes the icon update for the provided entry and returns the updated packages
*/
private <T> Set<PackageUserKey> executeIconUpdate(T object, CachingLogic<T> cachingLogic) {
HashSet<PackageUserKey> updates = new HashSet<>();
runOnExecutorSync(MODEL_EXECUTOR, () -> {
IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
updateHandler.updateIcons(
Collections.singletonList(object),
cachingLogic,
(a, b) -> a.forEach(p -> updates.add(new PackageUserKey(p, b))));
updateHandler.finish();
});
waitForUpdateHandlerToFinish(mIconCache);
return updates;
}
private CacheableShortcutInfo mockShortcutInfo(long updateTime) {
ShortcutInfo info = new ShortcutInfo.Builder(
getInstrumentation().getContext(), "test-shortcut")
.setIntent(new Intent(Intent.ACTION_VIEW))
.setShortLabel("Test")
.setIcon(Icon.createWithBitmap(Bitmap.createBitmap(200, 200, Config.ARGB_8888)))
.build();
ShortcutInfo spied = spy(info);
doReturn(updateTime).when(spied).getLastChangedTimestamp();
return new CacheableShortcutInfo(spied,
new ApplicationInfoWrapper(getInstrumentation().getContext().getApplicationInfo()));
}
private ItemInfoWithIcon getBadgingInfo(Context context,
@Nullable ComponentName cn, @Nullable String badgeOverride) throws Exception {
Builder builder = new Builder(context, "test-shortcut")
@@ -25,6 +25,8 @@ import androidx.test.filters.SmallTest
import com.android.launcher3.icons.cache.BaseIconCache
import com.android.launcher3.icons.cache.CachingLogic
import com.android.launcher3.icons.cache.IconCacheUpdateHandler
import com.android.launcher3.util.RoboApiWrapper
import java.util.concurrent.FutureTask
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -51,7 +53,7 @@ class IconCacheUpdateHandlerTest {
System.currentTimeMillis(),
1,
1.0.toLong(),
"stateOfConfusion"
"stateOfConfusion",
)
@Before
@@ -81,17 +83,32 @@ class IconCacheUpdateHandlerTest {
componentMap,
ignorePackages,
user,
cachingLogic
cachingLogic,
)
assert(result == null)
}
}
/** Utility method to wait for the icon update handler to finish */
fun IconCache.waitForUpdateHandlerToFinish() {
var cacheUpdateInProgress = true
while (cacheUpdateInProgress) {
val cacheCheck = FutureTask {
// Check for pending message on the worker thread itself as some task may be
// running currently
workerHandler.hasMessages(0, iconUpdateToken)
}
workerHandler.postDelayed(cacheCheck, 10)
RoboApiWrapper.waitForLooperSync(workerHandler.looper)
cacheUpdateInProgress = cacheCheck.get()
}
}
data class IconCacheRowData(
val component: String,
val lastUpdated: Long,
val version: Int,
val row: Long,
val systemState: String
val systemState: String,
)
@@ -19,16 +19,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.LauncherAppState
import com.android.launcher3.icons.BitmapInfo
import com.android.launcher3.icons.waitForUpdateHandlerToFinish
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.util.Executors
import com.android.launcher3.util.LauncherLayoutBuilder
import com.android.launcher3.util.LauncherModelHelper
import com.android.launcher3.util.LauncherModelHelper.*
import com.android.launcher3.util.RoboApiWrapper
import com.android.launcher3.util.TestUtil
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import java.util.concurrent.CountDownLatch
import org.junit.After
import org.junit.Before
import org.junit.Rule
@@ -147,14 +146,9 @@ class FolderIconLoadTest {
// The first load initializes the DB, load again so that icons are now used from the DB
// Wait for the icon cache to be updated and then reload
val app = LauncherAppState.getInstance(modelHelper.sandboxContext)
val cache = app.iconCache
while (cache.isIconUpdateInProgress) {
val wait = CountDownLatch(1)
Executors.MODEL_EXECUTOR.handler.postDelayed({ wait.countDown() }, 10)
RoboApiWrapper.waitForLooperSync(Executors.MODEL_EXECUTOR.handler.looper)
wait.await()
}
TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { cache.clearMemoryCache() }
app.iconCache.waitForUpdateHandlerToFinish()
TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { app.iconCache.clearMemoryCache() }
// Reload again with correct icon state
app.model.forceReload()
modelHelper.loadModelSync()