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