LauncherAppState.java revision ee52336a9ed0c98f78831a0e44b21f5a8d8c17d1
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.app.SearchManager; 20import android.content.ComponentName; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.content.res.Configuration; 26import android.content.res.Resources; 27import android.database.ContentObserver; 28import android.os.Handler; 29import android.util.Log; 30 31import com.android.launcher3.compat.LauncherAppsCompat; 32import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; 33 34import java.lang.ref.WeakReference; 35import java.util.ArrayList; 36 37public 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 60 public static LauncherAppState getInstance() { 61 if (INSTANCE == null) { 62 INSTANCE = new LauncherAppState(); 63 } 64 return INSTANCE; 65 } 66 67 public static LauncherAppState getInstanceNoCreate() { 68 return INSTANCE; 69 } 70 71 public Context getContext() { 72 return sContext; 73 } 74 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 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 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 */ 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 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 164 public IconCache getIconCache() { 165 return mIconCache; 166 } 167 168 LauncherModel getModel() { 169 return mModel; 170 } 171 172 boolean shouldShowAppOrWidgetProvider(ComponentName componentName) { 173 return mAppFilter == null || mAppFilter.shouldShowApp(componentName); 174 } 175 176 WidgetPreviewLoader.CacheDb getWidgetPreviewCacheDb() { 177 return mWidgetPreviewCacheDb; 178 } 179 180 static void setLauncherProvider(LauncherProvider provider) { 181 sLauncherProvider = new WeakReference<LauncherProvider>(provider); 182 } 183 184 static LauncherProvider getLauncherProvider() { 185 return sLauncherProvider.get(); 186 } 187 188 public static String getSharedPreferencesKey() { 189 return SHARED_PREFERENCES_KEY; 190 } 191 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 } 209 public DynamicGrid getDynamicGrid() { 210 return mDynamicGrid; 211 } 212 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 218 public static boolean isScreenLarge(Resources res) { 219 return res.getBoolean(R.bool.is_large_tablet); 220 } 221 222 public static boolean isScreenLandscape(Context context) { 223 return context.getResources().getConfiguration().orientation == 224 Configuration.ORIENTATION_LANDSCAPE; 225 } 226 227 public float getScreenDensity() { 228 return mScreenDensity; 229 } 230 231 public int getLongPressTimeout() { 232 return mLongPressTimeout; 233 } 234 235 public void onWallpaperChanged() { 236 mWallpaperChangedSinceLastCheck = true; 237 } 238 239 public boolean hasWallpaperChangedSinceLastCheck() { 240 boolean result = mWallpaperChangedSinceLastCheck; 241 mWallpaperChangedSinceLastCheck = false; 242 return result; 243 } 244 245 @Override 246 public void onAvailableSizeChanged(DeviceProfile grid) { 247 Utilities.setIconSize(grid.iconSizePx); 248 } 249 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 256 public static boolean isDogfoodBuild() { 257 return getInstance().mBuildInfo.isDogfoodBuild(); 258 } 259 260 public void setPackageState(ArrayList<PackageInstallInfo> installInfo) { 261 mModel.setPackageState(installInfo); 262 } 263} 264