Merge "Focus handling - RTL support" into ub-launcher3-burnaby
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 9e91f67..a5b25aa 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -57,7 +57,6 @@
android:id="@+id/widget_dims"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
android:layout_marginStart="5dp"
android:layout_marginLeft="5dp"
android:layout_weight="0"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1b58d75..52306e3 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 3240cbf..80b1564 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -37,6 +37,11 @@
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 @@
/**
* 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/IconCache.java b/src/com/android/launcher3/IconCache.java
index f6238da..48b38f1 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -283,8 +283,8 @@
}
ContentValues values = updateCacheAndGetContentValues(app);
mIconDb.getWritableDatabase().update(IconDB.TABLE_NAME, values,
- IconDB.COLUMN_COMPONENT + " = ?",
- new String[] { cn });
+ IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
+ new String[] {cn, Long.toString(userSerial)});
updatedPackages.add(component.getPackageName());
}
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 5422de9..0c69154 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -210,7 +210,7 @@
// 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 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/Launcher.java b/src/com/android/launcher3/Launcher.java
index 3d2a346..42e145b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -132,7 +132,7 @@
implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener,
LauncherStateTransitionAnimation.Callbacks {
- static final String TAG = "Launcher - MERONG";
+ static final String TAG = "Launcher";
static final boolean LOGD = true;
static final boolean PROFILE_STARTUP = false;
diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
index 42f1914..cfc1bd9 100644
--- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
@@ -124,7 +124,7 @@
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 3bd3850..6e77d06 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -149,7 +149,7 @@
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 699cb37..9dd8dc5 100644
--- a/src/com/android/launcher3/LauncherFiles.java
+++ b/src/com/android/launcher3/LauncherFiles.java
@@ -21,6 +21,7 @@
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 @@
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 98ba09b..37f1ea8 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -59,6 +59,7 @@
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 @@
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 @@
@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 @@
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 @@
* @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 @@
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 @@
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 @@
* 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 @@
*/
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 @@
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 @@
}
}
});
+ // 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 @@
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 @@
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 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 9f7da6c..5bef845 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -24,7 +24,9 @@
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 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 1374b4e..a79d946 100644
--- a/src/com/android/launcher3/compat/UserManagerCompat.java
+++ b/src/com/android/launcher3/compat/UserManagerCompat.java
@@ -43,4 +43,5 @@
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 32f972e..ffe698c 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatV16.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatV16.java
@@ -48,4 +48,9 @@
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 19eeabd..884d6fe 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 @@
}
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 0000000..cefa71c
--- /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);
+ }
+}
diff --git a/src/com/android/launcher3/widget/PackageItemInfo.java b/src/com/android/launcher3/widget/PackageItemInfo.java
index d7edf22..1a1de55 100644
--- a/src/com/android/launcher3/widget/PackageItemInfo.java
+++ b/src/com/android/launcher3/widget/PackageItemInfo.java
@@ -39,11 +39,12 @@
*/
public boolean usingLowResIcon;
- public ComponentName componentName;
+ public String packageName;
int flags = 0;
- PackageItemInfo() {
+ PackageItemInfo(String packageName) {
+ this.packageName = packageName;
}
@Override
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 93ee94a..d10c304 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -47,7 +47,7 @@
*/
public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
- private static final String TAG = "PagedViewWidget";
+ private static final String TAG = "WidgetCell";
private static final boolean DEBUG = false;
// Temporary preset width and height of the image to keep them aligned.
@@ -120,7 +120,16 @@
Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
}
super.onDetachedFromWindow();
- deletePreview(true);
+ deletePreview(false);
+ }
+
+ public void reset() {
+ ImageView image = (ImageView) findViewById(R.id.widget_preview);
+ final TextView name = (TextView) findViewById(R.id.widget_name);
+ final TextView dims = (TextView) findViewById(R.id.widget_dims);
+ image.setImageDrawable(null);
+ name.setText(null);
+ dims.setText(null);
}
public void deletePreview(boolean recycleImage) {
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index 8d1f20c..afeb2d3 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -88,14 +88,13 @@
@Override
public void onBindViewHolder(WidgetsRowViewHolder holder, int pos) {
- String packageName = mWidgetsModel.getPackageName(pos);
- List<Object> infoList = mWidgetsModel.getSortedWidgets(packageName);
+ List<Object> infoList = mWidgetsModel.getSortedWidgets(pos);
ViewGroup row = ((ViewGroup) holder.getContent().findViewById(R.id.widgets_cell_list));
if (DEBUG) {
Log.d(TAG, String.format(
- "onBindViewHolder [pos=%d, packageName=%s, widget#=%d, row.getChildCount=%d]",
- pos, packageName, infoList.size(), row.getChildCount()));
+ "onBindViewHolder [pos=%d, widget#=%d, row.getChildCount=%d]",
+ pos, infoList.size(), row.getChildCount()));
}
// Add more views.
@@ -120,11 +119,11 @@
}
// Bind the views in the application info section.
- PackageItemInfo infoOut = mWidgetsModel.getPackageItemInfo(packageName);
+ PackageItemInfo infoOut = mWidgetsModel.getPackageItemInfo(pos);
if (infoOut.usingLowResIcon) {
- mIconCache.getTitleAndIconForApp(packageName, UserHandleCompat.myUserHandle(),
- false /* useLowResIcon */, infoOut);
- mWidgetsModel.setPackageItemInfo(packageName, infoOut);
+ // TODO(hyunyoungs): call this in none UI thread in the same way as BubbleTextView.
+ mIconCache.getTitleAndIconForApp(infoOut.packageName,
+ UserHandleCompat.myUserHandle(), false /* useLowResIcon */, infoOut);
}
((TextView) holder.getContent().findViewById(R.id.section)).setText(infoOut.title);
ImageView iv = (ImageView) holder.getContent().findViewById(R.id.section_image);
@@ -133,7 +132,8 @@
// Bind the view in the widget horizontal tray region.
for (int i=0; i < infoList.size(); i++) {
WidgetCell widget = (WidgetCell) row.getChildAt(i);
- if (getWidgetPreviewLoader() == null || widget == null) {
+ widget.reset();
+ if (getWidgetPreviewLoader() == null) {
return;
}
if (infoList.get(i) instanceof LauncherAppWidgetProviderInfo) {
@@ -150,7 +150,6 @@
widget.setVisibility(View.VISIBLE);
widget.ensurePreview();
}
- // TODO(hyunyoungs): Draw the scrollable indicator.
}
@Override
@@ -175,15 +174,4 @@
}
return mWidgetPreviewLoader;
}
-
- /**
- * TODO(hyunyoungs): this is temporary. Figure out the width of each widget cell
- * and then check if the total sum is longer than the parent width.
- */
- private void addScrollableIndicator(int contentSize, ViewGroup parent) {
- if (contentSize > 2) {
- ViewGroup indicator = (ViewGroup) parent.findViewById(R.id.scrollable_indicator);
- indicator.setVisibility(View.VISIBLE);
- }
- }
}
diff --git a/src/com/android/launcher3/widget/WidgetsModel.java b/src/com/android/launcher3/widget/WidgetsModel.java
index 463c79e..1447bef 100644
--- a/src/com/android/launcher3/widget/WidgetsModel.java
+++ b/src/com/android/launcher3/widget/WidgetsModel.java
@@ -31,12 +31,10 @@
private static final boolean DEBUG = false;
/* List of packages that is tracked by this model. */
- private List<String> mPackageNames = new ArrayList<>();
-
- private Map<String, PackageItemInfo> mPackageItemInfoList = new HashMap<>();
+ private List<PackageItemInfo> mPackageItemInfos = new ArrayList<>();
/* Map of widgets and shortcuts that are tracked per package. */
- private Map<String, ArrayList<Object>> mWidgetsList = new HashMap<>();
+ private Map<PackageItemInfo, ArrayList<Object>> mWidgetsList = new HashMap<>();
/* Notifies the adapter when data changes. */
private RecyclerView.Adapter mAdapter;
@@ -53,20 +51,16 @@
// Access methods that may be deleted if the private fields are made package-private.
public int getPackageSize() {
- return mPackageNames.size();
+ return mPackageItemInfos.size();
}
// Access methods that may be deleted if the private fields are made package-private.
- public String getPackageName(int pos) {
- return mPackageNames.get(pos);
+ public PackageItemInfo getPackageItemInfo(int pos) {
+ return mPackageItemInfos.get(pos);
}
- public PackageItemInfo getPackageItemInfo(String packageName) {
- return mPackageItemInfoList.get(packageName);
- }
-
- public List<Object> getSortedWidgets(String packageName) {
- return mWidgetsList.get(packageName);
+ public List<Object> getSortedWidgets(int pos) {
+ return mWidgetsList.get(mPackageItemInfos.get(pos));
}
public void addWidgetsAndShortcuts(ArrayList<Object> widgetsShortcuts, PackageManager pm) {
@@ -74,8 +68,10 @@
Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + widgetsShortcuts.size());
}
+ // Temporary list for {@link PackageItemInfos} to avoid having to go through
+ // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
+ HashMap<String, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
// clear the lists.
- mPackageNames.clear();
mWidgetsList.clear();
// add and update.
@@ -90,51 +86,41 @@
} else {
Log.e(TAG, String.format("addWidgetsAndShortcuts, nothing added for class=%s",
o.getClass().toString()));
-
}
- ArrayList<Object> widgetsShortcutsList = mWidgetsList.get(packageName);
+ PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName);
+ ArrayList<Object> widgetsShortcutsList = mWidgetsList.get(pInfo);
if (widgetsShortcutsList != null) {
widgetsShortcutsList.add(o);
} else {
widgetsShortcutsList = new ArrayList<Object>();
widgetsShortcutsList.add(o);
- mWidgetsList.put(packageName, widgetsShortcutsList);
- mPackageNames.add(packageName);
- }
- }
- for (String packageName: mPackageNames) {
- PackageItemInfo pInfo = mPackageItemInfoList.get(packageName);
- if (pInfo == null) {
- pInfo = new PackageItemInfo();
+
+ pInfo = new PackageItemInfo(packageName);
mIconCache.getTitleAndIconForApp(packageName, UserHandleCompat.myUserHandle(),
true /* useLowResIcon */, pInfo);
- mPackageItemInfoList.put(packageName, pInfo);
+ mWidgetsList.put(pInfo, widgetsShortcutsList);
+ tmpPackageItemInfos.put(packageName, pInfo);
+ mPackageItemInfos.add(pInfo);
}
}
// sort.
- sortPackageList();
- for (String packageName: mPackageNames) {
- Collections.sort(mWidgetsList.get(packageName), mWidgetAndShortcutNameComparator);
+ sortPackageItemInfos();
+ for (PackageItemInfo p: mPackageItemInfos) {
+ Collections.sort(mWidgetsList.get(p), mWidgetAndShortcutNameComparator);
}
// notify.
mAdapter.notifyDataSetChanged();
}
- private void sortPackageList() {
- Collections.sort(mPackageNames, new Comparator<String>() {
+ private void sortPackageItemInfos() {
+ Collections.sort(mPackageItemInfos, new Comparator<PackageItemInfo>() {
@Override
- public int compare(String lhs, String rhs) {
- String lhsTitle = mPackageItemInfoList.get(lhs).title.toString();
- String rhsTitle = mPackageItemInfoList.get(rhs).title.toString();
- return lhsTitle.compareTo(rhsTitle);
+ public int compare(PackageItemInfo lhs, PackageItemInfo rhs) {
+ return lhs.title.toString().compareTo(rhs.title.toString());
}
});
}
-
- public void setPackageItemInfo(String packageName, PackageItemInfo infoOut) {
- mPackageItemInfoList.put(packageName, infoOut);
- }
-}
+}
\ No newline at end of file