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