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 getInstance()50 public static LauncherAppState getInstance() { 51 if (INSTANCE == null) { 52 INSTANCE = new LauncherAppState(); 53 } 54 return INSTANCE; 55 } 56 getInstanceNoCreate()57 public static LauncherAppState getInstanceNoCreate() { 58 return INSTANCE; 59 } 60 getContext()61 public Context getContext() { 62 return sContext; 63 } 64 setApplicationContext(Context context)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 LauncherAppState()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 recreateWidgetPreviewDb()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 */ onTerminate()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 setLauncher(Launcher launcher)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 getIconCache()157 IconCache getIconCache() { 158 return mIconCache; 159 } 160 getModel()161 LauncherModel getModel() { 162 return mModel; 163 } 164 shouldShowAppOrWidgetProvider(ComponentName componentName)165 boolean shouldShowAppOrWidgetProvider(ComponentName componentName) { 166 return mAppFilter == null || mAppFilter.shouldShowApp(componentName); 167 } 168 getWidgetPreviewCacheDb()169 WidgetPreviewLoader.CacheDb getWidgetPreviewCacheDb() { 170 return mWidgetPreviewCacheDb; 171 } 172 setLauncherProvider(LauncherProvider provider)173 static void setLauncherProvider(LauncherProvider provider) { 174 sLauncherProvider = new WeakReference<LauncherProvider>(provider); 175 } 176 getLauncherProvider()177 static LauncherProvider getLauncherProvider() { 178 return sLauncherProvider.get(); 179 } 180 getSharedPreferencesKey()181 public static String getSharedPreferencesKey() { 182 return SHARED_PREFERENCES_KEY; 183 } 184 initDynamicGrid(Context context, int minWidth, int minHeight, int width, int height, int availableWidth, int availableHeight)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 } getDynamicGrid()202 public DynamicGrid getDynamicGrid() { 203 return mDynamicGrid; 204 } 205 isScreenLarge()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 isScreenLarge(Resources res)211 public static boolean isScreenLarge(Resources res) { 212 return res.getBoolean(R.bool.is_large_tablet); 213 } 214 isScreenLandscape(Context context)215 public static boolean isScreenLandscape(Context context) { 216 return context.getResources().getConfiguration().orientation == 217 Configuration.ORIENTATION_LANDSCAPE; 218 } 219 getScreenDensity()220 public float getScreenDensity() { 221 return mScreenDensity; 222 } 223 getLongPressTimeout()224 public int getLongPressTimeout() { 225 return mLongPressTimeout; 226 } 227 onWallpaperChanged()228 public void onWallpaperChanged() { 229 mWallpaperChangedSinceLastCheck = true; 230 } 231 hasWallpaperChangedSinceLastCheck()232 public boolean hasWallpaperChangedSinceLastCheck() { 233 boolean result = mWallpaperChangedSinceLastCheck; 234 mWallpaperChangedSinceLastCheck = false; 235 return result; 236 } 237 238 @Override onAvailableSizeChanged(DeviceProfile grid)239 public void onAvailableSizeChanged(DeviceProfile grid) { 240 Utilities.setIconSize(grid.iconSizePx); 241 } 242 isDisableAllApps()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 isDogfoodBuild()249 public static boolean isDogfoodBuild() { 250 return getInstance().mBuildInfo.isDogfoodBuild(); 251 } 252 } 253