14d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal/*
24d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal * Copyright (C) 2015 The Android Open Source Project
34d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal *
44d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal * Licensed under the Apache License, Version 2.0 (the "License");
54d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal * you may not use this file except in compliance with the License.
64d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal * You may obtain a copy of the License at
74d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal *
84d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal *      http://www.apache.org/licenses/LICENSE-2.0
94d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal *
104d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal * Unless required by applicable law or agreed to in writing, software
114d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal * distributed under the License is distributed on an "AS IS" BASIS,
124d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal * See the License for the specific language governing permissions and
144d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal * limitations under the License.
154d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal */
164d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal
1718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalpackage com.android.launcher3.util;
1818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
194d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyalimport android.annotation.TargetApi;
2018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport android.content.Context;
2118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport android.content.SharedPreferences;
2218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport android.content.pm.PackageInfo;
2318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport android.content.pm.PackageManager;
2418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport android.content.pm.PackageManager.NameNotFoundException;
254d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyalimport android.os.Build;
2618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport android.util.Log;
2718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
2818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.FolderInfo;
2918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.ItemInfo;
3018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.LauncherAppState;
3118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.LauncherFiles;
3218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.LauncherModel;
3318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.MainThreadExecutor;
3418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.R;
3518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.ShortcutInfo;
3618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.Utilities;
3718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.compat.LauncherActivityInfoCompat;
3818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.compat.LauncherAppsCompat;
3918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.compat.UserHandleCompat;
4018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport com.android.launcher3.compat.UserManagerCompat;
4118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
4218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport java.util.ArrayList;
4318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport java.util.Collections;
44a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyalimport java.util.Comparator;
4518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport java.util.HashSet;
4618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalimport java.util.List;
47a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyalimport java.util.Set;
4818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
4918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal/**
5018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal * Handles addition of app shortcuts for managed profiles.
5118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal * Methods of class should only be called on {@link LauncherModel#sWorkerThread}.
5218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal */
534d113a5ff44ff1a7f19263bde21581fbf9a54212Sunny Goyal@TargetApi(Build.VERSION_CODES.LOLLIPOP)
5418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyalpublic class ManagedProfileHeuristic {
5518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
5618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private static final String TAG = "ManagedProfileHeuristic";
5718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
5818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    /**
5918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     * Maintain a set of packages installed per user.
6018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     */
6118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private static final String INSTALLED_PACKAGES_PREFIX = "installed_packages_for_user_";
6218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
6318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private static final String USER_FOLDER_ID_PREFIX = "user_folder_";
6418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
6518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    /**
6618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     * Duration (in milliseconds) for which app shortcuts will be added to work folder.
6718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     */
6818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private static final long AUTO_ADD_TO_FOLDER_DURATION = 8 * 60 * 60 * 1000;
6918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
7018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    public static ManagedProfileHeuristic get(Context context, UserHandleCompat user) {
719fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal        if (Utilities.ATLEAST_LOLLIPOP && !UserHandleCompat.myUserHandle().equals(user)) {
7218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            return new ManagedProfileHeuristic(context, user);
7318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
7418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        return null;
7518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
7618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
7718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private final Context mContext;
7818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private final UserHandleCompat mUser;
7918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private final LauncherModel mModel;
8018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
8118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private final SharedPreferences mPrefs;
8218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private final long mUserSerial;
8318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private final long mUserCreationTime;
8418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private final String mPackageSetKey;
8518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
86a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal    private ArrayList<ShortcutInfo> mHomescreenApps;
87a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal    private ArrayList<ShortcutInfo> mWorkFolderApps;
8818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
8918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private ManagedProfileHeuristic(Context context, UserHandleCompat user) {
9018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        mContext = context;
9118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        mUser = user;
9218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        mModel = LauncherAppState.getInstance().getModel();
9318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
9418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        UserManagerCompat userManager = UserManagerCompat.getInstance(context);
9518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        mUserSerial = userManager.getSerialNumberForUser(user);
9618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        mUserCreationTime = userManager.getUserCreationTime(user);
9718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        mPackageSetKey = INSTALLED_PACKAGES_PREFIX + mUserSerial;
9818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
9918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        mPrefs = mContext.getSharedPreferences(LauncherFiles.MANAGED_USER_PREFERENCES_KEY,
10018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                Context.MODE_PRIVATE);
10118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
10218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
10318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    /**
10418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     * Checks the list of user apps and adds icons for newly installed apps on the homescreen or
10518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     * workfolder.
10618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     */
10718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    public void processUserApps(List<LauncherActivityInfoCompat> apps) {
108a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        mHomescreenApps = new ArrayList<>();
109a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        mWorkFolderApps = new ArrayList<>();
110a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal
111a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        HashSet<String> packageSet = new HashSet<>();
112a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        final boolean userAppsExisted = getUserApps(packageSet);
113a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal
11418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        boolean newPackageAdded = false;
11518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
11618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        for (LauncherActivityInfoCompat info : apps) {
11718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            String packageName = info.getComponentName().getPackageName();
11818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            if (!packageSet.contains(packageName)) {
11918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                packageSet.add(packageName);
12018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                newPackageAdded = true;
12118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
12218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                try {
12318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                    PackageInfo pkgInfo = mContext.getPackageManager()
12418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                            .getPackageInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
12518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                    markForAddition(info, pkgInfo.firstInstallTime);
12618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                } catch (NameNotFoundException e) {
12718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                    Log.e(TAG, "Unknown package " + packageName, e);
12818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                }
12918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            }
13018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
13118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
13218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        if (newPackageAdded) {
13318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply();
134a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            // Do not add shortcuts on the homescreen for the first time. This prevents the launcher
135a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            // getting filled with the managed user apps, when it start with a fresh DB (or after
136a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            // a very long time).
137a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            finalizeAdditions(userAppsExisted);
13818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
13918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
14018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
14118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private void markForAddition(LauncherActivityInfoCompat info, long installTime) {
142a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        ArrayList<ShortcutInfo> targetList =
14318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                (installTime <= mUserCreationTime + AUTO_ADD_TO_FOLDER_DURATION) ?
14418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                        mWorkFolderApps : mHomescreenApps;
14518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        targetList.add(ShortcutInfo.fromActivityInfo(info, mContext));
14618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
14718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
14818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    /**
14918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     * Adds and binds shortcuts marked to be added to the work folder.
15018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     */
15118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private void finalizeWorkFolder() {
15218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        if (mWorkFolderApps.isEmpty()) {
15318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            return;
15418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
155a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        Collections.sort(mWorkFolderApps, new Comparator<ShortcutInfo>() {
156a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal
157a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            @Override
158a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            public int compare(ShortcutInfo lhs, ShortcutInfo rhs) {
159a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal                return Long.compare(lhs.firstInstallTime, rhs.firstInstallTime);
160a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            }
161a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        });
16218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
16318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        // Try to get a work folder.
16418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        String folderIdKey = USER_FOLDER_ID_PREFIX + mUserSerial;
16518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        if (mPrefs.contains(folderIdKey)) {
16618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            long folderId = mPrefs.getLong(folderIdKey, 0);
16718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            final FolderInfo workFolder = mModel.findFolderById(folderId);
16818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
16918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            if (workFolder == null || !workFolder.hasOption(FolderInfo.FLAG_WORK_FOLDER)) {
17018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                // Could not get a work folder. Add all the icons to homescreen.
17118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                mHomescreenApps.addAll(mWorkFolderApps);
17218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                return;
17318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            }
17418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            saveWorkFolderShortcuts(folderId, workFolder.contents.size());
17518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
176a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            final ArrayList<ShortcutInfo> shortcuts = mWorkFolderApps;
17718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            // FolderInfo could already be bound. We need to add shortcuts on the UI thread.
17818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            new MainThreadExecutor().execute(new Runnable() {
17918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
18018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                @Override
18118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                public void run() {
182a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal                    for (ShortcutInfo info : shortcuts) {
183a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal                        workFolder.add(info);
18418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                    }
18518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                }
18618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            });
18718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        } else {
18818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            // Create a new folder.
18918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            final FolderInfo workFolder = new FolderInfo();
19018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            workFolder.title = mContext.getText(R.string.work_folder_name);
19118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            workFolder.setOption(FolderInfo.FLAG_WORK_FOLDER, true, null);
19218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
19318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            // Add all shortcuts before adding it to the UI, as an empty folder might get deleted.
194a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            for (ShortcutInfo info : mWorkFolderApps) {
195a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal                workFolder.add(info);
19618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            }
19718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
19818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            // Add the item to home screen and DB. This also generates an item id synchronously.
19918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            ArrayList<ItemInfo> itemList = new ArrayList<ItemInfo>(1);
20018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            itemList.add(workFolder);
20118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            mModel.addAndBindAddedWorkspaceItems(mContext, itemList);
20218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            mPrefs.edit().putLong(USER_FOLDER_ID_PREFIX + mUserSerial, workFolder.id).apply();
20318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
20418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            saveWorkFolderShortcuts(workFolder.id, 0);
20518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
20618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
20718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
20818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    /**
20918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     * Add work folder shortcuts to the DB.
21018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     */
21118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private void saveWorkFolderShortcuts(long workFolderId, int startingRank) {
21218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        for (ItemInfo info : mWorkFolderApps) {
21318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            info.rank = startingRank++;
21418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            LauncherModel.addItemToDatabase(mContext, info, workFolderId, 0, 0, 0);
21518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
21618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
21718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
21818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    /**
21918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     * Adds and binds all shortcuts marked for addition.
22018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     */
221a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal    private void finalizeAdditions(boolean addHomeScreenShortcuts) {
22218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        finalizeWorkFolder();
22318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
224a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        if (addHomeScreenShortcuts && !mHomescreenApps.isEmpty()) {
22518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            mModel.addAndBindAddedWorkspaceItems(mContext, mHomescreenApps);
22618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
22718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
22818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
22918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    /**
23018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     * Updates the list of installed apps and adds any new icons on homescreen or work folder.
23118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     */
23218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    public void processPackageAdd(String[] packages) {
233a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        mHomescreenApps = new ArrayList<>();
234a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        mWorkFolderApps = new ArrayList<>();
235a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal
236a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        HashSet<String> packageSet = new HashSet<>();
237a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        final boolean userAppsExisted = getUserApps(packageSet);
238a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal
23918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        boolean newPackageAdded = false;
24018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        long installTime = System.currentTimeMillis();
24118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
24218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
24318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        for (String packageName : packages) {
24418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            if (!packageSet.contains(packageName)) {
24518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                packageSet.add(packageName);
24618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                newPackageAdded = true;
24718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
24818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                List<LauncherActivityInfoCompat> activities =
24918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                        launcherApps.getActivityList(packageName, mUser);
25018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                if (!activities.isEmpty()) {
25118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                    markForAddition(activities.get(0), installTime);
25218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                }
25318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            }
25418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
25518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
25618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        if (newPackageAdded) {
25718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply();
258a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            finalizeAdditions(userAppsExisted);
25918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
26018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
26118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
26218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    /**
26318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     * Updates the list of installed packages for the user.
26418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     */
26518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    public void processPackageRemoved(String[] packages) {
266a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        HashSet<String> packageSet = new HashSet<String>();
267a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        getUserApps(packageSet);
26818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        boolean packageRemoved = false;
26918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
27018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        for (String packageName : packages) {
27118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            if (packageSet.remove(packageName)) {
27218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                packageRemoved = true;
27318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            }
27418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
27518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
27618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        if (packageRemoved) {
27718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply();
27818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
27918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
28018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
281a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal    /**
282a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal     * Reads the list of user apps which have already been processed.
283a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal     * @return false if the list didn't exist, true otherwise
284a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal     */
285a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal    private boolean getUserApps(HashSet<String> outExistingApps) {
286a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        Set<String> userApps = mPrefs.getStringSet(mPackageSetKey, null);
287a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        if (userApps == null) {
288a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            return false;
289a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        } else {
290a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            outExistingApps.addAll(userApps);
291a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal            return true;
292a214a63bfe365a0e81bc3082d56896c6df24d0b4Sunny Goyal        }
29318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
29418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
29518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    /**
29618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     * Verifies that entries corresponding to {@param users} exist and removes all invalid entries.
29718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal     */
29818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    public static void processAllUsers(List<UserHandleCompat> users, Context context) {
2999fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal        if (!Utilities.ATLEAST_LOLLIPOP) {
30018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            return;
30118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
30218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        UserManagerCompat userManager = UserManagerCompat.getInstance(context);
30318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        HashSet<String> validKeys = new HashSet<String>();
30418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        for (UserHandleCompat user : users) {
30518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            addAllUserKeys(userManager.getSerialNumberForUser(user), validKeys);
30618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
30718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
30818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        SharedPreferences prefs = context.getSharedPreferences(
30918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                LauncherFiles.MANAGED_USER_PREFERENCES_KEY,
31018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                Context.MODE_PRIVATE);
31118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        SharedPreferences.Editor editor = prefs.edit();
31218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        for (String key : prefs.getAll().keySet()) {
31318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            if (!validKeys.contains(key)) {
31418bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal                editor.remove(key);
31518bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal            }
31618bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        }
31718bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        editor.apply();
31818bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
31918bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal
32018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    private static void addAllUserKeys(long userSerial, HashSet<String> keysOut) {
32118bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        keysOut.add(INSTALLED_PACKAGES_PREFIX + userSerial);
32218bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal        keysOut.add(USER_FOLDER_ID_PREFIX + userSerial);
32318bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal    }
324e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal
325e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal    /**
326e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal     * For each user, if a work folder has not been created, mark it such that the folder will
327e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal     * never get created.
328e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal     */
329e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal    public static void markExistingUsersForNoFolderCreation(Context context) {
330e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal        UserManagerCompat userManager = UserManagerCompat.getInstance(context);
331e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal        UserHandleCompat myUser = UserHandleCompat.myUserHandle();
332e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal
333e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal        SharedPreferences prefs = null;
334e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal        for (UserHandleCompat user : userManager.getUserProfiles()) {
335e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal            if (myUser.equals(user)) {
336e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal                continue;
337e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal            }
338e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal
339e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal            if (prefs == null) {
340e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal                prefs = context.getSharedPreferences(
341e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal                        LauncherFiles.MANAGED_USER_PREFERENCES_KEY,
342e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal                        Context.MODE_PRIVATE);
343e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal            }
344e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal            String folderIdKey = USER_FOLDER_ID_PREFIX + userManager.getSerialNumberForUser(user);
345e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal            if (!prefs.contains(folderIdKey)) {
346e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal                prefs.edit().putLong(folderIdKey, ItemInfo.NO_ID).apply();
347e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal            }
348e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal        }
349e2fba6cba10d9b7996ebb86dfd67bed96cff0dedSunny Goyal    }
35018bf8e2ffde3444d53aaa9654da02cdedd0b7cd1Sunny Goyal}
351