Converting LauncherAppState to Dagger
Bug: 361850561
Test: Presubmit
Flag: EXEMPT dagger
Change-Id: I336a233d2703c23a7e9065474bde471786886144
diff --git a/quickstep/dagger/com/android/launcher3/dagger/AppModule.kt b/quickstep/dagger/com/android/launcher3/dagger/AppModule.kt
index 29586c4..d88fc94 100644
--- a/quickstep/dagger/com/android/launcher3/dagger/AppModule.kt
+++ b/quickstep/dagger/com/android/launcher3/dagger/AppModule.kt
@@ -16,10 +16,17 @@
package com.android.launcher3.dagger
+import com.android.launcher3.model.ModelDelegate
+import com.android.launcher3.model.QuickstepModelDelegate
+import dagger.Binds
import dagger.Module
/**
* Module containing bindings for the final derivative app, an implementation of this module should
* be included in the final app code.
*/
-@Module abstract class AppModule {}
+@Module
+abstract class AppModule {
+
+ @Binds abstract fun bindModelDelegate(impl: QuickstepModelDelegate): ModelDelegate
+}
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index a530325..d699cdf 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -27,7 +27,6 @@
<string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
<string name="app_launch_tracker_class" translatable="false">com.android.launcher3.appprediction.PredictionAppTracker</string>
<string name="main_process_initializer_class" translatable="false">com.android.quickstep.QuickstepProcessInitializer</string>
- <string name="model_delegate_class" translatable="false">com.android.launcher3.model.QuickstepModelDelegate</string>
<string name="secondary_display_predictions_class" translatable="false">com.android.launcher3.secondarydisplay.SecondaryDisplayPredictionsImpl</string>
<string name="taskbar_model_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarModelCallbacksFactory</string>
<string name="taskbar_view_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarViewCallbacksFactory</string>
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 40e8fc2..74b73d4 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -47,6 +47,7 @@
import android.content.pm.ShortcutInfo;
import android.os.Bundle;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
import android.util.StatsEvent;
@@ -61,6 +62,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.dagger.ApplicationContext;
import com.android.launcher3.icons.cache.CacheLookupFlag;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.InstanceId;
@@ -89,6 +91,9 @@
import java.util.Objects;
import java.util.stream.IntStream;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* Model delegate which loads prediction items
*/
@@ -114,18 +119,29 @@
CONTAINER_WIDGETS_PREDICTION, "widgets_prediction", DESKTOP_ICON_FLAG);
private final InvariantDeviceProfile mIDP;
+ private final PackageManagerHelper mPmHelper;
private final AppEventProducer mAppEventProducer;
+
private final StatsManager mStatsManager;
protected boolean mActive = false;
- public QuickstepModelDelegate(Context context) {
+ @Inject
+ public QuickstepModelDelegate(@ApplicationContext Context context,
+ InvariantDeviceProfile idp,
+ PackageManagerHelper pmHelper,
+ @Nullable @Named("ICONS_DB") String dbFileName) {
super(context);
- mAppEventProducer = new AppEventProducer(context, this::onAppTargetEvent);
+ mIDP = idp;
+ mPmHelper = pmHelper;
- mIDP = InvariantDeviceProfile.INSTANCE.get(context);
+ mAppEventProducer = new AppEventProducer(context, this::onAppTargetEvent);
StatsLogCompatManager.LOGS_CONSUMER.add(mAppEventProducer);
- mStatsManager = context.getSystemService(StatsManager.class);
+
+ // Only register for launcher snapshot logging if this is the primary ModelDelegate
+ // instance, as there will be additional instances that may be destroyed at any time.
+ mStatsManager = TextUtils.isEmpty(dbFileName)
+ ? null : context.getSystemService(StatsManager.class);
}
@CallSuper
@@ -154,10 +170,10 @@
// TODO: Implement caching and preloading
WorkspaceItemFactory factory =
- new WorkspaceItemFactory(mApp, ums, mPmHelper, pinnedShortcuts, numColumns,
+ new WorkspaceItemFactory(mContext, ums, mPmHelper, pinnedShortcuts, numColumns,
state.containerId, state.lookupFlag);
FixedContainerItems fci = new FixedContainerItems(state.containerId,
- state.storage.read(mApp.getContext(), factory, ums.allUsers::get));
+ state.storage.read(mContext, factory, ums.allUsers::get));
mDataModel.extraItems.put(state.containerId, fci);
}
@@ -220,7 +236,7 @@
super.modelLoadComplete();
// Log snapshot of the model
- LauncherPrefs prefs = LauncherPrefs.get(mApp.getContext());
+ LauncherPrefs prefs = LauncherPrefs.get(mContext);
long lastSnapshotTimeMillis = prefs.get(LAST_SNAPSHOT_TIME_MILLIS);
// Log snapshot only if previous snapshot was older than a day
long now = System.currentTimeMillis();
@@ -245,11 +261,7 @@
prefs.put(LAST_SNAPSHOT_TIME_MILLIS, now);
}
- // Only register for launcher snapshot logging if this is the primary ModelDelegate
- // instance, as there will be additional instances that may be destroyed at any time.
- if (mIsPrimaryInstance) {
- registerSnapshotLoggingCallback();
- }
+ registerSnapshotLoggingCallback();
}
protected void additionalSnapshotEvents(InstanceId snapshotInstanceId){}
@@ -257,9 +269,9 @@
/**
* Registers a callback to log launcher workspace layout using Statsd pulled atom.
*/
- protected void registerSnapshotLoggingCallback() {
+ private void registerSnapshotLoggingCallback() {
if (mStatsManager == null) {
- Log.d(TAG, "Failed to get StatsManager");
+ Log.d(TAG, "Skipping snapshot logging");
}
try {
@@ -332,7 +344,7 @@
super.destroy();
mActive = false;
StatsLogCompatManager.LOGS_CONSUMER.remove(mAppEventProducer);
- if (mIsPrimaryInstance && mStatsManager != null) {
+ if (mStatsManager != null) {
try {
mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
} catch (RuntimeException e) {
@@ -354,25 +366,24 @@
if (!mActive) {
return;
}
- Context context = mApp.getContext();
- AppPredictionManager apm = context.getSystemService(AppPredictionManager.class);
+ AppPredictionManager apm = mContext.getSystemService(AppPredictionManager.class);
if (apm == null) {
return;
}
registerPredictor(mAllAppsState, apm.createAppPredictionSession(
- new AppPredictionContext.Builder(context)
+ new AppPredictionContext.Builder(mContext)
.setUiSurface("home")
.setPredictedTargetCount(mIDP.numDatabaseAllAppsColumns)
.build()));
// TODO: get bundle
- registerHotseatPredictor(apm, context);
+ registerHotseatPredictor(apm, mContext);
registerWidgetsPredictor(apm.createAppPredictionSession(
- new AppPredictionContext.Builder(context)
+ new AppPredictionContext.Builder(mContext)
.setUiSurface("widgets")
- .setExtras(getBundleForWidgetsOnWorkspace(context, mDataModel))
+ .setExtras(getBundleForWidgetsOnWorkspace(mContext, mDataModel))
.setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION)
.build()));
}
@@ -383,12 +394,11 @@
if (!mActive) {
return;
}
- Context context = mApp.getContext();
- AppPredictionManager apm = context.getSystemService(AppPredictionManager.class);
+ AppPredictionManager apm = mContext.getSystemService(AppPredictionManager.class);
if (apm == null) {
return;
}
- registerHotseatPredictor(apm, context);
+ registerHotseatPredictor(apm, mContext);
}
private void registerHotseatPredictor(AppPredictionManager apm, Context context) {
@@ -413,7 +423,7 @@
// No diff, skip
return;
}
- mApp.getModel().enqueueModelUpdateTask(new PredictionUpdateTask(state, targets));
+ mModel.enqueueModelUpdateTask(new PredictionUpdateTask(state, targets));
}
private void registerWidgetsPredictor(AppPredictor predictor) {
@@ -424,7 +434,7 @@
// No diff, skip
return;
}
- mApp.getModel().enqueueModelUpdateTask(
+ mModel.enqueueModelUpdateTask(
new WidgetsPredictionUpdateTask(mWidgetsRecommendationState, targets));
});
mWidgetsRecommendationState.predictor.requestPredictionUpdate();
@@ -536,7 +546,7 @@
private static class WorkspaceItemFactory implements PersistedItemArray.ItemFactory<ItemInfo> {
- private final LauncherAppState mAppState;
+ private final Context mContext;
private final UserManagerState mUMS;
private final PackageManagerHelper mPmHelper;
private final Map<ShortcutKey, ShortcutInfo> mPinnedShortcuts;
@@ -546,10 +556,11 @@
private int mReadCount = 0;
- protected WorkspaceItemFactory(LauncherAppState appState, UserManagerState ums,
+ protected WorkspaceItemFactory(
+ Context context, UserManagerState ums,
PackageManagerHelper pmHelper, Map<ShortcutKey, ShortcutInfo> pinnedShortcuts,
int maxCount, int container, CacheLookupFlag lookupFlag) {
- mAppState = appState;
+ mContext = context;
mUMS = ums;
mPmHelper = pmHelper;
mPinnedShortcuts = pinnedShortcuts;
@@ -566,7 +577,7 @@
}
switch (itemType) {
case ITEM_TYPE_APPLICATION: {
- LauncherActivityInfo lai = mAppState.getContext()
+ LauncherActivityInfo lai = mContext
.getSystemService(LauncherApps.class)
.resolveActivity(intent, user);
if (lai == null) {
@@ -574,14 +585,15 @@
}
AppInfo info = new AppInfo(
lai,
- UserCache.INSTANCE.get(mAppState.getContext()).getUserInfo(user),
- ApiWrapper.INSTANCE.get(mAppState.getContext()),
+ UserCache.INSTANCE.get(mContext).getUserInfo(user),
+ ApiWrapper.INSTANCE.get(mContext),
mPmHelper,
mUMS.isUserQuiet(user));
info.container = mContainer;
- mAppState.getIconCache().getTitleAndIcon(info, lai, mLookupFlag);
+ LauncherAppState.getInstance(mContext).getIconCache()
+ .getTitleAndIcon(info, lai, mLookupFlag);
mReadCount++;
- return info.makeWorkspaceItem(mAppState.getContext());
+ return info.makeWorkspaceItem(mContext);
}
case ITEM_TYPE_DEEP_SHORTCUT: {
ShortcutKey key = ShortcutKey.fromIntent(intent, user);
@@ -592,9 +604,9 @@
if (si == null) {
return null;
}
- WorkspaceItemInfo wii = new WorkspaceItemInfo(si, mAppState.getContext());
+ WorkspaceItemInfo wii = new WorkspaceItemInfo(si, mContext);
wii.container = mContainer;
- mAppState.getIconCache().getShortcutIcon(wii, si);
+ LauncherAppState.getInstance(mContext).getIconCache().getShortcutIcon(wii, si);
mReadCount++;
return wii;
}
diff --git a/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java b/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java
index 8c98bab..d3ac975 100644
--- a/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java
+++ b/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java
@@ -203,7 +203,7 @@
List<ItemInfo> items;
if (enableCategorizedWidgetSuggestions()) {
WidgetRecommendationCategoryProvider categoryProvider =
- WidgetRecommendationCategoryProvider.newInstance(mContext);
+ new WidgetRecommendationCategoryProvider();
items = widgetItems.stream()
.map(it -> new PendingAddWidgetInfo(it.widgetInfo, CONTAINER_WIDGETS_PREDICTION,
categoryProvider.getWidgetRecommendationCategory(mContext, it)))
diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
index 40e1c10..aa81695 100644
--- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
@@ -137,7 +137,7 @@
List<ItemInfo> items;
if (enableCategorizedWidgetSuggestions()) {
WidgetRecommendationCategoryProvider categoryProvider =
- WidgetRecommendationCategoryProvider.newInstance(context);
+ new WidgetRecommendationCategoryProvider();
items = servicePredictedItems.stream()
.map(it -> new PendingAddWidgetInfo(it.widgetInfo, CONTAINER_WIDGETS_PREDICTION,
categoryProvider.getWidgetRecommendationCategory(context, it)))
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 594c99a..58e54cf 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -382,18 +382,15 @@
return;
}
- if (mItemInfo.container < 0 || !LauncherAppState.INSTANCE.executeIfCreated(app -> {
- // Item is inside a collection, fetch collection info in a BG thread
- // and then write to StatsLog.
- app.getModel().enqueueModelUpdateTask((taskController, dataModel, apps) ->
- write(event, applyOverwrites(mItemInfo.buildProto(
- (CollectionInfo) dataModel.itemsIdMap.get(mItemInfo.container),
- mContext))));
- })) {
- // Write log on the model thread so that logs do not go out of order
- // (for eg: drop comes after drag)
- Executors.MODEL_EXECUTOR.execute(
- () -> write(event, applyOverwrites(mItemInfo.buildProto(mContext))));
+ // Item is inside a collection, fetch collection info in a BG thread
+ // and then write to StatsLog.
+ if (mItemInfo.container < 0) {
+ LauncherAppState.INSTANCE.get(mContext).getModel().enqueueModelUpdateTask(
+ (taskController, dataModel, apps) -> write(event, applyOverwrites(
+ mItemInfo.buildProto(
+ (CollectionInfo) dataModel.itemsIdMap
+ .get(mItemInfo.container),
+ mContext))));
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
index 0005df6..09c62aa 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
@@ -19,7 +19,6 @@
import android.app.prediction.AppTarget
import android.app.prediction.AppTargetEvent
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WALLPAPERS
@@ -54,11 +53,17 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
modelHelper = LauncherModelHelper()
- underTest = QuickstepModelDelegate(modelHelper.sandboxContext)
+ underTest =
+ QuickstepModelDelegate(
+ modelHelper.sandboxContext,
+ modelHelper.sandboxContext.appComponent.idp,
+ modelHelper.sandboxContext.appComponent.packageManagerHelper,
+ "", /* dbFileName */
+ )
underTest.mAllAppsState.predictor = allAppsPredictor
underTest.mHotseatState.predictor = hotseatPredictor
underTest.mWidgetsRecommendationState.predictor = widgetRecommendationPredictor
- underTest.mApp = LauncherAppState.getInstance(modelHelper.sandboxContext)
+ underTest.mModel = modelHelper.model
underTest.mDataModel = BgDataModel()
}
diff --git a/res/values/config.xml b/res/values/config.xml
index 07f97bc..1a2ac9e 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -67,7 +67,6 @@
<string name="main_process_initializer_class" translatable="false"></string>
<string name="app_launch_tracker_class" translatable="false"></string>
<string name="test_information_handler_class" translatable="false"></string>
- <string name="model_delegate_class" translatable="false"></string>
<string name="secondary_display_predictions_class" translatable="false"></string>
<string name="widget_holder_factory_class" translatable="false"></string>
<string name="taskbar_search_session_controller_class" translatable="false"></string>
@@ -75,8 +74,6 @@
<string name="taskbar_view_callbacks_factory_class" translatable="false"></string>
<string name="launcher_restore_event_logger_class" translatable="false"></string>
<string name="taskbar_edu_tooltip_controller_class" translatable="false"></string>
- <!-- Used for determining category of a widget presented in widget recommendations. -->
- <string name="widget_recommendation_category_provider_class" translatable="false"></string>
<!-- Default packages -->
<string name="wallpaper_picker_package" translatable="false"></string>
diff --git a/src/com/android/launcher3/AppFilter.java b/src/com/android/launcher3/AppFilter.java
index 3db456c..8ee7053 100644
--- a/src/com/android/launcher3/AppFilter.java
+++ b/src/com/android/launcher3/AppFilter.java
@@ -3,10 +3,14 @@
import android.content.ComponentName;
import android.content.Context;
+import com.android.launcher3.dagger.ApplicationContext;
+
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
+import javax.inject.Inject;
+
/**
* Utility class to filter out components from various lists
*/
@@ -14,7 +18,8 @@
private final Set<ComponentName> mFilteredComponents;
- public AppFilter(Context context) {
+ @Inject
+ public AppFilter(@ApplicationContext Context context) {
mFilteredComponents = Arrays.stream(
context.getResources().getStringArray(R.array.filtered_components))
.map(ComponentName::unflattenFromString)
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
deleted file mode 100644
index bf2ad92..0000000
--- a/src/com/android/launcher3/LauncherAppState.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.util.Log;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.dagger.LauncherComponentProvider;
-import com.android.launcher3.graphics.ThemeManager;
-import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.icons.IconProvider;
-import com.android.launcher3.icons.LauncherIconProvider;
-import com.android.launcher3.model.ModelInitializer;
-import com.android.launcher3.model.WidgetsFilterDataProvider;
-import com.android.launcher3.pm.InstallSessionHelper;
-import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.launcher3.util.PackageManagerHelper;
-import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.RunnableList;
-import com.android.launcher3.util.SafeCloseable;
-import com.android.launcher3.util.SettingsCache;
-import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
-
-public class LauncherAppState implements SafeCloseable {
-
- public static final String TAG = "LauncherAppState";
-
- // We do not need any synchronization for this variable as its only written on UI thread.
- public static final MainThreadInitializedObject<LauncherAppState> INSTANCE =
- new MainThreadInitializedObject<>(LauncherAppState::new);
-
- private final Context mContext;
- private final LauncherModel mModel;
- private final LauncherIconProvider mIconProvider;
- private final IconCache mIconCache;
- private final InvariantDeviceProfile mInvariantDeviceProfile;
- private boolean mIsSafeModeEnabled;
-
- private final RunnableList mOnTerminateCallback = new RunnableList();
-
- public static LauncherAppState getInstance(Context context) {
- return INSTANCE.get(context);
- }
-
- public Context getContext() {
- return mContext;
- }
-
- @SuppressWarnings("NewApi")
- public LauncherAppState(Context context) {
- this(context, LauncherFiles.APP_ICONS_DB);
- Log.v(Launcher.TAG, "LauncherAppState initiated");
- Preconditions.assertUIThread();
-
- mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
- () -> context.getPackageManager().isSafeMode());
-
- ModelInitializer initializer = new ModelInitializer(
- context,
- LauncherComponentProvider.get(context).getIconPool(),
- mIconCache,
- mInvariantDeviceProfile,
- ThemeManager.INSTANCE.get(context),
- UserCache.INSTANCE.get(context),
- SettingsCache.INSTANCE.get(context),
- mIconProvider,
- CustomWidgetManager.INSTANCE.get(context),
- InstallSessionHelper.INSTANCE.get(context),
- closeable -> mOnTerminateCallback.add(closeable::close)
- );
- initializer.initialize(mModel);
- }
-
- public LauncherAppState(Context context, @Nullable String iconCacheFileName) {
- mContext = context;
-
- mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
- mIconProvider = new LauncherIconProvider(context);
- mIconCache = new IconCache(mContext, mInvariantDeviceProfile,
- iconCacheFileName, mIconProvider);
- mModel = new LauncherModel(context, this, mIconCache,
- WidgetsFilterDataProvider.Companion.newInstance(context), new AppFilter(mContext),
- PackageManagerHelper.INSTANCE.get(context), iconCacheFileName != null);
- mOnTerminateCallback.add(mIconCache::close);
- mOnTerminateCallback.add(mModel::destroy);
- }
-
- /**
- * Call from Application.onTerminate(), which is not guaranteed to ever be called.
- */
- @Override
- public void close() {
- mOnTerminateCallback.executeAllAndDestroy();
- }
-
- public IconProvider getIconProvider() {
- return mIconProvider;
- }
-
- public IconCache getIconCache() {
- return mIconCache;
- }
-
- public LauncherModel getModel() {
- return mModel;
- }
-
- public InvariantDeviceProfile getInvariantDeviceProfile() {
- return mInvariantDeviceProfile;
- }
-
- public boolean isSafeModeEnabled() {
- return mIsSafeModeEnabled;
- }
-
- /**
- * Shorthand for {@link #getInvariantDeviceProfile()}
- */
- public static InvariantDeviceProfile getIDP(Context context) {
- return InvariantDeviceProfile.INSTANCE.get(context);
- }
-}
diff --git a/src/com/android/launcher3/LauncherAppState.kt b/src/com/android/launcher3/LauncherAppState.kt
new file mode 100644
index 0000000..ff84c3c
--- /dev/null
+++ b/src/com/android/launcher3/LauncherAppState.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3
+
+import android.content.Context
+import com.android.launcher3.dagger.ApplicationContext
+import com.android.launcher3.icons.IconCache
+import com.android.launcher3.icons.LauncherIconProvider
+import com.android.launcher3.util.DaggerSingletonObject
+import javax.inject.Inject
+import javax.inject.Named
+
+/** A collection of common dependencies used across Launcher */
+@Deprecated("Inject the specific targets directly instead of using LauncherAppState")
+data class LauncherAppState
+@Inject
+constructor(
+ @ApplicationContext val context: Context,
+ val iconProvider: LauncherIconProvider,
+ val iconCache: IconCache,
+ val model: LauncherModel,
+ val invariantDeviceProfile: InvariantDeviceProfile,
+ @Named("SAFE_MODE") val isSafeModeEnabled: Boolean,
+) {
+
+ companion object {
+
+ @JvmField var INSTANCE = DaggerSingletonObject { it.launcherAppState }
+
+ @JvmStatic fun getInstance(context: Context) = INSTANCE[context]
+
+ /** Shorthand for [.getInvariantDeviceProfile] */
+ @JvmStatic fun getIDP(context: Context) = InvariantDeviceProfile.INSTANCE[context]
+ }
+}
diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java
index 678901b..03eaeea 100644
--- a/src/com/android/launcher3/LauncherApplication.java
+++ b/src/com/android/launcher3/LauncherApplication.java
@@ -20,6 +20,7 @@
import com.android.launcher3.dagger.DaggerLauncherAppComponent;
import com.android.launcher3.dagger.LauncherAppComponent;
import com.android.launcher3.dagger.LauncherBaseAppComponent;
+import com.android.launcher3.util.TraceHelper;
/**
* Main application class for Launcher
@@ -41,7 +42,8 @@
if (mAppComponent == null) {
// Initialize the dagger component on demand as content providers can get
// accessed before the Launcher application (b/36917845#comment4)
- initDaggerComponent(DaggerLauncherAppComponent.builder());
+ initDaggerComponent(DaggerLauncherAppComponent.builder()
+ .iconsDbName(LauncherFiles.APP_ICONS_DB));
}
}
}
@@ -55,7 +57,11 @@
/**
* Init with the desired dagger component.
*/
- public void initDaggerComponent(LauncherAppComponent.Builder componentBuilder) {
- mAppComponent = componentBuilder.appContext(this).build();
+ public void initDaggerComponent(LauncherBaseAppComponent.Builder componentBuilder) {
+ mAppComponent = componentBuilder
+ .appContext(this)
+ .setSafeModeEnabled(TraceHelper.allowIpcs(
+ "isSafeMode", () -> getPackageManager().isSafeMode()))
+ .build();
}
}
diff --git a/src/com/android/launcher3/LauncherModel.kt b/src/com/android/launcher3/LauncherModel.kt
index 6e4276d..33b63ce 100644
--- a/src/com/android/launcher3/LauncherModel.kt
+++ b/src/com/android/launcher3/LauncherModel.kt
@@ -23,6 +23,8 @@
import android.util.Pair
import androidx.annotation.WorkerThread
import com.android.launcher3.celllayout.CellPosMapper
+import com.android.launcher3.dagger.ApplicationContext
+import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.icons.IconCache
import com.android.launcher3.model.AddWorkspaceItemsTask
import com.android.launcher3.model.AllAppsList
@@ -33,6 +35,7 @@
import com.android.launcher3.model.LoaderTask
import com.android.launcher3.model.ModelDbController
import com.android.launcher3.model.ModelDelegate
+import com.android.launcher3.model.ModelInitializer
import com.android.launcher3.model.ModelLauncherCallbacks
import com.android.launcher3.model.ModelTaskController
import com.android.launcher3.model.ModelWriter
@@ -45,31 +48,42 @@
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.pm.UserCache
import com.android.launcher3.shortcuts.ShortcutRequest
+import com.android.launcher3.util.DaggerSingletonTracker
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
-import com.android.launcher3.util.PackageManagerHelper
import com.android.launcher3.util.PackageUserKey
import com.android.launcher3.util.Preconditions
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.concurrent.CancellationException
import java.util.function.Consumer
+import javax.inject.Inject
+import javax.inject.Named
+import javax.inject.Provider
/**
* Maintains in-memory state of the Launcher. It is expected that there should be only one
* LauncherModel object held in a static. Also provide APIs for updating the database state for the
* Launcher.
*/
-class LauncherModel(
- private val context: Context,
- private val mApp: LauncherAppState,
+@LauncherAppSingleton
+class LauncherModel
+@Inject
+constructor(
+ @ApplicationContext private val context: Context,
+ private val appProvider: Provider<LauncherAppState>,
private val iconCache: IconCache,
- private val widgetsFilterDataProvider: WidgetsFilterDataProvider,
+ private val prefs: LauncherPrefs,
+ private val installQueue: ItemInstallQueue,
appFilter: AppFilter,
- mPmHelper: PackageManagerHelper,
- isPrimaryInstance: Boolean,
+ @Named("ICONS_DB") dbFileName: String?,
+ initializer: ModelInitializer,
+ lifecycle: DaggerSingletonTracker,
+ val modelDelegate: ModelDelegate,
) {
+ private val widgetsFilterDataProvider = WidgetsFilterDataProvider.newInstance(context)
+
private val mCallbacksList = ArrayList<BgDataModel.Callbacks>(1)
// < only access in worker thread >
@@ -81,16 +95,6 @@
*/
private val mBgDataModel = BgDataModel()
- val modelDelegate: ModelDelegate =
- ModelDelegate.newInstance(
- context,
- mApp,
- mPmHelper,
- mBgAllAppsList,
- mBgDataModel,
- isPrimaryInstance,
- )
-
val modelDbController = ModelDbController(context)
private val mLock = Any()
@@ -125,6 +129,14 @@
}
}
+ init {
+ if (!dbFileName.isNullOrEmpty()) {
+ initializer.initialize(this)
+ }
+ lifecycle.addCloseable { destroy() }
+ modelDelegate.init(this, mBgAllAppsList, mBgDataModel)
+ }
+
fun newModelCallbacks() = ModelLauncherCallbacks(this::enqueueModelUpdateTask)
/** Adds the provided items to the workspace. */
@@ -137,7 +149,7 @@
verifyChanges: Boolean,
cellPosMapper: CellPosMapper?,
owner: BgDataModel.Callbacks?,
- ) = ModelWriter(mApp.context, this, mBgDataModel, verifyChanges, cellPosMapper, owner)
+ ) = ModelWriter(context, this, mBgDataModel, verifyChanges, cellPosMapper, owner)
/** Returns the [WidgetsFilterDataProvider] that manages widget filters. */
fun getWidgetsFilterDataProvider(): WidgetsFilterDataProvider {
@@ -202,7 +214,7 @@
UserCache.ACTION_PROFILE_UNLOCKED ->
enqueueModelUpdateTask(UserLockStateChangedTask(user, true))
Intent.ACTION_MANAGED_PROFILE_REMOVED -> {
- LauncherPrefs.get(mApp.context).put(LauncherPrefs.WORK_EDU_STEP, 0)
+ prefs.put(LauncherPrefs.WORK_EDU_STEP, 0)
forceReload()
}
UserCache.ACTION_PROFILE_ADDED,
@@ -233,6 +245,13 @@
rebindCallbacks()
}
+ /** Reloads the model if it is already in use */
+ fun reloadIfActive() {
+ val wasActive: Boolean
+ synchronized(mLock) { wasActive = mModelLoaded || stopLoader() }
+ if (wasActive) forceReload()
+ }
+
/** Rebinds all existing callbacks with already loaded model */
fun rebindCallbacks() {
if (hasCallbacks()) {
@@ -280,7 +299,7 @@
private fun startLoader(newCallbacks: Array<BgDataModel.Callbacks>): Boolean {
// Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
- ItemInstallQueue.INSTANCE.get(context).pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING)
+ installQueue.pauseModelPush(ItemInstallQueue.FLAG_LOADER_RUNNING)
synchronized(mLock) {
// If there is already one running, tell it to stop.
val wasRunning = stopLoader()
@@ -292,7 +311,12 @@
callbacksList.forEach { MAIN_EXECUTOR.execute(it::clearPendingBinds) }
val launcherBinder =
- BaseLauncherBinder(mApp, mBgDataModel, mBgAllAppsList, callbacksList)
+ BaseLauncherBinder(
+ appProvider.get(),
+ mBgDataModel,
+ mBgAllAppsList,
+ callbacksList,
+ )
if (bindDirectly) {
// Divide the set of loaded items into those that we are binding synchronously,
// and everything else that is to be bound normally (asynchronously).
@@ -306,7 +330,7 @@
} else {
mLoaderTask =
LoaderTask(
- mApp,
+ appProvider.get(),
mBgAllAppsList,
mBgDataModel,
this.modelDelegate,
@@ -412,7 +436,7 @@
/** Called when the labels for the widgets has updated in the icon cache. */
fun onWidgetLabelsUpdated(updatedPackages: HashSet<String?>, user: UserHandle) {
enqueueModelUpdateTask { taskController, dataModel, _ ->
- dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, mApp)
+ dataModel.widgetsModel.onPackageIconsUpdated(updatedPackages, user, appProvider.get())
taskController.bindUpdatedWidgets(dataModel)
}
}
@@ -435,7 +459,13 @@
return@execute
}
task.execute(
- ModelTaskController(mApp, mBgDataModel, mBgAllAppsList, this, MAIN_EXECUTOR),
+ ModelTaskController(
+ appProvider.get(),
+ mBgDataModel,
+ mBgAllAppsList,
+ this,
+ MAIN_EXECUTOR,
+ ),
mBgDataModel,
mBgAllAppsList,
)
@@ -496,8 +526,6 @@
}
companion object {
- private const val DEBUG_RECEIVER = false
-
const val TAG = "Launcher.Model"
}
}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index a526b89..03ecf14 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -61,11 +61,10 @@
*/
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- LauncherAppState.INSTANCE.executeIfCreated(appState -> {
- if (appState.getModel().isModelLoaded()) {
- appState.getModel().dumpState("", fd, writer, args);
- }
- });
+ LauncherModel model = LauncherAppState.INSTANCE.get(getContext()).getModel();
+ if (model.isModelLoaded()) {
+ model.dumpState("", fd, writer, args);
+ }
}
@Override
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 31d0da0..be385d2 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -18,7 +18,10 @@
import android.content.Context;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.graphics.ThemeManager;
import com.android.launcher3.icons.LauncherIcons.IconPool;
@@ -43,6 +46,8 @@
import dagger.BindsInstance;
+import javax.inject.Named;
+
/**
* Launcher base component for Dagger injection.
*
@@ -74,10 +79,13 @@
LockedUserState getLockedUserState();
InvariantDeviceProfile getIDP();
IconPool getIconPool();
+ LauncherAppState getLauncherAppState();
/** Builder for LauncherBaseAppComponent. */
interface Builder {
@BindsInstance Builder appContext(@ApplicationContext Context context);
+ @BindsInstance Builder iconsDbName(@Nullable @Named("ICONS_DB") String dbFileName);
+ @BindsInstance Builder setSafeModeEnabled(@Named("SAFE_MODE") boolean safeModeEnabled);
LauncherBaseAppComponent build();
}
}
diff --git a/src/com/android/launcher3/dagger/LauncherComponentProvider.kt b/src/com/android/launcher3/dagger/LauncherComponentProvider.kt
index 71e3354..6199149 100644
--- a/src/com/android/launcher3/dagger/LauncherComponentProvider.kt
+++ b/src/com/android/launcher3/dagger/LauncherComponentProvider.kt
@@ -39,8 +39,10 @@
// Create a new component
return Holder(
- DaggerLauncherAppComponent.builder().appContext(app).build()
- as LauncherAppComponent,
+ DaggerLauncherAppComponent.builder()
+ .appContext(app)
+ .setSafeModeEnabled(true)
+ .build() as LauncherAppComponent,
existingFilter,
)
.apply { inflater.filter = this }
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 03f0582..332a6bb 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -67,7 +67,6 @@
import com.android.launcher3.Hotseat;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.ProxyPrefs;
@@ -146,8 +145,6 @@
prefs.put(GRID_NAME, gridName);
initDaggerComponent(
DaggerLauncherPreviewRenderer_PreviewAppComponent.builder().bindPrefs(prefs));
- putObject(LauncherAppState.INSTANCE,
- new LauncherAppState(this, null /* iconCacheFileName */));
}
@Override
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 9f99e8f..fc0c1bb 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -51,6 +51,8 @@
import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.icons.cache.BaseIconCache;
import com.android.launcher3.icons.cache.CacheLookupFlag;
import com.android.launcher3.icons.cache.CachedObject;
@@ -66,6 +68,7 @@
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.DaggerSingletonTracker;
import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.widget.WidgetSections;
@@ -79,9 +82,13 @@
import java.util.function.Supplier;
import java.util.stream.Stream;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* Cache of application icons. Icons can be made from any thread.
*/
+@LauncherAppSingleton
public class IconCache extends BaseIconCache {
// Shortcut extra which can point to a packageName and can be used to indicate an alternate
@@ -96,24 +103,39 @@
private final LauncherApps mLauncherApps;
private final UserCache mUserManager;
+ private final InstallSessionHelper mInstallSessionHelper;
private final InstantAppResolver mInstantAppResolver;
private final CancellableTask mCancelledTask;
+ private final LauncherIcons.IconPool mIconPool;
private final SparseArray<BitmapInfo> mWidgetCategoryBitmapInfos;
private int mPendingIconRequestCount = 0;
- public IconCache(Context context, InvariantDeviceProfile idp, String dbFileName,
- IconProvider iconProvider) {
+ @Inject
+ public IconCache(
+ @ApplicationContext Context context,
+ InvariantDeviceProfile idp,
+ @Nullable @Named("ICONS_DB") String dbFileName,
+ UserCache userCache,
+ LauncherIconProvider iconProvider,
+ InstallSessionHelper installSessionHelper,
+ LauncherIcons.IconPool iconPool,
+ DaggerSingletonTracker lifecycle) {
super(context, dbFileName, MODEL_EXECUTOR.getLooper(),
idp.fillResIconDpi, idp.iconBitmapSize, true /* inMemoryCache */, iconProvider);
mLauncherApps = context.getSystemService(LauncherApps.class);
- mUserManager = UserCache.INSTANCE.get(context);
+ mUserManager = userCache;
+ mInstallSessionHelper = installSessionHelper;
+ mIconPool = iconPool;
+
mInstantAppResolver = InstantAppResolver.newInstance(context);
mWidgetCategoryBitmapInfos = new SparseArray<>();
mCancelledTask = new CancellableTask(() -> null, MAIN_EXECUTOR, c -> { });
mCancelledTask.cancel();
+
+ lifecycle.addCloseable(this::close);
}
@Override
@@ -129,7 +151,7 @@
@NonNull
@Override
public BaseIconFactory getIconFactory() {
- return LauncherIcons.obtain(context);
+ return mIconPool.obtain();
}
/**
@@ -279,8 +301,7 @@
String override = shortcutInfo.getExtras() == null ? null
: shortcutInfo.getExtras().getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE);
if (!TextUtils.isEmpty(override)
- && InstallSessionHelper.INSTANCE.get(context)
- .isTrustedPackage(pkg, shortcutInfo.getUserHandle())) {
+ && mInstallSessionHelper.isTrustedPackage(pkg, shortcutInfo.getUserHandle())) {
pkg = override;
} else {
// Try component based badge before trying the normal package badge
@@ -536,7 +557,7 @@
return;
}
- try (LauncherIcons li = LauncherIcons.obtain(context)) {
+ try (LauncherIcons li = mIconPool.obtain()) {
final BitmapInfo tempBitmap = li.createBadgedIconBitmap(
context.getDrawable(widgetSection.mSectionDrawable),
new BaseIconFactory.IconOptions());
diff --git a/src/com/android/launcher3/icons/LauncherIconProvider.java b/src/com/android/launcher3/icons/LauncherIconProvider.java
index 836b7d1..7241198 100644
--- a/src/com/android/launcher3/icons/LauncherIconProvider.java
+++ b/src/com/android/launcher3/icons/LauncherIconProvider.java
@@ -30,6 +30,8 @@
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.graphics.ShapeDelegate;
import com.android.launcher3.graphics.ThemeManager;
import com.android.launcher3.util.ApiWrapper;
@@ -39,9 +41,12 @@
import java.util.Collections;
import java.util.Map;
+import javax.inject.Inject;
+
/**
* Extension of {@link IconProvider} with support for overriding theme icons
*/
+@LauncherAppSingleton
public class LauncherIconProvider extends IconProvider {
private static final String TAG_ICON = "icon";
@@ -56,10 +61,14 @@
private final ApiWrapper mApiWrapper;
private final ThemeManager mThemeManager;
- public LauncherIconProvider(Context context) {
+ @Inject
+ public LauncherIconProvider(
+ @ApplicationContext Context context,
+ ThemeManager themeManager,
+ ApiWrapper apiWrapper) {
super(context);
- mThemeManager = ThemeManager.INSTANCE.get(context);
- mApiWrapper = ApiWrapper.INSTANCE.get(context);
+ mThemeManager = themeManager;
+ mApiWrapper = apiWrapper;
setIconThemeSupported(mThemeManager.isMonoThemeEnabled());
}
@@ -79,7 +88,7 @@
@Override
public void updateSystemState() {
super.updateSystemState();
- mSystemState += "," + ThemeManager.INSTANCE.get(mContext).getIconState().toUniqueId();
+ mSystemState += "," + mThemeManager.getIconState().toUniqueId();
}
@Override
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 5a2aef0..52a2188 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -23,62 +23,45 @@
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.R;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.dagger.ApplicationContext;
import com.android.launcher3.shortcuts.ShortcutKey;
-import com.android.launcher3.util.PackageManagerHelper;
-import com.android.launcher3.util.ResourceBasedOverride;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Map;
+import javax.inject.Inject;
+
/**
* Class to extend LauncherModel functionality to provide extra data
*/
-public class ModelDelegate implements ResourceBasedOverride {
-
- /**
- * Creates and initializes a new instance of the delegate
- */
- public static ModelDelegate newInstance(
- Context context, LauncherAppState app, PackageManagerHelper pmHelper,
- AllAppsList appsList, BgDataModel dataModel, boolean isPrimaryInstance) {
- ModelDelegate delegate = Overrides.getObject(
- ModelDelegate.class, context, R.string.model_delegate_class);
- delegate.init(app, pmHelper, appsList, dataModel, isPrimaryInstance);
- return delegate;
- }
+public class ModelDelegate {
protected final Context mContext;
- protected PackageManagerHelper mPmHelper;
- protected LauncherAppState mApp;
+ protected LauncherModel mModel;
protected AllAppsList mAppsList;
protected BgDataModel mDataModel;
- protected boolean mIsPrimaryInstance;
- public ModelDelegate(Context context) {
+ @Inject
+ public ModelDelegate(@ApplicationContext Context context) {
mContext = context;
}
/**
* Initializes the object with the given params.
*/
- private void init(LauncherAppState app, PackageManagerHelper pmHelper, AllAppsList appsList,
- BgDataModel dataModel, boolean isPrimaryInstance) {
- this.mApp = app;
- this.mPmHelper = pmHelper;
+ public void init(LauncherModel model, AllAppsList appsList, BgDataModel dataModel) {
+ this.mModel = model;
this.mAppsList = appsList;
this.mDataModel = dataModel;
- this.mIsPrimaryInstance = isPrimaryInstance;
}
/** Called periodically to validate and update any data */
@WorkerThread
public void validateData() {
- if (hasShortcutsPermission(mApp.getContext())
- != mAppsList.hasShortcutHostPermission()) {
- mApp.getModel().forceReload();
+ if (hasShortcutsPermission(mContext) != mAppsList.hasShortcutHostPermission()) {
+ mModel.forceReload();
}
}
diff --git a/src/com/android/launcher3/model/ModelInitializer.kt b/src/com/android/launcher3/model/ModelInitializer.kt
index 69a320a..735a52a 100644
--- a/src/com/android/launcher3/model/ModelInitializer.kt
+++ b/src/com/android/launcher3/model/ModelInitializer.kt
@@ -38,18 +38,20 @@
import com.android.launcher3.notification.NotificationListener
import com.android.launcher3.pm.InstallSessionHelper
import com.android.launcher3.pm.UserCache
+import com.android.launcher3.util.DaggerSingletonTracker
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
-import com.android.launcher3.util.SafeCloseable
import com.android.launcher3.util.SettingsCache
import com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI
import com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI
import com.android.launcher3.util.SimpleBroadcastReceiver
import com.android.launcher3.widget.custom.CustomWidgetManager
-import java.util.function.Consumer
+import javax.inject.Inject
/** Utility class for initializing all model callbacks */
-class ModelInitializer(
+class ModelInitializer
+@Inject
+constructor(
@ApplicationContext private val context: Context,
private val iconPool: IconPool,
private val iconCache: IconCache,
@@ -60,7 +62,7 @@
private val iconProvider: LauncherIconProvider,
private val customWidgetManager: CustomWidgetManager,
private val installSessionHelper: InstallSessionHelper,
- private val closeActions: Consumer<SafeCloseable>,
+ private val lifeCycle: DaggerSingletonTracker,
) {
fun initialize(model: LauncherModel) {
@@ -75,18 +77,18 @@
if (modelChanged) refreshAndReloadLauncher()
}
idp.addOnChangeListener(idpChangeListener)
- closeActions.accept { idp.removeOnChangeListener(idpChangeListener) }
+ lifeCycle.addCloseable { idp.removeOnChangeListener(idpChangeListener) }
// Theme changes
val themeChangeListener = ThemeChangeListener { refreshAndReloadLauncher() }
themeManager.addChangeListener(themeChangeListener)
- closeActions.accept { themeManager.removeChangeListener(themeChangeListener) }
+ lifeCycle.addCloseable { themeManager.removeChangeListener(themeChangeListener) }
// System changes
val modelCallbacks = model.newModelCallbacks()
val launcherApps = context.getSystemService(LauncherApps::class.java)!!
- launcherApps.registerCallback(modelCallbacks)
- closeActions.accept { launcherApps.unregisterCallback(modelCallbacks) }
+ launcherApps.registerCallback(modelCallbacks, MODEL_EXECUTOR.handler)
+ lifeCycle.addCloseable { launcherApps.unregisterCallback(modelCallbacks) }
if (Utilities.ATLEAST_V && Flags.enableSupportForArchiving()) {
launcherApps.setArchiveCompatibility(
@@ -101,23 +103,23 @@
val dpUpdateReceiver =
SimpleBroadcastReceiver(context, UI_HELPER_EXECUTOR) { model.reloadStringCache() }
dpUpdateReceiver.register(ACTION_DEVICE_POLICY_RESOURCE_UPDATED)
- closeActions.accept { dpUpdateReceiver.unregisterReceiverSafely() }
+ lifeCycle.addCloseable { dpUpdateReceiver.unregisterReceiverSafely() }
// Development helper
if (BuildConfig.IS_STUDIO_BUILD) {
val reloadReceiver =
SimpleBroadcastReceiver(context, UI_HELPER_EXECUTOR) { model.forceReload() }
reloadReceiver.register(Context.RECEIVER_EXPORTED, ACTION_FORCE_RELOAD)
- closeActions.accept { reloadReceiver.unregisterReceiverSafely() }
+ lifeCycle.addCloseable { reloadReceiver.unregisterReceiverSafely() }
}
// User changes
- closeActions.accept(userCache.addUserEventListener(model::onUserEvent))
+ lifeCycle.addCloseable(userCache.addUserEventListener(model::onUserEvent))
// Private space settings changes
val psSettingsListener = SettingsCache.OnChangeListener { model.forceReload() }
settingsCache.register(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI, psSettingsListener)
- closeActions.accept {
+ lifeCycle.addCloseable {
settingsCache.unregister(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI, psSettingsListener)
}
@@ -131,7 +133,7 @@
}
settingsCache.register(NOTIFICATION_BADGING_URI, notificationChanges)
notificationChanges.onSettingsChanged(settingsCache.getValue(NOTIFICATION_BADGING_URI))
- closeActions.accept {
+ lifeCycle.addCloseable {
settingsCache.unregister(NOTIFICATION_BADGING_URI, notificationChanges)
}
@@ -142,21 +144,21 @@
if (LoaderTask.SMARTSPACE_ON_HOME_SCREEN == key) model.forceReload()
}
getPrefs(context).registerOnSharedPreferenceChangeListener(smartSpacePrefChanges)
- closeActions.accept {
+ lifeCycle.addCloseable {
getPrefs(context).unregisterOnSharedPreferenceChangeListener(smartSpacePrefChanges)
}
}
// Custom widgets
- closeActions.accept(customWidgetManager.addWidgetRefreshCallback(model::rebindCallbacks))
+ lifeCycle.addCloseable(customWidgetManager.addWidgetRefreshCallback(model::rebindCallbacks))
// Icon changes
- closeActions.accept(
+ lifeCycle.addCloseable(
iconProvider.registerIconChangeListener(model::onAppIconChanged, MODEL_EXECUTOR.handler)
)
// Install session changes
- closeActions.accept(installSessionHelper.registerInstallTracker(modelCallbacks))
+ lifeCycle.addCloseable(installSessionHelper.registerInstallTracker(modelCallbacks))
}
companion object {
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index ff40f30..b60b8cc 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.os.Process;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.Flags;
@@ -44,6 +45,7 @@
/**
* The bitmap for the application icon
*/
+ @NonNull
public BitmapInfo bitmap = BitmapInfo.LOW_RES_INFO;
/**
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 34c9117..5ad8af2 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -535,7 +535,7 @@
}
logFavoritesTable(controller.getDb(), "launcher db after remap widget ids", null, null);
- LauncherAppState.INSTANCE.executeIfCreated(app -> app.getModel().forceReload());
+ LauncherAppState.INSTANCE.get(context).getModel().reloadIfActive();
}
private static void logDatabaseWidgetInfo(ModelDbController controller) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
index f8dc6b0..8f34fe3 100644
--- a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
@@ -35,19 +35,7 @@
* own implementation. Method {@code getWidgetRecommendationCategory} is called per widget to get
* the category.</p>
*/
-public class WidgetRecommendationCategoryProvider implements ResourceBasedOverride {
- private static final String TAG = "WidgetRecommendationCategoryProvider";
-
- /**
- * Retrieve instance of this object that can be overridden in runtime based on the build
- * variant of the application.
- */
- public static WidgetRecommendationCategoryProvider newInstance(Context context) {
- Preconditions.assertWorkerThread();
- return Overrides.getObject(
- WidgetRecommendationCategoryProvider.class, context.getApplicationContext(),
- R.string.widget_recommendation_category_provider_class);
- }
+public class WidgetRecommendationCategoryProvider {
/**
* Returns a {@link WidgetRecommendationCategory} for the provided widget item that can be used
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
index 9026748..0aaf4d7 100644
--- a/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/IconCacheTest.java
@@ -56,7 +56,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.icons.cache.CachingLogic;
import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
import com.android.launcher3.icons.cache.LauncherActivityCachingLogic;
@@ -69,11 +69,13 @@
import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.SandboxApplication;
import com.google.common.truth.Truth;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -85,20 +87,18 @@
@RunWith(AndroidJUnit4.class)
public class IconCacheTest {
- private Context mContext;
+ @Rule public SandboxApplication mContext = new SandboxApplication();
+
private IconCache mIconCache;
private ComponentName mMyComponent;
@Before
public void setup() {
- mContext = getInstrumentation().getTargetContext();
mMyComponent = new ComponentName(mContext, SettingsActivity.class);
// In memory icon cache
- mIconCache = new IconCache(mContext,
- InvariantDeviceProfile.INSTANCE.get(mContext), null,
- new LauncherIconProvider(mContext));
+ mIconCache = LauncherAppState.getInstance(mContext).getIconCache();
}
@After
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
index ce04682..08b8f81 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
@@ -155,7 +155,7 @@
private fun verifyItemSpaceFinderCall(nonEmptyScreenIds: List<Int>, numberOfExpectedCall: Int) {
verify(mWorkspaceItemSpaceFinder, times(numberOfExpectedCall))
.findSpaceForItem(
- same(mAppState),
+ eq(mAppState),
same(mModelHelper.bgDataModel),
eq(IntArray.wrap(*nonEmptyScreenIds.toIntArray())),
eq(IntArray()),
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
index 11047fb..ad40818 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -70,6 +70,7 @@
import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -258,7 +259,6 @@
initCursor(ITEM_TYPE_APPLICATION, "title");
assertTrue(mLoaderCursor.moveToNext());
WorkspaceItemInfo itemInfo = new WorkspaceItemInfo();
- itemInfo.bitmap = null;
itemInfo.runtimeStatusFlags |= FLAG_ARCHIVED;
Bitmap expectedBitmap = LauncherIcons.obtain(mContext)
.createIconBitmap(decodeByteArray(sTestBlob, 0, sTestBlob.length))
@@ -289,7 +289,7 @@
initCursor(ITEM_TYPE_APPLICATION, "title");
assertTrue(mLoaderCursor.moveToNext());
WorkspaceItemInfo itemInfo = new WorkspaceItemInfo();
- itemInfo.bitmap = null;
+ BitmapInfo original = itemInfo.bitmap;
itemInfo.runtimeStatusFlags |= FLAG_ARCHIVED;
Intent intent = new Intent();
intent.setComponent(new ComponentName("package", "class"));
@@ -297,7 +297,7 @@
// When
mLoaderCursor.loadWorkspaceTitleAndIcon(false, false, itemInfo);
// Then
- assertThat(itemInfo.bitmap).isNull();
+ assertThat(itemInfo.bitmap).isEqualTo(original);
}
@Test
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
index 09b9a3b..cee5559 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -21,8 +21,8 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
import static com.android.launcher3.util.TestUtil.grantWriteSecurePermission;
+import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -51,6 +51,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.ModelDbController;
@@ -267,14 +268,6 @@
}
@Override
- public <T extends SafeCloseable> T createObject(MainThreadInitializedObject<T> object) {
- if (object == LauncherAppState.INSTANCE) {
- return (T) new LauncherAppState(this, null /* iconCacheFileName */);
- }
- return super.createObject(object);
- }
-
- @Override
public File getDatabasePath(String name) {
if (!mDbDir.exists()) {
mDbDir.mkdirs();
@@ -342,5 +335,10 @@
}
return success;
}
+
+ @Override
+ public void initDaggerComponent(LauncherBaseAppComponent.Builder componentBuilder) {
+ super.initDaggerComponent(componentBuilder.iconsDbName(null));
+ }
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
similarity index 97%
rename from tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
rename to tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
index 15accbd..c956395 100644
--- a/tests/multivalentTests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
+++ b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
import android.os.Process
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
@@ -61,11 +62,11 @@
import org.junit.runner.Description
import org.junit.runner.RunWith
import org.junit.runners.model.Statement
+import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
-import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@@ -85,6 +86,7 @@
@Before
fun setup() {
+ MockitoAnnotations.initMocks(this)
modelHelper = LauncherModelHelper()
context = modelHelper.sandboxContext
context.initDaggerComponent(DaggerPreviewItemManagerTestComponent.builder())
@@ -93,10 +95,8 @@
}
folderIcon = FolderIcon(ActivityContextWrapper(context))
- val app = spy(LauncherAppState.getInstance(context))
- iconCache = spy(app.iconCache)
- doReturn(iconCache).whenever(app).iconCache
- context.putObject(LauncherAppState.INSTANCE, app)
+ iconCache = LauncherAppState.INSTANCE[context].iconCache
+ spyOn(iconCache)
doReturn(null).whenever(iconCache).updateIconInBackground(any(), any())
previewItemManager = PreviewItemManager(folderIcon)
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index 8f64e84..582cf3c 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -14,6 +14,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
import com.android.launcher3.Flags
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherModel
@@ -67,7 +68,6 @@
import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
-import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness
@@ -92,7 +92,6 @@
)
private lateinit var mockitoSession: MockitoSession
- @Mock private lateinit var app: LauncherAppState
@Mock private lateinit var bgAllAppsList: AllAppsList
@Mock private lateinit var modelDelegate: ModelDelegate
@Mock private lateinit var launcherBinder: BaseLauncherBinder
@@ -108,6 +107,9 @@
@get:Rule val setFlagsRule = SetFlagsRule()
+ private val app: LauncherAppState
+ get() = context.appComponent.launcherAppState
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
@@ -118,32 +120,28 @@
.strictness(Strictness.LENIENT)
.mockStatic(FirstScreenBroadcastHelper::class.java)
.startMocking()
- val idp =
- context.appComponent.idp.apply {
- numRows = 5
- numColumns = 6
- numDatabaseHotseatIcons = 5
- }
- context.putObject(LauncherAppState.INSTANCE, app)
-
doReturn(TestViewHelpers.findWidgetProvider(false))
.`when`(context.spyService(AppWidgetManager::class.java))
.getAppWidgetInfo(any())
- `when`(app.context).thenReturn(context)
- `when`(app.model).thenReturn(launcherModel)
`when`(launcherModel.beginLoader(any())).thenReturn(transaction)
- `when`(app.iconCache).thenReturn(iconCache)
`when`(launcherModel.modelDbController)
.thenReturn(FactitiousDbController(context, INSERTION_STATEMENT_FILE))
- `when`(app.invariantDeviceProfile).thenReturn(idp)
`when`(launcherBinder.newIdleLock(any())).thenReturn(idleLock)
`when`(idleLock.awaitLocked(1000)).thenReturn(false)
`when`(iconCache.getUpdateHandler()).thenReturn(iconCacheUpdateHandler)
`when`(widgetsFilterDataProvider.getDefaultWidgetsFilter()).thenReturn(Predicate { true })
context.initDaggerComponent(
- DaggerLoaderTaskTest_TestComponent.builder().bindUserCache(userCache)
+ DaggerLoaderTaskTest_TestComponent.builder()
+ .bindUserCache(userCache)
+ .bindIconCache(iconCache)
+ .bindLauncherModel(launcherModel)
)
+ context.appComponent.idp.apply {
+ numRows = 5
+ numColumns = 6
+ numDatabaseHotseatIcons = 5
+ }
TestUtil.grantWriteSecurePermission()
}
@@ -281,8 +279,8 @@
@EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
fun `When broadcast flag on and is restore and secure setting off then send new broadcast`() {
// Given
- val spyContext = spy(context)
- `when`(app.context).thenReturn(spyContext)
+ spyOn(context)
+ val spyContext = context
whenever(
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
any(),
@@ -357,8 +355,8 @@
@EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
fun `When not a restore then installed item broadcast not sent`() {
// Given
- val spyContext = spy(context)
- `when`(app.context).thenReturn(spyContext)
+ spyOn(context)
+ val spyContext = context
whenever(
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
any(),
@@ -398,8 +396,8 @@
@DisableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
fun `When broadcast flag off then installed item broadcast not sent`() {
// Given
- val spyContext = spy(context)
- `when`(app.context).thenReturn(spyContext)
+ spyOn(context)
+ val spyContext = context
whenever(
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
any(),
@@ -444,8 +442,8 @@
@EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
fun `When failsafe secure setting on then installed item broadcast not sent`() {
// Given
- val spyContext = spy(context)
- `when`(app.context).thenReturn(spyContext)
+ spyOn(context)
+ val spyContext = context
whenever(
FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
any(),
@@ -644,6 +642,10 @@
interface Builder : LauncherAppComponent.Builder {
@BindsInstance fun bindUserCache(userCache: UserCache): Builder
+ @BindsInstance fun bindLauncherModel(model: LauncherModel): Builder
+
+ @BindsInstance fun bindIconCache(iconCache: IconCache): Builder
+
override fun build(): TestComponent
}
}