summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKenny Guy <kennyguy@google.com>2014-04-30 03:02:21 +0100
committerKenny Guy <kennyguy@google.com>2014-04-30 23:43:00 +0100
commited13187a745866483139e2878037e1f8427ce567 (patch)
treea60e4ab78d5365095fe90026df4dfa4e98e80d46 /src
parent70c3d1da65fcdaf32b860a5582b211c1f0ae8718 (diff)
downloadandroid_packages_apps_Trebuchet-ed13187a745866483139e2878037e1f8427ce567.tar.gz
android_packages_apps_Trebuchet-ed13187a745866483139e2878037e1f8427ce567.tar.bz2
android_packages_apps_Trebuchet-ed13187a745866483139e2878037e1f8427ce567.zip
Launcher3 multi-profile support
Use LauncherApps API and badging APIs instead of PackageManager. With compatability layer that uses PackageManager pre L. Adds support to show apps from current user and any managed profiles. Background: Managed profiles are user sandboxes that are visible from the primary user and can be launched as if they are a part of this user. A launcher should now be capable of listing apps from this user as well as related profiles of this user. Launching of activities is now via the LauncherApps interface, to allow for cross-profile app launching. Only activities with category LAUNCHER can be added as a shortcut on the workspace for a managed profile. Widgets and non-application shortcuts are only supported for the current profile. Widgets from the managed profile are not available. Change-Id: I5f396b1bf7f91ad91a5710ea4a0fd14573972eb9
Diffstat (limited to 'src')
-rw-r--r--src/com/android/launcher3/AllAppsList.java92
-rw-r--r--src/com/android/launcher3/AppInfo.java58
-rw-r--r--src/com/android/launcher3/AppsCustomizePagedView.java3
-rw-r--r--src/com/android/launcher3/DeleteDropTarget.java26
-rw-r--r--src/com/android/launcher3/FolderInfo.java8
-rw-r--r--src/com/android/launcher3/IconCache.java151
-rw-r--r--src/com/android/launcher3/ItemInfo.java21
-rw-r--r--src/com/android/launcher3/Launcher.java103
-rw-r--r--src/com/android/launcher3/LauncherAppState.java13
-rw-r--r--src/com/android/launcher3/LauncherAppWidgetInfo.java9
-rw-r--r--src/com/android/launcher3/LauncherBackupHelper.java15
-rw-r--r--src/com/android/launcher3/LauncherModel.java468
-rw-r--r--src/com/android/launcher3/LauncherProvider.java63
-rw-r--r--src/com/android/launcher3/LauncherSettings.java8
-rw-r--r--src/com/android/launcher3/ShortcutInfo.java56
-rw-r--r--src/com/android/launcher3/Workspace.java20
-rw-r--r--src/com/android/launcher3/compat/LauncherActivityInfoCompat.java34
-rw-r--r--src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java94
-rw-r--r--src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java82
-rw-r--r--src/com/android/launcher3/compat/LauncherAppsCompat.java74
-rw-r--r--src/com/android/launcher3/compat/LauncherAppsCompatV16.java191
-rw-r--r--src/com/android/launcher3/compat/LauncherAppsCompatVL.java204
-rw-r--r--src/com/android/launcher3/compat/ReflectUtils.java159
-rw-r--r--src/com/android/launcher3/compat/UserHandleCompat.java81
-rw-r--r--src/com/android/launcher3/compat/UserManagerCompat.java44
-rw-r--r--src/com/android/launcher3/compat/UserManagerCompatV16.java47
-rw-r--r--src/com/android/launcher3/compat/UserManagerCompatV17.java42
-rw-r--r--src/com/android/launcher3/compat/UserManagerCompatVL.java68
28 files changed, 1732 insertions, 502 deletions
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index 89b291f28..c25aa4094 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -23,6 +23,10 @@ import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import com.android.launcher3.compat.LauncherActivityInfoCompat;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+
import java.util.ArrayList;
import java.util.List;
@@ -66,7 +70,7 @@ class AllAppsList {
if (mAppFilter != null && !mAppFilter.shouldShowApp(info.componentName)) {
return;
}
- if (findActivity(data, info.componentName)) {
+ if (findActivity(data, info.componentName, info.user)) {
return;
}
data.add(info);
@@ -92,12 +96,14 @@ class AllAppsList {
/**
* Add the icons for the supplied apk called packageName.
*/
- public void addPackage(Context context, String packageName) {
- final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName);
+ public void addPackage(Context context, String packageName, UserHandleCompat user) {
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ final List<LauncherActivityInfoCompat> matches = launcherApps.getActivityList(packageName,
+ user);
if (matches.size() > 0) {
- for (ResolveInfo info : matches) {
- add(new AppInfo(context.getPackageManager(), info, mIconCache, null));
+ for (LauncherActivityInfoCompat info : matches) {
+ add(new AppInfo(context, info, user, mIconCache, null));
}
}
}
@@ -105,34 +111,37 @@ class AllAppsList {
/**
* Remove the apps for the given apk identified by packageName.
*/
- public void removePackage(String packageName) {
+ public void removePackage(String packageName, UserHandleCompat user) {
final List<AppInfo> data = this.data;
for (int i = data.size() - 1; i >= 0; i--) {
AppInfo info = data.get(i);
final ComponentName component = info.intent.getComponent();
- if (packageName.equals(component.getPackageName())) {
+ if (info.user.equals(user) && packageName.equals(component.getPackageName())) {
removed.add(info);
data.remove(i);
}
}
- mIconCache.remove(packageName);
+ mIconCache.remove(packageName, user);
}
/**
* Add and remove icons for this package which has been updated.
*/
- public void updatePackage(Context context, String packageName) {
- final List<ResolveInfo> matches = findActivitiesForPackage(context, packageName);
+ public void updatePackage(Context context, String packageName, UserHandleCompat user) {
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ final List<LauncherActivityInfoCompat> matches = launcherApps.getActivityList(packageName,
+ user);
if (matches.size() > 0) {
// Find disabled/removed activities and remove them from data and add them
// to the removed list.
for (int i = data.size() - 1; i >= 0; i--) {
final AppInfo applicationInfo = data.get(i);
final ComponentName component = applicationInfo.intent.getComponent();
- if (packageName.equals(component.getPackageName())) {
+ if (user.equals(applicationInfo.user)
+ && packageName.equals(component.getPackageName())) {
if (!findActivity(matches, component)) {
removed.add(applicationInfo);
- mIconCache.remove(component);
+ mIconCache.remove(component, user);
data.remove(i);
}
}
@@ -142,14 +151,14 @@ class AllAppsList {
// Also updates existing activities with new labels/icons
int count = matches.size();
for (int i = 0; i < count; i++) {
- final ResolveInfo info = matches.get(i);
+ final LauncherActivityInfoCompat info = matches.get(i);
AppInfo applicationInfo = findApplicationInfoLocked(
- info.activityInfo.applicationInfo.packageName,
- info.activityInfo.name);
+ info.getComponentName().getPackageName(), user,
+ info.getComponentName().getShortClassName());
if (applicationInfo == null) {
- add(new AppInfo(context.getPackageManager(), info, mIconCache, null));
+ add(new AppInfo(context, info, user, mIconCache, null));
} else {
- mIconCache.remove(applicationInfo.componentName);
+ mIconCache.remove(applicationInfo.componentName, user);
mIconCache.getTitleAndIcon(applicationInfo, info, null);
modified.add(applicationInfo);
}
@@ -159,37 +168,24 @@ class AllAppsList {
for (int i = data.size() - 1; i >= 0; i--) {
final AppInfo applicationInfo = data.get(i);
final ComponentName component = applicationInfo.intent.getComponent();
- if (packageName.equals(component.getPackageName())) {
+ if (user.equals(applicationInfo.user)
+ && packageName.equals(component.getPackageName())) {
removed.add(applicationInfo);
- mIconCache.remove(component);
+ mIconCache.remove(component, user);
data.remove(i);
}
}
}
}
- /**
- * Query the package manager for MAIN/LAUNCHER activities in the supplied package.
- */
- static List<ResolveInfo> findActivitiesForPackage(Context context, String packageName) {
- final PackageManager packageManager = context.getPackageManager();
-
- final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- mainIntent.setPackage(packageName);
-
- final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
- return apps != null ? apps : new ArrayList<ResolveInfo>();
- }
/**
* Returns whether <em>apps</em> contains <em>component</em>.
*/
- private static boolean findActivity(List<ResolveInfo> apps, ComponentName component) {
- final String className = component.getClassName();
- for (ResolveInfo info : apps) {
- final ActivityInfo activityInfo = info.activityInfo;
- if (activityInfo.name.equals(className)) {
+ private static boolean findActivity(List<LauncherActivityInfoCompat> apps,
+ ComponentName component) {
+ for (LauncherActivityInfoCompat info : apps) {
+ if (info.getComponentName().equals(component)) {
return true;
}
}
@@ -197,13 +193,24 @@ class AllAppsList {
}
/**
+ * Query the launcher apps service for whether the supplied package has
+ * MAIN/LAUNCHER activities in the supplied package.
+ */
+ static boolean packageHasActivities(Context context, String packageName,
+ UserHandleCompat user) {
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ return launcherApps.getActivityList(packageName, user).size() > 0;
+ }
+
+ /**
* Returns whether <em>apps</em> contains <em>component</em>.
*/
- private static boolean findActivity(ArrayList<AppInfo> apps, ComponentName component) {
+ private static boolean findActivity(ArrayList<AppInfo> apps, ComponentName component,
+ UserHandleCompat user) {
final int N = apps.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
final AppInfo info = apps.get(i);
- if (info.componentName.equals(component)) {
+ if (info.user.equals(user) && info.componentName.equals(component)) {
return true;
}
}
@@ -213,10 +220,11 @@ class AllAppsList {
/**
* Find an ApplicationInfo object for the given packageName and className.
*/
- private AppInfo findApplicationInfoLocked(String packageName, String className) {
+ private AppInfo findApplicationInfoLocked(String packageName, UserHandleCompat user,
+ String className) {
for (AppInfo info: data) {
final ComponentName component = info.intent.getComponent();
- if (packageName.equals(component.getPackageName())
+ if (user.equals(info.user) && packageName.equals(component.getPackageName())
&& className.equals(component.getClassName())) {
return info;
}
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index c16e98f0c..40e8e6d0e 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -17,14 +17,18 @@
package com.android.launcher3;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.util.Log;
+import com.android.launcher3.compat.LauncherActivityInfoCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -72,28 +76,24 @@ public class AppInfo extends ItemInfo {
/**
* Must not hold the Context.
*/
- public AppInfo(PackageManager pm, ResolveInfo info, IconCache iconCache,
- HashMap<Object, CharSequence> labelCache) {
- final String packageName = info.activityInfo.applicationInfo.packageName;
-
- this.componentName = new ComponentName(packageName, info.activityInfo.name);
+ public AppInfo(Context context, LauncherActivityInfoCompat info, UserHandleCompat user,
+ IconCache iconCache, HashMap<Object, CharSequence> labelCache) {
+ this.componentName = info.getComponentName();
this.container = ItemInfo.NO_ID;
- this.setActivity(componentName,
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-
- try {
- PackageInfo pi = pm.getPackageInfo(packageName, 0);
- flags = initFlags(pi);
- firstInstallTime = initFirstInstallTime(pi);
- } catch (NameNotFoundException e) {
- Log.d(TAG, "PackageManager.getApplicationInfo failed for " + packageName);
- }
+ flags = initFlags(info);
+ firstInstallTime = info.getFirstInstallTime();
iconCache.getTitleAndIcon(this, info, labelCache);
+ intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.setComponent(info.getComponentName());
+ long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
+ intent.putExtra(EXTRA_PROFILE, serialNumber);
+ this.user = user;
}
- public static int initFlags(PackageInfo pi) {
- int appFlags = pi.applicationInfo.flags;
+ private static int initFlags(LauncherActivityInfoCompat info) {
+ int appFlags = info.getApplicationFlags();
int flags = 0;
if ((appFlags & android.content.pm.ApplicationInfo.FLAG_SYSTEM) == 0) {
flags |= DOWNLOADED_FLAG;
@@ -105,10 +105,6 @@ public class AppInfo extends ItemInfo {
return flags;
}
- public static long initFirstInstallTime(PackageInfo pi) {
- return pi.firstInstallTime;
- }
-
public AppInfo(AppInfo info) {
super(info);
componentName = info.componentName;
@@ -116,21 +112,7 @@ public class AppInfo extends ItemInfo {
intent = new Intent(info.intent);
flags = info.flags;
firstInstallTime = info.firstInstallTime;
- }
-
- /**
- * Creates the application intent based on a component name and various launch flags.
- * Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}.
- *
- * @param className the class name of the component representing the intent
- * @param launchFlags the launch flags
- */
- final void setActivity(ComponentName className, int launchFlags) {
- intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- intent.setComponent(className);
- intent.setFlags(launchFlags);
- itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
+ iconBitmap = info.iconBitmap;
}
@Override
@@ -139,7 +121,7 @@ public class AppInfo extends ItemInfo {
+ " type=" + this.itemType + " container=" + this.container
+ " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY
+ " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos)
- + ")";
+ + " user=" + user + ")";
}
public static void dumpApplicationInfoList(String tag, String label, ArrayList<AppInfo> list) {
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index d6e0bb49e..9d86959c4 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -1575,7 +1575,8 @@ public class AppsCustomizePagedView extends PagedViewWithDraggableItems implemen
int length = list.size();
for (int i = 0; i < length; ++i) {
AppInfo info = list.get(i);
- if (info.intent.getComponent().equals(removeComponent)) {
+ if (info.user.equals(item.user)
+ && info.intent.getComponent().equals(removeComponent)) {
return i;
}
}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 75d906bc2..20546b8d8 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -38,6 +38,9 @@ import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+
import java.util.List;
import java.util.Set;
@@ -184,6 +187,11 @@ public class DeleteDropTarget extends ButtonDropTarget {
if (!willAcceptDrop(info) || isAllAppsWidget(source, info)) {
isVisible = false;
}
+ if (useUninstallLabel &&
+ !(((ItemInfo) info).user.equals(UserHandleCompat.myUserHandle()))) {
+ // Don't support uninstall for apps from other profiles.
+ isVisible = false;
+ }
if (useUninstallLabel) {
setCompoundDrawablesRelativeWithIntrinsicBounds(mUninstallDrawable, null, null, null);
@@ -279,25 +287,27 @@ public class DeleteDropTarget extends ButtonDropTarget {
if (isAllAppsApplication(d.dragSource, item)) {
// Uninstall the application if it is being dragged from AppsCustomize
AppInfo appInfo = (AppInfo) item;
- mLauncher.startApplicationUninstallActivity(appInfo.componentName, appInfo.flags);
+ // We don't support uninstalling apps from other profiles.
+ if (item.user.equals(UserHandleCompat.myUserHandle())) {
+ mLauncher.startApplicationUninstallActivity(appInfo.componentName, appInfo.flags);
+ }
} else if (isUninstallFromWorkspace(d)) {
ShortcutInfo shortcut = (ShortcutInfo) item;
- if (shortcut.intent != null && shortcut.intent.getComponent() != null) {
+ // We don't support uninstalling apps from other profiles.
+ if (shortcut.intent != null && shortcut.intent.getComponent() != null &&
+ shortcut.user.equals(UserHandleCompat.myUserHandle())) {
final ComponentName componentName = shortcut.intent.getComponent();
final DragSource dragSource = d.dragSource;
- int flags = AppInfo.initFlags(
- ShortcutInfo.getPackageInfo(getContext(), componentName.getPackageName()));
mWaitingForUninstall =
- mLauncher.startApplicationUninstallActivity(componentName, flags);
+ mLauncher.startApplicationUninstallActivity(componentName, shortcut.flags);
if (mWaitingForUninstall) {
final Runnable checkIfUninstallWasSuccess = new Runnable() {
@Override
public void run() {
mWaitingForUninstall = false;
String packageName = componentName.getPackageName();
- List<ResolveInfo> activities =
- AllAppsList.findActivitiesForPackage(getContext(), packageName);
- boolean uninstallSuccessful = activities.size() == 0;
+ boolean uninstallSuccessful = !AllAppsList.packageHasActivities(
+ getContext(), packageName, UserHandleCompat.myUserHandle());
if (dragSource instanceof Folder) {
((Folder) dragSource).
onUninstallActivityReturned(uninstallSuccessful);
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 61fa7e574..85a792f4b 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -17,6 +17,9 @@
package com.android.launcher3;
import android.content.ContentValues;
+import android.content.Context;
+
+import com.android.launcher3.compat.UserHandleCompat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -40,6 +43,7 @@ public class FolderInfo extends ItemInfo {
FolderInfo() {
itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
+ user = UserHandleCompat.myUserHandle();
}
/**
@@ -76,8 +80,8 @@ public class FolderInfo extends ItemInfo {
}
@Override
- void onAddToDatabase(ContentValues values) {
- super.onAddToDatabase(values);
+ void onAddToDatabase(Context context, ContentValues values) {
+ super.onAddToDatabase(context, values);
values.put(LauncherSettings.Favorites.TITLE, title.toString());
}
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index ee9f4d4b0..05be2141e 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -31,8 +31,14 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.util.Log;
+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.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -61,11 +67,35 @@ public class IconCache {
public String title;
}
- private final Bitmap mDefaultIcon;
+ private static class CacheKey {
+ public ComponentName componentName;
+ public UserHandleCompat user;
+
+ CacheKey(ComponentName componentName, UserHandleCompat user) {
+ this.componentName = componentName;
+ this.user = user;
+ }
+
+ @Override
+ public int hashCode() {
+ return componentName.hashCode() + user.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ CacheKey other = (CacheKey) o;
+ return other.componentName.equals(componentName) && other.user.equals(user);
+ }
+ }
+
+ private final HashMap<UserHandleCompat, Bitmap> mDefaultIcons =
+ new HashMap<UserHandleCompat, Bitmap>();
private final Context mContext;
private final PackageManager mPackageManager;
- private final HashMap<ComponentName, CacheEntry> mCache =
- new HashMap<ComponentName, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
+ private final UserManagerCompat mUserManager;
+ private final LauncherAppsCompat mLauncherApps;
+ private final HashMap<CacheKey, CacheEntry> mCache =
+ new HashMap<CacheKey, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
private int mIconDpi;
public IconCache(Context context) {
@@ -74,10 +104,13 @@ public class IconCache {
mContext = context;
mPackageManager = context.getPackageManager();
+ mUserManager = UserManagerCompat.getInstance(mContext);
+ mLauncherApps = LauncherAppsCompat.getInstance(mContext);
mIconDpi = activityManager.getLauncherLargeIconDensity();
// need to set mIconDpi before getting default icon
- mDefaultIcon = makeDefaultIcon();
+ UserHandleCompat myUser = UserHandleCompat.myUserHandle();
+ mDefaultIcons.put(myUser, makeDefaultIcon(myUser));
}
public Drawable getFullResDefaultActivityIcon() {
@@ -134,8 +167,9 @@ public class IconCache {
return getFullResDefaultActivityIcon();
}
- private Bitmap makeDefaultIcon() {
- Drawable d = getFullResDefaultActivityIcon();
+ private Bitmap makeDefaultIcon(UserHandleCompat user) {
+ Drawable unbadged = getFullResDefaultActivityIcon();
+ Drawable d = mUserManager.getBadgedDrawableForUser(unbadged, user);
Bitmap b = Bitmap.createBitmap(Math.max(d.getIntrinsicWidth(), 1),
Math.max(d.getIntrinsicHeight(), 1),
Bitmap.Config.ARGB_8888);
@@ -149,24 +183,25 @@ public class IconCache {
/**
* Remove any records for the supplied ComponentName.
*/
- public void remove(ComponentName componentName) {
+ public void remove(ComponentName componentName, UserHandleCompat user) {
synchronized (mCache) {
- mCache.remove(componentName);
+ mCache.remove(new CacheKey(componentName, user));
}
}
/**
* Remove any records for the supplied package name.
*/
- public void remove(String packageName) {
- HashSet<ComponentName> forDeletion = new HashSet<ComponentName>();
- for (ComponentName componentName: mCache.keySet()) {
- if (componentName.getPackageName().equals(packageName)) {
- forDeletion.add(componentName);
+ public void remove(String packageName, UserHandleCompat user) {
+ HashSet<CacheKey> forDeletion = new HashSet<CacheKey>();
+ for (CacheKey key: mCache.keySet()) {
+ if (key.componentName.getPackageName().equals(packageName)
+ && key.user.equals(user)) {
+ forDeletion.add(key);
}
}
- for (ComponentName condemned: forDeletion) {
- remove(condemned);
+ for (CacheKey condemned: forDeletion) {
+ mCache.remove(condemned);
}
}
@@ -184,7 +219,7 @@ public class IconCache {
*/
public void flushInvalidIcons(DeviceProfile grid) {
synchronized (mCache) {
- Iterator<Entry<ComponentName, CacheEntry>> it = mCache.entrySet().iterator();
+ Iterator<Entry<CacheKey, CacheEntry>> it = mCache.entrySet().iterator();
while (it.hasNext()) {
final CacheEntry e = it.next().getValue();
if (e.icon.getWidth() < grid.iconSizePx || e.icon.getHeight() < grid.iconSizePx) {
@@ -197,30 +232,32 @@ public class IconCache {
/**
* Fill in "application" with the icon and label for "info."
*/
- public void getTitleAndIcon(AppInfo application, ResolveInfo info,
+ public void getTitleAndIcon(AppInfo application, LauncherActivityInfoCompat info,
HashMap<Object, CharSequence> labelCache) {
synchronized (mCache) {
- CacheEntry entry = cacheLocked(application.componentName, info, labelCache);
+ CacheEntry entry = cacheLocked(application.componentName, info, labelCache,
+ info.getUser());
application.title = entry.title;
application.iconBitmap = entry.icon;
}
}
- public Bitmap getIcon(Intent intent) {
- return getIcon(intent, null);
+ public Bitmap getIcon(Intent intent, UserHandleCompat user) {
+ return getIcon(intent, null, user);
}
- public Bitmap getIcon(Intent intent, String title) {
+ public Bitmap getIcon(Intent intent, String title, UserHandleCompat user) {
synchronized (mCache) {
- final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0);
+ final LauncherActivityInfoCompat launcherActInfo =
+ mLauncherApps.resolveActivity(intent, user);
ComponentName component = intent.getComponent();
- if (component == null) {
- return mDefaultIcon;
+ if (launcherActInfo == null || component == null) {
+ return getDefaultIcon(user);
}
- CacheEntry entry = cacheLocked(component, resolveInfo, null);
+ CacheEntry entry = cacheLocked(component, launcherActInfo, null, user);
if (title != null) {
entry.title = title;
}
@@ -228,49 +265,54 @@ public class IconCache {
}
}
- public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo,
+ public Bitmap getDefaultIcon(UserHandleCompat user) {
+ if (!mDefaultIcons.containsKey(user)) {
+ mDefaultIcons.put(user, makeDefaultIcon(user));
+ }
+ return mDefaultIcons.get(user);
+ }
+
+ public Bitmap getIcon(ComponentName component, LauncherActivityInfoCompat info,
HashMap<Object, CharSequence> labelCache) {
synchronized (mCache) {
- if (resolveInfo == null || component == null) {
+ if (info == null || component == null) {
return null;
}
- CacheEntry entry = cacheLocked(component, resolveInfo, labelCache);
+ CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser());
return entry.icon;
}
}
- public boolean isDefaultIcon(Bitmap icon) {
- return mDefaultIcon == icon;
+ public boolean isDefaultIcon(Bitmap icon, UserHandleCompat user) {
+ return mDefaultIcons.get(user) == icon;
}
- private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info,
- HashMap<Object, CharSequence> labelCache) {
- CacheEntry entry = mCache.get(componentName);
+ private CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfoCompat info,
+ HashMap<Object, CharSequence> labelCache, UserHandleCompat user) {
+ CacheKey cacheKey = new CacheKey(componentName, user);
+ CacheEntry entry = mCache.get(cacheKey);
if (entry == null) {
entry = new CacheEntry();
- mCache.put(componentName, entry);
+ mCache.put(cacheKey, entry);
if (info != null) {
- ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info);
- if (labelCache != null && labelCache.containsKey(key)) {
- entry.title = labelCache.get(key).toString();
+ ComponentName labelKey = info.getComponentName();
+ if (labelCache != null && labelCache.containsKey(labelKey)) {
+ entry.title = labelCache.get(labelKey).toString();
} else {
- entry.title = info.loadLabel(mPackageManager).toString();
+ entry.title = info.getLabel().toString();
if (labelCache != null) {
- labelCache.put(key, entry.title);
+ labelCache.put(labelKey, entry.title);
}
}
- if (entry.title == null) {
- entry.title = info.activityInfo.name;
- }
entry.icon = Utilities.createIconBitmap(
- getFullResIcon(info), mContext);
+ info.getBadgedIcon(mIconDpi), mContext);
} else {
entry.title = "";
- Bitmap preloaded = getPreloadedIcon(componentName);
+ Bitmap preloaded = getPreloadedIcon(componentName, user);
if (preloaded != null) {
if (DEBUG) Log.d(TAG, "using preloaded icon for " +
componentName.toShortString());
@@ -278,7 +320,7 @@ public class IconCache {
} else {
if (DEBUG) Log.d(TAG, "using default icon for " +
componentName.toShortString());
- entry.icon = mDefaultIcon;
+ entry.icon = getDefaultIcon(user);
}
}
}
@@ -288,9 +330,9 @@ public class IconCache {
public HashMap<ComponentName,Bitmap> getAllIcons() {
synchronized (mCache) {
HashMap<ComponentName,Bitmap> set = new HashMap<ComponentName,Bitmap>();
- for (ComponentName cn : mCache.keySet()) {
- final CacheEntry e = mCache.get(cn);
- set.put(cn, e.icon);
+ for (CacheKey ck : mCache.keySet()) {
+ final CacheEntry e = mCache.get(ck);
+ set.put(ck.componentName, e.icon);
}
return set;
}
@@ -353,9 +395,14 @@ public class IconCache {
* @param componentName the component that should own the icon
* @returns a bitmap if one is cached, or null.
*/
- private Bitmap getPreloadedIcon(ComponentName componentName) {
+ private Bitmap getPreloadedIcon(ComponentName componentName, UserHandleCompat user) {
final String key = componentName.flattenToShortString();
+ // We don't keep icons for other profiles in persistent cache.
+ if (!user.equals(UserHandleCompat.myUserHandle())) {
+ return null;
+ }
+
if (DEBUG) Log.v(TAG, "looking for pre-load icon for " + key);
Bitmap icon = null;
FileInputStream resourceFile = null;
@@ -396,7 +443,11 @@ public class IconCache {
* @param componentName the component that should own the icon
* @returns true on success
*/
- public boolean deletePreloadedIcon(ComponentName componentName) {
+ public boolean deletePreloadedIcon(ComponentName componentName, UserHandleCompat user) {
+ // We don't keep icons for other profiles in persistent cache.
+ if (!user.equals(UserHandleCompat.myUserHandle())) {
+ return false;
+ }
if (componentName == null) {
return false;
}
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 12bbee780..74f16e325 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -17,10 +17,14 @@
package com.android.launcher3;
import android.content.ContentValues;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.util.Log;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
@@ -29,6 +33,11 @@ import java.util.Arrays;
* Represents an item in the launcher.
*/
public class ItemInfo {
+
+ /**
+ * Intent extra to store the profile. Format: UserHandle
+ */
+ static final String EXTRA_PROFILE = "profile";
static final int NO_ID = -1;
@@ -103,6 +112,8 @@ public class ItemInfo {
*/
int[] dropPos = null;
+ UserHandleCompat user;
+
ItemInfo() {
}
@@ -115,6 +126,7 @@ public class ItemInfo {
screenId = info.screenId;
itemType = info.itemType;
container = info.container;
+ user = info.user;
// tempdebug:
LauncherModel.checkItemInfo(this);
}
@@ -130,9 +142,11 @@ public class ItemInfo {
/**
* Write the fields of this item to the DB
*
+ * @param context A context object to use for getting UserManagerCompat
* @param values
*/
- void onAddToDatabase(ContentValues values) {
+
+ void onAddToDatabase(Context context, ContentValues values) {
values.put(LauncherSettings.BaseLauncherColumns.ITEM_TYPE, itemType);
values.put(LauncherSettings.Favorites.CONTAINER, container);
values.put(LauncherSettings.Favorites.SCREEN, screenId);
@@ -140,6 +154,8 @@ public class ItemInfo {
values.put(LauncherSettings.Favorites.CELLY, cellY);
values.put(LauncherSettings.Favorites.SPANX, spanX);
values.put(LauncherSettings.Favorites.SPANY, spanY);
+ long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
+ values.put(LauncherSettings.Favorites.PROFILE_ID, serialNumber);
if (screenId == Workspace.EXTRA_EMPTY_SCREEN_ID) {
// We should never persist an item on the extra empty screen.
@@ -188,6 +204,7 @@ public class ItemInfo {
public String toString() {
return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container
+ " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
- + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos) + ")";
+ + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos)
+ + " user=" + user + ")";
}
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ff5b1eb3c..217219412 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -95,6 +95,10 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
+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 com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.PagedView.PageSwitchListener;
@@ -134,7 +138,6 @@ public class Launcher extends Activity
private static final int REQUEST_CREATE_SHORTCUT = 1;
private static final int REQUEST_CREATE_APPWIDGET = 5;
- private static final int REQUEST_PICK_APPLICATION = 6;
private static final int REQUEST_PICK_SHORTCUT = 7;
private static final int REQUEST_PICK_APPWIDGET = 9;
private static final int REQUEST_PICK_WALLPAPER = 10;
@@ -734,10 +737,6 @@ public class Launcher extends Activity
private boolean completeAdd(PendingAddArguments args) {
boolean result = false;
switch (args.requestCode) {
- case REQUEST_PICK_APPLICATION:
- completeAddApplication(args.intent, args.container, args.screenId, args.cellX,
- args.cellY);
- break;
case REQUEST_PICK_SHORTCUT:
processShortcut(args.intent);
break;
@@ -1368,38 +1367,6 @@ public class Launcher extends Activity
}
/**
- * Add an application shortcut to the workspace.
- *
- * @param data The intent describing the application.
- * @param cellInfo The position on screen where to create the shortcut.
- */
- void completeAddApplication(Intent data, long container, long screenId, int cellX, int cellY) {
- final int[] cellXY = mTmpAddItemCellCoordinates;
- final CellLayout layout = getCellLayout(container, screenId);
-
- // First we check if we already know the exact location where we want to add this item.
- if (cellX >= 0 && cellY >= 0) {
- cellXY[0] = cellX;
- cellXY[1] = cellY;
- } else if (!layout.findCellForSpan(cellXY, 1, 1)) {
- showOutOfSpaceMessage(isHotseatLayout(layout));
- return;
- }
-
- final ShortcutInfo info = mModel.getShortcutInfo(getPackageManager(), data, this);
-
- if (info != null) {
- info.setActivity(this, data.getComponent(), Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- info.container = ItemInfo.NO_ID;
- mWorkspace.addApplicationShortcut(info, layout, container, screenId, cellXY[0], cellXY[1],
- isWorkspaceLocked(), cellX, cellY);
- } else {
- Log.e(TAG, "Couldn't find ActivityInfo for selected application: " + data);
- }
- }
-
- /**
* Add a shortcut to the workspace.
*
* @param data The intent describing the shortcut.
@@ -2220,21 +2187,7 @@ public class Launcher extends Activity
}
void processShortcut(Intent intent) {
- // Handle case where user selected "Applications"
- String applicationName = getResources().getString(R.string.group_applications);
- String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
-
- if (applicationName != null && applicationName.equals(shortcutName)) {
- Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
- Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
- pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
- pickIntent.putExtra(Intent.EXTRA_TITLE, getText(R.string.title_select_application));
- Utilities.startActivityForResultSafely(this, pickIntent, REQUEST_PICK_APPLICATION);
- } else {
- Utilities.startActivityForResultSafely(this, intent, REQUEST_CREATE_SHORTCUT);
- }
+ Utilities.startActivityForResultSafely(this, intent, REQUEST_CREATE_SHORTCUT);
}
void processWallpaper(Intent intent) {
@@ -2651,18 +2604,29 @@ public class Launcher extends Activity
}
boolean startActivity(View v, Intent intent, Object tag) {
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
try {
// Only launch using the new animation if the shortcut has not opted out (this is a
// private contract between launcher and may be ignored in the future).
boolean useLaunchAnimation = (v != null) &&
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
+ LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this);
+ UserManagerCompat userManager = UserManagerCompat.getInstance(this);
+ long serialNumber = intent.getLongExtra(AppInfo.EXTRA_PROFILE, 0);
+ UserHandleCompat user = serialNumber == 0 ? null :
+ userManager.getUserForSerialNumber(serialNumber);
+
if (useLaunchAnimation) {
ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
v.getMeasuredWidth(), v.getMeasuredHeight());
-
- startActivity(intent, opts.toBundle());
+ if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
+ // Could be launching some bookkeeping activity
+ startActivity(intent, opts.toBundle());
+ } else {
+ launcherApps.startActivityForProfile(intent.getComponent(),
+ intent.getSourceBounds(),
+ opts.toBundle(), user);
+ }
} else {
startActivity(intent);
}
@@ -4270,10 +4234,10 @@ public class Launcher extends Activity
* Implementation of the method from LauncherModel.Callbacks.
*/
public void bindComponentsRemoved(final ArrayList<String> packageNames,
- final ArrayList<AppInfo> appInfos) {
+ final ArrayList<AppInfo> appInfos, final UserHandleCompat user) {
Runnable r = new Runnable() {
public void run() {
- bindComponentsRemoved(packageNames, appInfos);
+ bindComponentsRemoved(packageNames, appInfos, user);
}
};
if (waitUntilResume(r)) {
@@ -4281,10 +4245,10 @@ public class Launcher extends Activity
}
if (!packageNames.isEmpty()) {
- mWorkspace.removeItemsByPackageName(packageNames);
+ mWorkspace.removeItemsByPackageName(packageNames, user);
}
if (!appInfos.isEmpty()) {
- mWorkspace.removeItemsByApplicationInfo(appInfos);
+ mWorkspace.removeItemsByApplicationInfo(appInfos, user);
}
// Notify the drag controller
@@ -4555,16 +4519,27 @@ public class Launcher extends Activity
}
public ItemInfo createAppDragInfo(Intent appLaunchIntent) {
- ResolveInfo ri = getPackageManager().resolveActivity(appLaunchIntent, 0);
- if (ri == null) {
+ // Called from search suggestion, not supported in other profiles.
+ final UserHandleCompat myUser = UserHandleCompat.myUserHandle();
+ LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this);
+ LauncherActivityInfoCompat activityInfo = launcherApps.resolveActivity(appLaunchIntent,
+ myUser);
+ if (activityInfo == null) {
return null;
}
- return new AppInfo(getPackageManager(), ri, mIconCache, null);
+ return new AppInfo(this, activityInfo, myUser, mIconCache, null);
}
public ItemInfo createShortcutDragInfo(Intent shortcutIntent, CharSequence caption,
Bitmap icon) {
- return new ShortcutInfo(shortcutIntent, caption, icon);
+ // Called from search suggestion, not supported in other profiles.
+ return createShortcutDragInfo(shortcutIntent, caption, icon,
+ UserHandleCompat.myUserHandle());
+ }
+
+ public ItemInfo createShortcutDragInfo(Intent shortcutIntent, CharSequence caption,
+ Bitmap icon, UserHandleCompat user) {
+ return new ShortcutInfo(shortcutIntent, caption, icon, user);
}
protected void moveWorkspaceToDefaultScreen() {
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index ad0101979..0725a652f 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -24,6 +24,8 @@ import android.database.ContentObserver;
import android.os.Handler;
import android.util.Log;
+import com.android.launcher3.compat.LauncherAppsCompat;
+
import java.lang.ref.WeakReference;
public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
@@ -92,16 +94,11 @@ public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class));
mBuildInfo = BuildInfo.loadByName(sContext.getString(R.string.build_info_class));
mModel = new LauncherModel(this, mIconCache, mAppFilter);
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(sContext);
+ launcherApps.addOnAppsChangedListener(mModel);
// Register intent receivers
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addDataScheme("package");
- sContext.registerReceiver(mModel, filter);
- filter = new IntentFilter();
- filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
sContext.registerReceiver(mModel, filter);
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index 950828e09..bec1f9eb3 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -19,6 +19,9 @@ package com.android.launcher3;
import android.appwidget.AppWidgetHostView;
import android.content.ComponentName;
import android.content.ContentValues;
+import android.content.Context;
+
+import com.android.launcher3.compat.UserHandleCompat;
/**
* Represents a widget (either instantiated or about to be) in the Launcher.
@@ -59,11 +62,13 @@ public class LauncherAppWidgetInfo extends ItemInfo {
// to indicate that they should be calculated based on the layout and minWidth/minHeight
spanX = -1;
spanY = -1;
+ // We only support app widgets on current user.
+ user = UserHandleCompat.myUserHandle();
}
@Override
- void onAddToDatabase(ContentValues values) {
- super.onAddToDatabase(values);
+ void onAddToDatabase(Context context, ContentValues values) {
+ super.onAddToDatabase(context, values);
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, providerName.flattenToString());
}
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index cab55c79e..275fccc16 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -28,6 +28,8 @@ import com.android.launcher3.backup.BackupProtos.Key;
import com.android.launcher3.backup.BackupProtos.Resource;
import com.android.launcher3.backup.BackupProtos.Screen;
import com.android.launcher3.backup.BackupProtos.Widget;
+import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.compat.UserHandleCompat;
import android.app.backup.BackupDataInputStream;
import android.app.backup.BackupDataOutput;
@@ -459,10 +461,15 @@ public class LauncherBackupHelper implements BackupHelper {
Set<String> savedIds = getSavedIdsByType(Key.ICON, in);
if (DEBUG) Log.d(TAG, "icon savedIds.size()=" + savedIds.size());
+ // Don't backup apps in other profiles for now.
+ UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
+ long userSerialNumber =
+ UserManagerCompat.getInstance(mContext).getSerialNumberForUser(myUserHandle);
int startRows = out.rows;
if (DEBUG) Log.d(TAG, "starting here: " + startRows);
- String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPLICATION + " OR " +
- Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_SHORTCUT;
+ String where = "(" + Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPLICATION + " OR " +
+ Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_SHORTCUT + ") AND" +
+ Favorites.PROFILE_ID + "=" + userSerialNumber;
Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
where, null, null);
Set<String> currentIds = new HashSet<String>(cursor.getCount());
@@ -492,9 +499,9 @@ public class LauncherBackupHelper implements BackupHelper {
if (DEBUG) Log.d(TAG, "I can count this high: " + out.rows);
if ((out.rows - startRows) < MAX_ICONS_PER_PASS) {
if (VERBOSE) Log.v(TAG, "saving icon " + backupKey);
- Bitmap icon = mIconCache.getIcon(intent);
+ Bitmap icon = mIconCache.getIcon(intent, myUserHandle);
keys.add(key);
- if (icon != null && !mIconCache.isDefaultIcon(icon)) {
+ if (icon != null && !mIconCache.isDefaultIcon(icon, myUserHandle)) {
byte[] blob = packIcon(dpi, icon);
writeRowToBackup(key, blob, out, data);
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 044ddbb44..15db057ec 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -44,6 +44,10 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+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 com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
import java.lang.ref.WeakReference;
@@ -67,7 +71,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
* LauncherModel object held in a static. Also provide APIs for updating the database state
* for the Launcher.
*/
-public class LauncherModel extends BroadcastReceiver {
+public class LauncherModel extends BroadcastReceiver
+ implements LauncherAppsCompat.OnAppsChangedListenerCompat {
static final boolean DEBUG_LOADERS = false;
private static final boolean DEBUG_RECEIVER = true; // STOPSHIP(cwren) temporary for debugging
@@ -153,10 +158,12 @@ public class LauncherModel extends BroadcastReceiver {
// </ only access in worker thread >
private IconCache mIconCache;
- private Bitmap mDefaultIcon;
protected int mPreviousConfigMcc;
+ private final LauncherAppsCompat mLauncherApps;
+ private final UserManagerCompat mUserManager;
+
public interface Callbacks {
public boolean setLoadOnResume();
public int getCurrentWorkspaceScreen();
@@ -176,7 +183,7 @@ public class LauncherModel extends BroadcastReceiver {
public void bindAppsUpdated(ArrayList<AppInfo> apps);
public void updatePackageState(String pkgName, int state);
public void bindComponentsRemoved(ArrayList<String> packageNames,
- ArrayList<AppInfo> appInfos);
+ ArrayList<AppInfo> appInfos, UserHandleCompat user);
public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
public void bindSearchablesChanged();
public boolean isAllAppsButtonRank(int rank);
@@ -206,6 +213,8 @@ public class LauncherModel extends BroadcastReceiver {
final Resources res = context.getResources();
Configuration config = res.getConfiguration();
mPreviousConfigMcc = config.mcc;
+ mLauncherApps = LauncherAppsCompat.getInstance(context);
+ mUserManager = UserManagerCompat.getInstance(context);
}
/** Runs the specified runnable immediately if called from the main thread, otherwise it is
@@ -325,7 +334,7 @@ public class LauncherModel extends BroadcastReceiver {
Iterator<AppInfo> iter = allAppsApps.iterator();
while (iter.hasNext()) {
ItemInfo a = iter.next();
- if (LauncherModel.appWasRestored(ctx, a.getIntent())) {
+ if (LauncherModel.appWasRestored(ctx, a.getIntent(), a.user)) {
restoredAppsFinal.add((AppInfo) a);
}
}
@@ -341,7 +350,8 @@ public class LauncherModel extends BroadcastReceiver {
for (AppInfo info : restoredAppsFinal) {
final Intent intent = info.getIntent();
if (intent != null) {
- mIconCache.deletePreloadedIcon(intent.getComponent());
+ mIconCache.deletePreloadedIcon(intent.getComponent(),
+ info.user);
}
}
callbacks.bindAppsUpdated(restoredAppsFinal);
@@ -393,7 +403,7 @@ public class LauncherModel extends BroadcastReceiver {
if (LauncherModel.shortcutExists(context, name, launchIntent)) {
// Only InstallShortcutReceiver sends us shortcutInfos, ignore them
if (a instanceof AppInfo &&
- LauncherModel.appWasRestored(context, launchIntent)) {
+ LauncherModel.appWasRestored(context, launchIntent, a.user)) {
restoredAppsFinal.add((AppInfo) a);
}
continue;
@@ -483,15 +493,6 @@ public class LauncherModel extends BroadcastReceiver {
runOnWorkerThread(r);
}
- public Bitmap getFallbackIcon() {
- if (mDefaultIcon == null) {
- final Context context = LauncherAppState.getInstance().getContext();
- mDefaultIcon = Utilities.createIconBitmap(
- mIconCache.getFullResDefaultActivityIcon(), context);
- }
- return Bitmap.createBitmap(mDefaultIcon);
- }
-
public void unbindItemInfosAndClearQueuedBindRunnables() {
if (sWorkerThread.getThreadId() == Process.myTid()) {
throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +
@@ -817,7 +818,7 @@ public class LauncherModel extends BroadcastReceiver {
*/
static void updateItemInDatabase(Context context, final ItemInfo item) {
final ContentValues values = new ContentValues();
- item.onAddToDatabase(values);
+ item.onAddToDatabase(context, values);
item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");
}
@@ -842,18 +843,22 @@ public class LauncherModel extends BroadcastReceiver {
/**
* Returns true if the shortcuts already exists in the database.
- * we identify a shortcut by the component name of the intent.
+ * we identify a shortcut by the component name of the intent
+ * and the user.
*/
- static boolean appWasRestored(Context context, Intent intent) {
+ static boolean appWasRestored(Context context, Intent intent, UserHandleCompat user) {
final ContentResolver cr = context.getContentResolver();
final ComponentName component = intent.getComponent();
if (component == null) {
return false;
}
String componentName = component.flattenToString();
- final String where = "intent glob \"*component=" + componentName + "*\" and restored = 1";
+ long serialNumber = UserManagerCompat.getInstance(context)
+ .getSerialNumberForUser(user);
+ final String where = "intent glob \"*component=" + componentName + "*\" and restored = 1"
+ + " and profileId = " + serialNumber;
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
- new String[]{"intent", "restored"}, where, null, null);
+ new String[]{"intent", "restored", "profileId"}, where, null, null);
boolean result = false;
try {
result = c.moveToFirst();
@@ -873,8 +878,10 @@ public class LauncherModel extends BroadcastReceiver {
final ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {
LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,
- LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
- LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null);
+ LauncherSettings.Favorites.SCREEN,
+ LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
+ LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY,
+ LauncherSettings.Favorites.PROFILE_ID }, null, null, null);
final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
@@ -883,7 +890,8 @@ public class LauncherModel extends BroadcastReceiver {
final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
-
+ final int profileIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID);
+ UserManagerCompat userManager = UserManagerCompat.getInstance(context);
try {
while (c.moveToNext()) {
ItemInfo item = new ItemInfo();
@@ -894,8 +902,12 @@ public class LauncherModel extends BroadcastReceiver {
item.container = c.getInt(containerIndex);
item.itemType = c.getInt(itemTypeIndex);
item.screenId = c.getInt(screenIndex);
-
- items.add(item);
+ int serialNumber = c.getInt(profileIdIndex);
+ item.user = userManager.getUserForSerialNumber(serialNumber);
+ // Skip if user has been deleted.
+ if (item.user != null) {
+ items.add(item);
+ }
}
} catch (Exception e) {
items.clear();
@@ -968,7 +980,7 @@ public class LauncherModel extends BroadcastReceiver {
final ContentValues values = new ContentValues();
final ContentResolver cr = context.getContentResolver();
- item.onAddToDatabase(values);
+ item.onAddToDatabase(context, values);
item.id = LauncherAppState.getLauncherProvider().generateNewItemId();
values.put(LauncherSettings.Favorites._ID, item.id);
@@ -1158,6 +1170,57 @@ public class LauncherModel extends BroadcastReceiver {
}
}
+ @Override
+ public void onPackageChanged(UserHandleCompat user, String packageName) {
+ int op = PackageUpdatedTask.OP_UPDATE;
+ enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },
+ user));
+ }
+
+ @Override
+ public void onPackageRemoved(UserHandleCompat user, String packageName) {
+ int op = PackageUpdatedTask.OP_REMOVE;
+ enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },
+ user));
+ }
+
+ @Override
+ public void onPackageAdded(UserHandleCompat user, String packageName) {
+ int op = PackageUpdatedTask.OP_ADD;
+ enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },
+ user));
+ }
+
+ @Override
+ public void onPackagesAvailable(UserHandleCompat user, String[] packageNames,
+ boolean replacing) {
+ if (!replacing) {
+ enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,
+ user));
+ if (mAppsCanBeOnRemoveableStorage) {
+ // Only rebind if we support removable storage. It catches the
+ // case where
+ // apps on the external sd card need to be reloaded
+ startLoaderFromBackground();
+ }
+ } else {
+ // If we are replacing then just update the packages in the list
+ enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,
+ packageNames, user));
+ }
+ }
+
+ @Override
+ public void onPackagesUnavailable(UserHandleCompat user, String[] packageNames,
+ boolean replacing) {
+ if (!replacing) {
+ enqueuePackageUpdated(new PackageUpdatedTask(
+ PackageUpdatedTask.OP_UNAVAILABLE, packageNames,
+ user));
+ }
+
+ }
+
/**
* Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
* ACTION_PACKAGE_CHANGED.
@@ -1167,65 +1230,7 @@ public class LauncherModel extends BroadcastReceiver {
if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);
final String action = intent.getAction();
-
- if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
- || Intent.ACTION_PACKAGE_REMOVED.equals(action)
- || Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- final String packageName = intent.getData().getSchemeSpecificPart();
- final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
-
- int op = PackageUpdatedTask.OP_NONE;
-
- if (packageName == null || packageName.length() == 0) {
- // they sent us a bad intent
- return;
- }
-
- if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
- op = PackageUpdatedTask.OP_UPDATE;
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- if (!replacing) {
- op = PackageUpdatedTask.OP_REMOVE;
- }
- // else, we are replacing the package, so a PACKAGE_ADDED will be sent
- // later, we will update the package at this time
- } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- if (!replacing) {
- op = PackageUpdatedTask.OP_ADD;
- } else {
- op = PackageUpdatedTask.OP_UPDATE;
- }
- }
-
- if (op != PackageUpdatedTask.OP_NONE) {
- enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }));
- }
-
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
- final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- if (!replacing) {
- enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages));
- if (mAppsCanBeOnRemoveableStorage) {
- // Only rebind if we support removable storage. It catches the case where
- // apps on the external sd card need to be reloaded
- startLoaderFromBackground();
- }
- } else {
- // If we are replacing then just update the packages in the list
- enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,
- packages));
- }
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
- final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- if (!replacing) {
- String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- enqueuePackageUpdated(new PackageUpdatedTask(
- PackageUpdatedTask.OP_UNAVAILABLE, packages));
- }
- // else, we are replacing the packages, so ignore this event and wait for
- // EXTERNAL_APPLICATIONS_AVAILABLE to update the packages at that time
- } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+ if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
// If we have changed locale we need to clear out the labels in all apps/workspace.
forceReload();
} else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
@@ -1659,7 +1664,7 @@ public class LauncherModel extends BroadcastReceiver {
ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();
synchronized (sBgLock) {
for (AppInfo app : mBgAllAppsList.data) {
- tmpInfos = getItemInfoForComponentName(app.componentName);
+ tmpInfos = getItemInfoForComponentName(app.componentName, app.user);
if (tmpInfos.isEmpty()) {
// We are missing an application icon, so add this to the workspace
added.add(app);
@@ -1864,6 +1869,8 @@ public class LauncherModel extends BroadcastReceiver {
LauncherSettings.Favorites.SPANY);
final int restoredIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.RESTORED);
+ final int profileIdIndex = c.getColumnIndexOrThrow(
+ LauncherSettings.Favorites.PROFILE_ID);
//final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
//final int displayModeIndex = c.getColumnIndexOrThrow(
// LauncherSettings.Favorites.DISPLAY_MODE);
@@ -1874,6 +1881,7 @@ public class LauncherModel extends BroadcastReceiver {
int container;
long id;
Intent intent;
+ UserHandleCompat user;
while (!mStopped && c.moveToNext()) {
AtomicBoolean deleteOnInvalidPlacement = new AtomicBoolean(false);
@@ -1886,10 +1894,17 @@ public class LauncherModel extends BroadcastReceiver {
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
id = c.getLong(idIndex);
intentDescription = c.getString(intentIndex);
+ int serialNumber = c.getInt(profileIdIndex);
+ user = mUserManager.getUserForSerialNumber(serialNumber);
+ if (user == null) {
+ // User has been deleted remove the item.
+ itemsToRemove.add(id);
+ continue;
+ }
try {
intent = Intent.parseUri(intentDescription, 0);
ComponentName cn = intent.getComponent();
- if (cn != null && !isValidPackageComponent(manager, cn)) {
+ if (cn != null && !isValidPackageActivity(context, cn, user)) {
if (restored) {
// might be installed later
Launcher.addDumpLog(TAG,
@@ -1921,14 +1936,20 @@ public class LauncherModel extends BroadcastReceiver {
}
if (restored) {
- Launcher.addDumpLog(TAG,
- "constructing info for partially restored package",
- true);
- info = getRestoredItemInfo(c, titleIndex, intent);
- intent = getRestoredItemIntent(c, context, intent);
+ if (user.equals(UserHandleCompat.myUserHandle())) {
+ Launcher.addDumpLog(TAG,
+ "constructing info for partially restored package",
+ true);
+ info = getRestoredItemInfo(c, titleIndex, intent);
+ intent = getRestoredItemIntent(c, context, intent);
+ } else {
+ // Don't restore items for other profiles.
+ itemsToRemove.add(id);
+ continue;
+ }
} else if (itemType ==
LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- info = getShortcutInfo(manager, intent, context, c, iconIndex,
+ info = getShortcutInfo(manager, intent, user, context, c, iconIndex,
titleIndex, mLabelCache);
} else {
info = getShortcutInfo(c, context, iconTypeIndex,
@@ -1958,6 +1979,7 @@ public class LauncherModel extends BroadcastReceiver {
info.cellY = c.getInt(cellYIndex);
info.spanX = 1;
info.spanY = 1;
+ info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);
// check & update map of what's occupied
deleteOnInvalidPlacement.set(false);
@@ -2612,42 +2634,42 @@ public class LauncherModel extends BroadcastReceiver {
return;
}
- final PackageManager packageManager = mContext.getPackageManager();
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();
+
// Clear the list of apps
mBgAllAppsList.clear();
+ for (UserHandleCompat user : profiles) {
+ // Query for the set of apps
+ final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+ List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "getActivityList took "
+ + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);
+ Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);
+ }
+ // Fail if we don't have any apps
+ if (apps == null || apps.isEmpty()) {
+ return;
+ }
+ // Sort the applications by name
+ final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+ Collections.sort(apps,
+ new LauncherModel.ShortcutNameComparator(mLabelCache));
+ if (DEBUG_LOADERS) {
+ Log.d(TAG, "sort took "
+ + (SystemClock.uptimeMillis()-sortTime) + "ms");
+ }
- // Query for the set of apps
- final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
- List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
- if (DEBUG_LOADERS) {
- Log.d(TAG, "queryIntentActivities took "
- + (SystemClock.uptimeMillis()-qiaTime) + "ms");
- Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps");
- }
- // Fail if we don't have any apps
- if (apps == null || apps.isEmpty()) {
- return;
- }
- // Sort the applications by name
- final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
- Collections.sort(apps,
- new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));
- if (DEBUG_LOADERS) {
- Log.d(TAG, "sort took "
- + (SystemClock.uptimeMillis()-sortTime) + "ms");
- }
-
- // Create the ApplicationInfos
- for (int i = 0; i < apps.size(); i++) {
- ResolveInfo app = apps.get(i);
- // This builds the icon bitmaps.
- mBgAllAppsList.add(new AppInfo(packageManager, app,
- mIconCache, mLabelCache));
+ // Create the ApplicationInfos
+ for (int i = 0; i < apps.size(); i++) {
+ LauncherActivityInfoCompat app = apps.get(i);
+ // This builds the icon bitmaps.
+ mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));
+ }
}
-
// Huh? Shouldn't this be inside the Runnable below?
final ArrayList<AppInfo> added = mBgAllAppsList.added;
mBgAllAppsList.added = new ArrayList<AppInfo>();
@@ -2693,6 +2715,7 @@ public class LauncherModel extends BroadcastReceiver {
private class PackageUpdatedTask implements Runnable {
int mOp;
String[] mPackages;
+ UserHandleCompat mUser;
public static final int OP_NONE = 0;
public static final int OP_ADD = 1;
@@ -2701,9 +2724,10 @@ public class LauncherModel extends BroadcastReceiver {
public static final int OP_UNAVAILABLE = 4; // external media unmounted
- public PackageUpdatedTask(int op, String[] packages) {
+ public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {
mOp = op;
mPackages = packages;
+ mUser = user;
}
public void run() {
@@ -2715,14 +2739,14 @@ public class LauncherModel extends BroadcastReceiver {
case OP_ADD:
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
- mIconCache.remove(packages[i]);
- mBgAllAppsList.addPackage(context, packages[i]);
+ mIconCache.remove(packages[i], mUser);
+ mBgAllAppsList.addPackage(context, packages[i], mUser);
}
break;
case OP_UPDATE:
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
- mBgAllAppsList.updatePackage(context, packages[i]);
+ mBgAllAppsList.updatePackage(context, packages[i], mUser);
WidgetPreviewLoader.removePackageFromDb(
mApp.getWidgetPreviewCacheDb(), packages[i]);
}
@@ -2731,7 +2755,7 @@ public class LauncherModel extends BroadcastReceiver {
case OP_UNAVAILABLE:
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
- mBgAllAppsList.removePackage(packages[i]);
+ mBgAllAppsList.removePackage(packages[i], mUser);
WidgetPreviewLoader.removePackageFromDb(
mApp.getWidgetPreviewCacheDb(), packages[i]);
}
@@ -2777,7 +2801,7 @@ public class LauncherModel extends BroadcastReceiver {
// Update the launcher db to reflect the changes
for (AppInfo a : modifiedFinal) {
ArrayList<ItemInfo> infos =
- getItemInfoForComponentName(a.componentName);
+ getItemInfoForComponentName(a.componentName, mUser);
for (ItemInfo i : infos) {
if (isShortcutInfoUpdateable(i)) {
ShortcutInfo info = (ShortcutInfo) i;
@@ -2806,21 +2830,21 @@ public class LauncherModel extends BroadcastReceiver {
// Mark disabled packages in the broadcast to be removed
final PackageManager pm = context.getPackageManager();
for (int i=0; i<N; i++) {
- if (isPackageDisabled(pm, packages[i])) {
+ if (isPackageDisabled(context, packages[i], mUser)) {
removedPackageNames.add(packages[i]);
}
}
}
// Remove all the components associated with this package
for (String pn : removedPackageNames) {
- ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn);
+ ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn, mUser);
for (ItemInfo i : infos) {
deleteItemFromDatabase(context, i);
}
}
// Remove all the specific components
for (AppInfo a : removedApps) {
- ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName);
+ ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser);
for (ItemInfo i : infos) {
deleteItemFromDatabase(context, i);
}
@@ -2836,14 +2860,14 @@ public class LauncherModel extends BroadcastReceiver {
public void run() {
Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
if (callbacks == cb && cb != null) {
- callbacks.bindComponentsRemoved(removedPackageNames, removedApps);
+ callbacks.bindComponentsRemoved(removedPackageNames, removedApps, mUser);
}
}
});
}
final ArrayList<Object> widgetsAndShortcuts =
- getSortedWidgetsAndShortcuts(context);
+ getSortedWidgetsAndShortcuts(context);
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -2878,31 +2902,22 @@ public class LauncherModel extends BroadcastReceiver {
return widgetsAndShortcuts;
}
- private static boolean isPackageDisabled(PackageManager pm, String packageName) {
- try {
- PackageInfo pi = pm.getPackageInfo(packageName, 0);
- return !pi.applicationInfo.enabled;
- } catch (NameNotFoundException e) {
- // Fall through
- }
- return false;
+ private static boolean isPackageDisabled(Context context, String packageName,
+ UserHandleCompat user) {
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ return !launcherApps.isPackageEnabledForProfile(packageName, user);
}
- public static boolean isValidPackageComponent(PackageManager pm, ComponentName cn) {
+ public static boolean isValidPackageActivity(Context context, ComponentName cn,
+ UserHandleCompat user) {
if (cn == null) {
return false;
}
- if (isPackageDisabled(pm, cn.getPackageName())) {
- return false;
- }
-
- try {
- // Check the activity
- PackageInfo pi = pm.getPackageInfo(cn.getPackageName(), 0);
- return (pm.getActivityInfo(cn, 0) != null);
- } catch (NameNotFoundException e) {
+ final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
+ if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {
return false;
}
+ return launcherApps.isActivityEnabledForProfile(cn, user);
}
/**
@@ -2916,7 +2931,8 @@ public class LauncherModel extends BroadcastReceiver {
} else {
info.title = "";
}
- info.setIcon(mIconCache.getIcon(intent, info.title.toString()));
+ info.user = UserHandleCompat.myUserHandle();
+ info.setIcon(mIconCache.getIcon(intent, info.title.toString(), info.user));
info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
info.restoredIntent = intent;
return info;
@@ -2944,8 +2960,9 @@ public class LauncherModel extends BroadcastReceiver {
* This is called from the code that adds shortcuts from the intent receiver. This
* doesn't have a Cursor, but
*/
- public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) {
- return getShortcutInfo(manager, intent, context, null, -1, -1, null);
+ public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
+ UserHandleCompat user, Context context) {
+ return getShortcutInfo(manager, intent, user, context, null, -1, -1, null);
}
/**
@@ -2953,54 +2970,37 @@ public class LauncherModel extends BroadcastReceiver {
*
* If c is not null, then it will be used to fill in missing data like the title and icon.
*/
- public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context,
- Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) {
+ public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
+ UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,
+ HashMap<Object, CharSequence> labelCache) {
+ if (user == null) {
+ Log.d(TAG, "Null user found in getShortcutInfo");
+ return null;
+ }
+
ComponentName componentName = intent.getComponent();
- final ShortcutInfo info = new ShortcutInfo();
- if (componentName != null && !isValidPackageComponent(manager, componentName)) {
- Log.d(TAG, "Invalid package found in getShortcutInfo: " + componentName);
+ if (componentName == null) {
+ Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);
return null;
- } else {
- try {
- PackageInfo pi = manager.getPackageInfo(componentName.getPackageName(), 0);
- info.initFlagsAndFirstInstallTime(pi);
- } catch (NameNotFoundException e) {
- Log.d(TAG, "getPackInfo failed for package " +
- componentName.getPackageName());
- }
}
- // TODO: See if the PackageManager knows about this case. If it doesn't
- // then return null & delete this.
+ Intent newIntent = new Intent(intent.getAction(), null);
+ newIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ newIntent.setComponent(componentName);
+ LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);
+ if (lai == null) {
+ Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);
+ return null;
+ }
+
+ final ShortcutInfo info = new ShortcutInfo();
// the resource -- This may implicitly give us back the fallback icon,
// but don't worry about that. All we're doing with usingFallbackIcon is
// to avoid saving lots of copies of that in the database, and most apps
// have icons anyway.
+ Bitmap icon = mIconCache.getIcon(componentName, lai, labelCache);
- // Attempt to use queryIntentActivities to get the ResolveInfo (with IntentFilter info) and
- // if that fails, or is ambiguious, fallback to the standard way of getting the resolve info
- // via resolveActivity().
- Bitmap icon = null;
- ResolveInfo resolveInfo = null;
- ComponentName oldComponent = intent.getComponent();
- Intent newIntent = new Intent(intent.getAction(), null);
- newIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- newIntent.setPackage(oldComponent.getPackageName());
- List<ResolveInfo> infos = manager.queryIntentActivities(newIntent, 0);
- for (ResolveInfo i : infos) {
- ComponentName cn = new ComponentName(i.activityInfo.packageName,
- i.activityInfo.name);
- if (cn.equals(oldComponent)) {
- resolveInfo = i;
- }
- }
- if (resolveInfo == null) {
- resolveInfo = manager.resolveActivity(intent, 0);
- }
- if (resolveInfo != null) {
- icon = mIconCache.getIcon(componentName, resolveInfo, labelCache);
- }
// the db
if (icon == null) {
if (c != null) {
@@ -3009,21 +3009,21 @@ public class LauncherModel extends BroadcastReceiver {
}
// the fallback icon
if (icon == null) {
- icon = getFallbackIcon();
+ icon = mIconCache.getDefaultIcon(user);
info.usingFallbackIcon = true;
}
info.setIcon(icon);
+ // From the cache.
+ if (labelCache != null) {
+ info.title = labelCache.get(componentName);
+ }
+
// from the resource
- if (resolveInfo != null) {
- ComponentName key = LauncherModel.getComponentNameFromResolveInfo(resolveInfo);
- if (labelCache != null && labelCache.containsKey(key)) {
- info.title = labelCache.get(key);
- } else {
- info.title = resolveInfo.activityInfo.loadLabel(manager);
- if (labelCache != null) {
- labelCache.put(key, info.title);
- }
+ if (info.title == null && lai != null) {
+ info.title = lai.getLabel();
+ if (labelCache != null) {
+ labelCache.put(componentName, info.title);
}
}
// from the db
@@ -3037,6 +3037,7 @@ public class LauncherModel extends BroadcastReceiver {
info.title = componentName.getClassName();
}
info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+ info.user = user;
return info;
}
@@ -3069,21 +3070,27 @@ public class LauncherModel extends BroadcastReceiver {
return new ArrayList<ItemInfo>(filtered);
}
- private ArrayList<ItemInfo> getItemInfoForPackageName(final String pn) {
+ private ArrayList<ItemInfo> getItemInfoForPackageName(final String pn,
+ final UserHandleCompat user) {
ItemInfoFilter filter = new ItemInfoFilter() {
@Override
public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {
- return cn.getPackageName().equals(pn);
+ return cn.getPackageName().equals(pn) && info.user.equals(user);
}
};
return filterItemInfos(sBgItemsIdMap.values(), filter);
}
- private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname) {
+ private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,
+ final UserHandleCompat user) {
ItemInfoFilter filter = new ItemInfoFilter() {
@Override
public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {
- return cn.equals(cname);
+ if (info.user == null) {
+ return cn.equals(cname);
+ } else {
+ return cn.equals(cname) && info.user.equals(user);
+ }
}
};
return filterItemInfos(sBgItemsIdMap.values(), filter);
@@ -3118,6 +3125,8 @@ public class LauncherModel extends BroadcastReceiver {
Bitmap icon = null;
final ShortcutInfo info = new ShortcutInfo();
+ // Non-app shortcuts are only supported for current user.
+ info.user = UserHandleCompat.myUserHandle();
info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
// TODO: If there's an explicit component and we can't install that, delete it.
@@ -3148,14 +3157,14 @@ public class LauncherModel extends BroadcastReceiver {
}
// the fallback icon
if (icon == null) {
- icon = getFallbackIcon();
+ icon = mIconCache.getDefaultIcon(info.user);
info.usingFallbackIcon = true;
}
break;
case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
icon = getIconFromCursor(c, iconIndex, context);
if (icon == null) {
- icon = getFallbackIcon();
+ icon = mIconCache.getDefaultIcon(info.user);
info.customIcon = false;
info.usingFallbackIcon = true;
} else {
@@ -3163,7 +3172,7 @@ public class LauncherModel extends BroadcastReceiver {
}
break;
default:
- icon = getFallbackIcon();
+ icon = mIconCache.getDefaultIcon(info.user);
info.usingFallbackIcon = true;
info.customIcon = false;
break;
@@ -3280,7 +3289,8 @@ public class LauncherModel extends BroadcastReceiver {
iconResource.packageName);
final int id = resources.getIdentifier(iconResource.resourceName, null, null);
icon = Utilities.createIconBitmap(
- mIconCache.getFullResIcon(resources, id), context);
+ mIconCache.getFullResIcon(resources, id),
+ context);
} catch (Exception e) {
Log.w(TAG, "Could not load shortcut icon: " + extra);
}
@@ -3289,11 +3299,14 @@ public class LauncherModel extends BroadcastReceiver {
final ShortcutInfo info = new ShortcutInfo();
+ // Only support intents for current user for now. Intents sent from other
+ // users wouldn't get here without intent forwarding anyway.
+ info.user = UserHandleCompat.myUserHandle();
if (icon == null) {
if (fallbackIcon != null) {
icon = fallbackIcon;
} else {
- icon = getFallbackIcon();
+ icon = mIconCache.getDefaultIcon(info.user);
info.usingFallbackIcon = true;
}
}
@@ -3365,12 +3378,18 @@ public class LauncherModel extends BroadcastReceiver {
final Collator collator = Collator.getInstance();
return new Comparator<AppInfo>() {
public final int compare(AppInfo a, AppInfo b) {
- int result = collator.compare(a.title.toString().trim(),
- b.title.toString().trim());
- if (result == 0) {
- result = a.componentName.compareTo(b.componentName);
+ if (a.user.equals(b.user)) {
+ int result = collator.compare(a.title.toString().trim(),
+ b.title.toString().trim());
+ if (result == 0) {
+ result = a.componentName.compareTo(b.componentName);
+ }
+ return result;
+ } else {
+ // TODO Need to figure out rules for sorting
+ // profiles, this puts work second.
+ return a.user.toString().compareTo(b.user.toString());
}
- return result;
}
};
}
@@ -3397,35 +3416,32 @@ public class LauncherModel extends BroadcastReceiver {
return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
}
}
- public static class ShortcutNameComparator implements Comparator<ResolveInfo> {
+ public static class ShortcutNameComparator implements Comparator<LauncherActivityInfoCompat> {
private Collator mCollator;
- private PackageManager mPackageManager;
private HashMap<Object, CharSequence> mLabelCache;
ShortcutNameComparator(PackageManager pm) {
- mPackageManager = pm;
mLabelCache = new HashMap<Object, CharSequence>();
mCollator = Collator.getInstance();
}
- ShortcutNameComparator(PackageManager pm, HashMap<Object, CharSequence> labelCache) {
- mPackageManager = pm;
+ ShortcutNameComparator(HashMap<Object, CharSequence> labelCache) {
mLabelCache = labelCache;
mCollator = Collator.getInstance();
}
- public final int compare(ResolveInfo a, ResolveInfo b) {
+ public final int compare(LauncherActivityInfoCompat a, LauncherActivityInfoCompat b) {
CharSequence labelA, labelB;
- ComponentName keyA = LauncherModel.getComponentNameFromResolveInfo(a);
- ComponentName keyB = LauncherModel.getComponentNameFromResolveInfo(b);
+ ComponentName keyA = a.getComponentName();
+ ComponentName keyB = b.getComponentName();
if (mLabelCache.containsKey(keyA)) {
labelA = mLabelCache.get(keyA);
} else {
- labelA = a.loadLabel(mPackageManager).toString().trim();
+ labelA = a.getLabel().toString().trim();
mLabelCache.put(keyA, labelA);
}
if (mLabelCache.containsKey(keyB)) {
labelB = mLabelCache.get(keyB);
} else {
- labelB = b.loadLabel(mPackageManager).toString().trim();
+ labelB = b.getLabel().toString().trim();
mLabelCache.put(keyB, labelB);
}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index e43b727aa..437c2ad96 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -56,8 +56,10 @@ import android.util.Log;
import android.util.SparseArray;
import android.util.Xml;
-import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.LauncherSettings.Favorites;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -75,7 +77,7 @@ public class LauncherProvider extends ContentProvider {
private static final String DATABASE_NAME = "launcher.db";
- private static final int DATABASE_VERSION = 19;
+ private static final int DATABASE_VERSION = 20;
static final String OLD_AUTHORITY = "com.android.launcher2.settings";
static final String AUTHORITY = ProviderConfig.AUTHORITY;
@@ -429,6 +431,10 @@ public class LauncherProvider extends ContentProvider {
mMaxScreenId = 0;
mNewDbCreated = true;
+ UserManagerCompat userManager = UserManagerCompat.getInstance(mContext);
+ long userSerialNumber = userManager.getSerialNumberForUser(
+ UserHandleCompat.myUserHandle());
+
db.execSQL("CREATE TABLE favorites (" +
"_id INTEGER PRIMARY KEY," +
"title TEXT," +
@@ -450,7 +456,8 @@ public class LauncherProvider extends ContentProvider {
"displayMode INTEGER," +
"appWidgetProvider TEXT," +
"modified INTEGER NOT NULL DEFAULT 0," +
- "restored INTEGER NOT NULL DEFAULT 0" +
+ "restored INTEGER NOT NULL DEFAULT 0," +
+ "profileId INTEGER DEFAULT " + userSerialNumber +
");");
addWorkspacesTable(db);
@@ -847,6 +854,14 @@ public class LauncherProvider extends ContentProvider {
version = 19;
}
+ if (version < 20) {
+ // Add userId column
+ if (addProfileColumn(db)) {
+ version = 20;
+ }
+ // else old version remains, which means we wipe old data
+ }
+
if (version != DATABASE_VERSION) {
Log.w(TAG, "Destroying all old data.");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
@@ -856,6 +871,29 @@ public class LauncherProvider extends ContentProvider {
}
}
+ private boolean addProfileColumn(SQLiteDatabase db) {
+ db.beginTransaction();
+ try {
+ UserManagerCompat userManager = UserManagerCompat.getInstance(mContext);
+ // Default to the serial number of this user, for older
+ // shortcuts.
+ long userSerialNumber = userManager.getSerialNumberForUser(
+ UserHandleCompat.myUserHandle());
+ // Insert new column for holding user serial number
+ db.execSQL("ALTER TABLE favorites " +
+ "ADD COLUMN profileId INTEGER DEFAULT "
+ + userSerialNumber + ";");
+ db.setTransactionSuccessful();
+ } catch (SQLException ex) {
+ // Old version remains, which means we wipe old data
+ Log.e(TAG, ex.getMessage(), ex);
+ return false;
+ } finally {
+ db.endTransaction();
+ }
+ return true;
+ }
+
private boolean updateContactsShortcuts(SQLiteDatabase db) {
final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE,
new int[] { Favorites.ITEM_TYPE_SHORTCUT });
@@ -1786,6 +1824,8 @@ public class LauncherProvider extends ContentProvider {
= c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
final int displayModeIndex
= c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
+ final int profileIndex
+ = c.getColumnIndex(LauncherSettings.Favorites.PROFILE_ID);
int i = 0;
int curX = 0;
@@ -1817,6 +1857,19 @@ public class LauncherProvider extends ContentProvider {
final int screen = c.getInt(screenIndex);
int container = c.getInt(containerIndex);
final String intentStr = c.getString(intentIndex);
+
+ UserManagerCompat userManager = UserManagerCompat.getInstance(mContext);
+ UserHandleCompat userHandle;
+ final long userSerialNumber;
+ if (profileIndex != -1 && !c.isNull(profileIndex)) {
+ userSerialNumber = c.getInt(profileIndex);
+ userHandle = userManager.getUserForSerialNumber(userSerialNumber);
+ } else {
+ // Default to the serial number of this user, for older
+ // shortcuts.
+ userHandle = UserHandleCompat.myUserHandle();
+ userSerialNumber = userManager.getSerialNumberForUser(userHandle);
+ }
Launcher.addDumpLog(TAG, "migrating \""
+ c.getString(titleIndex) + "\" ("
+ cellX + "," + cellY + "@"
@@ -1843,7 +1896,8 @@ public class LauncherProvider extends ContentProvider {
Launcher.addDumpLog(TAG, "skipping empty intent", true);
continue;
} else if (cn != null &&
- !LauncherModel.isValidPackageComponent(pm, cn)) {
+ !LauncherModel.isValidPackageActivity(mContext, cn,
+ userHandle)) {
// component no longer exists.
Launcher.addDumpLog(TAG, "skipping item whose component " +
"no longer exists.", true);
@@ -1882,6 +1936,7 @@ public class LauncherProvider extends ContentProvider {
values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
values.put(LauncherSettings.Favorites.DISPLAY_MODE,
c.getInt(displayModeIndex));
+ values.put(LauncherSettings.Favorites.PROFILE_ID, userSerialNumber);
if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
hotseat.put(screen, values);
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 2a768a278..355370283 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -212,6 +212,14 @@ class LauncherSettings {
static final String SPANY = "spanY";
/**
+ * The profile id of the item in the cell.
+ * <P>
+ * Type: INTEGER
+ * </P>
+ */
+ static final String PROFILE_ID = "profileId";
+
+ /**
* The favorite is a user created folder
*/
static final int ITEM_TYPE_FOLDER = 2;
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 92b582dba..f40cf9fa1 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -26,6 +26,8 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.util.Log;
+import com.android.launcher3.compat.UserHandleCompat;
+
import java.util.ArrayList;
import java.util.Arrays;
@@ -111,12 +113,12 @@ public class ShortcutInfo extends ItemInfo {
}
}
-
- ShortcutInfo(Intent intent, CharSequence title, Bitmap icon) {
+ ShortcutInfo(Intent intent, CharSequence title, Bitmap icon, UserHandleCompat user) {
this();
this.intent = intent;
this.title = title;
mIcon = icon;
+ this.user = user;
}
public ShortcutInfo(Context context, ShortcutInfo info) {
@@ -130,8 +132,9 @@ public class ShortcutInfo extends ItemInfo {
}
mIcon = info.mIcon; // TODO: should make a copy here. maybe we don't need this ctor at all
customIcon = info.customIcon;
- initFlagsAndFirstInstallTime(
- getPackageInfo(context, intent.getComponent().getPackageName()));
+ flags = info.flags;
+ firstInstallTime = info.firstInstallTime;
+ user = info.user;
}
/** TODO: Remove this. It's only called by ApplicationInfo.makeShortcut. */
@@ -144,22 +147,6 @@ public class ShortcutInfo extends ItemInfo {
firstInstallTime = info.firstInstallTime;
}
- public static PackageInfo getPackageInfo(Context context, String packageName) {
- PackageInfo pi = null;
- try {
- PackageManager pm = context.getPackageManager();
- pi = pm.getPackageInfo(packageName, 0);
- } catch (NameNotFoundException e) {
- Log.d("ShortcutInfo", "PackageManager.getPackageInfo failed for " + packageName);
- }
- return pi;
- }
-
- void initFlagsAndFirstInstallTime(PackageInfo pi) {
- flags = AppInfo.initFlags(pi);
- firstInstallTime = AppInfo.initFirstInstallTime(pi);
- }
-
public void setIcon(Bitmap b) {
mIcon = b;
}
@@ -172,30 +159,13 @@ public class ShortcutInfo extends ItemInfo {
}
public void updateIcon(IconCache iconCache) {
- mIcon = iconCache.getIcon(intent);
- usingFallbackIcon = iconCache.isDefaultIcon(mIcon);
- }
-
- /**
- * Creates the application intent based on a component name and various launch flags.
- * Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}.
- *
- * @param className the class name of the component representing the intent
- * @param launchFlags the launch flags
- */
- final void setActivity(Context context, ComponentName className, int launchFlags) {
- intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- intent.setComponent(className);
- intent.setFlags(launchFlags);
- itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
- initFlagsAndFirstInstallTime(
- getPackageInfo(context, intent.getComponent().getPackageName()));
+ mIcon = iconCache.getIcon(intent, user);
+ usingFallbackIcon = iconCache.isDefaultIcon(mIcon, user);
}
@Override
- void onAddToDatabase(ContentValues values) {
- super.onAddToDatabase(values);
+ void onAddToDatabase(Context context, ContentValues values) {
+ super.onAddToDatabase(context, values);
String titleStr = title != null ? title.toString() : null;
values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr);
@@ -224,10 +194,10 @@ public class ShortcutInfo extends ItemInfo {
@Override
public String toString() {
- return "ShortcutInfo(title=" + title.toString() + "intent=" + intent + "id=" + this.id
+ return "ShortcutInfo(title=" + title + "intent=" + intent + "id=" + this.id
+ " type=" + this.itemType + " container=" + this.container + " screen=" + screenId
+ " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY
- + " dropPos=" + Arrays.toString(dropPos) + ")";
+ + " dropPos=" + Arrays.toString(dropPos) + " user=" + user + ")";
}
public static void dumpShortcutInfoList(String tag, String label,
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index f7ca141a7..9bf2c2343 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -60,6 +60,8 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.TextView;
+
+import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.FolderIcon.FolderRingAnimator;
import com.android.launcher3.Launcher.CustomContentCallbacks;
import com.android.launcher3.LauncherSettings.Favorites;
@@ -4621,7 +4623,7 @@ public class Workspace extends SmoothPagedView
// Removes ALL items that match a given package name, this is usually called when a package
// has been removed and we want to remove all components (widgets, shortcuts, apps) that
// belong to that package.
- void removeItemsByPackageName(final ArrayList<String> packages) {
+ void removeItemsByPackageName(final ArrayList<String> packages, final UserHandleCompat user) {
final HashSet<String> packageNames = new HashSet<String>();
packageNames.addAll(packages);
@@ -4641,7 +4643,8 @@ public class Workspace extends SmoothPagedView
@Override
public boolean filterItem(ItemInfo parent, ItemInfo info,
ComponentName cn) {
- if (packageNames.contains(cn.getPackageName())) {
+ if (packageNames.contains(cn.getPackageName())
+ && info.user.equals(user)) {
cns.add(cn);
return true;
}
@@ -4651,13 +4654,13 @@ public class Workspace extends SmoothPagedView
LauncherModel.filterItemInfos(infos, filter);
// Remove the affected components
- removeItemsByComponentName(cns);
+ removeItemsByComponentName(cns, user);
}
// Removes items that match the application info specified, when applications are removed
// as a part of an update, this is called to ensure that other widgets and application
// shortcuts are not removed.
- void removeItemsByApplicationInfo(final ArrayList<AppInfo> appInfos) {
+ void removeItemsByApplicationInfo(final ArrayList<AppInfo> appInfos, UserHandleCompat user) {
// Just create a hash table of all the specific components that this will affect
HashSet<ComponentName> cns = new HashSet<ComponentName>();
for (AppInfo info : appInfos) {
@@ -4665,10 +4668,11 @@ public class Workspace extends SmoothPagedView
}
// Remove all the things
- removeItemsByComponentName(cns);
+ removeItemsByComponentName(cns, user);
}
- void removeItemsByComponentName(final HashSet<ComponentName> componentNames) {
+ void removeItemsByComponentName(final HashSet<ComponentName> componentNames,
+ final UserHandleCompat user) {
ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
for (final CellLayout layoutParent: cellLayouts) {
final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
@@ -4687,7 +4691,7 @@ public class Workspace extends SmoothPagedView
public boolean filterItem(ItemInfo parent, ItemInfo info,
ComponentName cn) {
if (parent instanceof FolderInfo) {
- if (componentNames.contains(cn)) {
+ if (componentNames.contains(cn) && info.user.equals(user)) {
FolderInfo folder = (FolderInfo) parent;
ArrayList<ShortcutInfo> appsToRemove;
if (folderAppsToRemove.containsKey(folder)) {
@@ -4700,7 +4704,7 @@ public class Workspace extends SmoothPagedView
return true;
}
} else {
- if (componentNames.contains(cn)) {
+ if (componentNames.contains(cn) && info.user.equals(user)) {
childrenToRemove.add(children.get(info));
return true;
}
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
new file mode 100644
index 000000000..3ba93ea91
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.content.ComponentName;
+import android.graphics.drawable.Drawable;
+
+public abstract class LauncherActivityInfoCompat {
+
+ LauncherActivityInfoCompat() {
+ }
+
+ public abstract ComponentName getComponentName();
+ public abstract UserHandleCompat getUser();
+ public abstract CharSequence getLabel();
+ public abstract Drawable getIcon(int density);
+ public abstract int getApplicationFlags();
+ public abstract long getFirstInstallTime();
+ public abstract Drawable getBadgedIcon(int density);
+}
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
new file mode 100644
index 000000000..9b9384d83
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+
+
+public class LauncherActivityInfoCompatV16 extends LauncherActivityInfoCompat {
+ private ActivityInfo mActivityInfo;
+ private ComponentName mComponentName;
+ private PackageManager mPm;
+
+ LauncherActivityInfoCompatV16(Context context, ResolveInfo info) {
+ super();
+ this.mActivityInfo = info.activityInfo;
+ mComponentName = new ComponentName(mActivityInfo.packageName, mActivityInfo.name);
+ mPm = context.getPackageManager();
+ }
+
+ public ComponentName getComponentName() {
+ return mComponentName;
+ }
+
+ public UserHandleCompat getUser() {
+ return UserHandleCompat.myUserHandle();
+ }
+
+ public CharSequence getLabel() {
+ return mActivityInfo.loadLabel(mPm);
+ }
+
+ public Drawable getIcon(int density) {
+ Drawable d = null;
+ if (mActivityInfo.getIconResource() != 0) {
+ Resources resources;
+ try {
+ resources = mPm.getResourcesForApplication(mActivityInfo.packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ resources = null;
+ }
+ if (resources != null) {
+ d = resources.getDrawableForDensity(mActivityInfo.getIconResource(), density);
+ }
+ }
+ if (d == null) {
+ Resources resources = Resources.getSystem();
+ d = resources.getDrawableForDensity(android.R.mipmap.sym_def_app_icon, density);
+ }
+ return d;
+ }
+
+ public int getApplicationFlags() {
+ return mActivityInfo.applicationInfo.flags;
+ }
+
+ public long getFirstInstallTime() {
+ try {
+ PackageInfo info = mPm.getPackageInfo(mActivityInfo.packageName, 0);
+ return info != null ? info.firstInstallTime : 0;
+ } catch (NameNotFoundException e) {
+ return 0;
+ }
+ }
+
+ public String getName() {
+ return mActivityInfo.name;
+ }
+
+ public Drawable getBadgedIcon(int density) {
+ return getIcon(density);
+ }
+}
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
new file mode 100644
index 000000000..76125bd6a
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.content.ComponentName;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class LauncherActivityInfoCompatVL extends LauncherActivityInfoCompat {
+ private Object mLauncherActivityInfo;
+ private Class mLauncherActivityInfoClass;
+ private Method mGetComponentName;
+ private Method mGetUser;
+ private Method mGetLabel;
+ private Method mGetIcon;
+ private Method mGetApplicationFlags;
+ private Method mGetFirstInstallTime;
+ private Method mGetBadgedIcon;
+
+ LauncherActivityInfoCompatVL(Object launcherActivityInfo) {
+ super();
+ mLauncherActivityInfo = launcherActivityInfo;
+ mLauncherActivityInfoClass = ReflectUtils.getClassForName(
+ "android.content.pm.LauncherActivityInfo");
+ mGetComponentName = ReflectUtils.getMethod(mLauncherActivityInfoClass, "getComponentName");
+ mGetUser = ReflectUtils.getMethod(mLauncherActivityInfoClass, "getUser");
+ mGetLabel = ReflectUtils.getMethod(mLauncherActivityInfoClass, "getLabel");
+ mGetIcon = ReflectUtils.getMethod(mLauncherActivityInfoClass, "getIcon", int.class);
+ mGetApplicationFlags = ReflectUtils.getMethod(mLauncherActivityInfoClass,
+ "getApplicationFlags");
+ mGetFirstInstallTime = ReflectUtils.getMethod(mLauncherActivityInfoClass,
+ "getFirstInstallTime");
+ mGetBadgedIcon = ReflectUtils.getMethod(mLauncherActivityInfoClass, "getBadgedIcon",
+ int.class);
+ }
+
+ public ComponentName getComponentName() {
+ return (ComponentName) ReflectUtils.invokeMethod(mLauncherActivityInfo, mGetComponentName);
+ }
+
+ public UserHandleCompat getUser() {
+ return UserHandleCompat.fromUser((UserHandle) ReflectUtils.invokeMethod(
+ mLauncherActivityInfo, mGetUser));
+ }
+
+ public CharSequence getLabel() {
+ return (CharSequence) ReflectUtils.invokeMethod(mLauncherActivityInfo, mGetLabel);
+ }
+
+ public Drawable getIcon(int density) {
+ return (Drawable) ReflectUtils.invokeMethod(mLauncherActivityInfo, mGetIcon, density);
+ }
+
+ public int getApplicationFlags() {
+ return (Integer) ReflectUtils.invokeMethod(mLauncherActivityInfo, mGetApplicationFlags);
+ }
+
+ public long getFirstInstallTime() {
+ return (Long) ReflectUtils.invokeMethod(mLauncherActivityInfo, mGetFirstInstallTime);
+ }
+
+ public Drawable getBadgedIcon(int density) {
+ return (Drawable) ReflectUtils.invokeMethod(mLauncherActivityInfo, mGetBadgedIcon, density);
+ }
+}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
new file mode 100644
index 000000000..59ee45c2c
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public abstract class LauncherAppsCompat {
+
+ public interface OnAppsChangedListenerCompat {
+ void onPackageRemoved(UserHandleCompat user, String packageName);
+ void onPackageAdded(UserHandleCompat user, String packageName);
+ void onPackageChanged(UserHandleCompat user, String packageName);
+ void onPackagesAvailable(UserHandleCompat user, String[] packageNames, boolean replacing);
+ void onPackagesUnavailable(UserHandleCompat user, String[] packageNames, boolean replacing);
+ }
+
+ protected LauncherAppsCompat() {
+ }
+
+ public static LauncherAppsCompat getInstance(Context context) {
+ // TODO change this to use api version once L gets an API number.
+ if ("L".equals(Build.VERSION.CODENAME)) {
+ Object launcherApps = context.getSystemService("launcherapps");
+ if (launcherApps != null) {
+ LauncherAppsCompatVL compat = LauncherAppsCompatVL.build(context, launcherApps);
+ if (compat != null) {
+ return compat;
+ }
+ }
+ }
+ // Pre L or lunacher apps service not running, or reflection failed to find something.
+ return new LauncherAppsCompatV16(context);
+ }
+
+ public abstract List<LauncherActivityInfoCompat> getActivityList(String packageName,
+ UserHandleCompat user);
+ public abstract LauncherActivityInfoCompat resolveActivity(Intent intent,
+ UserHandleCompat user);
+ public abstract void startActivityForProfile(ComponentName component, Rect sourceBounds,
+ Bundle opts, UserHandleCompat user);
+ public abstract void addOnAppsChangedListener(OnAppsChangedListenerCompat listener);
+ public abstract void removeOnAppsChangedListener(OnAppsChangedListenerCompat listener);
+ public abstract boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user);
+ public abstract boolean isActivityEnabledForProfile(ComponentName component,
+ UserHandleCompat user);
+} \ No newline at end of file
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
new file mode 100644
index 000000000..c739eb9d2
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageInfo;
+import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class LauncherAppsCompatV16 extends LauncherAppsCompat {
+
+ private PackageManager mPm;
+ private Context mContext;
+ private List<OnAppsChangedListenerCompat> mListeners
+ = new ArrayList<OnAppsChangedListenerCompat>();
+ private PackageMonitor mPackageMonitor;
+
+ LauncherAppsCompatV16(Context context) {
+ mPm = context.getPackageManager();
+ mContext = context;
+ mPackageMonitor = new PackageMonitor();
+ }
+
+ public List<LauncherActivityInfoCompat> getActivityList(String packageName,
+ UserHandleCompat user) {
+ final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ mainIntent.setPackage(packageName);
+ List<ResolveInfo> infos = mPm.queryIntentActivities(mainIntent, 0);
+ List<LauncherActivityInfoCompat> list =
+ new ArrayList<LauncherActivityInfoCompat>(infos.size());
+ for (ResolveInfo info : infos) {
+ list.add(new LauncherActivityInfoCompatV16(mContext, info));
+ }
+ return list;
+ }
+
+ public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandleCompat user) {
+ ResolveInfo info = mPm.resolveActivity(intent, 0);
+ if (info != null) {
+ return new LauncherActivityInfoCompatV16(mContext, info);
+ }
+ return null;
+ }
+
+ public void startActivityForProfile(ComponentName component, Rect sourceBounds,
+ Bundle opts, UserHandleCompat user) {
+ Intent launchIntent = new Intent(Intent.ACTION_MAIN);
+ launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ launchIntent.setComponent(component);
+ launchIntent.setSourceBounds(sourceBounds);
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(launchIntent, opts);
+ }
+
+ public synchronized void addOnAppsChangedListener(OnAppsChangedListenerCompat listener) {
+ if (listener != null && !mListeners.contains(listener)) {
+ mListeners.add(listener);
+ if (mListeners.size() == 1) {
+ registerForPackageIntents();
+ }
+ }
+ }
+
+ public synchronized void removeOnAppsChangedListener(OnAppsChangedListenerCompat listener) {
+ mListeners.remove(listener);
+ if (mListeners.size() == 0) {
+ unregisterForPackageIntents();
+ }
+ }
+
+ public boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user) {
+ try {
+ PackageInfo info = mPm.getPackageInfo(packageName, 0);
+ return info != null && info.applicationInfo.enabled;
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ public boolean isActivityEnabledForProfile(ComponentName component, UserHandleCompat user) {
+ try {
+ ActivityInfo info = mPm.getActivityInfo(component, 0);
+ return info != null && info.isEnabled();
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ private void unregisterForPackageIntents() {
+ mContext.unregisterReceiver(mPackageMonitor);
+ }
+
+ private void registerForPackageIntents() {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(mPackageMonitor, filter);
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ mContext.registerReceiver(mPackageMonitor, filter);
+ }
+
+ private synchronized List<OnAppsChangedListenerCompat> getListeners() {
+ return new ArrayList<OnAppsChangedListenerCompat>(mListeners);
+ }
+
+ private class PackageMonitor extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final UserHandleCompat user = UserHandleCompat.myUserHandle();
+
+ if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
+ || Intent.ACTION_PACKAGE_REMOVED.equals(action)
+ || Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ final String packageName = intent.getData().getSchemeSpecificPart();
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+
+ if (packageName == null || packageName.length() == 0) {
+ // they sent us a bad intent
+ return;
+ }
+ if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ for (OnAppsChangedListenerCompat listener : getListeners()) {
+ listener.onPackageChanged(user, packageName);
+ }
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ if (!replacing) {
+ for (OnAppsChangedListenerCompat listener : getListeners()) {
+ listener.onPackageRemoved(user, packageName);
+ }
+ }
+ // else, we are replacing the package, so a PACKAGE_ADDED will be sent
+ // later, we will update the package at this time
+ } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ if (!replacing) {
+ for (OnAppsChangedListenerCompat listener : getListeners()) {
+ listener.onPackageAdded(user, packageName);
+ }
+ } else {
+ for (OnAppsChangedListenerCompat listener : getListeners()) {
+ listener.onPackageChanged(user, packageName);
+ }
+ }
+ }
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+ String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ for (OnAppsChangedListenerCompat listener : getListeners()) {
+ listener.onPackagesAvailable(user, packages, replacing);
+ }
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+ String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ for (OnAppsChangedListenerCompat listener : getListeners()) {
+ listener.onPackagesUnavailable(user, packages, replacing);
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
new file mode 100644
index 000000000..c933712a9
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import java.lang.reflect.InvocationHandler;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Method;
+
+public class LauncherAppsCompatVL extends LauncherAppsCompat {
+
+ private Object mLauncherApps;
+ private Class mLauncherAppsClass;
+ private Class mListenerClass;
+ private Method mGetActivityList;
+ private Method mResolveActivity;
+ private Method mStartActivityForProfile;
+ private Method mAddOnAppsChangedListener;
+ private Method mRemoveOnAppsChangedListener;
+ private Method mIsPackageEnabledForProfile;
+ private Method mIsActivityEnabledForProfile;
+
+ private Map<OnAppsChangedListenerCompat, Object> mListeners
+ = new HashMap<OnAppsChangedListenerCompat, Object>();
+
+ static LauncherAppsCompatVL build(Context context, Object launcherApps) {
+ LauncherAppsCompatVL compat = new LauncherAppsCompatVL(context, launcherApps);
+
+ compat.mListenerClass = ReflectUtils.getClassForName(
+ "android.content.pm.LauncherApps$OnAppsChangedListener");
+ compat.mLauncherAppsClass = ReflectUtils.getClassForName("android.content.pm.LauncherApps");
+
+ compat.mGetActivityList = ReflectUtils.getMethod(compat.mLauncherAppsClass,
+ "getActivityList",
+ String.class, UserHandle.class);
+ compat.mResolveActivity = ReflectUtils.getMethod(compat.mLauncherAppsClass,
+ "resolveActivity",
+ Intent.class, UserHandle.class);
+ compat.mStartActivityForProfile = ReflectUtils.getMethod(compat.mLauncherAppsClass,
+ "startActivityForProfile",
+ ComponentName.class, Rect.class, Bundle.class, UserHandle.class);
+ compat.mAddOnAppsChangedListener = ReflectUtils.getMethod(compat.mLauncherAppsClass,
+ "addOnAppsChangedListener", compat.mListenerClass);
+ compat.mRemoveOnAppsChangedListener = ReflectUtils.getMethod(compat.mLauncherAppsClass,
+ "removeOnAppsChangedListener", compat.mListenerClass);
+ compat.mIsPackageEnabledForProfile = ReflectUtils.getMethod(compat.mLauncherAppsClass,
+ "isPackageEnabledForProfile", String.class, UserHandle.class);
+ compat.mIsActivityEnabledForProfile = ReflectUtils.getMethod(compat.mLauncherAppsClass,
+ "isActivityEnabledForProfile", ComponentName.class, UserHandle.class);
+
+ if (compat.mListenerClass != null
+ && compat.mLauncherAppsClass != null
+ && compat.mGetActivityList != null
+ && compat.mResolveActivity != null
+ && compat.mStartActivityForProfile != null
+ && compat.mAddOnAppsChangedListener != null
+ && compat.mRemoveOnAppsChangedListener != null
+ && compat.mIsPackageEnabledForProfile != null
+ && compat.mIsActivityEnabledForProfile != null) {
+ return compat;
+ }
+ return null;
+ }
+
+ private LauncherAppsCompatVL(Context context, Object launcherApps) {
+ super();
+ mLauncherApps = launcherApps;
+ }
+
+ public List<LauncherActivityInfoCompat> getActivityList(String packageName,
+ UserHandleCompat user) {
+ List<Object> list = (List<Object>) ReflectUtils.invokeMethod(mLauncherApps,
+ mGetActivityList, packageName, user.getUser());
+ if (list.size() == 0) {
+ return Collections.EMPTY_LIST;
+ }
+ ArrayList<LauncherActivityInfoCompat> compatList =
+ new ArrayList<LauncherActivityInfoCompat>(list.size());
+ for (Object info : list) {
+ compatList.add(new LauncherActivityInfoCompatVL(info));
+ }
+ return compatList;
+ }
+
+ public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandleCompat user) {
+ return new LauncherActivityInfoCompatVL(ReflectUtils.invokeMethod(mLauncherApps,
+ mResolveActivity, intent, user.getUser()));
+ }
+
+ public void startActivityForProfile(ComponentName component, Rect sourceBounds,
+ Bundle opts, UserHandleCompat user) {
+ ReflectUtils.invokeMethod(mLauncherApps, mStartActivityForProfile,
+ component, sourceBounds, opts, user.getUser());
+ }
+
+ public void addOnAppsChangedListener(LauncherAppsCompat.OnAppsChangedListenerCompat listener) {
+ Object wrappedListener = Proxy.newProxyInstance(mListenerClass.getClassLoader(),
+ new Class[]{mListenerClass}, new WrappedListener(listener));
+ synchronized (mListeners) {
+ mListeners.put(listener, wrappedListener);
+ }
+ ReflectUtils.invokeMethod(mLauncherApps, mAddOnAppsChangedListener, wrappedListener);
+ }
+
+ public void removeOnAppsChangedListener(
+ LauncherAppsCompat.OnAppsChangedListenerCompat listener) {
+ Object wrappedListener = null;
+ synchronized (mListeners) {
+ wrappedListener = mListeners.remove(listener);
+ }
+ if (wrappedListener != null) {
+ ReflectUtils.invokeMethod(mLauncherApps, mRemoveOnAppsChangedListener, wrappedListener);
+ }
+ }
+
+ public boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user) {
+ return (Boolean) ReflectUtils.invokeMethod(mLauncherApps, mIsPackageEnabledForProfile,
+ packageName, user.getUser());
+ }
+
+ public boolean isActivityEnabledForProfile(ComponentName component, UserHandleCompat user) {
+ return (Boolean) ReflectUtils.invokeMethod(mLauncherApps, mIsActivityEnabledForProfile,
+ component, user.getUser());
+ }
+
+ private static class WrappedListener implements InvocationHandler {
+ private LauncherAppsCompat.OnAppsChangedListenerCompat mListener;
+
+ public WrappedListener(LauncherAppsCompat.OnAppsChangedListenerCompat listener) {
+ mListener = listener;
+ }
+
+ public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
+ try {
+ String methodName = m.getName();
+ if ("onPackageRemoved".equals(methodName)) {
+ onPackageRemoved((UserHandle) args[0], (String) args[1]);
+ } else if ("onPackageAdded".equals(methodName)) {
+ onPackageAdded((UserHandle) args[0], (String) args[1]);
+ } else if ("onPackageChanged".equals(methodName)) {
+ onPackageChanged((UserHandle) args[0], (String) args[1]);
+ } else if ("onPackagesAvailable".equals(methodName)) {
+ onPackagesAvailable((UserHandle) args[0], (String []) args[1],
+ (Boolean) args[2]);
+ } else if ("onPackagesUnavailable".equals(methodName)) {
+ onPackagesUnavailable((UserHandle) args[0], (String []) args[1],
+ (Boolean) args[2]);
+ }
+ } finally {
+ return null;
+ }
+ }
+
+ public void onPackageRemoved(UserHandle user, String packageName) {
+ mListener.onPackageRemoved(UserHandleCompat.fromUser(user), packageName);
+ }
+
+ public void onPackageAdded(UserHandle user, String packageName) {
+ mListener.onPackageAdded(UserHandleCompat.fromUser(user), packageName);
+ }
+
+ public void onPackageChanged(UserHandle user, String packageName) {
+ mListener.onPackageChanged(UserHandleCompat.fromUser(user), packageName);
+ }
+
+ public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing) {
+ mListener.onPackagesAvailable(UserHandleCompat.fromUser(user), packageNames, replacing);
+ }
+
+ public void onPackagesUnavailable(UserHandle user, String[] packageNames,
+ boolean replacing) {
+ mListener.onPackagesUnavailable(UserHandleCompat.fromUser(user), packageNames,
+ replacing);
+ }
+ }
+}
+
diff --git a/src/com/android/launcher3/compat/ReflectUtils.java b/src/com/android/launcher3/compat/ReflectUtils.java
new file mode 100644
index 000000000..e1b8a1f95
--- /dev/null
+++ b/src/com/android/launcher3/compat/ReflectUtils.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class ReflectUtils {
+ private static final String TAG = "LauncherReflect";
+
+ public static Class getClassForName(String className) {
+ try {
+ return Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ Log.e(TAG, "Couldn't find class " + className, e);
+ return null;
+ }
+ }
+
+ public static Method getMethod(Class clazz, String method) {
+ try {
+ return clazz.getMethod(method);
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "Couldn't find methid " + clazz.getName() + " " + method, e);
+ return null;
+ }
+ }
+
+ public static Method getMethod(Class clazz, String method, Class param1) {
+ try {
+ return clazz.getMethod(method, param1);
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "Couldn't find methid " + clazz.getName() + " " + method, e);
+ return null;
+ }
+ }
+
+ public static Method getMethod(Class clazz, String method, Class param1, Class param2) {
+ try {
+ return clazz.getMethod(method, param1, param2);
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "Couldn't find methid " + clazz.getName() + " " + method, e);
+ return null;
+ }
+ }
+
+ public static Method getMethod(Class clazz, String method, Class param1, Class param2,
+ Class param3) {
+ try {
+ return clazz.getMethod(method, param1, param2, param3);
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "Couldn't find methid " + clazz.getName() + " " + method, e);
+ return null;
+ }
+ }
+
+ public static Method getMethod(Class clazz, String method, Class param1, Class param2,
+ Class param3, Class param4) {
+ try {
+ return clazz.getMethod(method, param1, param2, param3, param4);
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "Couldn't find methid " + clazz.getName() + " " + method, e);
+ return null;
+ }
+ }
+
+ public static Object invokeMethod(Object object, Method method) {
+ try {
+ return method.invoke(object);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (InvocationTargetException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ }
+ return null;
+ }
+
+ public static Object invokeMethod(Object object, Method method, Object param1) {
+ try {
+ return method.invoke(object, param1);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (InvocationTargetException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ }
+ return null;
+ }
+
+ public static Object invokeMethod(Object object, Method method, Object param1, Object param2) {
+ try {
+ return method.invoke(object, param1, param2);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (InvocationTargetException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ }
+ return null;
+ }
+
+ public static Object invokeMethod(Object object, Method method, Object param1, Object param2,
+ Object param3) {
+ try {
+ return method.invoke(object, param1, param2, param3);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (InvocationTargetException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ }
+ return null;
+ }
+
+ public static Object invokeMethod(Object object, Method method, Object param1, Object param2,
+ Object param3, Object param4) {
+ try {
+ return method.invoke(object, param1, param2, param3, param4);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ } catch (InvocationTargetException e) {
+ Log.e(TAG, "Couldn't invoke method " + method, e);
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/launcher3/compat/UserHandleCompat.java b/src/com/android/launcher3/compat/UserHandleCompat.java
new file mode 100644
index 000000000..8f5dda238
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserHandleCompat.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.os.Build;
+import android.os.UserHandle;
+
+public class UserHandleCompat {
+ private UserHandle mUser;
+
+ private UserHandleCompat(UserHandle user) {
+ mUser = user;
+ }
+
+ private UserHandleCompat() {
+ }
+
+ public static UserHandleCompat myUserHandle() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ return new UserHandleCompat(android.os.Process.myUserHandle());
+ } else {
+ return new UserHandleCompat();
+ }
+ }
+
+ static UserHandleCompat fromUser(UserHandle user) {
+ if (user == null) {
+ return null;
+ } else {
+ return new UserHandleCompat(user);
+ }
+ }
+
+ UserHandle getUser() {
+ return mUser;
+ }
+
+ @Override
+ public String toString() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ return mUser.toString();
+ } else {
+ return "";
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof UserHandleCompat)) {
+ return false;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ return mUser.equals(((UserHandleCompat) other).mUser);
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ return mUser.hashCode();
+ } else {
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java
new file mode 100644
index 000000000..256e04a7b
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserManagerCompat.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+
+import java.util.List;
+
+public abstract class UserManagerCompat {
+ protected UserManagerCompat() {
+ }
+
+ public static UserManagerCompat getInstance(Context context) {
+ // TODO change this to use api version once L gets an API number.
+ if ("L".equals(Build.VERSION.CODENAME)) {
+ return new UserManagerCompatVL(context);
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ return new UserManagerCompatV17(context);
+ } else {
+ return new UserManagerCompatV16();
+ }
+ }
+
+ public abstract List<UserHandleCompat> getUserProfiles();
+ public abstract long getSerialNumberForUser(UserHandleCompat user);
+ public abstract UserHandleCompat getUserForSerialNumber(long serialNumber);
+ public abstract Drawable getBadgedDrawableForUser(Drawable unbadged, UserHandleCompat user);
+}
diff --git a/src/com/android/launcher3/compat/UserManagerCompatV16.java b/src/com/android/launcher3/compat/UserManagerCompatV16.java
new file mode 100644
index 000000000..2009e4e27
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserManagerCompatV16.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.graphics.drawable.Drawable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UserManagerCompatV16 extends UserManagerCompat {
+
+ UserManagerCompatV16() {
+ }
+
+ public List<UserHandleCompat> getUserProfiles() {
+ List<UserHandleCompat> profiles = new ArrayList<UserHandleCompat>(1);
+ profiles.add(UserHandleCompat.myUserHandle());
+ return profiles;
+ }
+
+ public UserHandleCompat getUserForSerialNumber(long serialNumber) {
+ return UserHandleCompat.myUserHandle();
+ }
+
+ public Drawable getBadgedDrawableForUser(Drawable unbadged,
+ UserHandleCompat user) {
+ return unbadged;
+ }
+
+ public long getSerialNumberForUser(UserHandleCompat user) {
+ return 0;
+ }
+}
diff --git a/src/com/android/launcher3/compat/UserManagerCompatV17.java b/src/com/android/launcher3/compat/UserManagerCompatV17.java
new file mode 100644
index 000000000..055359afe
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserManagerCompatV17.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UserManagerCompatV17 extends UserManagerCompatV16 {
+ protected UserManager mUserManager;
+
+ UserManagerCompatV17(Context context) {
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ }
+
+ public long getSerialNumberForUser(UserHandleCompat user) {
+ return mUserManager.getSerialNumberForUser(user.getUser());
+ }
+
+ public UserHandleCompat getUserForSerialNumber(long serialNumber) {
+ return UserHandleCompat.fromUser(mUserManager.getUserForSerialNumber(serialNumber));
+ }
+}
+
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java
new file mode 100644
index 000000000..8d3ca8577
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright (C) 2014 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.compat;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+public class UserManagerCompatVL extends UserManagerCompatV17 {
+
+ UserManagerCompatVL(Context context) {
+ super(context);
+ }
+
+ public List<UserHandleCompat> getUserProfiles() {
+ Method method = ReflectUtils.getMethod(mUserManager.getClass(), "getUserProfiles");
+ if (method != null) {
+ List<UserHandle> users = (List<UserHandle>) ReflectUtils.invokeMethod(
+ mUserManager, method);
+ if (users != null) {
+ ArrayList<UserHandleCompat> compatUsers = new ArrayList<UserHandleCompat>(
+ users.size());
+ for (UserHandle user : users) {
+ compatUsers.add(UserHandleCompat.fromUser(user));
+ }
+ return compatUsers;
+ }
+ }
+ // Fall back to non L version.
+ return super.getUserProfiles();
+ }
+
+ public Drawable getBadgedDrawableForUser(Drawable unbadged, UserHandleCompat user) {
+ Method method = ReflectUtils.getMethod(mUserManager.getClass(), "getBadgedDrawableForUser",
+ Drawable.class, UserHandle.class);
+ if (method != null) {
+ Drawable d = (Drawable) ReflectUtils.invokeMethod(mUserManager, method, unbadged,
+ user.getUser());
+ if (d != null) {
+ return d;
+ }
+ }
+ // Fall back to non L version.
+ return super.getBadgedDrawableForUser(unbadged, user);
+ }
+}
+