• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3.model
18 
19 import android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED
20 import android.content.ComponentName
21 import android.content.Context
22 import android.content.SharedPreferences
23 import android.content.pm.LauncherApps
24 import android.content.pm.LauncherApps.ArchiveCompatibilityParams
25 import com.android.launcher3.BuildConfig
26 import com.android.launcher3.Flags
27 import com.android.launcher3.InvariantDeviceProfile
28 import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener
29 import com.android.launcher3.LauncherModel
30 import com.android.launcher3.LauncherPrefs.Companion.getPrefs
31 import com.android.launcher3.Utilities
32 import com.android.launcher3.dagger.ApplicationContext
33 import com.android.launcher3.graphics.ThemeManager
34 import com.android.launcher3.graphics.ThemeManager.ThemeChangeListener
35 import com.android.launcher3.icons.IconCache
36 import com.android.launcher3.icons.LauncherIconProvider
37 import com.android.launcher3.icons.LauncherIcons.IconPool
38 import com.android.launcher3.notification.NotificationListener
39 import com.android.launcher3.pm.InstallSessionHelper
40 import com.android.launcher3.pm.UserCache
41 import com.android.launcher3.util.DaggerSingletonTracker
42 import com.android.launcher3.util.Executors.MODEL_EXECUTOR
43 import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
44 import com.android.launcher3.util.SettingsCache
45 import com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI
46 import com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI
47 import com.android.launcher3.util.SimpleBroadcastReceiver
48 import com.android.launcher3.widget.custom.CustomWidgetManager
49 import javax.inject.Inject
50 
51 /** Utility class for initializing all model callbacks */
52 class ModelInitializer
53 @Inject
54 constructor(
55     @ApplicationContext private val context: Context,
56     private val iconPool: IconPool,
57     private val iconCache: IconCache,
58     private val idp: InvariantDeviceProfile,
59     private val themeManager: ThemeManager,
60     private val userCache: UserCache,
61     private val settingsCache: SettingsCache,
62     private val iconProvider: LauncherIconProvider,
63     private val customWidgetManager: CustomWidgetManager,
64     private val installSessionHelper: InstallSessionHelper,
65     private val lifeCycle: DaggerSingletonTracker,
66 ) {
67 
68     fun initialize(model: LauncherModel) {
69         fun refreshAndReloadLauncher() {
70             iconPool.clear()
71             iconCache.updateIconParams(idp.fillResIconDpi, idp.iconBitmapSize)
72             model.forceReload()
73         }
74 
75         // IDP changes
76         val idpChangeListener = OnIDPChangeListener { modelChanged ->
77             if (modelChanged) refreshAndReloadLauncher()
78         }
79         idp.addOnChangeListener(idpChangeListener)
80         lifeCycle.addCloseable { idp.removeOnChangeListener(idpChangeListener) }
81 
82         // Theme changes
83         val themeChangeListener = ThemeChangeListener { refreshAndReloadLauncher() }
84         themeManager.addChangeListener(themeChangeListener)
85         lifeCycle.addCloseable { themeManager.removeChangeListener(themeChangeListener) }
86 
87         // System changes
88         val modelCallbacks = model.newModelCallbacks()
89         val launcherApps = context.getSystemService(LauncherApps::class.java)!!
90         launcherApps.registerCallback(modelCallbacks, MODEL_EXECUTOR.handler)
91         lifeCycle.addCloseable { launcherApps.unregisterCallback(modelCallbacks) }
92 
93         if (Utilities.ATLEAST_V && Flags.enableSupportForArchiving()) {
94             launcherApps.setArchiveCompatibility(
95                 ArchiveCompatibilityParams().apply {
96                     setEnableUnarchivalConfirmation(false)
97                     setEnableIconOverlay(!Flags.useNewIconForArchivedApps())
98                 }
99             )
100         }
101 
102         // Device profile policy changes
103         val dpUpdateReceiver =
104             SimpleBroadcastReceiver(context, UI_HELPER_EXECUTOR) { model.reloadStringCache() }
105         dpUpdateReceiver.register(ACTION_DEVICE_POLICY_RESOURCE_UPDATED)
106         lifeCycle.addCloseable { dpUpdateReceiver.unregisterReceiverSafely() }
107 
108         // Development helper
109         if (BuildConfig.IS_STUDIO_BUILD) {
110             val reloadReceiver =
111                 SimpleBroadcastReceiver(context, UI_HELPER_EXECUTOR) { model.forceReload() }
112             reloadReceiver.register(Context.RECEIVER_EXPORTED, ACTION_FORCE_RELOAD)
113             lifeCycle.addCloseable { reloadReceiver.unregisterReceiverSafely() }
114         }
115 
116         // User changes
117         lifeCycle.addCloseable(userCache.addUserEventListener(model::onUserEvent))
118 
119         // Private space settings changes
120         val psSettingsListener = SettingsCache.OnChangeListener { model.forceReload() }
121         settingsCache.register(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI, psSettingsListener)
122         lifeCycle.addCloseable {
123             settingsCache.unregister(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI, psSettingsListener)
124         }
125 
126         // Notification dots changes
127         val notificationChanges =
128             SettingsCache.OnChangeListener { dotsEnabled ->
129                 if (dotsEnabled)
130                     NotificationListener.requestRebind(
131                         ComponentName(context, NotificationListener::class.java)
132                     )
133             }
134         settingsCache.register(NOTIFICATION_BADGING_URI, notificationChanges)
135         notificationChanges.onSettingsChanged(settingsCache.getValue(NOTIFICATION_BADGING_URI))
136         lifeCycle.addCloseable {
137             settingsCache.unregister(NOTIFICATION_BADGING_URI, notificationChanges)
138         }
139 
140         // removable smartspace
141         if (Flags.enableSmartspaceRemovalToggle()) {
142             val smartSpacePrefChanges =
143                 SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
144                     if (LoaderTask.SMARTSPACE_ON_HOME_SCREEN == key) model.forceReload()
145                 }
146             getPrefs(context).registerOnSharedPreferenceChangeListener(smartSpacePrefChanges)
147             lifeCycle.addCloseable {
148                 getPrefs(context).unregisterOnSharedPreferenceChangeListener(smartSpacePrefChanges)
149             }
150         }
151 
152         // Custom widgets
153         lifeCycle.addCloseable(customWidgetManager.addWidgetRefreshCallback(model::rebindCallbacks))
154 
155         // Icon changes
156         lifeCycle.addCloseable(
157             iconProvider.registerIconChangeListener(model::onAppIconChanged, MODEL_EXECUTOR.handler)
158         )
159 
160         // Install session changes
161         lifeCycle.addCloseable(installSessionHelper.registerInstallTracker(modelCallbacks))
162     }
163 
164     companion object {
165         private const val ACTION_FORCE_RELOAD = "force-reload-launcher"
166     }
167 }
168