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
19fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyalimport android.content.ContentProviderClient;
20e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport android.content.Context;
21e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport android.content.Intent;
22e755d469d40b95e763a9dcb67d0e4f511d1948ddSunny Goyalimport android.content.IntentFilter;
23fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyalimport android.os.Looper;
24b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandlerimport android.util.Log;
2571b5c0b988a64b3a0613ded5403749bc537ee8a5Sunny Goyal
26ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport com.android.launcher3.compat.LauncherAppsCompat;
274390acea35aefae52bd3fe38f5fdbb7ea322afb0Sunny Goyalimport com.android.launcher3.compat.PackageInstallerCompat;
28823fd5090209017a029460e7dbd8ab9d51d013ddSunny Goyalimport com.android.launcher3.compat.UserManagerCompat;
29e26d1008eb587303db25797ca02cc32464e45656Sunny Goyalimport com.android.launcher3.config.ProviderConfig;
30827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickhamimport com.android.launcher3.dynamicui.ExtractionUtils;
31ae50284e0a838139c67caf0064a0977c871497faSunny Goyalimport com.android.launcher3.util.ConfigMonitor;
32fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyalimport com.android.launcher3.util.Preconditions;
33322d55622031985c75f7e5db07964b7730a97dacSunny Goyalimport com.android.launcher3.util.TestingUtils;
3471b5c0b988a64b3a0613ded5403749bc537ee8a5Sunny Goyal
35fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyalimport java.util.concurrent.Callable;
36fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyalimport java.util.concurrent.ExecutionException;
37cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
38c6205603efe1f2987caf96504c87d720a25b5a94Sunny Goyalpublic class LauncherAppState {
39aeff7ea43409d817490fbb8c22b8d4b9725bb54fChris Wren
40e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal    public static final boolean PROFILE_STARTUP = ProviderConfig.IS_DOGFOOD_BUILD;
41e26d1008eb587303db25797ca02cc32464e45656Sunny Goyal
42fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    // We do not need any synchronization for this variable as its only written on UI thread.
43fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private static LauncherAppState INSTANCE;
44fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal
45fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private final Context mContext;
46fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private final LauncherModel mModel;
47e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal    private final IconCache mIconCache;
485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal    private final WidgetPreviewLoader mWidgetCache;
49fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private final InvariantDeviceProfile mInvariantDeviceProfile;
50e0f58d73646871497596fb8f7321d407e7565c28Sunny Goyal
51cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
52fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    public static LauncherAppState getInstance(final Context context) {
53e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        if (INSTANCE == null) {
54fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            if (Looper.myLooper() == Looper.getMainLooper()) {
55fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                INSTANCE = new LauncherAppState(context.getApplicationContext());
56fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            } else {
57fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                try {
58fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                    return new MainThreadExecutor().submit(new Callable<LauncherAppState>() {
59fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                        @Override
60fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                        public LauncherAppState call() throws Exception {
61fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                            return LauncherAppState.getInstance(context);
62fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                        }
63fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                    }).get();
64fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                } catch (InterruptedException|ExecutionException e) {
65fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                    throw new RuntimeException(e);
66fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                }
67fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            }
68e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        }
69cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        return INSTANCE;
70cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
71cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
72d8fe6de10d5ffc293f771b070bd1361a027757bbChris Wren    public static LauncherAppState getInstanceNoCreate() {
73d8fe6de10d5ffc293f771b070bd1361a027757bbChris Wren        return INSTANCE;
74d8fe6de10d5ffc293f771b070bd1361a027757bbChris Wren    }
75d8fe6de10d5ffc293f771b070bd1361a027757bbChris Wren
76cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    public Context getContext() {
77fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        return mContext;
78cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
79cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
80fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private LauncherAppState(Context context) {
81fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        if (getLocalProvider(context) == null) {
82fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            throw new RuntimeException(
83fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                    "Initializing LauncherAppState in the absence of LauncherProvider");
84e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        }
850de011705b132eacdd10f7bfb5cdc4bd79a147e8Hyunyoung Song        Log.v(Launcher.TAG, "LauncherAppState initiated");
86fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        Preconditions.assertUIThread();
87fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mContext = context;
88924b993c750e6de8537afb750c2d2b9932efbdacDaniel Sandler
89322d55622031985c75f7e5db07964b7730a97dacSunny Goyal        if (TestingUtils.MEMORY_DUMP_ENABLED) {
90fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            TestingUtils.startTrackingMemory(mContext);
91b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler        }
92b9eb2865af05d9ade572e71934a9e6a50421aa7dDaniel Sandler
93fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mInvariantDeviceProfile = new InvariantDeviceProfile(mContext);
94fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mIconCache = new IconCache(mContext, mInvariantDeviceProfile);
95fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
961307f63f8a93541bf6e2d29c11fab69778a25e42Bjorn Bringert
97ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal        mModel = new LauncherModel(this, mIconCache,
98fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                Utilities.getOverrideObject(AppFilter.class, mContext, R.string.app_filter_class));
9927595796b3c0373d1a1d56af9a30392bc7016624Sunny Goyal
100fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        LauncherAppsCompat.getInstance(mContext).addOnAppsChangedCallback(mModel);
101cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
102cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        // Register intent receivers
103ed13187a745866483139e2878037e1f8427ce567Kenny Guy        IntentFilter filter = new IntentFilter();
104cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        filter.addAction(Intent.ACTION_LOCALE_CHANGED);
105957c13f032fc4088b3273cec08603c67c069e2c6Sunny Goyal        // For handling managed profiles
106d3b87ef1963fb96177ca85bcd6a25879e27e419cSunny Goyal        filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
107d3b87ef1963fb96177ca85bcd6a25879e27e419cSunny Goyal        filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
108d3b87ef1963fb96177ca85bcd6a25879e27e419cSunny Goyal        filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
109d3b87ef1963fb96177ca85bcd6a25879e27e419cSunny Goyal        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
110d3b87ef1963fb96177ca85bcd6a25879e27e419cSunny Goyal        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
111827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham        // For extracting colors from the wallpaper
112f5e3744637db1598c389e62450627b2548f8f517Sunny Goyal        if (Utilities.ATLEAST_NOUGAT) {
113827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham            // TODO: add a broadcast entry to the manifest for pre-N.
114827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham            filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
115827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham        }
116957c13f032fc4088b3273cec08603c67c069e2c6Sunny Goyal
117fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mContext.registerReceiver(mModel, filter);
118fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        UserManagerCompat.getInstance(mContext).enableAndResetCache();
119fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        new ConfigMonitor(mContext).register();
120827cef203f386cb548b98a7fa9888b75478c8e20Tony Wickham
121fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        ExtractionUtils.startColorExtractionServiceIfNecessary(mContext);
122cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
1231317e2dd4a2fb097d1e54759536d515fdeca2c3eKenny Guy
124cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    /**
125cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler     * Call from Application.onTerminate(), which is not guaranteed to ever be called.
126cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler     */
127cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    public void onTerminate() {
128fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        mContext.unregisterReceiver(mModel);
129fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
130c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy        launcherApps.removeOnAppsChangedCallback(mModel);
131fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        PackageInstallerCompat.getInstance(mContext).onStop();
132cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
133cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
134cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    LauncherModel setLauncher(Launcher launcher) {
135fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
136cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        mModel.initialize(launcher);
137cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        return mModel;
138cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
139cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
140349426234e8c5a0e5bcf2c8d94dbb9844b5f724aSunny Goyal    public IconCache getIconCache() {
141cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        return mIconCache;
142cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
143cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
14418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    public LauncherModel getModel() {
145cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        return mModel;
146cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler    }
147cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler
1485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal    public WidgetPreviewLoader getWidgetCache() {
1495b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal        return mWidgetCache;
1505b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal    }
151a6a0547fa6df0769fcd107a2e5f7c7d527fa0700Michael Jurka
1522e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen    public InvariantDeviceProfile getInvariantDeviceProfile() {
1532e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen        return mInvariantDeviceProfile;
1542e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen    }
15587f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal
15687f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal    /**
15787f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal     * Shorthand for {@link #getInvariantDeviceProfile()}
15887f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal     */
15987f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal    public static InvariantDeviceProfile getIDP(Context context) {
16087f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal        return LauncherAppState.getInstance(context).getInvariantDeviceProfile();
16187f784c285fdeed9091a4de8b9b44db3eca677d8Sunny Goyal    }
162fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal
163fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    private static LauncherProvider getLocalProvider(Context context) {
164fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        try (ContentProviderClient cl = context.getContentResolver()
165fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal                .acquireContentProviderClient(LauncherProvider.AUTHORITY)) {
166fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal            return (LauncherProvider) cl.getLocalContentProvider();
167fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal        }
168fdbef27759bdd5ccaca6a0e70fbdf008c0053981Sunny Goyal    }
169cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler}
170