LauncherAppState.java revision 00c3184fa6fae69123d160b92977799a1a47fa34
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.*;
21import android.content.res.Configuration;
22import android.content.res.Resources;
23import android.database.ContentObserver;
24import android.os.Handler;
25import android.util.Log;
26
27import java.lang.ref.WeakReference;
28
29public 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