Convert UserCache to use Dagger

Bug: 372012340
Test: Presubmit
Flag: EXEMPT Dagger Change
Change-Id: I36a0a3f56540c0515d99badc127c2ab8534e684e
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/AppEventProducerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/AppEventProducerTest.java
index d4dd580..06a939a 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/AppEventProducerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/AppEventProducerTest.java
@@ -35,9 +35,12 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.launcher3.dagger.LauncherAppComponent;
+import com.android.launcher3.dagger.LauncherAppSingleton;
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.AllModulesForTest;
 import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
 import com.android.launcher3.util.UserIconInfo;
 import com.android.systemui.shared.system.SysUiStatsLog;
@@ -51,6 +54,9 @@
 
 import java.util.Arrays;
 
+import dagger.BindsInstance;
+import dagger.Component;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class AppEventProducerTest {
@@ -72,7 +78,9 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = new SandboxContext(getApplicationContext());
-        mContext.putObject(UserCache.INSTANCE, mUserCache);
+        mContext.initDaggerComponent(
+                DaggerAppEventProducerTest_TestComponent.builder().bindUserCache(mUserCache)
+        );
         mAppEventProducer = new AppEventProducer(mContext, null);
     }
 
@@ -129,4 +137,15 @@
                 .build());
         return itemBuilder.build();
     }
+
+    @LauncherAppSingleton
+    @Component(modules = { AllModulesForTest.class })
+    interface TestComponent extends LauncherAppComponent {
+        @Component.Builder
+        interface Builder extends LauncherAppComponent.Builder {
+            @BindsInstance
+            AppEventProducerTest.TestComponent.Builder bindUserCache(UserCache userCache);
+            @Override LauncherAppComponent build();
+        }
+    }
 }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt
index 5cee434..be71640 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt
@@ -21,15 +21,19 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.Flags.enableRefactorTaskThumbnail
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppSingleton
 import com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE
 import com.android.launcher3.model.data.TaskViewItemInfo.Companion.createTaskViewAtom
 import com.android.launcher3.pm.UserCache
+import com.android.launcher3.util.AllModulesForTest
 import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.launcher3.util.TransformingTouchDelegate
 import com.android.launcher3.util.UserIconInfo
 import com.android.quickstep.TaskOverlayFactory
 import com.android.quickstep.TaskOverlayFactory.TaskOverlay
+import com.android.quickstep.TestComponent
 import com.android.quickstep.recents.di.RecentsDependencies
 import com.android.quickstep.task.thumbnail.TaskThumbnailView
 import com.android.quickstep.views.RecentsView
@@ -41,6 +45,8 @@
 import com.android.systemui.shared.recents.model.Task
 import com.android.systemui.shared.recents.model.Task.TaskKey
 import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -66,7 +72,9 @@
         whenever(recentsView.indexOfChild(taskView)).thenReturn(TASK_VIEW_INDEX)
         whenever(userInfo.isPrivate).thenReturn(false)
         whenever(userCache.getUserInfo(any())).thenReturn(userInfo)
-        context.putObject(UserCache.INSTANCE, userCache)
+        context.initDaggerComponent(
+            DaggerTaskViewItemInfoTest_TestComponent.builder().bindUserCache(userCache)
+        )
         RecentsDependencies.initialize(context)
     }
 
@@ -176,6 +184,17 @@
         )
     }
 
