summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/compat
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/compat')
-rw-r--r--src/com/android/launcher3/compat/AppWidgetManagerCompat.java82
-rw-r--r--src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java90
-rw-r--r--src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java139
-rw-r--r--src/com/android/launcher3/compat/LauncherActivityInfoCompat.java35
-rw-r--r--src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java99
-rw-r--r--src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java60
-rw-r--r--src/com/android/launcher3/compat/LauncherAppsCompat.java76
-rw-r--r--src/com/android/launcher3/compat/LauncherAppsCompatV16.java210
-rw-r--r--src/com/android/launcher3/compat/LauncherAppsCompatVL.java137
-rw-r--r--src/com/android/launcher3/compat/PackageInstallerCompat.java75
-rw-r--r--src/com/android/launcher3/compat/PackageInstallerCompatV16.java175
-rw-r--r--src/com/android/launcher3/compat/PackageInstallerCompatVL.java201
-rw-r--r--src/com/android/launcher3/compat/UserHandleCompat.java95
-rw-r--r--src/com/android/launcher3/compat/UserManagerCompat.java46
-rw-r--r--src/com/android/launcher3/compat/UserManagerCompatV16.java51
-rw-r--r--src/com/android/launcher3/compat/UserManagerCompatV17.java42
-rw-r--r--src/com/android/launcher3/compat/UserManagerCompatVL.java65
17 files changed, 1678 insertions, 0 deletions
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
new file mode 100644
index 000000000..6512d427e
--- /dev/null
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.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.app.Activity;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.Utilities;
+
+import java.util.List;
+
+public abstract class AppWidgetManagerCompat {
+
+ private static final Object sInstanceLock = new Object();
+ private static AppWidgetManagerCompat sInstance;
+
+
+ public static AppWidgetManagerCompat getInstance(Context context) {
+ synchronized (sInstanceLock) {
+ if (sInstance == null) {
+ if (Utilities.isLmpOrAbove()) {
+ sInstance = new AppWidgetManagerCompatVL(context.getApplicationContext());
+ } else {
+ sInstance = new AppWidgetManagerCompatV16(context.getApplicationContext());
+ }
+ }
+ return sInstance;
+ }
+ }
+
+ final AppWidgetManager mAppWidgetManager;
+ final Context mContext;
+
+ AppWidgetManagerCompat(Context context) {
+ mContext = context;
+ mAppWidgetManager = AppWidgetManager.getInstance(context);
+ }
+
+ public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
+ return mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+ }
+
+ public abstract List<AppWidgetProviderInfo> getAllProviders();
+
+ public abstract String loadLabel(AppWidgetProviderInfo info);
+
+ public abstract boolean bindAppWidgetIdIfAllowed(
+ int appWidgetId, AppWidgetProviderInfo info, Bundle options);
+
+ public abstract UserHandleCompat getUser(AppWidgetProviderInfo info);
+
+ public abstract void startConfigActivity(AppWidgetProviderInfo info, int widgetId,
+ Activity activity, AppWidgetHost host, int requestCode);
+
+ public abstract Drawable loadPreview(AppWidgetProviderInfo info);
+
+ public abstract Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache);
+
+ public abstract Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap);
+
+}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
new file mode 100644
index 000000000..f599f4303
--- /dev/null
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
@@ -0,0 +1,90 @@
+/*
+ * 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.app.Activity;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.Utilities;
+
+import java.util.List;
+
+class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat {
+
+ AppWidgetManagerCompatV16(Context context) {
+ super(context);
+ }
+
+ @Override
+ public List<AppWidgetProviderInfo> getAllProviders() {
+ return mAppWidgetManager.getInstalledProviders();
+ }
+
+ @Override
+ public String loadLabel(AppWidgetProviderInfo info) {
+ return info.label.trim();
+ }
+
+ @Override
+ public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
+ Bundle options) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider);
+ } else {
+ return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider, options);
+ }
+ }
+
+ @Override
+ public UserHandleCompat getUser(AppWidgetProviderInfo info) {
+ return UserHandleCompat.myUserHandle();
+ }
+
+ @Override
+ public void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity,
+ AppWidgetHost host, int requestCode) {
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
+ intent.setComponent(info.configure);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
+ Utilities.startActivityForResultSafely(activity, intent, requestCode);
+ }
+
+ @Override
+ public Drawable loadPreview(AppWidgetProviderInfo info) {
+ return mContext.getPackageManager().getDrawable(
+ info.provider.getPackageName(), info.previewImage, null);
+ }
+
+ @Override
+ public Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache) {
+ return cache.getFullResIcon(info.provider.getPackageName(), info.icon);
+ }
+
+ @Override
+ public Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap) {
+ return bitmap;
+ }
+}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
new file mode 100644
index 000000000..c3853ab62
--- /dev/null
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -0,0 +1,139 @@
+/*
+ * 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.annotation.TargetApi;
+import android.app.Activity;
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@TargetApi(Build.VERSION_CODES.L)
+class AppWidgetManagerCompatVL extends AppWidgetManagerCompat {
+
+ private final UserManager mUserManager;
+ private final PackageManager mPm;
+
+ AppWidgetManagerCompatVL(Context context) {
+ super(context);
+ mPm = context.getPackageManager();
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ }
+
+ @Override
+ public List<AppWidgetProviderInfo> getAllProviders() {
+ ArrayList<AppWidgetProviderInfo> providers = new ArrayList<AppWidgetProviderInfo>();
+ for (UserHandle user : mUserManager.getUserProfiles()) {
+ providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user));
+ }
+ return providers;
+ }
+
+ @Override
+ public String loadLabel(AppWidgetProviderInfo info) {
+ return info.loadLabel(mPm);
+ }
+
+ @Override
+ public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
+ Bundle options) {
+ return mAppWidgetManager.bindAppWidgetIdIfAllowed(
+ appWidgetId, info.getProfile(), info.provider, options);
+ }
+
+ @Override
+ public UserHandleCompat getUser(AppWidgetProviderInfo info) {
+ return UserHandleCompat.fromUser(info.getProfile());
+ }
+
+ @Override
+ public void startConfigActivity(AppWidgetProviderInfo info, int widgetId, Activity activity,
+ AppWidgetHost host, int requestCode) {
+ try {
+ host.startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, null);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+ } catch (SecurityException e) {
+ Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public Drawable loadPreview(AppWidgetProviderInfo info) {
+ return info.loadPreviewImage(mContext, 0);
+ }
+
+ @Override
+ public Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache) {
+ return info.loadIcon(mContext, cache.getFullResIconDpi());
+ }
+
+ @Override
+ public Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap) {
+ if (info.getProfile().equals(android.os.Process.myUserHandle())) {
+ return bitmap;
+ }
+
+ // Add a user badge in the bottom right of the image.
+ final Resources res = mContext.getResources();
+ final int badgeSize = res.getDimensionPixelSize(R.dimen.profile_badge_size);
+ final int badgeMargin = res.getDimensionPixelSize(R.dimen.profile_badge_margin);
+ final Rect badgeLocation = new Rect(0, 0, badgeSize, badgeSize);
+
+ final int top = bitmap.getHeight() - badgeSize - badgeMargin;
+ if (res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ badgeLocation.offset(badgeMargin, top);
+ } else {
+ badgeLocation.offset(bitmap.getWidth() - badgeSize - badgeMargin, top);
+ }
+
+ Drawable drawable = mPm.getUserBadgedDrawableForDensity(
+ new BitmapDrawable(res, bitmap), info.getProfile(), badgeLocation, 0);
+
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) drawable).getBitmap();
+ }
+
+ bitmap.eraseColor(Color.TRANSPARENT);
+ Canvas c = new Canvas(bitmap);
+ drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ drawable.draw(c);
+ c.setBitmap(null);
+ return bitmap;
+ }
+}
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
new file mode 100644
index 000000000..90a4d1a1f
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
@@ -0,0 +1,35 @@
+/*
+ * 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.pm.ApplicationInfo;
+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 ApplicationInfo getApplicationInfo();
+ 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..1d41a6ff6
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
@@ -0,0 +1,99 @@
+/*
+ * 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.ApplicationInfo;
+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) {
+ try {
+ d = resources.getDrawableForDensity(mActivityInfo.getIconResource(), density);
+ } catch (Resources.NotFoundException e) {
+ // Return default icon below.
+ }
+ }
+ }
+ if (d == null) {
+ Resources resources = Resources.getSystem();
+ d = resources.getDrawableForDensity(android.R.mipmap.sym_def_app_icon, density);
+ }
+ return d;
+ }
+
+ public ApplicationInfo getApplicationInfo() {
+ return mActivityInfo.applicationInfo;
+ }
+
+ 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..b52cf1de2
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
@@ -0,0 +1,60 @@
+/*
+ * 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.pm.ApplicationInfo;
+import android.content.pm.LauncherActivityInfo;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+
+public class LauncherActivityInfoCompatVL extends LauncherActivityInfoCompat {
+ private LauncherActivityInfo mLauncherActivityInfo;
+
+ LauncherActivityInfoCompatVL(LauncherActivityInfo launcherActivityInfo) {
+ super();
+ mLauncherActivityInfo = launcherActivityInfo;
+ }
+
+ public ComponentName getComponentName() {
+ return mLauncherActivityInfo.getComponentName();
+ }
+
+ public UserHandleCompat getUser() {
+ return UserHandleCompat.fromUser(mLauncherActivityInfo.getUser());
+ }
+
+ public CharSequence getLabel() {
+ return mLauncherActivityInfo.getLabel();
+ }
+
+ public Drawable getIcon(int density) {
+ return mLauncherActivityInfo.getIcon(density);
+ }
+
+ public ApplicationInfo getApplicationInfo() {
+ return mLauncherActivityInfo.getApplicationInfo();
+ }
+
+ public long getFirstInstallTime() {
+ return mLauncherActivityInfo.getFirstInstallTime();
+ }
+
+ public Drawable getBadgedIcon(int density) {
+ return mLauncherActivityInfo.getBadgedIcon(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..6efcc00fd
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -0,0 +1,76 @@
+/*
+ * 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 com.android.launcher3.Utilities;
+
+import java.util.List;
+
+public abstract class LauncherAppsCompat {
+
+ public static final String ACTION_MANAGED_PROFILE_ADDED =
+ "android.intent.action.MANAGED_PROFILE_ADDED";
+ public static final String ACTION_MANAGED_PROFILE_REMOVED =
+ "android.intent.action.MANAGED_PROFILE_REMOVED";
+
+ public interface OnAppsChangedCallbackCompat {
+ void onPackageRemoved(String packageName, UserHandleCompat user);
+ void onPackageAdded(String packageName, UserHandleCompat user);
+ void onPackageChanged(String packageName, UserHandleCompat user);
+ void onPackagesAvailable(String[] packageNames, UserHandleCompat user, boolean replacing);
+ void onPackagesUnavailable(String[] packageNames, UserHandleCompat user, boolean replacing);
+ }
+
+ protected LauncherAppsCompat() {
+ }
+
+ private static LauncherAppsCompat sInstance;
+ private static Object sInstanceLock = new Object();
+
+ public static LauncherAppsCompat getInstance(Context context) {
+ synchronized (sInstanceLock) {
+ if (sInstance == null) {
+ if (Utilities.isLmpOrAbove()) {
+ sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
+ } else {
+ sInstance = new LauncherAppsCompatV16(context.getApplicationContext());
+ }
+ }
+ return sInstance;
+ }
+ }
+
+ public abstract List<LauncherActivityInfoCompat> getActivityList(String packageName,
+ UserHandleCompat user);
+ public abstract LauncherActivityInfoCompat resolveActivity(Intent intent,
+ UserHandleCompat user);
+ public abstract void startActivityForProfile(ComponentName component, UserHandleCompat user,
+ Rect sourceBounds, Bundle opts);
+ public abstract void showAppDetailsForProfile(ComponentName component, UserHandleCompat user);
+ public abstract void addOnAppsChangedCallback(OnAppsChangedCallbackCompat listener);
+ public abstract void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat 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..7e5e6bf2c
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
@@ -0,0 +1,210 @@
+/*
+ * 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.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.provider.Settings;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Version of {@link LauncherAppsCompat} for devices with API level 16.
+ * Devices Pre-L don't support multiple profiles in one launcher so
+ * user parameters are ignored and all methods operate on the current user.
+ */
+public class LauncherAppsCompatV16 extends LauncherAppsCompat {
+
+ private PackageManager mPm;
+ private Context mContext;
+ private List<OnAppsChangedCallbackCompat> mCallbacks
+ = new ArrayList<OnAppsChangedCallbackCompat>();
+ 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, UserHandleCompat user,
+ Rect sourceBounds, Bundle opts) {
+ 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 void showAppDetailsForProfile(ComponentName component, UserHandleCompat user) {
+ String packageName = component.getPackageName();
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ Uri.fromParts("package", packageName, null));
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
+ Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ mContext.startActivity(intent, null);
+ }
+
+ public synchronized void addOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) {
+ if (callback != null && !mCallbacks.contains(callback)) {
+ mCallbacks.add(callback);
+ if (mCallbacks.size() == 1) {
+ registerForPackageIntents();
+ }
+ }
+ }
+
+ public synchronized void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) {
+ mCallbacks.remove(callback);
+ if (mCallbacks.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<OnAppsChangedCallbackCompat> getCallbacks() {
+ return new ArrayList<OnAppsChangedCallbackCompat>(mCallbacks);
+ }
+
+ 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 (OnAppsChangedCallbackCompat callback : getCallbacks()) {
+ callback.onPackageChanged(packageName, user);
+ }
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ if (!replacing) {
+ for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
+ callback.onPackageRemoved(packageName, user);
+ }
+ }
+ // 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 (OnAppsChangedCallbackCompat callback : getCallbacks()) {
+ callback.onPackageAdded(packageName, user);
+ }
+ } else {
+ for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
+ callback.onPackageChanged(packageName, user);
+ }
+ }
+ }
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+ // EXTRA_REPLACING is available Kitkat onwards. For lower devices, it is broadcasted
+ // when moving a package or mounting/un-mounting external storage. Assume that
+ // it is a replacing operation.
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING,
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT);
+ String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
+ callback.onPackagesAvailable(packages, user, replacing);
+ }
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING,
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT);
+ String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
+ callback.onPackagesUnavailable(packages, user, 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..e0d28b566
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -0,0 +1,137 @@
+/*
+ * 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.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
+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.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class LauncherAppsCompatVL extends LauncherAppsCompat {
+
+ private LauncherApps mLauncherApps;
+
+ private Map<OnAppsChangedCallbackCompat, WrappedCallback> mCallbacks
+ = new HashMap<OnAppsChangedCallbackCompat, WrappedCallback>();
+
+ LauncherAppsCompatVL(Context context) {
+ super();
+ mLauncherApps = (LauncherApps) context.getSystemService("launcherapps");
+ }
+
+ public List<LauncherActivityInfoCompat> getActivityList(String packageName,
+ UserHandleCompat user) {
+ List<LauncherActivityInfo> list = mLauncherApps.getActivityList(packageName,
+ user.getUser());
+ if (list.size() == 0) {
+ return Collections.EMPTY_LIST;
+ }
+ ArrayList<LauncherActivityInfoCompat> compatList =
+ new ArrayList<LauncherActivityInfoCompat>(list.size());
+ for (LauncherActivityInfo info : list) {
+ compatList.add(new LauncherActivityInfoCompatVL(info));
+ }
+ return compatList;
+ }
+
+ public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandleCompat user) {
+ LauncherActivityInfo activity = mLauncherApps.resolveActivity(intent, user.getUser());
+ if (activity != null) {
+ return new LauncherActivityInfoCompatVL(activity);
+ } else {
+ return null;
+ }
+ }
+
+ public void startActivityForProfile(ComponentName component, UserHandleCompat user,
+ Rect sourceBounds, Bundle opts) {
+ mLauncherApps.startMainActivity(component, user.getUser(), sourceBounds, opts);
+ }
+
+ public void showAppDetailsForProfile(ComponentName component, UserHandleCompat user) {
+ mLauncherApps.startAppDetailsActivity(component, user.getUser(), null, null);
+ }
+
+ public void addOnAppsChangedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) {
+ WrappedCallback wrappedCallback = new WrappedCallback(callback);
+ synchronized (mCallbacks) {
+ mCallbacks.put(callback, wrappedCallback);
+ }
+ mLauncherApps.registerCallback(wrappedCallback);
+ }
+
+ public void removeOnAppsChangedCallback(
+ LauncherAppsCompat.OnAppsChangedCallbackCompat callback) {
+ WrappedCallback wrappedCallback = null;
+ synchronized (mCallbacks) {
+ wrappedCallback = mCallbacks.remove(callback);
+ }
+ if (wrappedCallback != null) {
+ mLauncherApps.unregisterCallback(wrappedCallback);
+ }
+ }
+
+ public boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user) {
+ return mLauncherApps.isPackageEnabled(packageName, user.getUser());
+ }
+
+ public boolean isActivityEnabledForProfile(ComponentName component, UserHandleCompat user) {
+ return mLauncherApps.isActivityEnabled(component, user.getUser());
+ }
+
+ private static class WrappedCallback extends LauncherApps.Callback {
+ private LauncherAppsCompat.OnAppsChangedCallbackCompat mCallback;
+
+ public WrappedCallback(LauncherAppsCompat.OnAppsChangedCallbackCompat callback) {
+ mCallback = callback;
+ }
+
+ public void onPackageRemoved(String packageName, UserHandle user) {
+ mCallback.onPackageRemoved(packageName, UserHandleCompat.fromUser(user));
+ }
+
+ public void onPackageAdded(String packageName, UserHandle user) {
+ mCallback.onPackageAdded(packageName, UserHandleCompat.fromUser(user));
+ }
+
+ public void onPackageChanged(String packageName, UserHandle user) {
+ mCallback.onPackageChanged(packageName, UserHandleCompat.fromUser(user));
+ }
+
+ public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
+ mCallback.onPackagesAvailable(packageNames, UserHandleCompat.fromUser(user), replacing);
+ }
+
+ public void onPackagesUnavailable(String[] packageNames, UserHandle user,
+ boolean replacing) {
+ mCallback.onPackagesUnavailable(packageNames, UserHandleCompat.fromUser(user),
+ replacing);
+ }
+ }
+}
+
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java
new file mode 100644
index 000000000..0eb8754e8
--- /dev/null
+++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java
@@ -0,0 +1,75 @@
+/*
+ * 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 com.android.launcher3.Utilities;
+
+import java.util.HashSet;
+
+public abstract class PackageInstallerCompat {
+
+ public static final int STATUS_INSTALLED = 0;
+ public static final int STATUS_INSTALLING = 1;
+ public static final int STATUS_FAILED = 2;
+
+ private static final Object sInstanceLock = new Object();
+ private static PackageInstallerCompat sInstance;
+
+ public static PackageInstallerCompat getInstance(Context context) {
+ synchronized (sInstanceLock) {
+ if (sInstance == null) {
+ if (Utilities.isLmpOrAbove()) {
+ sInstance = new PackageInstallerCompatVL(context);
+ } else {
+ sInstance = new PackageInstallerCompatV16(context) { };
+ }
+ }
+ return sInstance;
+ }
+ }
+
+ public abstract HashSet<String> updateAndGetActiveSessionCache();
+
+ public abstract void onPause();
+
+ public abstract void onResume();
+
+ public abstract void onFinishBind();
+
+ public abstract void onStop();
+
+ public abstract void recordPackageUpdate(String packageName, int state, int progress);
+
+ public static final class PackageInstallInfo {
+ public final String packageName;
+
+ public int state;
+ public int progress;
+
+ public PackageInstallInfo(String packageName) {
+ this.packageName = packageName;
+ }
+
+ public PackageInstallInfo(String packageName, int state, int progress) {
+ this.packageName = packageName;
+ this.state = state;
+ this.progress = progress;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
new file mode 100644
index 000000000..1910d22ae
--- /dev/null
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
@@ -0,0 +1,175 @@
+/*
+ * 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.content.SharedPreferences;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.launcher3.LauncherAppState;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONStringer;
+import org.json.JSONTokener;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+public class PackageInstallerCompatV16 extends PackageInstallerCompat {
+
+ private static final String TAG = "PackageInstallerCompatV16";
+ private static final boolean DEBUG = false;
+
+ private static final String KEY_PROGRESS = "progress";
+ private static final String KEY_STATE = "state";
+
+ private static final String PREFS =
+ "com.android.launcher3.compat.PackageInstallerCompatV16.queue";
+
+ protected final SharedPreferences mPrefs;
+
+ boolean mUseQueue;
+ boolean mFinishedBind;
+ boolean mReplayPending;
+
+ PackageInstallerCompatV16(Context context) {
+ mPrefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
+ }
+
+ @Override
+ public void onPause() {
+ mUseQueue = true;
+ if (DEBUG) Log.d(TAG, "updates paused");
+ }
+
+ @Override
+ public void onResume() {
+ mUseQueue = false;
+ if (mFinishedBind) {
+ replayUpdates();
+ }
+ }
+
+ @Override
+ public void onFinishBind() {
+ mFinishedBind = true;
+ if (!mUseQueue) {
+ replayUpdates();
+ }
+ }
+
+ @Override
+ public void onStop() { }
+
+ private void replayUpdates() {
+ if (DEBUG) Log.d(TAG, "updates resumed");
+ LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+ if (app == null) {
+ mReplayPending = true; // try again later
+ if (DEBUG) Log.d(TAG, "app is null, delaying send");
+ return;
+ }
+ mReplayPending = false;
+ ArrayList<PackageInstallInfo> updates = new ArrayList<PackageInstallInfo>();
+ for (String packageName: mPrefs.getAll().keySet()) {
+ final String json = mPrefs.getString(packageName, null);
+ if (!TextUtils.isEmpty(json)) {
+ updates.add(infoFromJson(packageName, json));
+ }
+ }
+ if (!updates.isEmpty()) {
+ sendUpdate(app, updates);
+ }
+ }
+
+ /**
+ * This should be called by the implementations to register a package update.
+ */
+ @Override
+ public synchronized void recordPackageUpdate(String packageName, int state, int progress) {
+ SharedPreferences.Editor editor = mPrefs.edit();
+ PackageInstallInfo installInfo = new PackageInstallInfo(packageName);
+ installInfo.progress = progress;
+ installInfo.state = state;
+ if (state == STATUS_INSTALLED) {
+ // no longer necessary to track this package
+ editor.remove(packageName);
+ if (DEBUG) Log.d(TAG, "no longer tracking " + packageName);
+ } else {
+ editor.putString(packageName, infoToJson(installInfo));
+ if (DEBUG)
+ Log.d(TAG, "saved state: " + infoToJson(installInfo)
+ + " for package: " + packageName);
+
+ }
+ editor.commit();
+
+ if (!mUseQueue) {
+ if (mReplayPending) {
+ replayUpdates();
+ } else if (state != STATUS_INSTALLED) {
+ LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+ ArrayList<PackageInstallInfo> update = new ArrayList<PackageInstallInfo>();
+ update.add(installInfo);
+ sendUpdate(app, update);
+ }
+ }
+ }
+
+ private void sendUpdate(LauncherAppState app, ArrayList<PackageInstallInfo> updates) {
+ if (app == null) {
+ mReplayPending = true; // try again later
+ if (DEBUG) Log.d(TAG, "app is null, delaying send");
+ } else {
+ app.setPackageState(updates);
+ }
+ }
+
+ private static PackageInstallInfo infoFromJson(String packageName, String json) {
+ PackageInstallInfo info = new PackageInstallInfo(packageName);
+ try {
+ JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
+ info.state = object.getInt(KEY_STATE);
+ info.progress = object.getInt(KEY_PROGRESS);
+ } catch (JSONException e) {
+ Log.e(TAG, "failed to deserialize app state update", e);
+ }
+ return info;
+ }
+
+ private static String infoToJson(PackageInstallInfo info) {
+ String value = null;
+ try {
+ JSONStringer json = new JSONStringer()
+ .object()
+ .key(KEY_STATE).value(info.state)
+ .key(KEY_PROGRESS).value(info.progress)
+ .endObject();
+ value = json.toString();
+ } catch (JSONException e) {
+ Log.e(TAG, "failed to serialize app state update", e);
+ }
+ return value;
+ }
+
+ @Override
+ public HashSet<String> updateAndGetActiveSessionCache() {
+ return new HashSet<String>();
+ }
+}
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
new file mode 100644
index 000000000..16ad3792a
--- /dev/null
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -0,0 +1,201 @@
+/*
+ * 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.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionCallback;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.LauncherAppState;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+public class PackageInstallerCompatVL extends PackageInstallerCompat {
+
+ private static final String TAG = "PackageInstallerCompatVL";
+ private static final boolean DEBUG = false;
+
+ private final SparseArray<SessionInfo> mPendingReplays = new SparseArray<SessionInfo>();
+ private final HashSet<String> mPendingBadgeUpdates = new HashSet<String>();
+ private final PackageInstaller mInstaller;
+ private final IconCache mCache;
+
+ private boolean mResumed;
+ private boolean mBound;
+
+ PackageInstallerCompatVL(Context context) {
+ mInstaller = context.getPackageManager().getPackageInstaller();
+ LauncherAppState.setApplicationContext(context.getApplicationContext());
+ mCache = LauncherAppState.getInstance().getIconCache();
+
+ mResumed = false;
+ mBound = false;
+
+ mInstaller.registerSessionCallback(mCallback);
+
+ // On start, send updates for all active sessions
+ for (SessionInfo info : mInstaller.getAllSessions()) {
+ mPendingReplays.append(info.getSessionId(), info);
+ }
+ }
+
+ @Override
+ public HashSet<String> updateAndGetActiveSessionCache() {
+ HashSet<String> activePackages = new HashSet<String>();
+ UserHandleCompat user = UserHandleCompat.myUserHandle();
+ for (SessionInfo info : mInstaller.getAllSessions()) {
+ addSessionInfoToCahce(info, user);
+ if (info.getAppPackageName() != null) {
+ activePackages.add(info.getAppPackageName());
+ }
+ }
+ return activePackages;
+ }
+
+ private void addSessionInfoToCahce(SessionInfo info, UserHandleCompat user) {
+ String packageName = info.getAppPackageName();
+ if (packageName != null) {
+ mCache.cachePackageInstallInfo(packageName, user, info.getAppIcon(),
+ info.getAppLabel());
+ }
+ }
+
+ @Override
+ public void onStop() {
+ }
+
+ @Override
+ public void onFinishBind() {
+ mBound = true;
+ replayUpdates(null);
+ }
+
+ @Override
+ public void onPause() {
+ mResumed = false;
+ }
+
+ @Override
+ public void onResume() {
+ mResumed = true;
+ replayUpdates(null);
+ }
+
+ @Override
+ public void recordPackageUpdate(String packageName, int state, int progress) {
+ // No op
+ }
+
+ private void replayUpdates(PackageInstallInfo newInfo) {
+ if (DEBUG) Log.d(TAG, "updates resumed");
+ if (!mResumed || !mBound) {
+ // Not yet ready
+ return;
+ }
+ if ((mPendingReplays.size() == 0) && (newInfo == null) && mPendingBadgeUpdates.isEmpty()) {
+ // Nothing to update
+ return;
+ }
+
+ LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+ if (app == null) {
+ // Try again later
+ if (DEBUG) Log.d(TAG, "app is null, delaying send");
+ return;
+ }
+
+ ArrayList<PackageInstallInfo> updates = new ArrayList<PackageInstallInfo>();
+ if ((newInfo != null) && (newInfo.state != STATUS_INSTALLED)) {
+ updates.add(newInfo);
+ }
+ for (int i = mPendingReplays.size() - 1; i >= 0; i--) {
+ SessionInfo session = mPendingReplays.valueAt(i);
+ if (session.getAppPackageName() != null) {
+ updates.add(new PackageInstallInfo(session.getAppPackageName(),
+ STATUS_INSTALLING,
+ (int) (session.getProgress() * 100)));
+ }
+ }
+ mPendingReplays.clear();
+ if (!updates.isEmpty()) {
+ app.setPackageState(updates);
+ }
+
+ if (!mPendingBadgeUpdates.isEmpty()) {
+ for (String pkg : mPendingBadgeUpdates) {
+ app.updatePackageBadge(pkg);
+ }
+ mPendingBadgeUpdates.clear();
+ }
+ }
+
+ private final SessionCallback mCallback = new SessionCallback() {
+
+ @Override
+ public void onCreated(int sessionId) {
+ pushSessionBadgeToLauncher(sessionId);
+ }
+
+ @Override
+ public void onFinished(int sessionId, boolean success) {
+ mPendingReplays.remove(sessionId);
+ SessionInfo session = mInstaller.getSessionInfo(sessionId);
+ if ((session != null) && (session.getAppPackageName() != null)) {
+ mPendingBadgeUpdates.remove(session.getAppPackageName());
+ // Replay all updates with a one time update for this installed package. No
+ // need to store this record for future updates, as the app list will get
+ // refreshed on resume.
+ replayUpdates(new PackageInstallInfo(session.getAppPackageName(),
+ success ? STATUS_INSTALLED : STATUS_FAILED, 0));
+ }
+ }
+
+ @Override
+ public void onProgressChanged(int sessionId, float progress) {
+ SessionInfo session = mInstaller.getSessionInfo(sessionId);
+ if (session != null) {
+ mPendingReplays.put(sessionId, session);
+ replayUpdates(null);
+ }
+ }
+
+ @Override
+ public void onActiveChanged(int sessionId, boolean active) { }
+
+ @Override
+ public void onBadgingChanged(int sessionId) {
+ pushSessionBadgeToLauncher(sessionId);
+ }
+
+ private void pushSessionBadgeToLauncher(int sessionId) {
+ SessionInfo session = mInstaller.getSessionInfo(sessionId);
+ if (session != null) {
+ addSessionInfoToCahce(session, UserHandleCompat.myUserHandle());
+ if (session.getAppPackageName() != null) {
+ mPendingBadgeUpdates.add(session.getAppPackageName());
+ }
+ mPendingReplays.put(sessionId, session);
+ replayUpdates(null);
+ }
+ }
+ };
+}
diff --git a/src/com/android/launcher3/compat/UserHandleCompat.java b/src/com/android/launcher3/compat/UserHandleCompat.java
new file mode 100644
index 000000000..2ae673171
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserHandleCompat.java
@@ -0,0 +1,95 @@
+/*
+ * 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.Intent;
+import android.os.Build;
+import android.os.UserHandle;
+
+import com.android.launcher3.Utilities;
+
+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;
+ }
+ }
+
+ /**
+ * Adds {@link UserHandle} to the intent in for L or above.
+ * Pre-L the launcher doesn't support showing apps for multiple
+ * profiles so this is a no-op.
+ */
+ public void addToIntent(Intent intent, String name) {
+ if (Utilities.isLmpOrAbove() && mUser != null) {
+ intent.putExtra(name, mUser);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java
new file mode 100644
index 000000000..1374b4e49
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserManagerCompat.java
@@ -0,0 +1,46 @@
+/*
+ * 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 com.android.launcher3.Utilities;
+
+import java.util.List;
+
+public abstract class UserManagerCompat {
+ protected UserManagerCompat() {
+ }
+
+ public static UserManagerCompat getInstance(Context context) {
+ if (Utilities.isLmpOrAbove()) {
+ 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);
+ public abstract CharSequence getBadgedLabelForUser(CharSequence label, 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..32f972e85
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserManagerCompatV16.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+ }
+
+ public CharSequence getBadgedLabelForUser(CharSequence label, UserHandleCompat user) {
+ return label;
+ }
+}
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..19eeabdcf
--- /dev/null
+++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java
@@ -0,0 +1,65 @@
+
+/*
+ * 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.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class UserManagerCompatVL extends UserManagerCompatV17 {
+ private final PackageManager mPm;
+
+ UserManagerCompatVL(Context context) {
+ super(context);
+ mPm = context.getPackageManager();
+ }
+
+ @Override
+ public List<UserHandleCompat> getUserProfiles() {
+ List<UserHandle> users = mUserManager.getUserProfiles();
+ if (users == null) {
+ return Collections.EMPTY_LIST;
+ }
+ ArrayList<UserHandleCompat> compatUsers = new ArrayList<UserHandleCompat>(
+ users.size());
+ for (UserHandle user : users) {
+ compatUsers.add(UserHandleCompat.fromUser(user));
+ }
+ return compatUsers;
+ }
+
+ @Override
+ public Drawable getBadgedDrawableForUser(Drawable unbadged, UserHandleCompat user) {
+ return mPm.getUserBadgedIcon(unbadged, user.getUser());
+ }
+
+ @Override
+ public CharSequence getBadgedLabelForUser(CharSequence label, UserHandleCompat user) {
+ if (user == null) {
+ return label;
+ }
+ return mPm.getUserBadgedLabel(label, user.getUser());
+ }
+}
+