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.app.SearchManager; 20 import android.content.ComponentName; 21 import android.content.ContentResolver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.res.Configuration; 26 import android.content.res.Resources; 27 import android.database.ContentObserver; 28 import android.os.Handler; 29 import android.util.Log; 30 31 import com.android.launcher3.compat.LauncherAppsCompat; 32 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; 33 34 import java.lang.ref.WeakReference; 35 import java.util.ArrayList; 36 37 public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { 38 private static final String TAG = "LauncherAppState"; 39 private static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs"; 40 41 private static final boolean DEBUG = false; 42 43 private final AppFilter mAppFilter; 44 private final BuildInfo mBuildInfo; 45 private LauncherModel mModel; 46 private IconCache mIconCache; 47 private WidgetPreviewLoader.CacheDb mWidgetPreviewCacheDb; 48 private boolean mIsScreenLarge; 49 private float mScreenDensity; 50 private int mLongPressTimeout = 300; 51 private boolean mWallpaperChangedSinceLastCheck; 52 53 private static WeakReference<LauncherProvider> sLauncherProvider; 54 private static Context sContext; 55 56 private static LauncherAppState INSTANCE; 57 58 private DynamicGrid mDynamicGrid; 59 getInstance()60 public static LauncherAppState getInstance() { 61 if (INSTANCE == null) { 62 INSTANCE = new LauncherAppState(); 63 } 64 return INSTANCE; 65 } 66 getInstanceNoCreate()67 public static LauncherAppState getInstanceNoCreate() { 68 return INSTANCE; 69 } 70 getContext()71 public Context getContext() { 72 return sContext; 73 } 74 setApplicationContext(Context context)75 public static void setApplicationContext(Context context) { 76 if (sContext != null) { 77 Log.w(Launcher.TAG, "setApplicationContext called twice! old=" + sContext + " new=" + context); 78 } 79 sContext = context.getApplicationContext(); 80 } 81 LauncherAppState()82 private LauncherAppState() { 83 if (sContext == null) { 84 throw new IllegalStateException("LauncherAppState inited before app context set"); 85 } 86 87 Log.v(Launcher.TAG, "LauncherAppState inited"); 88 89 if (sContext.getResources().getBoolean(R.bool.debug_memory_enabled)) { 90 MemoryTracker.startTrackingMe(sContext, "L"); 91 } 92 93 // set sIsScreenXLarge and mScreenDensity *before* creating icon cache 94 mIsScreenLarge = isScreenLarge(sContext.getResources()); 95 mScreenDensity = sContext.getResources().getDisplayMetrics().density; 96 97 recreateWidgetPreviewDb(); 98 mIconCache = new IconCache(sContext); 99 100 mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class)); 101 mBuildInfo = BuildInfo.loadByName(sContext.getString(R.string.build_info_class)); 102 mModel = new LauncherModel(this, mIconCache, mAppFilter); 103 final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(sContext); 104 launcherApps.addOnAppsChangedCallback(mModel); 105 106 // Register intent receivers 107 IntentFilter filter = new IntentFilter(); 108 filter.addAction(Intent.ACTION_LOCALE_CHANGED); 109 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 110 sContext.registerReceiver(mModel, filter); 111 filter = new IntentFilter(); 112 filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED); 113 sContext.registerReceiver(mModel, filter); 114 filter = new IntentFilter(); 115 filter.addAction(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED); 116 sContext.registerReceiver(mModel, filter); 117 118 // Register for changes to the favorites 119 ContentResolver resolver = sContext.getContentResolver(); 120 resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true, 121 mFavoritesObserver); 122 } 123 recreateWidgetPreviewDb()124 public void recreateWidgetPreviewDb() { 125 if (mWidgetPreviewCacheDb != null) { 126 mWidgetPreviewCacheDb.close(); 127 } 128 mWidgetPreviewCacheDb = new WidgetPreviewLoader.CacheDb(sContext); 129 } 130 131 /** 132 * Call from Application.onTerminate(), which is not guaranteed to ever be called. 133 */ onTerminate()134 public void onTerminate() { 135 sContext.unregisterReceiver(mModel); 136 final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(sContext); 137 launcherApps.removeOnAppsChangedCallback(mModel); 138 139 ContentResolver resolver = sContext.getContentResolver(); 140 resolver.unregisterContentObserver(mFavoritesObserver); 141 } 142 143 /** 144 * Receives notifications whenever the user favorites have changed. 145 */ 146 private final ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) { 147 @Override 148 public void onChange(boolean selfChange) { 149 // If the database has ever changed, then we really need to force a reload of the 150 // workspace on the next load 151 mModel.resetLoadedState(false, true); 152 mModel.startLoaderFromBackground(); 153 } 154 }; 155 setLauncher(Launcher launcher)156 LauncherModel setLauncher(Launcher launcher) { 157 if (mModel == null) { 158 throw new IllegalStateException("setLauncher() called before init()"); 159 } 160 mModel.initialize(launcher); 161 return mModel; 162 } 163 getIconCache()164 public IconCache getIconCache() { 165 return mIconCache; 166 } 167 getModel()168 LauncherModel getModel() { 169 return mModel; 170 } 171 shouldShowAppOrWidgetProvider(ComponentName componentName)172 boolean shouldShowAppOrWidgetProvider(ComponentName componentName) { 173 return mAppFilter == null || mAppFilter.shouldShowApp(componentName); 174 } 175 getWidgetPreviewCacheDb()176 WidgetPreviewLoader.CacheDb getWidgetPreviewCacheDb() { 177 return mWidgetPreviewCacheDb; 178 } 179 setLauncherProvider(LauncherProvider provider)180 static void setLauncherProvider(LauncherProvider provider) { 181 sLauncherProvider = new WeakReference<LauncherProvider>(provider); 182 } 183 getLauncherProvider()184 static LauncherProvider getLauncherProvider() { 185 return sLauncherProvider.get(); 186 } 187 getSharedPreferencesKey()188 public static String getSharedPreferencesKey() { 189 return SHARED_PREFERENCES_KEY; 190 } 191 initDynamicGrid(Context context, int minWidth, int minHeight, int width, int height, int availableWidth, int availableHeight)192 DeviceProfile initDynamicGrid(Context context, int minWidth, int minHeight, 193 int width, int height, 194 int availableWidth, int availableHeight) { 195 if (mDynamicGrid == null) { 196 mDynamicGrid = new DynamicGrid(context, 197 context.getResources(), 198 minWidth, minHeight, width, height, 199 availableWidth, availableHeight); 200 mDynamicGrid.getDeviceProfile().addCallback(this); 201 } 202 203 // Update the icon size 204 DeviceProfile grid = mDynamicGrid.getDeviceProfile(); 205 grid.updateFromConfiguration(context, context.getResources(), width, height, 206 availableWidth, availableHeight); 207 return grid; 208 } getDynamicGrid()209 public DynamicGrid getDynamicGrid() { 210 return mDynamicGrid; 211 } 212 isScreenLarge()213 public boolean isScreenLarge() { 214 return mIsScreenLarge; 215 } 216 217 // Need a version that doesn't require an instance of LauncherAppState for the wallpaper picker isScreenLarge(Resources res)218 public static boolean isScreenLarge(Resources res) { 219 return res.getBoolean(R.bool.is_large_tablet); 220 } 221 isScreenLandscape(Context context)222 public static boolean isScreenLandscape(Context context) { 223 return context.getResources().getConfiguration().orientation == 224 Configuration.ORIENTATION_LANDSCAPE; 225 } 226 getScreenDensity()227 public float getScreenDensity() { 228 return mScreenDensity; 229 } 230 getLongPressTimeout()231 public int getLongPressTimeout() { 232 return mLongPressTimeout; 233 } 234 onWallpaperChanged()235 public void onWallpaperChanged() { 236 mWallpaperChangedSinceLastCheck = true; 237 } 238 hasWallpaperChangedSinceLastCheck()239 public boolean hasWallpaperChangedSinceLastCheck() { 240 boolean result = mWallpaperChangedSinceLastCheck; 241 mWallpaperChangedSinceLastCheck = false; 242 return result; 243 } 244 245 @Override onAvailableSizeChanged(DeviceProfile grid)246 public void onAvailableSizeChanged(DeviceProfile grid) { 247 Utilities.setIconSize(grid.iconSizePx); 248 } 249 isDisableAllApps()250 public static boolean isDisableAllApps() { 251 // Returns false on non-dogfood builds. 252 return getInstance().mBuildInfo.isDogfoodBuild() && 253 Launcher.isPropertyEnabled(Launcher.DISABLE_ALL_APPS_PROPERTY); 254 } 255 isDogfoodBuild()256 public static boolean isDogfoodBuild() { 257 return getInstance().mBuildInfo.isDogfoodBuild(); 258 } 259 setPackageState(ArrayList<PackageInstallInfo> installInfo)260 public void setPackageState(ArrayList<PackageInstallInfo> installInfo) { 261 mModel.setPackageState(installInfo); 262 } 263 264 /** 265 * Updates the icons and label of all icons for the provided package name. 266 */ updatePackageBadge(String packageName)267 public void updatePackageBadge(String packageName) { 268 mModel.updatePackageBadge(packageName); 269 } 270 } 271