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