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.provider.Settings; 26 import android.util.Log; 27 import android.view.Display; 28 29 import java.lang.ref.WeakReference; 30 31 public class LauncherAppState { 32 private static final String TAG = "LauncherAppState"; 33 private static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs"; 34 35 private LauncherModel mModel; 36 private IconCache mIconCache; 37 private AppFilter mAppFilter; 38 private WidgetPreviewLoader.CacheDb mWidgetPreviewCacheDb; 39 private boolean mIsScreenLarge; 40 private float mScreenDensity; 41 private int mLongPressTimeout = 300; 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 mWidgetPreviewCacheDb = new WidgetPreviewLoader.CacheDb(sContext); 88 mIconCache = new IconCache(sContext); 89 90 mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class)); 91 mModel = new LauncherModel(this, mIconCache, mAppFilter); 92 93 // Register intent receivers 94 IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); 95 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 96 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 97 filter.addDataScheme("package"); 98 sContext.registerReceiver(mModel, filter); 99 filter = new IntentFilter(); 100 filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 101 filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 102 filter.addAction(Intent.ACTION_LOCALE_CHANGED); 103 filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 104 sContext.registerReceiver(mModel, filter); 105 filter = new IntentFilter(); 106 filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED); 107 sContext.registerReceiver(mModel, filter); 108 filter = new IntentFilter(); 109 filter.addAction(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED); 110 sContext.registerReceiver(mModel, filter); 111 112 // Register for changes to the favorites 113 ContentResolver resolver = sContext.getContentResolver(); 114 resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true, 115 mFavoritesObserver); 116 } 117 118 /** 119 * Call from Application.onTerminate(), which is not guaranteed to ever be called. 120 */ 121 public void onTerminate() { 122 sContext.unregisterReceiver(mModel); 123 124 ContentResolver resolver = sContext.getContentResolver(); 125 resolver.unregisterContentObserver(mFavoritesObserver); 126 } 127 128 /** 129 * Receives notifications whenever the user favorites have changed. 130 */ 131 private final ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) { 132 @Override 133 public void onChange(boolean selfChange) { 134 // If the database has ever changed, then we really need to force a reload of the 135 // workspace on the next load 136 mModel.resetLoadedState(false, true); 137 mModel.startLoaderFromBackground(); 138 } 139 }; 140 141 LauncherModel setLauncher(Launcher launcher) { 142 if (mModel == null) { 143 throw new IllegalStateException("setLauncher() called before init()"); 144 } 145 mModel.initialize(launcher); 146 return mModel; 147 } 148 149 IconCache getIconCache() { 150 return mIconCache; 151 } 152 153 LauncherModel getModel() { 154 return mModel; 155 } 156 157 boolean shouldShowAppOrWidgetProvider(ComponentName componentName) { 158 return mAppFilter == null || mAppFilter.shouldShowApp(componentName); 159 } 160 161 WidgetPreviewLoader.CacheDb getWidgetPreviewCacheDb() { 162 return mWidgetPreviewCacheDb; 163 } 164 165 static void setLauncherProvider(LauncherProvider provider) { 166 sLauncherProvider = new WeakReference<LauncherProvider>(provider); 167 } 168 169 static LauncherProvider getLauncherProvider() { 170 return sLauncherProvider.get(); 171 } 172 173 public static String getSharedPreferencesKey() { 174 return SHARED_PREFERENCES_KEY; 175 } 176 177 DeviceProfile initDynamicGrid(Context context, int minWidth, int minHeight, 178 int width, int height, 179 int availableWidth, int availableHeight) { 180 if (mDynamicGrid == null) { 181 mDynamicGrid = new DynamicGrid(context, 182 context.getResources(), 183 minWidth, minHeight, width, height, 184 availableWidth, availableHeight); 185 } 186 187 // Update the icon size 188 DeviceProfile grid = mDynamicGrid.getDeviceProfile(); 189 Utilities.setIconSize(grid.iconSizePx); 190 grid.updateFromConfiguration(context.getResources(), width, height, 191 availableWidth, availableHeight); 192 return grid; 193 } 194 DynamicGrid getDynamicGrid() { 195 return mDynamicGrid; 196 } 197 198 public boolean isScreenLarge() { 199 return mIsScreenLarge; 200 } 201 202 // Need a version that doesn't require an instance of LauncherAppState for the wallpaper picker 203 public static boolean isScreenLarge(Resources res) { 204 return res.getBoolean(R.bool.is_large_tablet); 205 } 206 207 public static boolean isScreenLandscape(Context context) { 208 return context.getResources().getConfiguration().orientation == 209 Configuration.ORIENTATION_LANDSCAPE; 210 } 211 212 public float getScreenDensity() { 213 return mScreenDensity; 214 } 215 216 public int getLongPressTimeout() { 217 return mLongPressTimeout; 218 } 219 } 220