diff options
Diffstat (limited to 'src/com/android/launcher3/compat')
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()); + } +} + |