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