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