+    @LauncherAppSingleton
+    @Component(modules = [AllModulesForTest::class])
+    interface TestComponent : LauncherAppComponent {
+        @Component.Builder
+        interface Builder : LauncherAppComponent.Builder {
+            @BindsInstance fun bindUserCache(userCache: UserCache): Builder
+
+            override fun build(): TestComponent
+        }
+    }
+
     companion object {
         const val PACKAGE = "package"
         const val CLASS = "class"
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 0b7b20f..7bd7c3e 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.graphics.ThemeManager;
 import com.android.launcher3.model.ItemInstallQueue;
 import com.android.launcher3.pm.InstallSessionHelper;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.DaggerSingletonTracker;
 import com.android.launcher3.util.DisplayController;
@@ -67,6 +68,7 @@
     WindowManagerProxy getWmProxy();
     LauncherPrefs getLauncherPrefs();
     ThemeManager getThemeManager();
+    UserCache getUserCache();
     DisplayController getDisplayController();
     WallpaperColorHints getWallpaperColorHints();
     LockedUserState getLockedUserState();
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index c22a8a5..588e759 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -439,8 +439,7 @@
         LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
         itemBuilder.setIsKidsMode(
                 SettingsCache.INSTANCE.get(context).getValue(NAV_BAR_KIDS_MODE, 0));
-        UserCache.INSTANCE.executeIfCreated(cache ->
-                itemBuilder.setUserType(getUserType(cache.getUserInfo(user))));
+        itemBuilder.setUserType(getUserType(UserCache.INSTANCE.get(context).getUserInfo(user)));
         itemBuilder.setRank(rank);
         itemBuilder.addAllItemAttributes(mAttributeList);
         return itemBuilder;
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index e861961..0b18a87 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -32,11 +32,15 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
 
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.UserBadgeDrawable;
 import com.android.launcher3.util.ApiWrapper;
+import com.android.launcher3.util.DaggerSingletonObject;
+import com.android.launcher3.util.DaggerSingletonTracker;
 import com.android.launcher3.util.FlagOp;
-import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.SimpleBroadcastReceiver;
 import com.android.launcher3.util.UserIconInfo;
@@ -47,10 +51,16 @@
 import java.util.Map;
 import java.util.function.BiConsumer;
 
+import javax.inject.Inject;
+
 /**
  * Class which manages a local cache of user handles to avoid system rpc
  */
-public class UserCache implements SafeCloseable {
+@LauncherAppSingleton
+public class UserCache {
+
+    public static DaggerSingletonObject<UserCache> INSTANCE =
+            new DaggerSingletonObject<>(LauncherBaseAppComponent::getUserCache);
 
     public static final String ACTION_PROFILE_ADDED = ATLEAST_U
             ? Intent.ACTION_PROFILE_ADDED : Intent.ACTION_MANAGED_PROFILE_ADDED;
@@ -65,9 +75,6 @@
     public static final String ACTION_PROFILE_UNAVAILABLE =
             "android.intent.action.PROFILE_UNAVAILABLE";
 
-    public static final MainThreadInitializedObject<UserCache> INSTANCE =
-            new MainThreadInitializedObject<>(UserCache::new);
-
     /** Returns an instance of UserCache bound to the context provided. */
     public static UserCache getInstance(Context context) {
         return INSTANCE.get(context);
@@ -78,6 +85,7 @@
             new SimpleBroadcastReceiver(MODEL_EXECUTOR, this::onUsersChanged);
 
     private final Context mContext;
+    private final ApiWrapper mApiWrapper;
 
     @NonNull
     private Map<UserHandle, UserIconInfo> mUserToSerialMap;
@@ -85,15 +93,17 @@
     @NonNull
     private Map<UserHandle, List<String>> mUserToPreInstallAppMap;
 
-    private UserCache(Context context) {
+    @Inject
+    public UserCache(
+            @ApplicationContext Context context,
+            DaggerSingletonTracker tracker,
+            ApiWrapper apiWrapper
+    ) {
         mContext = context;
+        mApiWrapper = apiWrapper;
         mUserToSerialMap = Collections.emptyMap();
         MODEL_EXECUTOR.execute(this::initAsync);
-    }
-
-    @Override
-    public void close() {
-        MODEL_EXECUTOR.execute(() -> mUserChangeReceiver.unregisterReceiverSafely(mContext));
+        tracker.addCloseable(() -> mUserChangeReceiver.unregisterReceiverSafely(mContext));
     }
 
     @WorkerThread
@@ -124,7 +134,7 @@
 
     @WorkerThread
     private void updateCache() {
-        mUserToSerialMap = ApiWrapper.INSTANCE.get(mContext).queryAllUsers();
+        mUserToSerialMap = mApiWrapper.queryAllUsers();
         mUserToPreInstallAppMap = fetchPreInstallApps();
     }
 
@@ -134,7 +144,7 @@
         mUserToSerialMap.forEach((userHandle, userIconInfo) -> {
             // Fetch only for private profile, as other profiles have no usages yet.
             List<String> preInstallApp = userIconInfo.isPrivate()
-                    ? ApiWrapper.INSTANCE.get(mContext).getPreInstalledSystemPackages(userHandle)
+                    ? mApiWrapper.getPreInstalledSystemPackages(userHandle)
                     : new ArrayList<>();
             userToPreInstallApp.put(userHandle, preInstallApp);
         });
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java b/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java
index 71637f1..393282f 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java
@@ -64,7 +64,7 @@
 
     public TestSandboxModelContextWrapper(SandboxContext base) {
         super(base);
-        mUserCache = base.getObject(UserCache.INSTANCE);
+        mUserCache = UserCache.getInstance(base);
         InstrumentationRegistry.getInstrumentation().runOnMainSync(() ->
                 mAppsView = new ActivityAllAppsContainerView<>(this));
         mAppsList = mAppsView.getPersonalAppList();
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index f04688d..dba7603 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -23,20 +23,23 @@
 import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR
 import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppSingleton
 import com.android.launcher3.icons.IconCache
 import com.android.launcher3.icons.cache.CachingLogic
 import com.android.launcher3.icons.cache.IconCacheUpdateHandler
 import com.android.launcher3.pm.UserCache
 import com.android.launcher3.provider.RestoreDbTask
 import com.android.launcher3.ui.TestViewHelpers
+import com.android.launcher3.util.AllModulesForTest
 import com.android.launcher3.util.Executors.MODEL_EXECUTOR
 import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
 import com.android.launcher3.util.LooperIdleLock
 import com.android.launcher3.util.TestUtil
 import com.android.launcher3.util.UserIconInfo
 import com.google.common.truth.Truth
-import java.util.concurrent.CountDownLatch
-import java.util.function.Predicate
+import dagger.BindsInstance
+import dagger.Component
 import junit.framework.Assert.assertEquals
 import org.junit.After
 import org.junit.Before
@@ -59,6 +62,8 @@
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 import org.mockito.quality.Strictness
+import java.util.concurrent.CountDownLatch
+import java.util.function.Predicate
 
 private const val INSERTION_STATEMENT_FILE = "databases/workspace_items.sql"
 
@@ -130,8 +135,9 @@
         `when`(idleLock.awaitLocked(1000)).thenReturn(false)
         `when`(iconCache.getUpdateHandler()).thenReturn(iconCacheUpdateHandler)
         `when`(widgetsFilterDataProvider.getDefaultWidgetsFilter()).thenReturn(Predicate { true })
-        context.putObject(UserCache.INSTANCE, userCache)
-
+        context.initDaggerComponent(
+            DaggerLoaderTaskTest_TestComponent.builder().bindUserCache(userCache)
+        )
         TestUtil.grantWriteSecurePermission()
     }
 
@@ -473,6 +479,17 @@
         // Then
         verify(spyContext, times(0)).sendBroadcast(any())
     }
+
+    @LauncherAppSingleton
+    @Component(modules = [AllModulesForTest::class])
+    interface TestComponent : LauncherAppComponent {
+        @Component.Builder
+        interface Builder : LauncherAppComponent.Builder {
+            @BindsInstance fun bindUserCache(userCache: UserCache): Builder
+
+            override fun build(): TestComponent
+        }
+    }
 }
 
 private fun LoaderTask.runSyncOnBackgroundThread() {
diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
index 075f667..2531f6b 100644
--- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
+++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
@@ -62,12 +62,15 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.PrivateProfileManager;
+import com.android.launcher3.dagger.LauncherAppComponent;
+import com.android.launcher3.dagger.LauncherAppSingleton;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.AllModulesForTest;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
 import com.android.launcher3.util.LauncherMultivalentJUnit;
@@ -88,6 +91,9 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import dagger.BindsInstance;
+import dagger.Component;
+
 @SmallTest
 @RunWith(LauncherMultivalentJUnit.class)
 public class SystemShortcutTest {
@@ -113,7 +119,9 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mSandboxContext.putObject(UserCache.INSTANCE, mUserCache);
+        mSandboxContext.initDaggerComponent(
+                DaggerSystemShortcutTest_TestComponent.builder().bindUserCache(mUserCache)
+        );
         mTestContext = new TestSandboxModelContextWrapper(mSandboxContext) {
             @Override
             public StatsLogManager getStatsLogManager() {
@@ -402,4 +410,15 @@
         systemShortcut.onClick(mView);
         verify(mSandboxContext).startActivity(any());
     }
+
+    @LauncherAppSingleton
+    @Component(modules = { AllModulesForTest.class })
+    interface TestComponent extends LauncherAppComponent {
+        @Component.Builder
+        interface Builder extends LauncherAppComponent.Builder {
+            @BindsInstance
+            SystemShortcutTest.TestComponent.Builder bindUserCache(UserCache userCache);
+            @Override LauncherAppComponent build();
+        }
+    }
 }