1 /* 2 * Copyright (C) 2013 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; 18 19 import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS; 20 import static com.android.launcher3.util.SecureSettingsObserver.newNotificationSettingsObserver; 21 22 import android.content.ComponentName; 23 import android.content.ContentProviderClient; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.os.Handler; 28 import android.util.Log; 29 30 import com.android.launcher3.compat.LauncherAppsCompat; 31 import com.android.launcher3.compat.PackageInstallerCompat; 32 import com.android.launcher3.compat.UserManagerCompat; 33 import com.android.launcher3.config.FeatureFlags; 34 import com.android.launcher3.icons.IconCache; 35 import com.android.launcher3.icons.LauncherIcons; 36 import com.android.launcher3.notification.NotificationListener; 37 import com.android.launcher3.util.MainThreadInitializedObject; 38 import com.android.launcher3.util.Preconditions; 39 import com.android.launcher3.util.SecureSettingsObserver; 40 import com.android.launcher3.widget.custom.CustomWidgetManager; 41 42 public class LauncherAppState { 43 44 public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher"; 45 46 // We do not need any synchronization for this variable as its only written on UI thread. 47 private static final MainThreadInitializedObject<LauncherAppState> INSTANCE = 48 new MainThreadInitializedObject<>(LauncherAppState::new); 49 50 private final Context mContext; 51 private final LauncherModel mModel; 52 private final IconCache mIconCache; 53 private final WidgetPreviewLoader mWidgetCache; 54 private final InvariantDeviceProfile mInvariantDeviceProfile; 55 private final SecureSettingsObserver mNotificationDotsObserver; 56 getInstance(final Context context)57 public static LauncherAppState getInstance(final Context context) { 58 return INSTANCE.get(context); 59 } 60 getInstanceNoCreate()61 public static LauncherAppState getInstanceNoCreate() { 62 return INSTANCE.getNoCreate(); 63 } 64 getContext()65 public Context getContext() { 66 return mContext; 67 } 68 LauncherAppState(Context context)69 private LauncherAppState(Context context) { 70 if (getLocalProvider(context) == null) { 71 throw new RuntimeException( 72 "Initializing LauncherAppState in the absence of LauncherProvider"); 73 } 74 Log.v(Launcher.TAG, "LauncherAppState initiated"); 75 Preconditions.assertUIThread(); 76 mContext = context; 77 78 mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(mContext); 79 mIconCache = new IconCache(mContext, mInvariantDeviceProfile); 80 mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); 81 mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext)); 82 83 LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel); 84 85 // Register intent receivers 86 IntentFilter filter = new IntentFilter(); 87 filter.addAction(Intent.ACTION_LOCALE_CHANGED); 88 // For handling managed profiles 89 filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); 90 filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); 91 filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); 92 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 93 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED); 94 95 if (FeatureFlags.IS_DOGFOOD_BUILD) { 96 filter.addAction(ACTION_FORCE_ROLOAD); 97 } 98 FeatureFlags.APP_SEARCH_IMPROVEMENTS.addChangeListener(context, mModel::forceReload); 99 100 mContext.registerReceiver(mModel, filter); 101 UserManagerCompat.getInstance(mContext).enableAndResetCache(); 102 mInvariantDeviceProfile.addOnChangeListener(this::onIdpChanged); 103 new Handler().post( () -> mInvariantDeviceProfile.verifyConfigChangedInBackground(context)); 104 105 if (!mContext.getResources().getBoolean(R.bool.notification_dots_enabled)) { 106 mNotificationDotsObserver = null; 107 } else { 108 // Register an observer to rebind the notification listener when dots are re-enabled. 109 mNotificationDotsObserver = 110 newNotificationSettingsObserver(mContext, this::onNotificationSettingsChanged); 111 mNotificationDotsObserver.register(); 112 mNotificationDotsObserver.dispatchOnChange(); 113 } 114 } 115 onNotificationSettingsChanged(boolean areNotificationDotsEnabled)116 protected void onNotificationSettingsChanged(boolean areNotificationDotsEnabled) { 117 if (areNotificationDotsEnabled) { 118 NotificationListener.requestRebind(new ComponentName( 119 mContext, NotificationListener.class)); 120 } 121 } 122 onIdpChanged(int changeFlags, InvariantDeviceProfile idp)123 private void onIdpChanged(int changeFlags, InvariantDeviceProfile idp) { 124 if (changeFlags == 0) { 125 return; 126 } 127 128 if ((changeFlags & CHANGE_FLAG_ICON_PARAMS) != 0) { 129 LauncherIcons.clearPool(); 130 mIconCache.updateIconParams(idp.fillResIconDpi, idp.iconBitmapSize); 131 mWidgetCache.refresh(); 132 } 133 134 mModel.forceReload(); 135 } 136 137 /** 138 * Call from Application.onTerminate(), which is not guaranteed to ever be called. 139 */ onTerminate()140 public void onTerminate() { 141 mContext.unregisterReceiver(mModel); 142 final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext); 143 launcherApps.removeOnAppsChangedCallback(mModel); 144 PackageInstallerCompat.getInstance(mContext).onStop(); 145 if (mNotificationDotsObserver != null) { 146 mNotificationDotsObserver.unregister(); 147 } 148 } 149 setLauncher(Launcher launcher)150 LauncherModel setLauncher(Launcher launcher) { 151 getLocalProvider(mContext).setLauncherProviderChangeListener(launcher); 152 mModel.initialize(launcher); 153 CustomWidgetManager.INSTANCE.get(launcher) 154 .setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts); 155 return mModel; 156 } 157 getIconCache()158 public IconCache getIconCache() { 159 return mIconCache; 160 } 161 getModel()162 public LauncherModel getModel() { 163 return mModel; 164 } 165 getWidgetCache()166 public WidgetPreviewLoader getWidgetCache() { 167 return mWidgetCache; 168 } 169 getInvariantDeviceProfile()170 public InvariantDeviceProfile getInvariantDeviceProfile() { 171 return mInvariantDeviceProfile; 172 } 173 174 /** 175 * Shorthand for {@link #getInvariantDeviceProfile()} 176 */ getIDP(Context context)177 public static InvariantDeviceProfile getIDP(Context context) { 178 return InvariantDeviceProfile.INSTANCE.get(context); 179 } 180 getLocalProvider(Context context)181 private static LauncherProvider getLocalProvider(Context context) { 182 try (ContentProviderClient cl = context.getContentResolver() 183 .acquireContentProviderClient(LauncherProvider.AUTHORITY)) { 184 return (LauncherProvider) cl.getLocalContentProvider(); 185 } 186 } 187 } 188