diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2015-04-08 18:13:46 -0700 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2015-04-10 19:37:13 -0700 |
commit | 18bf8e2ffde3444d53aaa9654da02cdedd0b7cd1 (patch) | |
tree | 15497c0479cbde4c3db977e4850ba72b60912c67 | |
parent | d9760ee2de0a245fe0a0c11891723ef3f1513de9 (diff) | |
download | android_packages_apps_Trebuchet-18bf8e2ffde3444d53aaa9654da02cdedd0b7cd1.tar.gz android_packages_apps_Trebuchet-18bf8e2ffde3444d53aaa9654da02cdedd0b7cd1.tar.bz2 android_packages_apps_Trebuchet-18bf8e2ffde3444d53aaa9654da02cdedd0b7cd1.zip |
Automatically adding managed profile shortcuts to homescreen.
When the managed profile is created, a "Work" folder is created
and added to the homescreen. All work profile apps are added to this
folder and icons for subsequent installs (withing a fixed time frame)
are automatically added to this folder.
If this folder get deleted or the time-frame expires, icon for any new
install is placed on the homescreen.
Bug: 17410319
Change-Id: I49f4e437707d5eabe4eec85320765bf6ba7fde97
-rw-r--r-- | res/values/strings.xml | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/FolderInfo.java | 9 | ||||
-rw-r--r-- | src/com/android/launcher3/InstallShortcutReceiver.java | 13 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherAccessibilityDelegate.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherAppState.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherFiles.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/LauncherModel.java | 108 | ||||
-rw-r--r-- | src/com/android/launcher3/ShortcutInfo.java | 16 | ||||
-rw-r--r-- | src/com/android/launcher3/compat/UserManagerCompat.java | 1 | ||||
-rw-r--r-- | src/com/android/launcher3/compat/UserManagerCompatV16.java | 5 | ||||
-rw-r--r-- | src/com/android/launcher3/compat/UserManagerCompatVL.java | 20 | ||||
-rw-r--r-- | src/com/android/launcher3/util/ManagedProfileHeuristic.java | 277 |
12 files changed, 370 insertions, 87 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml index 1b58d75b9..52306e30e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -38,6 +38,8 @@ <string name="uid_name">Android Core Apps</string> <!-- Default folder name --> <string name="folder_name"></string> + <!-- Work folder name --> + <string name="work_folder_name">Work</string> <!-- Displayed when user selects a shortcut for an app that was uninstalled [CHAR_LIMIT=none]--> <string name="activity_not_found">App isn\'t installed.</string> <!-- Displayed when user selects a shortcut for an app that is current not available [CHAR_LIMIT=none]--> diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java index 3240cbf22..80b156413 100644 --- a/src/com/android/launcher3/FolderInfo.java +++ b/src/com/android/launcher3/FolderInfo.java @@ -37,6 +37,11 @@ public class FolderInfo extends ItemInfo { public static final int FLAG_ITEMS_SORTED = 0x00000001; /** + * It is a work folder + */ + public static final int FLAG_WORK_FOLDER = 0x00000002; + + /** * Whether this folder has been opened */ boolean opened; @@ -46,11 +51,11 @@ public class FolderInfo extends ItemInfo { /** * The apps and shortcuts */ - ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>(); + public ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>(); ArrayList<FolderListener> listeners = new ArrayList<FolderListener>(); - FolderInfo() { + public FolderInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER; user = UserHandleCompat.myUserHandle(); } diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index 5422de951..0c69154aa 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -210,7 +210,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { // Add the new apps to the model and bind them if (!addShortcuts.isEmpty()) { LauncherAppState app = LauncherAppState.getInstance(); - app.getModel().addAndBindAddedWorkspaceApps(context, addShortcuts); + app.getModel().addAndBindAddedWorkspaceItems(context, addShortcuts); } } } @@ -352,16 +352,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { public ShortcutInfo getShortcutInfo() { if (activityInfo != null) { - final ShortcutInfo info = new ShortcutInfo(); - info.user = user; - info.title = label; - info.contentDescription = label; - info.customIcon = false; - info.intent = launchIntent; - info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; - info.flags = AppInfo.initFlags(activityInfo); - info.firstInstallTime = activityInfo.getFirstInstallTime(); - return info; + return ShortcutInfo.fromActivityInfo(activityInfo, mContext); } else { return LauncherAppState.getInstance().getModel().infoFromShortcutIntent(mContext, data); } diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/LauncherAccessibilityDelegate.java index 42f1914c6..cfc1bd96c 100644 --- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/LauncherAccessibilityDelegate.java @@ -124,7 +124,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate { mLauncher.showWorkspace(true, new Runnable() { @Override public void run() { - mLauncher.getModel().addAndBindAddedWorkspaceApps( + mLauncher.getModel().addAndBindAddedWorkspaceItems( mLauncher, addShortcuts, screenProvider, 0, true); announceConfirmation(R.string.item_added_to_workspace); } diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 3bd385028..6e77d0628 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -149,7 +149,7 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks { return mIconCache; } - LauncherModel getModel() { + public LauncherModel getModel() { return mModel; } diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java index 699cb37ff..9dd8dc50c 100644 --- a/src/com/android/launcher3/LauncherFiles.java +++ b/src/com/android/launcher3/LauncherFiles.java @@ -21,6 +21,7 @@ public class LauncherFiles { public static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs"; public static final String WALLPAPER_CROP_PREFERENCES_KEY = "com.android.launcher3.WallpaperCropActivity"; + public static final String MANAGED_USER_PREFERENCES_KEY = "com.android.launcher3.managedusers.prefs"; public static final String WALLPAPER_IMAGES_DB = "saved_wallpaper_images.db"; public static final String WIDGET_PREVIEWS_DB = "widgetpreviews.db"; @@ -35,6 +36,7 @@ public class LauncherFiles { WALLPAPER_CROP_PREFERENCES_KEY + XML, WALLPAPER_IMAGES_DB, WIDGET_PREVIEWS_DB, + MANAGED_USER_PREFERENCES_KEY, APP_ICONS_DB)); // TODO: Delete these files on upgrade diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 98ba09bc6..37f1ea86e 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -59,6 +59,7 @@ import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.ManagedProfileHeuristic; import com.android.launcher3.util.Thunk; import java.lang.ref.WeakReference; @@ -87,7 +88,6 @@ public class LauncherModel extends BroadcastReceiver static final boolean DEBUG_LOADERS = false; private static final boolean DEBUG_RECEIVER = false; private static final boolean REMOVE_UNRESTORED_ICONS = true; - private static final boolean ADD_MANAGED_PROFILE_SHORTCUTS = false; static final String TAG = "Launcher.Model"; @@ -107,11 +107,6 @@ public class LauncherModel extends BroadcastReceiver @Thunk LoaderTask mLoaderTask; @Thunk boolean mIsLoaderTaskRunning; - /** - * Maintain a set of packages per user, for which we added a shortcut on the workspace. - */ - private static final String INSTALLED_SHORTCUTS_SET_PREFIX = "installed_shortcuts_set_for_user_"; - // Specific runnable types that are run on the main thread deferred handler, this allows us to // clear all queued binding runnables when the Launcher activity is destroyed. private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0; @@ -338,9 +333,9 @@ public class LauncherModel extends BroadcastReceiver runOnWorkerThread(r); } - public void addAndBindAddedWorkspaceApps(final Context context, + public void addAndBindAddedWorkspaceItems(final Context context, final ArrayList<ItemInfo> workspaceApps) { - addAndBindAddedWorkspaceApps(context, workspaceApps, + addAndBindAddedWorkspaceItems(context, workspaceApps, new ScreenPosProvider() { @Override @@ -518,7 +513,7 @@ public class LauncherModel extends BroadcastReceiver * @param fallbackStartScreen the screen to start search for empty space if * preferredScreen is not available. */ - public void addAndBindAddedWorkspaceApps(final Context context, + public void addAndBindAddedWorkspaceItems(final Context context, final ArrayList<ItemInfo> workspaceApps, final ScreenPosProvider preferredScreen, final int fallbackStartScreen, @@ -539,7 +534,7 @@ public class LauncherModel extends BroadcastReceiver ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context); synchronized(sBgLock) { for (ItemInfo item : workspaceApps) { - if (!allowDuplicate) { + if (!allowDuplicate && item instanceof ShortcutInfo) { // Short-circuit this logic if the icon exists somewhere on the workspace if (shortcutExists(context, item.title.toString(), item.getIntent(), item.user)) { @@ -554,21 +549,21 @@ public class LauncherModel extends BroadcastReceiver long screenId = coords.first; int[] cordinates = coords.second; - ShortcutInfo shortcutInfo; - if (item instanceof ShortcutInfo) { - shortcutInfo = (ShortcutInfo) item; + ItemInfo itemInfo; + if (item instanceof ShortcutInfo || item instanceof FolderInfo) { + itemInfo = item; } else if (item instanceof AppInfo) { - shortcutInfo = ((AppInfo) item).makeShortcut(); + itemInfo = ((AppInfo) item).makeShortcut(); } else { throw new RuntimeException("Unexpected info type"); } // Add the shortcut to the db - addItemToDatabase(context, shortcutInfo, + addItemToDatabase(context, itemInfo, LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, cordinates[0], cordinates[1]); // Save the ShortcutInfo for binding in the workspace - addedShortcutsFinal.add(shortcutInfo); + addedShortcutsFinal.add(itemInfo); } } @@ -993,7 +988,7 @@ public class LauncherModel extends BroadcastReceiver * Add an item to the database in a specified container. Sets the container, screen, cellX and * cellY fields of the item. Also assigns an ID to the item. */ - static void addItemToDatabase(Context context, final ItemInfo item, final long container, + public static void addItemToDatabase(Context context, final ItemInfo item, final long container, final long screenId, final int cellX, final int cellY) { item.container = container; item.cellX = cellX; @@ -1097,7 +1092,6 @@ public class LauncherModel extends BroadcastReceiver */ static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) { final ContentResolver cr = context.getContentResolver(); - Runnable r = new Runnable() { public void run() { for (ItemInfo item : items) { @@ -2845,23 +2839,11 @@ public class LauncherModel extends BroadcastReceiver mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache)); } - if (ADD_MANAGED_PROFILE_SHORTCUTS && !user.equals(UserHandleCompat.myUserHandle())) { - // Add shortcuts for packages which were installed while launcher was dead. - String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX - + mUserManager.getSerialNumberForUser(user); - Set<String> packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET); - HashSet<String> newPackageSet = new HashSet<String>(); - - for (LauncherActivityInfoCompat info : apps) { - String packageName = info.getComponentName().getPackageName(); - if (!packagesAdded.contains(packageName) - && !newPackageSet.contains(packageName)) { - InstallShortcutReceiver.queueInstallShortcut(info, mContext); - } - newPackageSet.add(packageName); + if (!user.equals(UserHandleCompat.myUserHandle())) { + ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user); + if (heuristic != null) { + heuristic.processUserApps(apps); } - - prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit(); } } // Huh? Shouldn't this be inside the Runnable below? @@ -2884,6 +2866,8 @@ public class LauncherModel extends BroadcastReceiver } } }); + // Cleanup any data stored for a deleted user. + ManagedProfileHeuristic.processAllUsers(profiles, mContext); if (DEBUG_LOADERS) { Log.d(TAG, "Icons processed in " @@ -2971,38 +2955,19 @@ public class LauncherModel extends BroadcastReceiver final String[] packages = mPackages; final int N = packages.length; switch (mOp) { - case OP_ADD: + case OP_ADD: { for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]); mIconCache.updateIconsForPkg(packages[i], mUser); mBgAllAppsList.addPackage(context, packages[i], mUser); } - // Auto add shortcuts for added packages. - if (ADD_MANAGED_PROFILE_SHORTCUTS - && !UserHandleCompat.myUserHandle().equals(mUser)) { - SharedPreferences prefs = context.getSharedPreferences( - LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); - String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX - + mUserManager.getSerialNumberForUser(mUser); - Set<String> shortcutSet = new HashSet<String>( - prefs.getStringSet(shortcutsSetKey,Collections.EMPTY_SET)); - - for (int i=0; i<N; i++) { - if (!shortcutSet.contains(packages[i])) { - shortcutSet.add(packages[i]); - List<LauncherActivityInfoCompat> activities = - mLauncherApps.getActivityList(packages[i], mUser); - if (activities != null && !activities.isEmpty()) { - InstallShortcutReceiver.queueInstallShortcut( - activities.get(0), context); - } - } - } - - prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit(); + ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser); + if (heuristic != null) { + heuristic.processPackageAdd(mPackages); } break; + } case OP_UPDATE: for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]); @@ -3011,25 +2976,17 @@ public class LauncherModel extends BroadcastReceiver mApp.getWidgetCache().removePackage(packages[i], mUser); } break; - case OP_REMOVE: - // Remove the packageName for the set of auto-installed shortcuts. This - // will ensure that the shortcut when the app is installed again. - if (ADD_MANAGED_PROFILE_SHORTCUTS - && !UserHandleCompat.myUserHandle().equals(mUser)) { - SharedPreferences prefs = context.getSharedPreferences( - LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); - String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX - + mUserManager.getSerialNumberForUser(mUser); - HashSet<String> shortcutSet = new HashSet<String>( - prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET)); - shortcutSet.removeAll(Arrays.asList(mPackages)); - prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit(); + case OP_REMOVE: { + ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser); + if (heuristic != null) { + heuristic.processPackageRemoved(mPackages); } for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]); mIconCache.removeIconsForPkg(packages[i], mUser); } // Fall through + } case OP_UNAVAILABLE: for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]); @@ -3677,4 +3634,13 @@ public class LauncherModel extends BroadcastReceiver public Callbacks getCallback() { return mCallbacks != null ? mCallbacks.get() : null; } + + /** + * @return {@link FolderInfo} if its already loaded. + */ + public FolderInfo findFolderById(Long folderId) { + synchronized (sBgLock) { + return sBgFolders.get(folderId); + } + } } diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java index 9f7da6c3d..5bef845bb 100644 --- a/src/com/android/launcher3/ShortcutInfo.java +++ b/src/com/android/launcher3/ShortcutInfo.java @@ -24,7 +24,9 @@ import android.graphics.Bitmap; import android.util.Log; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.compat.LauncherActivityInfoCompat; import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.compat.UserManagerCompat; import java.util.ArrayList; import java.util.Arrays; @@ -274,5 +276,19 @@ public class ShortcutInfo extends ItemInfo { public boolean shouldUseLowResIcon() { return usingLowResIcon && container >= 0 && rank >= FolderIcon.NUM_ITEMS_IN_PREVIEW; } + + public static ShortcutInfo fromActivityInfo(LauncherActivityInfoCompat info, Context context) { + final ShortcutInfo shortcut = new ShortcutInfo(); + shortcut.user = info.getUser(); + shortcut.title = info.getLabel().toString(); + shortcut.contentDescription = UserManagerCompat.getInstance(context) + .getBadgedLabelForUser(info.getLabel(), info.getUser()); + shortcut.customIcon = false; + shortcut.intent = AppInfo.makeLaunchIntent(context, info, info.getUser()); + shortcut.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; + shortcut.flags = AppInfo.initFlags(info); + shortcut.firstInstallTime = info.getFirstInstallTime(); + return shortcut; + } } diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java index 1374b4e49..a79d94646 100644 --- a/src/com/android/launcher3/compat/UserManagerCompat.java +++ b/src/com/android/launcher3/compat/UserManagerCompat.java @@ -43,4 +43,5 @@ public abstract class UserManagerCompat { public abstract UserHandleCompat getUserForSerialNumber(long serialNumber); public abstract Drawable getBadgedDrawableForUser(Drawable unbadged, UserHandleCompat user); public abstract CharSequence getBadgedLabelForUser(CharSequence label, UserHandleCompat user); + public abstract long getUserCreationTime(UserHandleCompat user); } diff --git a/src/com/android/launcher3/compat/UserManagerCompatV16.java b/src/com/android/launcher3/compat/UserManagerCompatV16.java index 32f972e85..ffe698c8b 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatV16.java +++ b/src/com/android/launcher3/compat/UserManagerCompatV16.java @@ -48,4 +48,9 @@ public class UserManagerCompatV16 extends UserManagerCompat { public CharSequence getBadgedLabelForUser(CharSequence label, UserHandleCompat user) { return label; } + + @Override + public long getUserCreationTime(UserHandleCompat user) { + return 0; + } } diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java index 19eeabdcf..884d6fe2a 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatVL.java +++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java @@ -18,21 +18,27 @@ package com.android.launcher3.compat; import android.content.Context; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.UserHandle; -import android.os.UserManager; + +import com.android.launcher3.LauncherAppState; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class UserManagerCompatVL extends UserManagerCompatV17 { + private static final String USER_CREATION_TIME_KEY = "user_creation_time_"; + private final PackageManager mPm; + private final Context mContext; UserManagerCompatVL(Context context) { super(context); mPm = context.getPackageManager(); + mContext = context; } @Override @@ -61,5 +67,17 @@ public class UserManagerCompatVL extends UserManagerCompatV17 { } return mPm.getUserBadgedLabel(label, user.getUser()); } + + @Override + public long getUserCreationTime(UserHandleCompat user) { + // TODO: Use system API once available. + SharedPreferences prefs = mContext.getSharedPreferences( + LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); + String key = USER_CREATION_TIME_KEY + getSerialNumberForUser(user); + if (!prefs.contains(key)) { + prefs.edit().putLong(key, System.currentTimeMillis()).apply(); + } + return prefs.getLong(key, 0); + } } diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java new file mode 100644 index 000000000..cefa71c39 --- /dev/null +++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java @@ -0,0 +1,277 @@ +package com.android.launcher3.util; + +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.util.Log; + +import com.android.launcher3.FolderInfo; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherFiles; +import com.android.launcher3.LauncherModel; +import com.android.launcher3.MainThreadExecutor; +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.HashSet; +import java.util.List; + +/** + * Handles addition of app shortcuts for managed profiles. + * Methods of class should only be called on {@link LauncherModel#sWorkerThread}. + */ +public class ManagedProfileHeuristic { + + private static final String TAG = "ManagedProfileHeuristic"; + + /** + * Maintain a set of packages installed per user. + */ + private static final String INSTALLED_PACKAGES_PREFIX = "installed_packages_for_user_"; + + private static final String USER_FOLDER_ID_PREFIX = "user_folder_"; + + /** + * Duration (in milliseconds) for which app shortcuts will be added to work folder. + */ + private static final long AUTO_ADD_TO_FOLDER_DURATION = 8 * 60 * 60 * 1000; + + public static ManagedProfileHeuristic get(Context context, UserHandleCompat user) { + if (Utilities.isLmpOrAbove() && !UserHandleCompat.myUserHandle().equals(user)) { + return new ManagedProfileHeuristic(context, user); + } + return null; + } + + 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<ItemInfo> mHomescreenApps; + private ArrayList<ItemInfo> mWorkFolderApps; + + 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); + } + + /** + * Checks the list of user apps and adds icons for newly installed apps on the homescreen or + * workfolder. + */ + public void processUserApps(List<LauncherActivityInfoCompat> apps) { + mHomescreenApps = new ArrayList<ItemInfo>(); + mWorkFolderApps = new ArrayList<ItemInfo>(); + HashSet<String> packageSet = getPackageSet(); + boolean newPackageAdded = false; + + for (LauncherActivityInfoCompat info : apps) { + String packageName = info.getComponentName().getPackageName(); + if (!packageSet.contains(packageName)) { + packageSet.add(packageName); + newPackageAdded = true; + + try { + PackageInfo pkgInfo = mContext.getPackageManager() + .getPackageInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES); + markForAddition(info, pkgInfo.firstInstallTime); + } catch (NameNotFoundException e) { + Log.e(TAG, "Unknown package " + packageName, e); + } + } + } + + if (newPackageAdded) { + mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply(); + finalizeAdditions(); + } + } + + private void markForAddition(LauncherActivityInfoCompat info, long installTime) { + ArrayList<ItemInfo> targetList = + (installTime <= mUserCreationTime + AUTO_ADD_TO_FOLDER_DURATION) ? + mWorkFolderApps : mHomescreenApps; + targetList.add(ShortcutInfo.fromActivityInfo(info, mContext)); + } + + /** + * Adds and binds shortcuts marked to be added to the work folder. + */ + private void finalizeWorkFolder() { + if (mWorkFolderApps.isEmpty()) { + return; + } + + // Try to get a work folder. + String folderIdKey = USER_FOLDER_ID_PREFIX + mUserSerial; + 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); + return; + } + saveWorkFolderShortcuts(folderId, workFolder.contents.size()); + + final ArrayList<ItemInfo> 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 (ItemInfo info : shortcuts) { + workFolder.add((ShortcutInfo) info); + } + } + }); + } else { + // Create a new folder. + final FolderInfo workFolder = new FolderInfo(); + workFolder.title = mContext.getText(R.string.work_folder_name); + 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 (ItemInfo info : mWorkFolderApps) { + workFolder.add((ShortcutInfo) info); + } + + // Add the item to home screen and DB. This also generates an item id synchronously. + 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(); + + saveWorkFolderShortcuts(workFolder.id, 0); + } + } + + /** + * Add work folder shortcuts to the DB. + */ + private void saveWorkFolderShortcuts(long workFolderId, int startingRank) { + for (ItemInfo info : mWorkFolderApps) { + info.rank = startingRank++; + LauncherModel.addItemToDatabase(mContext, info, workFolderId, 0, 0, 0); + } + } + + /** + * Adds and binds all shortcuts marked for addition. + */ + private void finalizeAdditions() { + finalizeWorkFolder(); + + if (!mHomescreenApps.isEmpty()) { + 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) { + mHomescreenApps = new ArrayList<ItemInfo>(); + mWorkFolderApps = new ArrayList<ItemInfo>(); + HashSet<String> packageSet = getPackageSet(); + 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(); + } + } + + /** + * Updates the list of installed packages for the user. + */ + public void processPackageRemoved(String[] packages) { + HashSet<String> packageSet = getPackageSet(); + boolean packageRemoved = false; + + for (String packageName : packages) { + if (packageSet.remove(packageName)) { + packageRemoved = true; + } + } + + if (packageRemoved) { + mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply(); + } + } + + @SuppressWarnings("unchecked") + private HashSet<String> getPackageSet() { + return new HashSet<String>(mPrefs.getStringSet(mPackageSetKey, Collections.EMPTY_SET)); + } + + /** + * Verifies that entries corresponding to {@param users} exist and removes all invalid entries. + */ + public static void processAllUsers(List<UserHandleCompat> users, Context context) { + if (!Utilities.isLmpOrAbove()) { + return; + } + UserManagerCompat userManager = UserManagerCompat.getInstance(context); + HashSet<String> validKeys = new HashSet<String>(); + for (UserHandleCompat user : users) { + addAllUserKeys(userManager.getSerialNumberForUser(user), validKeys); + } + + SharedPreferences prefs = context.getSharedPreferences( + LauncherFiles.MANAGED_USER_PREFERENCES_KEY, + Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + for (String key : prefs.getAll().keySet()) { + if (!validKeys.contains(key)) { + editor.remove(key); + } + } + editor.apply(); + } + + private static void addAllUserKeys(long userSerial, HashSet<String> keysOut) { + keysOut.add(INSTALLED_PACKAGES_PREFIX + userSerial); + keysOut.add(USER_FOLDER_ID_PREFIX + userSerial); + } +} |