Removing dependency on PackageInfo in IconCache
Bug: 363324203
Flag: EXEMPT bugfix
Test: atest IconCacheTest
atest IconCacheUpdateHandler
Change-Id: I85005ef1069960a17a0f3e7265749a8ef3004172
This commit is contained in:
@@ -24,6 +24,7 @@ import static com.android.launcher3.icons.IconCacheUpdateHandlerTestKt.waitForUp
|
||||
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_ACTIVITY2;
|
||||
import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
|
||||
import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
|
||||
|
||||
@@ -210,6 +211,70 @@ public class IconCacheTest {
|
||||
() -> assertNull(mIconCache.getInMemoryEntryLocked(cacheKey)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void item_kept_in_db_if_nothing_changes() {
|
||||
RoboApiWrapper.INSTANCE.initialize();
|
||||
ComponentName cn = new ComponentName(TEST_PACKAGE, TEST_ACTIVITY);
|
||||
UserHandle user = myUserHandle();
|
||||
|
||||
LauncherActivityInfo lai = mContext.getSystemService(LauncherApps.class)
|
||||
.resolveActivity(makeLaunchIntent(cn), user);
|
||||
assertNotNull(lai);
|
||||
|
||||
// Since this is a new update, there should not be any update
|
||||
Truth.assertThat(executeIconUpdate(lai, LauncherActivityCachingLogic.INSTANCE)).isEmpty();
|
||||
assertTrue(mIconCache.isItemInDb(new ComponentKey(cn, user)));
|
||||
|
||||
// Another update should not cause any changes
|
||||
Truth.assertThat(executeIconUpdate(lai, LauncherActivityCachingLogic.INSTANCE)).isEmpty();
|
||||
assertTrue(mIconCache.isItemInDb(new ComponentKey(cn, user)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void item_updated_in_db_if_appInfo_changes() {
|
||||
RoboApiWrapper.INSTANCE.initialize();
|
||||
ComponentName cn = new ComponentName(TEST_PACKAGE, TEST_ACTIVITY);
|
||||
UserHandle user = myUserHandle();
|
||||
|
||||
LauncherActivityInfo lai = mContext.getSystemService(LauncherApps.class)
|
||||
.resolveActivity(makeLaunchIntent(cn), user);
|
||||
assertNotNull(lai);
|
||||
|
||||
// Since this is a new update, there should not be any update
|
||||
Truth.assertThat(executeIconUpdate(lai, LauncherActivityCachingLogic.INSTANCE)).isEmpty();
|
||||
assertTrue(mIconCache.isItemInDb(new ComponentKey(cn, user)));
|
||||
|
||||
// Another update should trigger an update
|
||||
lai.getApplicationInfo().sourceDir = "some-random-source-dir";
|
||||
Truth.assertThat(executeIconUpdate(lai, LauncherActivityCachingLogic.INSTANCE))
|
||||
.containsExactly(new PackageUserKey(TEST_PACKAGE, user));
|
||||
assertTrue(mIconCache.isItemInDb(new ComponentKey(cn, user)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void item_removed_in_db_if_item_removed() {
|
||||
RoboApiWrapper.INSTANCE.initialize();
|
||||
ComponentName cn = new ComponentName(TEST_PACKAGE, TEST_ACTIVITY);
|
||||
UserHandle user = myUserHandle();
|
||||
|
||||
LauncherActivityInfo lai = mContext.getSystemService(LauncherApps.class)
|
||||
.resolveActivity(makeLaunchIntent(cn), user);
|
||||
assertNotNull(lai);
|
||||
|
||||
// Since this is a new update, there should not be any update
|
||||
Truth.assertThat(executeIconUpdate(lai, LauncherActivityCachingLogic.INSTANCE)).isEmpty();
|
||||
assertTrue(mIconCache.isItemInDb(new ComponentKey(cn, user)));
|
||||
|
||||
// Another update should trigger an update
|
||||
ComponentName cn2 = new ComponentName(TEST_PACKAGE, TEST_ACTIVITY2);
|
||||
LauncherActivityInfo lai2 = mContext.getSystemService(LauncherApps.class)
|
||||
.resolveActivity(makeLaunchIntent(cn2), user);
|
||||
|
||||
Truth.assertThat(executeIconUpdate(lai2, LauncherActivityCachingLogic.INSTANCE)).isEmpty();
|
||||
assertFalse(mIconCache.isItemInDb(new ComponentKey(cn, user)));
|
||||
assertTrue(mIconCache.isItemInDb(new ComponentKey(cn2, user)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the icon update for the provided entry and returns the updated packages
|
||||
*/
|
||||
|
||||
+83
-45
@@ -17,77 +17,109 @@
|
||||
package com.android.launcher3.icons
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.pm.PackageInfo
|
||||
import android.database.Cursor
|
||||
import android.os.UserHandle
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.database.MatrixCursor
|
||||
import android.os.Process.myUserHandle
|
||||
import androidx.test.core.app.ApplicationProvider.getApplicationContext
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
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.BaseIconCache.IconDB
|
||||
import com.android.launcher3.icons.cache.CachedObject
|
||||
import com.android.launcher3.icons.cache.CachedObjectCachingLogic
|
||||
import com.android.launcher3.icons.cache.IconCacheUpdateHandler
|
||||
import com.android.launcher3.util.RoboApiWrapper
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.util.concurrent.FutureTask
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class IconCacheUpdateHandlerTest {
|
||||
|
||||
@Mock private lateinit var cursor: Cursor
|
||||
@Mock private lateinit var user: UserHandle
|
||||
@Mock private lateinit var cachingLogic: CachingLogic<String>
|
||||
@Mock private lateinit var iconProvider: IconProvider
|
||||
@Mock private lateinit var baseIconCache: BaseIconCache
|
||||
|
||||
private var componentMap: HashMap<ComponentName, String> = hashMapOf()
|
||||
private var ignorePackages: Set<String> = setOf()
|
||||
private var packageInfoMap: HashMap<String, PackageInfo> = hashMapOf()
|
||||
|
||||
private val dummyRowData =
|
||||
IconCacheRowData(
|
||||
"com.android.fake/.FakeActivity",
|
||||
System.currentTimeMillis(),
|
||||
1,
|
||||
1.0.toLong(),
|
||||
"stateOfConfusion",
|
||||
)
|
||||
private var cursor: MatrixCursor? = null
|
||||
private var cachingLogic = CachedObjectCachingLogic<BaseIconCache>(getApplicationContext())
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
|
||||
MockitoAnnotations.initMocks(this)
|
||||
// Load in a specific row to the database
|
||||
doReturn(0).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_COMPONENT)
|
||||
doReturn(1).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_LAST_UPDATED)
|
||||
doReturn(2).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_VERSION)
|
||||
doReturn(3).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_ROWID)
|
||||
doReturn(4).`when`(cursor).getColumnIndex(BaseIconCache.IconDB.COLUMN_SYSTEM_STATE)
|
||||
doReturn(dummyRowData.component).`when`(cursor).getString(0)
|
||||
doReturn(dummyRowData.lastUpdated).`when`(cursor).getLong(1)
|
||||
doReturn(dummyRowData.version).`when`(cursor).getInt(2)
|
||||
doReturn(dummyRowData.row).`when`(cursor).getLong(3)
|
||||
doReturn(dummyRowData.systemState).`when`(cursor).getString(4)
|
||||
doReturn(iconProvider).whenever(baseIconCache).iconProvider
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
cursor?.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `IconCacheUpdateHandler returns null if the component name is malformed`() {
|
||||
val updateHandlerUnderTest = IconCacheUpdateHandler(packageInfoMap, baseIconCache)
|
||||
val updateHandlerUnderTest = IconCacheUpdateHandler(baseIconCache)
|
||||
val cn = ComponentName.unflattenFromString("com.android.fake/.FakeActivity")!!
|
||||
|
||||
val result =
|
||||
updateHandlerUnderTest.updateOrDeleteIcon(
|
||||
cursor,
|
||||
componentMap,
|
||||
ignorePackages,
|
||||
user,
|
||||
createCursor(1, cn.flattenToString() + "#", "freshId-old"),
|
||||
hashMapOf(cn to TestCachedObject(cn, "freshId")),
|
||||
setOf(),
|
||||
myUserHandle(),
|
||||
cachingLogic,
|
||||
)
|
||||
|
||||
assert(result == null)
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `IconCacheUpdateHandler returns null if the freshId match`() {
|
||||
val updateHandlerUnderTest = IconCacheUpdateHandler(baseIconCache)
|
||||
val cn = ComponentName.unflattenFromString("com.android.fake/.FakeActivity")!!
|
||||
|
||||
val result =
|
||||
updateHandlerUnderTest.updateOrDeleteIcon(
|
||||
createCursor(1, cn.flattenToString(), "freshId"),
|
||||
hashMapOf(cn to TestCachedObject(cn, "freshId")),
|
||||
setOf(),
|
||||
myUserHandle(),
|
||||
cachingLogic,
|
||||
)
|
||||
assertThat(result).isNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `IconCacheUpdateHandler returns non-null if the freshId do not match`() {
|
||||
val updateHandlerUnderTest = IconCacheUpdateHandler(baseIconCache)
|
||||
val cn = ComponentName.unflattenFromString("com.android.fake/.FakeActivity")!!
|
||||
val testObj = TestCachedObject(cn, "freshId")
|
||||
|
||||
val result =
|
||||
updateHandlerUnderTest.updateOrDeleteIcon(
|
||||
createCursor(1, cn.flattenToString(), "freshId-old"),
|
||||
hashMapOf(cn to testObj),
|
||||
setOf(),
|
||||
myUserHandle(),
|
||||
cachingLogic,
|
||||
)
|
||||
assertThat(result).isEqualTo(testObj)
|
||||
}
|
||||
|
||||
private fun createCursor(row: Long, component: String, appState: String) =
|
||||
MatrixCursor(
|
||||
arrayOf(IconDB.COLUMN_ROWID, IconDB.COLUMN_COMPONENT, IconDB.COLUMN_FRESHNESS_ID)
|
||||
)
|
||||
.apply { addRow(arrayOf(row, component, appState)) }
|
||||
.apply {
|
||||
cursor = this
|
||||
moveToNext()
|
||||
}
|
||||
}
|
||||
|
||||
/** Utility method to wait for the icon update handler to finish */
|
||||
@@ -105,10 +137,16 @@ fun IconCache.waitForUpdateHandlerToFinish() {
|
||||
}
|
||||
}
|
||||
|
||||
data class IconCacheRowData(
|
||||
val component: String,
|
||||
val lastUpdated: Long,
|
||||
val version: Int,
|
||||
val row: Long,
|
||||
val systemState: String,
|
||||
)
|
||||
class TestCachedObject(val cn: ComponentName, val freshnessId: String) :
|
||||
CachedObject<BaseIconCache> {
|
||||
|
||||
override fun getComponent() = cn
|
||||
|
||||
override fun getUser() = myUserHandle()
|
||||
|
||||
override fun getLabel(pm: PackageManager?): CharSequence? = null
|
||||
|
||||
override fun getApplicationInfo(): ApplicationInfo? = null
|
||||
|
||||
override fun getFreshnessIdentifier(iconProvider: IconProvider): String? = freshnessId
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ class GeneratedPreviewTest {
|
||||
@get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
|
||||
private val providerName =
|
||||
ComponentName(
|
||||
"com.android.launcher3.tests",
|
||||
"com.android.launcher3.testcomponent.AppWidgetNoConfig"
|
||||
getInstrumentation().getContext().getPackageName(),
|
||||
"com.android.launcher3.testcomponent.AppWidgetNoConfig",
|
||||
)
|
||||
private val generatedPreviewLayout =
|
||||
getInstrumentation().context.run {
|
||||
@@ -61,7 +61,7 @@ class GeneratedPreviewTest {
|
||||
ActivityContextWrapper(
|
||||
ContextThemeWrapper(
|
||||
context,
|
||||
com.android.launcher3.R.style.WidgetContainerTheme
|
||||
com.android.launcher3.R.style.WidgetContainerTheme,
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -78,7 +78,7 @@ class GeneratedPreviewTest {
|
||||
object : WidgetManagerHelper(context) {
|
||||
override fun loadGeneratedPreview(
|
||||
info: AppWidgetProviderInfo,
|
||||
widgetCategory: Int
|
||||
widgetCategory: Int,
|
||||
) =
|
||||
generatedPreview.takeIf {
|
||||
info === appWidgetProviderInfo &&
|
||||
|
||||
Reference in New Issue
Block a user