diff options
6 files changed, 64 insertions, 156 deletions
diff --git a/api/current.txt b/api/current.txt index 8514584..e70be0e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5747,7 +5747,7 @@ package android.appwidget { method protected android.appwidget.AppWidgetHostView onCreateView(android.content.Context, int, android.appwidget.AppWidgetProviderInfo); method protected void onProviderChanged(int, android.appwidget.AppWidgetProviderInfo); method protected void onProvidersChanged(); - method public final void startAppWidgetConfigureActivityForResult(android.app.Activity, android.content.Intent, int); + method public final void startAppWidgetConfigureActivityForResult(android.app.Activity, int, int, int, android.os.Bundle); method public void startListening(); method public void stopListening(); } @@ -5775,7 +5775,7 @@ package android.appwidget { method public android.appwidget.AppWidgetProviderInfo getAppWidgetInfo(int); method public android.os.Bundle getAppWidgetOptions(int); method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProviders(); - method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForProfiles(android.os.UserHandle[]); + method public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForProfile(android.os.UserHandle); method public static android.appwidget.AppWidgetManager getInstance(android.content.Context); method public void notifyAppWidgetViewDataChanged(int[], int); method public void notifyAppWidgetViewDataChanged(int, int); diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java index 66a6eb6..69716e5 100644 --- a/core/java/android/appwidget/AppWidgetHost.java +++ b/core/java/android/appwidget/AppWidgetHost.java @@ -19,12 +19,15 @@ package android.appwidget; import java.util.ArrayList; import java.util.HashMap; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.os.Binder; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -199,32 +202,30 @@ public class AppWidgetHost { /** * Starts an app widget provider configure activity for result on behalf of the caller. * Use this method if the provider is in another profile as you are not allowed to start - * an activity in another profile. The provided intent must have action {@link - * AppWidgetManager#ACTION_APPWIDGET_CONFIGURE}. The widget id must be specified by - * the {@link AppWidgetManager#EXTRA_APPWIDGET_ID} extra. The provider configure - * activity must be specified as the component name of the intent via {@link - * Intent#setComponent(android.content.ComponentName)}. The user profile under which - * the provider operates is specified via the {@link - * AppWidgetManager#EXTRA_APPWIDGET_PROVIDER_PROFILE} extra. If a user profile is - * not provided, the current user is used. Finally, you can optionally provide a - * request code that is returned in {@link Activity#onActivityResult(int, int, - * android.content.Intent)}. + * an activity in another profile. You can optionally provide a request code that is + * returned in {@link Activity#onActivityResult(int, int, android.content.Intent)} and + * an options bundle to be passed to the started activity. + * <p> + * Note that the provided app widget has to be bound for this method to work. + * </p> * * @param activity The activity from which to start the configure one. - * @param intent Properly populated intent for launching the configuration activity. + * @param appWidgetId The bound app widget whose provider's config activity to start. * @param requestCode Optional request code retuned with the result. + * @param intentFlags Optional intent flags. * * @throws android.content.ActivityNotFoundException If the activity is not found. * * @see AppWidgetProviderInfo#getProfile() */ - public final void startAppWidgetConfigureActivityForResult(Activity activity, Intent intent, - int requestCode) { + public final void startAppWidgetConfigureActivityForResult(@NonNull Activity activity, + int appWidgetId, int intentFlags, int requestCode, @Nullable Bundle options) { try { IntentSender intentSender = sService.createAppWidgetConfigIntentSender( - mContext.getPackageName(), intent); + mContext.getPackageName(), appWidgetId, intentFlags); if (intentSender != null) { - activity.startIntentSenderForResult(intentSender, requestCode, null, 0, 0, 0); + activity.startIntentSenderForResult(intentSender, requestCode, null, 0, 0, 0, + options); } else { throw new ActivityNotFoundException(); } diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index e5d1d95..086eb7d 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -16,6 +16,7 @@ package android.appwidget; +import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -673,24 +674,24 @@ public class AppWidgetManager { } /** - * Gets the AppWidget providers for the given user profiles. User profiles can only + * Gets the AppWidget providers for the given user profile. User profile can only * be the current user or a profile of the current user. For example, the current * user may have a corporate profile. In this case the parent user profile has a * child profile, the corporate one. * - * @param profiles The profiles for which to get providers. Passing null is equivaled + * @param profile The profile for which to get providers. Passing null is equivaled * to passing only the current user handle. * @return The intalled providers. * * @see android.os.Process#myUserHandle() * @see android.os.UserManager#getUserProfiles() */ - public List<AppWidgetProviderInfo> getInstalledProvidersForProfiles(UserHandle[] profiles) { + public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(@Nullable UserHandle profile) { if (mService == null) { return Collections.emptyList(); } - return getInstalledProvidersForProfiles(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, - profiles); + return getInstalledProvidersForProfile(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, + profile); } /** @@ -700,7 +701,7 @@ public class AppWidgetManager { if (mService == null) { return Collections.emptyList(); } - return getInstalledProvidersForProfiles(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, + return getInstalledProvidersForProfile(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, null); } @@ -720,18 +721,18 @@ public class AppWidgetManager { if (mService == null) { return Collections.emptyList(); } - return getInstalledProvidersForProfiles(categoryFilter, null); + return getInstalledProvidersForProfile(categoryFilter, null); } /** - * Gets the AppWidget providers for the given user profiles. User profiles can only + * Gets the AppWidget providers for the given user profile. User profile can only * be the current user or a profile of the current user. For example, the current * user may have a corporate profile. In this case the parent user profile has a * child profile, the corporate one. * * @param categoryFilter Will only return providers which register as any of the specified * specified categories. See {@link AppWidgetProviderInfo#widgetCategory}. - * @param profiles Child profiles of the current user which to be queried. The user + * @param profile A profile of the current user which to be queried. The user * is itself also a profile. If null, the providers only for the current user * are returned. * @return The intalled providers. @@ -741,25 +742,19 @@ public class AppWidgetManager { * * @hide */ - public List<AppWidgetProviderInfo> getInstalledProvidersForProfiles(int categoryFilter, - UserHandle[] profiles) { + public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter, + UserHandle profile) { if (mService == null) { return Collections.emptyList(); } - int[] profileIds = null; - - if (profiles != null) { - final int profileCount = profiles.length; - profileIds = new int[profileCount]; - for (int i = 0; i < profileCount; i++) { - profileIds[i] = profiles[i].getIdentifier(); - } + if (profile == null) { + profile = Process.myUserHandle(); } try { - List<AppWidgetProviderInfo> providers = mService.getInstalledProviders(categoryFilter, - profileIds); + List<AppWidgetProviderInfo> providers = mService.getInstalledProvidersForProfile( + categoryFilter, profile.getIdentifier()); if (providers == null) { return Collections.emptyList(); } diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 6835368..a767246 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -16,6 +16,7 @@ package android.appwidget; +import android.annotation.NonNull; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; @@ -269,7 +270,7 @@ public class AppWidgetProviderInfo implements Parcelable { * {@link android.util.DisplayMetrics#densityDpi}. * @return The provider icon. */ - public final Drawable loadIcon(Context context, int density) { + public final Drawable loadIcon(@NonNull Context context, int density) { return loadDrawable(context, density, providerInfo.getIconResource()); } @@ -289,7 +290,7 @@ public class AppWidgetProviderInfo implements Parcelable { * {@link android.util.DisplayMetrics#densityDpi}. * @return The widget preview image. */ - public final Drawable loadPreviewImage(Context context, int density) { + public final Drawable loadPreviewImage(@NonNull Context context, int density) { return loadDrawable(context, density, previewImage); } diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl index 9da1c9d..008d38b 100644 --- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl +++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl @@ -41,7 +41,8 @@ interface IAppWidgetService { void deleteAllHosts(); RemoteViews getAppWidgetViews(String callingPackage, int appWidgetId); int[] getAppWidgetIdsForHost(String callingPackage, int hostId); - IntentSender createAppWidgetConfigIntentSender(String callingPackage, in Intent intent); + IntentSender createAppWidgetConfigIntentSender(String callingPackage, int appWidgetId, + int intentFlags); // // for AppWidgetManager @@ -53,8 +54,8 @@ interface IAppWidgetService { in RemoteViews views); void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views); void notifyAppWidgetViewDataChanged(String packageName, in int[] appWidgetIds, int viewId); - List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, - in int[] profileIds); + List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter, + int profileId); AppWidgetProviderInfo getAppWidgetInfo(String callingPackage, int appWidgetId); boolean hasBindAppWidgetPermission(in String packageName, int userId); void setBindAppWidgetPermission(in String packageName, int userId, in boolean permission); diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 4315e0d..609ffda 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -121,8 +121,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private static final int LOADED_PROFILE_ID = -1; - private static final int DISABLED_PROFILE = -1; - private static final int UNKNOWN_USER_ID = -10; // Bump if the stored widgets need to be upgraded. @@ -660,7 +658,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } @Override - public IntentSender createAppWidgetConfigIntentSender(String callingPackage, Intent intent) { + public IntentSender createAppWidgetConfigIntentSender(String callingPackage, int appWidgetId, + int intentFlags) { final int userId = UserHandle.getCallingUserId(); if (DEBUG) { @@ -670,57 +669,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // Make sure the package runs under the caller uid. mSecurityPolicy.enforceCallFromPackage(callingPackage); - // The only allowed action is the one to start the configure activity. - if (!AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) { - throw new IllegalArgumentException("Only allowed action is " - + AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); - } - - // Verify that widget id is provided. - final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID); - if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { - throw new IllegalArgumentException("Widget id required"); - } - - // Make sure a component name is provided. - ComponentName component = intent.getComponent(); - if (component == null) { - throw new IllegalArgumentException("Component name required"); - } - - // Verify the user handle. - UserHandle userHandle = intent.getParcelableExtra( - AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE); - if (userHandle != null) { - // Remove the profile extra as the receiver already runs under this - // user and this information is of no use to this receiver. - intent.removeExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE); - - // If the user handle is not the caller, check if it is an enabled - // profile for which the package is white-listed. - final int profileId = userHandle.getIdentifier(); - if (profileId != userId) { - // Make sure the passed user handle is a profile in the group. - final int[] profileIds = mSecurityPolicy.resolveCallerEnabledGroupProfiles( - new int[]{profileId}); - if (profileIds.length <= 0) { - // The profile is not in the group or not enabled, done. - return null; - } - - // Make sure the provider is white-listed. - if (!mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed( - component.getPackageName(), profileId)) { - throw new IllegalArgumentException("Cannot access provider " - + component + " in user " + profileIds); - } - } - } else { - // If a profile is not specified use the caller user id. - userHandle = new UserHandle(userId); - } - synchronized (mLock) { ensureGroupStateLoadedLocked(userId); @@ -738,19 +686,18 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku throw new IllegalArgumentException("Widget not bound " + appWidgetId); } - // Make sure the component refers to the provider config activity. - if (!component.equals(provider.info.configure) - || !provider.info.getProfile().equals(userHandle)) { - throw new IllegalArgumentException("No component" + component - + " for user " + userHandle.getIdentifier()); - } + Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); + intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); + intent.setComponent(provider.info.configure); + intent.setFlags(intentFlags); // All right, create the sender. final long identity = Binder.clearCallingIdentity(); try { return PendingIntent.getActivityAsUser( mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_CANCEL_CURRENT, null, userHandle) + | PendingIntent.FLAG_CANCEL_CURRENT, null, + new UserHandle(provider.getUserId())) .getIntentSender(); } finally { Binder.restoreCallingIdentity(identity); @@ -771,9 +718,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku mSecurityPolicy.enforceCallFromPackage(callingPackage); // Check that if a cross-profile binding is attempted, it is allowed. - final int[] profileIds = mSecurityPolicy.resolveCallerEnabledGroupProfiles( - new int[] {providerProfileId}); - if (profileIds.length <= 0) { + if (!mSecurityPolicy.isEnabledGroupProfile(providerProfileId)) { return false; } @@ -1309,28 +1254,23 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } @Override - public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int[] profileIds) { + public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter, + int profileId) { final int userId = UserHandle.getCallingUserId(); if (DEBUG) { Slog.i(TAG, "getInstalledProvidersForProfiles() " + userId); } - if (profileIds != null && profileIds.length > 0) { - // Make sure the profile ids are children of the calling user. - profileIds = mSecurityPolicy.resolveCallerEnabledGroupProfiles(profileIds); - } else { - profileIds = new int[] {userId}; - } - - if (profileIds.length == 0) { + // Ensure the profile is in the group and enabled. + if (!mSecurityPolicy.isEnabledGroupProfile(profileId)) { return null; } synchronized (mLock) { ensureGroupStateLoadedLocked(userId); - ArrayList<AppWidgetProviderInfo> result = new ArrayList<>(); + ArrayList<AppWidgetProviderInfo> result = null; final int providerCount = mProviders.size(); for (int i = 0; i < providerCount; i++) { @@ -1342,19 +1282,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku continue; } - // Add providers only for the requested profiles ... + // Add providers only for the requested profile that are white-listed. final int providerProfileId = info.getProfile().getIdentifier(); - final int profileCount = profileIds.length; - for (int j = 0; j < profileCount; j++) { - final int profileId = profileIds[j]; - if (providerProfileId == profileId) { - // ... that are white-listed by the profile manager. - if (mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed( - provider.id.componentName.getPackageName(), providerProfileId)) { - result.add(cloneIfLocalBinder(info)); - } - break; + if (providerProfileId == profileId + && mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed( + provider.id.componentName.getPackageName(), providerProfileId)) { + if (result == null) { + result = new ArrayList<>(); } + result.add(cloneIfLocalBinder(info)); } } @@ -2967,35 +2903,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private final class SecurityPolicy { - public int[] resolveCallerEnabledGroupProfiles(int[] profileIds) { + public boolean isEnabledGroupProfile(int profileId) { final int parentId = UserHandle.getCallingUserId(); - - int enabledProfileCount = 0; - final int profileCount = profileIds.length; - for (int i = 0; i < profileCount; i++) { - final int profileId = profileIds[i]; - if (!isParentOrProfile(parentId, profileId)) { - throw new SecurityException("Not the current user or" - + " a child profile: " + profileId); - } - if (!isProfileEnabled(profileId)) { - profileIds[i] = DISABLED_PROFILE; - } else { - enabledProfileCount++; - } - } - - int resolvedProfileIndex = 0; - final int[] resolvedProfiles = new int[enabledProfileCount]; - for (int i = 0; i < profileCount; i++) { - final int profileId = profileIds[i]; - if (profileId != DISABLED_PROFILE) { - resolvedProfiles[resolvedProfileIndex] = profileId; - resolvedProfileIndex++; - } - } - - return resolvedProfiles; + return isParentOrProfile(parentId, profileId) && isProfileEnabled(profileId); } public int[] getEnabledGroupProfileIds(int userId) { |