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