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.app.KeyguardManager; 23 import android.content.ComponentName; 24 import android.content.ContentProviderClient; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.os.Handler; 29 import android.os.Process; 30 import android.util.Log; 31 32 import com.android.launcher3.compat.LauncherAppsCompat; 33 import com.android.launcher3.compat.PackageInstallerCompat; 34 import com.android.launcher3.compat.UserManagerCompat; 35 import com.android.launcher3.config.FeatureFlags; 36 import com.android.launcher3.icons.IconCache; 37 import com.android.launcher3.icons.LauncherIcons; 38 import com.android.launcher3.notification.NotificationListener; 39 import com.android.launcher3.util.MainThreadInitializedObject; 40 import com.android.launcher3.util.Preconditions; 41 import com.android.launcher3.util.SecureSettingsObserver; 42 43 public class LauncherAppState { 44 45 public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher"; 46 47 // We do not need any synchronization for this variable as its only written on UI thread. 48 private static final MainThreadInitializedObject<LauncherAppState> INSTANCE = 49 new MainThreadInitializedObject<>((c) -> new LauncherAppState(c)); 50 51 private final Context mContext; 52 private final LauncherModel mModel; 53 private final IconCache mIconCache; 54 private final WidgetPreviewLoader mWidgetCache; 55 private final InvariantDeviceProfile mInvariantDeviceProfile; 56 private final SecureSettingsObserver mNotificationDotsObserver; 57 getInstance(final Context context)58 public static LauncherAppState getInstance(final Context context) { 59 return INSTANCE.get(context); 60 } 61 getInstanceNoCreate()62 public static LauncherAppState getInstanceNoCreate() { 63 return INSTANCE.getNoCreate(); 64 } 65 getContext()66 public Context getContext() { 67 return mContext; 68 } 69 LauncherAppState(Context context)70 private LauncherAppState(Context context) { 71 if (getLocalProvider(context) == null) { 72 throw new RuntimeException( 73 "Initializing LauncherAppState in the absence of LauncherProvider"); 74 } 75 Log.v(Launcher.TAG, "LauncherAppState initiated"); 76 Preconditions.assertUIThread(); 77 mContext = context; 78 79 mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(mContext); 80 mIconCache = new IconCache(mContext, mInvariantDeviceProfile); 81 mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache); 82 mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext)); 83 84 LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel); 85 86 // Register intent receivers 87 IntentFilter filter = new IntentFilter(); 88 filter.addAction(Intent.ACTION_LOCALE_CHANGED); 89 // For handling managed profiles 90 filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); 91 filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); 92 filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE); 93 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 94 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED); 95 96 if (FeatureFlags.IS_DOGFOOD_BUILD) { 97 filter.addAction(ACTION_FORCE_ROLOAD); 98 } 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 return mModel; 154 } 155 getIconCache()156 public IconCache getIconCache() { 157 return mIconCache; 158 } 159 getModel()160 public LauncherModel getModel() { 161 return mModel; 162 } 163 getWidgetCache()164 public WidgetPreviewLoader getWidgetCache() { 165 return mWidgetCache; 166 } 167 getInvariantDeviceProfile()168 public InvariantDeviceProfile getInvariantDeviceProfile() { 169 return mInvariantDeviceProfile; 170 } 171 172 /** 173 * Shorthand for {@link #getInvariantDeviceProfile()} 174 */ getIDP(Context context)175 public static InvariantDeviceProfile getIDP(Context context) { 176 return InvariantDeviceProfile.INSTANCE.get(context); 177 } 178 getLocalProvider(Context context)179 private static LauncherProvider getLocalProvider(Context context) { 180 try (ContentProviderClient cl = context.getContentResolver() 181 .acquireContentProviderClient(LauncherProvider.AUTHORITY)) { 182 return (LauncherProvider) cl.getLocalContentProvider(); 183 } 184 } 185 } 186