1cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler/*
2cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler * Copyright (C) 2013 The Android Open Source Project
3cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler *
4cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler * Licensed under the Apache License, Version 2.0 (the "License");
5cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler * you may not use this file except in compliance with the License.
6cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler * You may obtain a copy of the License at
7cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler *
8cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler *      http://www.apache.org/licenses/LICENSE-2.0
9cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler *
10cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler * Unless required by applicable law or agreed to in writing, software
11cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler * distributed under the License is distributed on an "AS IS" BASIS,
12cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler * See the License for the specific language governing permissions and
14cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler * limitations under the License.
15cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler */
16cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
17cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandlerpackage com.android.launcher3;
18cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
19d48710c2835d891b216914ef1fdd3740e6cfc101Tonyimport android.content.ComponentName;
20fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyalimport android.content.ContentProviderClient;
21e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport android.content.Context;
22e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport android.content.Intent;
23e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport android.content.IntentFilter;
24fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyalimport android.os.Looper;
25b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandlerimport android.util.Log;
2671b5c0b988a64b3a0613ded5403749bc537ee8a5Sunny Goyal
27ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport com.android.launcher3.compat.LauncherAppsCompat;
284390acea35aefae52bd3fe38f5fdbb7ea322afb0Sunny Goyalimport com.android.launcher3.compat.PackageInstallerCompat;
29823fd5090209017a029460e7dbd8ab9d51d013ddSunny Goyalimport com.android.launcher3.compat.UserManagerCompat;
303d706ad70365052e3224fc4f4b0e7d1f5e8abf22Sunny Goyalimport com.android.launcher3.config.FeatureFlags;
31827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickhamimport com.android.launcher3.dynamicui.ExtractionUtils;
32d48710c2835d891b216914ef1fdd3740e6cfc101Tonyimport com.android.launcher3.notification.NotificationListener;
33ae50284e0a838139c67caf0064a0977c871497faSunny Goyalimport com.android.launcher3.util.ConfigMonitor;
34fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyalimport com.android.launcher3.util.Preconditions;
35d48710c2835d891b216914ef1fdd3740e6cfc101Tonyimport com.android.launcher3.util.SettingsObserver;
36322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport com.android.launcher3.util.TestingUtils;
3771b5c0b988a64b3a0613ded5403749bc537ee8a5Sunny Goyal
38fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyalimport java.util.concurrent.Callable;
39fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyalimport java.util.concurrent.ExecutionException;
40cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
41d48710c2835d891b216914ef1fdd3740e6cfc101Tonyimport static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
42d48710c2835d891b216914ef1fdd3740e6cfc101Tony
43c6205603efe1f2987caf96504c87d720a25b5a94Sunny Goyalpublic class LauncherAppState {
44aeff7ea43409d817490fbb8c22b8d4b9725bb54fChris Wren
453d706ad70365052e3224fc4f4b0e7d1f5e8abf22Sunny Goyal    public static final boolean PROFILE_STARTUP = FeatureFlags.IS_DOGFOOD_BUILD;
46e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal
47fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    // We do not need any synchronization for this variable as its only written on UI thread.
48fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private static LauncherAppState INSTANCE;
49fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal
50fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private final Context mContext;
51fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private final LauncherModel mModel;
52e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal    private final IconCache mIconCache;
535b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal    private final WidgetPreviewLoader mWidgetCache;
54fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private final InvariantDeviceProfile mInvariantDeviceProfile;
55d48710c2835d891b216914ef1fdd3740e6cfc101Tony    private final SettingsObserver mNotificationBadgingObserver;
56cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
57fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    public static LauncherAppState getInstance(final Context context) {
58e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        if (INSTANCE == null) {
59fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            if (Looper.myLooper() == Looper.getMainLooper()) {
60fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                INSTANCE = new LauncherAppState(context.getApplicationContext());
61fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            } else {
62fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                try {
63fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                    return new MainThreadExecutor().submit(new Callable<LauncherAppState>() {
64fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                        @Override
65fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                        public LauncherAppState call() throws Exception {
66fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                            return LauncherAppState.getInstance(context);
67fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                        }
68fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                    }).get();
69fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                } catch (InterruptedException|ExecutionException e) {
70fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                    throw new RuntimeException(e);
71fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                }
72fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            }
73e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        }
74cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        return INSTANCE;
75cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
76cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
77d8fe6de10d5ffc293f771b070bd1361a027757bbChris Wren    public static LauncherAppState getInstanceNoCreate() {
78d8fe6de10d5ffc293f771b070bd1361a027757bbChris Wren        return INSTANCE;
79d8fe6de10d5ffc293f771b070bd1361a027757bbChris Wren    }
80d8fe6de10d5ffc293f771b070bd1361a027757bbChris Wren
81cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    public Context getContext() {
82fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        return mContext;
83cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
84cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
85fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private LauncherAppState(Context context) {
86fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        if (getLocalProvider(context) == null) {
87fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            throw new RuntimeException(
88fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                    "Initializing LauncherAppState in the absence of LauncherProvider");
89e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        }
900de011705b132eacdd10f7bfb5cdc4bd79a147e8Hyunyoung Song        Log.v(Launcher.TAG, "LauncherAppState initiated");
91fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        Preconditions.assertUIThread();
92fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mContext = context;
93924b993c750e6de8537afb750c2d2b9932efbdacDaniel Sandler
94322d55622031985c75f7e5db07964b7730a97dacSunny Goyal        if (TestingUtils.MEMORY_DUMP_ENABLED) {
95fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            TestingUtils.startTrackingMemory(mContext);
96b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler        }
97b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler
98fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mInvariantDeviceProfile = new InvariantDeviceProfile(mContext);
99fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mIconCache = new IconCache(mContext, mInvariantDeviceProfile);
100fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
101c6e97692e4144a6fc33eb74fabb73b1aae9ff908Sunny Goyal        mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext));
10227595796b3c0373d1a1d56af9a30392bc7016624Sunny Goyal
103fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel);
104cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
105cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        // Register intent receivers
106ed13187a745866483139e2878037e1f8427ce567Kenny Guy        IntentFilter filter = new IntentFilter();
107cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        filter.addAction(Intent.ACTION_LOCALE_CHANGED);
108957c13f032fc4088b3273cec08603c67c069e2c6Sunny Goyal        // For handling managed profiles
109d3b87ef1963fb96177ca85bcd6a25879e27e419cSunny Goyal        filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
110d3b87ef1963fb96177ca85bcd6a25879e27e419cSunny Goyal        filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
111d3b87ef1963fb96177ca85bcd6a25879e27e419cSunny Goyal        filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
112d3b87ef1963fb96177ca85bcd6a25879e27e419cSunny Goyal        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
113d3b87ef1963fb96177ca85bcd6a25879e27e419cSunny Goyal        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
114827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham        // For extracting colors from the wallpaper
115f5e3744637db1598c389e62450627b2548f8f517Sunny Goyal        if (Utilities.ATLEAST_NOUGAT) {
116827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham            // TODO: add a broadcast entry to the manifest for pre-N.
117827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham            filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
118827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham        }
119957c13f032fc4088b3273cec08603c67c069e2c6Sunny Goyal
120fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mContext.registerReceiver(mModel, filter);
121fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        UserManagerCompat.getInstance(mContext).enableAndResetCache();
122fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        new ConfigMonitor(mContext).register();
123827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham
124fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        ExtractionUtils.startColorExtractionServiceIfNecessary(mContext);
125d48710c2835d891b216914ef1fdd3740e6cfc101Tony
126d48710c2835d891b216914ef1fdd3740e6cfc101Tony        if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) {
127d48710c2835d891b216914ef1fdd3740e6cfc101Tony            mNotificationBadgingObserver = null;
128d48710c2835d891b216914ef1fdd3740e6cfc101Tony        } else {
129d48710c2835d891b216914ef1fdd3740e6cfc101Tony            // Register an observer to rebind the notification listener when badging is re-enabled.
130d48710c2835d891b216914ef1fdd3740e6cfc101Tony            mNotificationBadgingObserver = new SettingsObserver.Secure(
131d48710c2835d891b216914ef1fdd3740e6cfc101Tony                    mContext.getContentResolver()) {
132d48710c2835d891b216914ef1fdd3740e6cfc101Tony                @Override
133d48710c2835d891b216914ef1fdd3740e6cfc101Tony                public void onSettingChanged(boolean isNotificationBadgingEnabled) {
134d48710c2835d891b216914ef1fdd3740e6cfc101Tony                    if (isNotificationBadgingEnabled) {
135d48710c2835d891b216914ef1fdd3740e6cfc101Tony                        NotificationListener.requestRebind(new ComponentName(
136d48710c2835d891b216914ef1fdd3740e6cfc101Tony                                mContext, NotificationListener.class));
137d48710c2835d891b216914ef1fdd3740e6cfc101Tony                    }
138d48710c2835d891b216914ef1fdd3740e6cfc101Tony                }
139d48710c2835d891b216914ef1fdd3740e6cfc101Tony            };
140d48710c2835d891b216914ef1fdd3740e6cfc101Tony            mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
141d48710c2835d891b216914ef1fdd3740e6cfc101Tony        }
142cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
1431317e2dd4a2fb097d1e54759536d515fdeca2c3eKenny Guy
144cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    /**
145cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler     * Call from Application.onTerminate(), which is not guaranteed to ever be called.
146cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler     */
147cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    public void onTerminate() {
148fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mContext.unregisterReceiver(mModel);
149fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
150c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy        launcherApps.removeOnAppsChangedCallback(mModel);
151fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        PackageInstallerCompat.getInstance(mContext).onStop();
152d48710c2835d891b216914ef1fdd3740e6cfc101Tony        if (mNotificationBadgingObserver != null) {
153d48710c2835d891b216914ef1fdd3740e6cfc101Tony            mNotificationBadgingObserver.unregister();
154d48710c2835d891b216914ef1fdd3740e6cfc101Tony        }
155cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
156cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
157cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    LauncherModel setLauncher(Launcher launcher) {
158fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
159cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        mModel.initialize(launcher);
160cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        return mModel;
161cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
162cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
163349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal    public IconCache getIconCache() {
164cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        return mIconCache;
165cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
166cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
16718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    public LauncherModel getModel() {
168cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        return mModel;
169cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
170cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
1715b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal    public WidgetPreviewLoader getWidgetCache() {
1725b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal        return mWidgetCache;
1735b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal    }
174a6a0547fa6df0769fcd107a2e5f7c7d527fa0700Michael Jurka
1752e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen    public InvariantDeviceProfile getInvariantDeviceProfile() {
1762e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen        return mInvariantDeviceProfile;
1772e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen    }
17887f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal
17987f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal    /**
18087f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal     * Shorthand for {@link #getInvariantDeviceProfile()}
18187f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal     */
18287f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal    public static InvariantDeviceProfile getIDP(Context context) {
18387f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal        return LauncherAppState.getInstance(context).getInvariantDeviceProfile();
18487f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal    }
185fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal
186fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private static LauncherProvider getLocalProvider(Context context) {
187fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        try (ContentProviderClient cl = context.getContentResolver()
188fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                .acquireContentProviderClient(LauncherProvider.AUTHORITY)) {
189fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            return (LauncherProvider) cl.getLocalContentProvider();
190fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        }
191fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    }
192cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler}
193