Loading src/com/android/launcher3/util/CachedPackageTracker.java 0 → 100644 +188 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.launcher3.util; import android.content.Context; import android.content.SharedPreferences; import com.android.launcher3.Utilities; import com.android.launcher3.compat.LauncherActivityInfoCompat; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.LauncherAppsCompat.OnAppsChangedCallbackCompat; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Utility class to track list of installed packages. It persists the list so that apps * installed/uninstalled while Launcher was dead can also be handled properly. */ public abstract class CachedPackageTracker implements OnAppsChangedCallbackCompat { protected static final String INSTALLED_PACKAGES_PREFIX = "installed_packages_for_user_"; protected final SharedPreferences mPrefs; protected final UserManagerCompat mUserManager; protected final LauncherAppsCompat mLauncherApps; public CachedPackageTracker(Context context, String preferenceFileName) { mPrefs = context.getSharedPreferences(preferenceFileName, Context.MODE_PRIVATE); mUserManager = UserManagerCompat.getInstance(context); mLauncherApps = LauncherAppsCompat.getInstance(context); } /** * Checks the list of user apps, and generates package event accordingly. * {@see #onLauncherAppsAdded}, {@see #onLauncherPackageRemoved} */ public void processUserApps(List<LauncherActivityInfoCompat> apps, UserHandleCompat user) { String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user); HashSet<String> oldPackageSet = new HashSet<>(); final boolean userAppsExisted = getUserApps(oldPackageSet, prefKey); HashSet<String> packagesRemoved = new HashSet<>(oldPackageSet); HashSet<String> newPackageSet = new HashSet<>(); ArrayList<LauncherActivityInstallInfo> packagesAdded = new ArrayList<>(); for (LauncherActivityInfoCompat info : apps) { String packageName = info.getComponentName().getPackageName(); newPackageSet.add(packageName); packagesRemoved.remove(packageName); if (!oldPackageSet.contains(packageName)) { oldPackageSet.add(packageName); packagesAdded.add(new LauncherActivityInstallInfo( info, info.getFirstInstallTime())); } } if (!packagesAdded.isEmpty() || !packagesRemoved.isEmpty()) { mPrefs.edit().putStringSet(prefKey, newPackageSet).apply(); if (!packagesAdded.isEmpty()) { Collections.sort(packagesAdded); onLauncherAppsAdded(packagesAdded, user, userAppsExisted); } if (!packagesRemoved.isEmpty()) { for (String pkg : packagesRemoved) { onLauncherPackageRemoved(pkg, user); } } } } /** * Reads the list of user apps which have already been processed. * @return false if the list didn't exist, true otherwise */ private boolean getUserApps(HashSet<String> outExistingApps, String prefKey) { Set<String> userApps = mPrefs.getStringSet(prefKey, null); if (userApps == null) { return false; } else { outExistingApps.addAll(userApps); return true; } } @Override public void onPackageRemoved(String packageName, UserHandleCompat user) { String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user); HashSet<String> packageSet = new HashSet<>(); if (getUserApps(packageSet, prefKey) && packageSet.remove(packageName)) { mPrefs.edit().putStringSet(prefKey, packageSet).apply(); } onLauncherPackageRemoved(packageName, user); } @Override public void onPackageAdded(String packageName, UserHandleCompat user) { String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user); HashSet<String> packageSet = new HashSet<>(); final boolean userAppsExisted = getUserApps(packageSet, prefKey); if (!packageSet.contains(packageName)) { List<LauncherActivityInfoCompat> activities = mLauncherApps.getActivityList(packageName, user); if (!activities.isEmpty()) { LauncherActivityInfoCompat activityInfo = activities.get(0); packageSet.add(packageName); mPrefs.edit().putStringSet(prefKey, packageSet).apply(); onLauncherAppsAdded(Arrays.asList( new LauncherActivityInstallInfo(activityInfo, System.currentTimeMillis())), user, userAppsExisted); } } } @Override public void onPackageChanged(String packageName, UserHandleCompat user) { } @Override public void onPackagesAvailable( String[] packageNames, UserHandleCompat user, boolean replacing) { } @Override public void onPackagesUnavailable( String[] packageNames, UserHandleCompat user, boolean replacing) { } @Override public void onPackagesSuspended(String[] packageNames, UserHandleCompat user) { } @Override public void onPackagesUnsuspended(String[] packageNames, UserHandleCompat user) { } /** * Called when new launcher apps are added. * @param apps list of newly added activities. Only one entry per package is sent. * @param user the user for this event. All activities in {@param apps} will belong to * the same user. * @param userAppsExisted false if the list was processed for the first time, like in case * when Launcher was newly installed or a new user was added. */ protected abstract void onLauncherAppsAdded(List<LauncherActivityInstallInfo> apps, UserHandleCompat user, boolean userAppsExisted); /** * Called when apps are removed from the system. */ protected abstract void onLauncherPackageRemoved(String packageName, UserHandleCompat user); protected static class LauncherActivityInstallInfo implements Comparable<LauncherActivityInstallInfo> { public final LauncherActivityInfoCompat info; public final long installTime; public LauncherActivityInstallInfo(LauncherActivityInfoCompat info, long installTime) { this.info = info; this.installTime = installTime; } @Override public int compareTo(LauncherActivityInstallInfo another) { return Utilities.longCompare(installTime, another.installTime); } } } src/com/android/launcher3/util/ManagedProfileHeuristic.java +90 −195 Original line number Diff line number Diff line Loading @@ -16,14 +16,8 @@ package com.android.launcher3.util; import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import android.util.Log; import com.android.launcher3.FolderInfo; import com.android.launcher3.ItemInfo; Loading @@ -35,27 +29,19 @@ import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; import com.android.launcher3.compat.LauncherActivityInfoCompat; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Handles addition of app shortcuts for managed profiles. * Methods of class should only be called on {@link LauncherModel#sWorkerThread}. */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) public class ManagedProfileHeuristic { private static final String TAG = "ManagedProfileHeuristic"; /** * Maintain a set of packages installed per user. */ Loading @@ -76,118 +62,100 @@ public class ManagedProfileHeuristic { } private final Context mContext; private final UserHandleCompat mUser; private final LauncherModel mModel; private final SharedPreferences mPrefs; private final long mUserSerial; private final long mUserCreationTime; private final String mPackageSetKey; private ArrayList<ShortcutInfo> mHomescreenApps; private ArrayList<ShortcutInfo> mWorkFolderApps; private HashMap<ShortcutInfo, Long> mShortcutToInstallTimeMap; private final UserHandleCompat mUser; private ManagedProfileHeuristic(Context context, UserHandleCompat user) { mContext = context; mUser = user; mModel = LauncherAppState.getInstance().getModel(); } UserManagerCompat userManager = UserManagerCompat.getInstance(context); mUserSerial = userManager.getSerialNumberForUser(user); mUserCreationTime = userManager.getUserCreationTime(user); mPackageSetKey = INSTALLED_PACKAGES_PREFIX + mUserSerial; mPrefs = mContext.getSharedPreferences(LauncherFiles.MANAGED_USER_PREFERENCES_KEY, Context.MODE_PRIVATE); public void processPackageRemoved(String[] packages) { Preconditions.assertWorkerThread(); ManagedProfilePackageHandler handler = new ManagedProfilePackageHandler(); for (String pkg : packages) { handler.onPackageRemoved(pkg, mUser); } } private void initVars() { mHomescreenApps = new ArrayList<>(); mWorkFolderApps = new ArrayList<>(); mShortcutToInstallTimeMap = new HashMap<>(); public void processPackageAdd(String[] packages) { Preconditions.assertWorkerThread(); ManagedProfilePackageHandler handler = new ManagedProfilePackageHandler(); for (String pkg : packages) { handler.onPackageAdded(pkg, mUser); } } /** * Checks the list of user apps and adds icons for newly installed apps on the homescreen or * workfolder. */ public void processUserApps(List<LauncherActivityInfoCompat> apps) { initVars(); Preconditions.assertWorkerThread(); new ManagedProfilePackageHandler().processUserApps(apps, mUser); } HashSet<String> packageSet = new HashSet<>(); final boolean userAppsExisted = getUserApps(packageSet); private class ManagedProfilePackageHandler extends CachedPackageTracker { boolean newPackageAdded = false; for (LauncherActivityInfoCompat info : apps) { String packageName = info.getComponentName().getPackageName(); if (!packageSet.contains(packageName)) { packageSet.add(packageName); newPackageAdded = true; markForAddition(info, info.getFirstInstallTime()); private ManagedProfilePackageHandler() { super(mContext, LauncherFiles.MANAGED_USER_PREFERENCES_KEY); } protected void onLauncherAppsAdded( List<LauncherActivityInstallInfo> apps, UserHandleCompat user, boolean userAppsExisted) { ArrayList<ShortcutInfo> workFolderApps = new ArrayList<>(); ArrayList<ShortcutInfo> homescreenApps = new ArrayList<>(); int count = apps.size(); long folderCreationTime = mUserManager.getUserCreationTime(user) + AUTO_ADD_TO_FOLDER_DURATION; for (int i = 0; i < count; i++) { LauncherActivityInstallInfo info = apps.get(i); ShortcutInfo si = ShortcutInfo.fromActivityInfo(info.info, mContext); ((info.installTime <= folderCreationTime) ? workFolderApps : homescreenApps).add(si); } if (newPackageAdded) { mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply(); finalizeWorkFolder(user, workFolderApps, homescreenApps); // Do not add shortcuts on the homescreen for the first time. This prevents the launcher // getting filled with the managed user apps, when it start with a fresh DB (or after // a very long time). finalizeAdditions(userAppsExisted); } if (userAppsExisted && !homescreenApps.isEmpty()) { mModel.addAndBindAddedWorkspaceItems(mContext, homescreenApps); } private void markForAddition(LauncherActivityInfoCompat info, long installTime) { ArrayList<ShortcutInfo> targetList = (installTime <= mUserCreationTime + AUTO_ADD_TO_FOLDER_DURATION) ? mWorkFolderApps : mHomescreenApps; ShortcutInfo si = ShortcutInfo.fromActivityInfo(info, mContext); mShortcutToInstallTimeMap.put(si, installTime); targetList.add(si); } private void sortList(ArrayList<ShortcutInfo> infos) { Collections.sort(infos, new Comparator<ShortcutInfo>() { @Override public int compare(ShortcutInfo lhs, ShortcutInfo rhs) { Long lhsTime = mShortcutToInstallTimeMap.get(lhs); Long rhsTime = mShortcutToInstallTimeMap.get(rhs); return Utilities.longCompare(lhsTime == null ? 0 : lhsTime, rhsTime == null ? 0 : rhsTime); } }); protected void onLauncherPackageRemoved(String packageName, UserHandleCompat user) { } /** * Adds and binds shortcuts marked to be added to the work folder. */ private void finalizeWorkFolder() { if (mWorkFolderApps.isEmpty()) { private void finalizeWorkFolder( UserHandleCompat user, final ArrayList<ShortcutInfo> workFolderApps, ArrayList<ShortcutInfo> homescreenApps) { if (workFolderApps.isEmpty()) { return; } sortList(mWorkFolderApps); // Try to get a work folder. String folderIdKey = USER_FOLDER_ID_PREFIX + mUserSerial; String folderIdKey = USER_FOLDER_ID_PREFIX + mUserManager.getSerialNumberForUser(user); if (mPrefs.contains(folderIdKey)) { long folderId = mPrefs.getLong(folderIdKey, 0); final FolderInfo workFolder = mModel.findFolderById(folderId); if (workFolder == null || !workFolder.hasOption(FolderInfo.FLAG_WORK_FOLDER)) { // Could not get a work folder. Add all the icons to homescreen. mHomescreenApps.addAll(mWorkFolderApps); homescreenApps.addAll(0, workFolderApps); return; } saveWorkFolderShortcuts(folderId, workFolder.contents.size()); saveWorkFolderShortcuts(folderId, workFolder.contents.size(), workFolderApps); final ArrayList<ShortcutInfo> shortcuts = mWorkFolderApps; // FolderInfo could already be bound. We need to add shortcuts on the UI thread. new MainThreadExecutor().execute(new Runnable() { @Override public void run() { for (ShortcutInfo info : shortcuts) { for (ShortcutInfo info : workFolderApps) { workFolder.add(info, false); } } Loading @@ -199,7 +167,7 @@ public class ManagedProfileHeuristic { workFolder.setOption(FolderInfo.FLAG_WORK_FOLDER, true, null); // Add all shortcuts before adding it to the UI, as an empty folder might get deleted. for (ShortcutInfo info : mWorkFolderApps) { for (ShortcutInfo info : workFolderApps) { workFolder.add(info, false); } Loading @@ -207,97 +175,24 @@ public class ManagedProfileHeuristic { ArrayList<ItemInfo> itemList = new ArrayList<ItemInfo>(1); itemList.add(workFolder); mModel.addAndBindAddedWorkspaceItems(mContext, itemList); mPrefs.edit().putLong(USER_FOLDER_ID_PREFIX + mUserSerial, workFolder.id).apply(); mPrefs.edit().putLong(folderIdKey, workFolder.id).apply(); saveWorkFolderShortcuts(workFolder.id, 0); saveWorkFolderShortcuts(workFolder.id, 0, workFolderApps); } } } /** * Add work folder shortcuts to the DB. */ private void saveWorkFolderShortcuts(long workFolderId, int startingRank) { for (ItemInfo info : mWorkFolderApps) { private void saveWorkFolderShortcuts( long workFolderId, int startingRank, ArrayList<ShortcutInfo> workFolderApps) { for (ItemInfo info : workFolderApps) { info.rank = startingRank++; LauncherModel.addItemToDatabase(mContext, info, workFolderId, 0, 0, 0); } } /** * Adds and binds all shortcuts marked for addition. */ private void finalizeAdditions(boolean addHomeScreenShortcuts) { finalizeWorkFolder(); if (addHomeScreenShortcuts && !mHomescreenApps.isEmpty()) { sortList(mHomescreenApps); mModel.addAndBindAddedWorkspaceItems(mContext, mHomescreenApps); } } /** * Updates the list of installed apps and adds any new icons on homescreen or work folder. */ public void processPackageAdd(String[] packages) { initVars(); HashSet<String> packageSet = new HashSet<>(); final boolean userAppsExisted = getUserApps(packageSet); boolean newPackageAdded = false; long installTime = System.currentTimeMillis(); LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext); for (String packageName : packages) { if (!packageSet.contains(packageName)) { packageSet.add(packageName); newPackageAdded = true; List<LauncherActivityInfoCompat> activities = launcherApps.getActivityList(packageName, mUser); if (!activities.isEmpty()) { markForAddition(activities.get(0), installTime); } } } if (newPackageAdded) { mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply(); finalizeAdditions(userAppsExisted); } } /** * Updates the list of installed packages for the user. */ public void processPackageRemoved(String[] packages) { HashSet<String> packageSet = new HashSet<String>(); getUserApps(packageSet); boolean packageRemoved = false; for (String packageName : packages) { if (packageSet.remove(packageName)) { packageRemoved = true; } } if (packageRemoved) { mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply(); } } /** * Reads the list of user apps which have already been processed. * @return false if the list didn't exist, true otherwise */ private boolean getUserApps(HashSet<String> outExistingApps) { Set<String> userApps = mPrefs.getStringSet(mPackageSetKey, null); if (userApps == null) { return false; } else { outExistingApps.addAll(userApps); return true; } } /** * Verifies that entries corresponding to {@param users} exist and removes all invalid entries. Loading Loading
src/com/android/launcher3/util/CachedPackageTracker.java 0 → 100644 +188 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.launcher3.util; import android.content.Context; import android.content.SharedPreferences; import com.android.launcher3.Utilities; import com.android.launcher3.compat.LauncherActivityInfoCompat; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.LauncherAppsCompat.OnAppsChangedCallbackCompat; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Utility class to track list of installed packages. It persists the list so that apps * installed/uninstalled while Launcher was dead can also be handled properly. */ public abstract class CachedPackageTracker implements OnAppsChangedCallbackCompat { protected static final String INSTALLED_PACKAGES_PREFIX = "installed_packages_for_user_"; protected final SharedPreferences mPrefs; protected final UserManagerCompat mUserManager; protected final LauncherAppsCompat mLauncherApps; public CachedPackageTracker(Context context, String preferenceFileName) { mPrefs = context.getSharedPreferences(preferenceFileName, Context.MODE_PRIVATE); mUserManager = UserManagerCompat.getInstance(context); mLauncherApps = LauncherAppsCompat.getInstance(context); } /** * Checks the list of user apps, and generates package event accordingly. * {@see #onLauncherAppsAdded}, {@see #onLauncherPackageRemoved} */ public void processUserApps(List<LauncherActivityInfoCompat> apps, UserHandleCompat user) { String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user); HashSet<String> oldPackageSet = new HashSet<>(); final boolean userAppsExisted = getUserApps(oldPackageSet, prefKey); HashSet<String> packagesRemoved = new HashSet<>(oldPackageSet); HashSet<String> newPackageSet = new HashSet<>(); ArrayList<LauncherActivityInstallInfo> packagesAdded = new ArrayList<>(); for (LauncherActivityInfoCompat info : apps) { String packageName = info.getComponentName().getPackageName(); newPackageSet.add(packageName); packagesRemoved.remove(packageName); if (!oldPackageSet.contains(packageName)) { oldPackageSet.add(packageName); packagesAdded.add(new LauncherActivityInstallInfo( info, info.getFirstInstallTime())); } } if (!packagesAdded.isEmpty() || !packagesRemoved.isEmpty()) { mPrefs.edit().putStringSet(prefKey, newPackageSet).apply(); if (!packagesAdded.isEmpty()) { Collections.sort(packagesAdded); onLauncherAppsAdded(packagesAdded, user, userAppsExisted); } if (!packagesRemoved.isEmpty()) { for (String pkg : packagesRemoved) { onLauncherPackageRemoved(pkg, user); } } } } /** * Reads the list of user apps which have already been processed. * @return false if the list didn't exist, true otherwise */ private boolean getUserApps(HashSet<String> outExistingApps, String prefKey) { Set<String> userApps = mPrefs.getStringSet(prefKey, null); if (userApps == null) { return false; } else { outExistingApps.addAll(userApps); return true; } } @Override public void onPackageRemoved(String packageName, UserHandleCompat user) { String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user); HashSet<String> packageSet = new HashSet<>(); if (getUserApps(packageSet, prefKey) && packageSet.remove(packageName)) { mPrefs.edit().putStringSet(prefKey, packageSet).apply(); } onLauncherPackageRemoved(packageName, user); } @Override public void onPackageAdded(String packageName, UserHandleCompat user) { String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user); HashSet<String> packageSet = new HashSet<>(); final boolean userAppsExisted = getUserApps(packageSet, prefKey); if (!packageSet.contains(packageName)) { List<LauncherActivityInfoCompat> activities = mLauncherApps.getActivityList(packageName, user); if (!activities.isEmpty()) { LauncherActivityInfoCompat activityInfo = activities.get(0); packageSet.add(packageName); mPrefs.edit().putStringSet(prefKey, packageSet).apply(); onLauncherAppsAdded(Arrays.asList( new LauncherActivityInstallInfo(activityInfo, System.currentTimeMillis())), user, userAppsExisted); } } } @Override public void onPackageChanged(String packageName, UserHandleCompat user) { } @Override public void onPackagesAvailable( String[] packageNames, UserHandleCompat user, boolean replacing) { } @Override public void onPackagesUnavailable( String[] packageNames, UserHandleCompat user, boolean replacing) { } @Override public void onPackagesSuspended(String[] packageNames, UserHandleCompat user) { } @Override public void onPackagesUnsuspended(String[] packageNames, UserHandleCompat user) { } /** * Called when new launcher apps are added. * @param apps list of newly added activities. Only one entry per package is sent. * @param user the user for this event. All activities in {@param apps} will belong to * the same user. * @param userAppsExisted false if the list was processed for the first time, like in case * when Launcher was newly installed or a new user was added. */ protected abstract void onLauncherAppsAdded(List<LauncherActivityInstallInfo> apps, UserHandleCompat user, boolean userAppsExisted); /** * Called when apps are removed from the system. */ protected abstract void onLauncherPackageRemoved(String packageName, UserHandleCompat user); protected static class LauncherActivityInstallInfo implements Comparable<LauncherActivityInstallInfo> { public final LauncherActivityInfoCompat info; public final long installTime; public LauncherActivityInstallInfo(LauncherActivityInfoCompat info, long installTime) { this.info = info; this.installTime = installTime; } @Override public int compareTo(LauncherActivityInstallInfo another) { return Utilities.longCompare(installTime, another.installTime); } } }
src/com/android/launcher3/util/ManagedProfileHeuristic.java +90 −195 Original line number Diff line number Diff line Loading @@ -16,14 +16,8 @@ package com.android.launcher3.util; import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import android.util.Log; import com.android.launcher3.FolderInfo; import com.android.launcher3.ItemInfo; Loading @@ -35,27 +29,19 @@ import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; import com.android.launcher3.compat.LauncherActivityInfoCompat; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Handles addition of app shortcuts for managed profiles. * Methods of class should only be called on {@link LauncherModel#sWorkerThread}. */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) public class ManagedProfileHeuristic { private static final String TAG = "ManagedProfileHeuristic"; /** * Maintain a set of packages installed per user. */ Loading @@ -76,118 +62,100 @@ public class ManagedProfileHeuristic { } private final Context mContext; private final UserHandleCompat mUser; private final LauncherModel mModel; private final SharedPreferences mPrefs; private final long mUserSerial; private final long mUserCreationTime; private final String mPackageSetKey; private ArrayList<ShortcutInfo> mHomescreenApps; private ArrayList<ShortcutInfo> mWorkFolderApps; private HashMap<ShortcutInfo, Long> mShortcutToInstallTimeMap; private final UserHandleCompat mUser; private ManagedProfileHeuristic(Context context, UserHandleCompat user) { mContext = context; mUser = user; mModel = LauncherAppState.getInstance().getModel(); } UserManagerCompat userManager = UserManagerCompat.getInstance(context); mUserSerial = userManager.getSerialNumberForUser(user); mUserCreationTime = userManager.getUserCreationTime(user); mPackageSetKey = INSTALLED_PACKAGES_PREFIX + mUserSerial; mPrefs = mContext.getSharedPreferences(LauncherFiles.MANAGED_USER_PREFERENCES_KEY, Context.MODE_PRIVATE); public void processPackageRemoved(String[] packages) { Preconditions.assertWorkerThread(); ManagedProfilePackageHandler handler = new ManagedProfilePackageHandler(); for (String pkg : packages) { handler.onPackageRemoved(pkg, mUser); } } private void initVars() { mHomescreenApps = new ArrayList<>(); mWorkFolderApps = new ArrayList<>(); mShortcutToInstallTimeMap = new HashMap<>(); public void processPackageAdd(String[] packages) { Preconditions.assertWorkerThread(); ManagedProfilePackageHandler handler = new ManagedProfilePackageHandler(); for (String pkg : packages) { handler.onPackageAdded(pkg, mUser); } } /** * Checks the list of user apps and adds icons for newly installed apps on the homescreen or * workfolder. */ public void processUserApps(List<LauncherActivityInfoCompat> apps) { initVars(); Preconditions.assertWorkerThread(); new ManagedProfilePackageHandler().processUserApps(apps, mUser); } HashSet<String> packageSet = new HashSet<>(); final boolean userAppsExisted = getUserApps(packageSet); private class ManagedProfilePackageHandler extends CachedPackageTracker { boolean newPackageAdded = false; for (LauncherActivityInfoCompat info : apps) { String packageName = info.getComponentName().getPackageName(); if (!packageSet.contains(packageName)) { packageSet.add(packageName); newPackageAdded = true; markForAddition(info, info.getFirstInstallTime()); private ManagedProfilePackageHandler() { super(mContext, LauncherFiles.MANAGED_USER_PREFERENCES_KEY); } protected void onLauncherAppsAdded( List<LauncherActivityInstallInfo> apps, UserHandleCompat user, boolean userAppsExisted) { ArrayList<ShortcutInfo> workFolderApps = new ArrayList<>(); ArrayList<ShortcutInfo> homescreenApps = new ArrayList<>(); int count = apps.size(); long folderCreationTime = mUserManager.getUserCreationTime(user) + AUTO_ADD_TO_FOLDER_DURATION; for (int i = 0; i < count; i++) { LauncherActivityInstallInfo info = apps.get(i); ShortcutInfo si = ShortcutInfo.fromActivityInfo(info.info, mContext); ((info.installTime <= folderCreationTime) ? workFolderApps : homescreenApps).add(si); } if (newPackageAdded) { mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply(); finalizeWorkFolder(user, workFolderApps, homescreenApps); // Do not add shortcuts on the homescreen for the first time. This prevents the launcher // getting filled with the managed user apps, when it start with a fresh DB (or after // a very long time). finalizeAdditions(userAppsExisted); } if (userAppsExisted && !homescreenApps.isEmpty()) { mModel.addAndBindAddedWorkspaceItems(mContext, homescreenApps); } private void markForAddition(LauncherActivityInfoCompat info, long installTime) { ArrayList<ShortcutInfo> targetList = (installTime <= mUserCreationTime + AUTO_ADD_TO_FOLDER_DURATION) ? mWorkFolderApps : mHomescreenApps; ShortcutInfo si = ShortcutInfo.fromActivityInfo(info, mContext); mShortcutToInstallTimeMap.put(si, installTime); targetList.add(si); } private void sortList(ArrayList<ShortcutInfo> infos) { Collections.sort(infos, new Comparator<ShortcutInfo>() { @Override public int compare(ShortcutInfo lhs, ShortcutInfo rhs) { Long lhsTime = mShortcutToInstallTimeMap.get(lhs); Long rhsTime = mShortcutToInstallTimeMap.get(rhs); return Utilities.longCompare(lhsTime == null ? 0 : lhsTime, rhsTime == null ? 0 : rhsTime); } }); protected void onLauncherPackageRemoved(String packageName, UserHandleCompat user) { } /** * Adds and binds shortcuts marked to be added to the work folder. */ private void finalizeWorkFolder() { if (mWorkFolderApps.isEmpty()) { private void finalizeWorkFolder( UserHandleCompat user, final ArrayList<ShortcutInfo> workFolderApps, ArrayList<ShortcutInfo> homescreenApps) { if (workFolderApps.isEmpty()) { return; } sortList(mWorkFolderApps); // Try to get a work folder. String folderIdKey = USER_FOLDER_ID_PREFIX + mUserSerial; String folderIdKey = USER_FOLDER_ID_PREFIX + mUserManager.getSerialNumberForUser(user); if (mPrefs.contains(folderIdKey)) { long folderId = mPrefs.getLong(folderIdKey, 0); final FolderInfo workFolder = mModel.findFolderById(folderId); if (workFolder == null || !workFolder.hasOption(FolderInfo.FLAG_WORK_FOLDER)) { // Could not get a work folder. Add all the icons to homescreen. mHomescreenApps.addAll(mWorkFolderApps); homescreenApps.addAll(0, workFolderApps); return; } saveWorkFolderShortcuts(folderId, workFolder.contents.size()); saveWorkFolderShortcuts(folderId, workFolder.contents.size(), workFolderApps); final ArrayList<ShortcutInfo> shortcuts = mWorkFolderApps; // FolderInfo could already be bound. We need to add shortcuts on the UI thread. new MainThreadExecutor().execute(new Runnable() { @Override public void run() { for (ShortcutInfo info : shortcuts) { for (ShortcutInfo info : workFolderApps) { workFolder.add(info, false); } } Loading @@ -199,7 +167,7 @@ public class ManagedProfileHeuristic { workFolder.setOption(FolderInfo.FLAG_WORK_FOLDER, true, null); // Add all shortcuts before adding it to the UI, as an empty folder might get deleted. for (ShortcutInfo info : mWorkFolderApps) { for (ShortcutInfo info : workFolderApps) { workFolder.add(info, false); } Loading @@ -207,97 +175,24 @@ public class ManagedProfileHeuristic { ArrayList<ItemInfo> itemList = new ArrayList<ItemInfo>(1); itemList.add(workFolder); mModel.addAndBindAddedWorkspaceItems(mContext, itemList); mPrefs.edit().putLong(USER_FOLDER_ID_PREFIX + mUserSerial, workFolder.id).apply(); mPrefs.edit().putLong(folderIdKey, workFolder.id).apply(); saveWorkFolderShortcuts(workFolder.id, 0); saveWorkFolderShortcuts(workFolder.id, 0, workFolderApps); } } } /** * Add work folder shortcuts to the DB. */ private void saveWorkFolderShortcuts(long workFolderId, int startingRank) { for (ItemInfo info : mWorkFolderApps) { private void saveWorkFolderShortcuts( long workFolderId, int startingRank, ArrayList<ShortcutInfo> workFolderApps) { for (ItemInfo info : workFolderApps) { info.rank = startingRank++; LauncherModel.addItemToDatabase(mContext, info, workFolderId, 0, 0, 0); } } /** * Adds and binds all shortcuts marked for addition. */ private void finalizeAdditions(boolean addHomeScreenShortcuts) { finalizeWorkFolder(); if (addHomeScreenShortcuts && !mHomescreenApps.isEmpty()) { sortList(mHomescreenApps); mModel.addAndBindAddedWorkspaceItems(mContext, mHomescreenApps); } } /** * Updates the list of installed apps and adds any new icons on homescreen or work folder. */ public void processPackageAdd(String[] packages) { initVars(); HashSet<String> packageSet = new HashSet<>(); final boolean userAppsExisted = getUserApps(packageSet); boolean newPackageAdded = false; long installTime = System.currentTimeMillis(); LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext); for (String packageName : packages) { if (!packageSet.contains(packageName)) { packageSet.add(packageName); newPackageAdded = true; List<LauncherActivityInfoCompat> activities = launcherApps.getActivityList(packageName, mUser); if (!activities.isEmpty()) { markForAddition(activities.get(0), installTime); } } } if (newPackageAdded) { mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply(); finalizeAdditions(userAppsExisted); } } /** * Updates the list of installed packages for the user. */ public void processPackageRemoved(String[] packages) { HashSet<String> packageSet = new HashSet<String>(); getUserApps(packageSet); boolean packageRemoved = false; for (String packageName : packages) { if (packageSet.remove(packageName)) { packageRemoved = true; } } if (packageRemoved) { mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply(); } } /** * Reads the list of user apps which have already been processed. * @return false if the list didn't exist, true otherwise */ private boolean getUserApps(HashSet<String> outExistingApps) { Set<String> userApps = mPrefs.getStringSet(mPackageSetKey, null); if (userApps == null) { return false; } else { outExistingApps.addAll(userApps); return true; } } /** * Verifies that entries corresponding to {@param users} exist and removes all invalid entries. Loading