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