Loading api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -7362,6 +7362,7 @@ package android.appwidget { method public void updateAppWidget(int, android.widget.RemoteViews); method public void updateAppWidget(android.content.ComponentName, android.widget.RemoteViews); method public void updateAppWidgetOptions(int, android.os.Bundle); method public void updateAppWidgetProviderInfo(android.content.ComponentName, java.lang.String); field public static final java.lang.String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND"; field public static final java.lang.String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE"; field public static final java.lang.String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED"; core/java/android/appwidget/AppWidgetManager.java +28 −0 Original line number Diff line number Diff line Loading @@ -676,6 +676,34 @@ public class AppWidgetManager { } } /** * Updates the info for the supplied AppWidget provider. * * <p> * The manifest entry of the provider should contain an additional meta-data tag similar to * {@link #META_DATA_APPWIDGET_PROVIDER} which should point to any additional definitions for * the provider. * * <p> * This is persisted across device reboots and app updates. If this meta-data key is not * present in the manifest entry, the info reverts to default. * * @param provider {@link ComponentName} for the {@link * android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget. * @param metaDataKey key for the meta-data tag pointing to the new provider info. Use null * to reset any previously set info. */ public void updateAppWidgetProviderInfo(ComponentName provider, @Nullable String metaDataKey) { if (mService == null) { return; } try { mService.updateAppWidgetProviderInfo(provider, metaDataKey); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Notifies the specified collection view in all the specified AppWidget instances * to invalidate their data. Loading core/java/com/android/internal/appwidget/IAppWidgetService.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ interface IAppWidgetService { void partiallyUpdateAppWidgetIds(String callingPackage, in int[] appWidgetIds, in RemoteViews views); void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views); void updateAppWidgetProviderInfo(in ComponentName provider, in String metadataKey); void notifyAppWidgetViewDataChanged(String packageName, in int[] appWidgetIds, int viewId); ParceledListSlice getInstalledProvidersForProfile(int categoryFilter, int profileId, String packageName); Loading services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +101 −23 Original line number Diff line number Diff line Loading @@ -120,7 +120,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; Loading @@ -134,6 +133,7 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; Loading Loading @@ -1567,6 +1567,57 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } @Override public void updateAppWidgetProviderInfo(ComponentName componentName, String metadataKey) { final int userId = UserHandle.getCallingUserId(); if (DEBUG) { Slog.i(TAG, "updateAppWidgetProvider() " + userId); } // Make sure the package runs under the caller uid. mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName()); synchronized (mLock) { ensureGroupStateLoadedLocked(userId); // NOTE: The lookup is enforcing security across users by making // sure the caller can access only its providers. ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName); Provider provider = lookupProviderLocked(providerId); if (provider == null) { throw new IllegalArgumentException( componentName + " is not a valid AppWidget provider"); } if (Objects.equals(provider.infoTag, metadataKey)) { // No change return; } String keyToUse = metadataKey == null ? AppWidgetManager.META_DATA_APPWIDGET_PROVIDER : metadataKey; AppWidgetProviderInfo info = parseAppWidgetProviderInfo(providerId, provider.info.providerInfo, keyToUse); if (info == null) { throw new IllegalArgumentException("Unable to parse " + keyToUse + " meta-data to a valid AppWidget provider"); } provider.info = info; provider.infoTag = metadataKey; // Update all widgets for this provider final int N = provider.widgets.size(); for (int i = 0; i < N; i++) { Widget widget = provider.widgets.get(i); scheduleNotifyProviderChangedLocked(widget); updateAppWidgetInstanceLocked(widget, widget.views, false /* isPartialUpdate */); } saveGroupStateAsync(userId); scheduleNotifyGroupHostsForProvidersChangedLocked(userId); } } @Override public boolean isRequestPinAppWidgetSupported() { return LocalServices.getService(ShortcutServiceInternal.class) Loading Loading @@ -2168,7 +2219,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku ri.activityInfo.name); ProviderId providerId = new ProviderId(ri.activityInfo.applicationInfo.uid, componentName); Provider provider = parseProviderInfoXml(providerId, ri); Provider provider = parseProviderInfoXml(providerId, ri, null); if (provider != null) { // we might have an inactive entry for this provider already due to // a preceding restore operation. if so, fix it up in place; otherwise Loading Loading @@ -2362,6 +2413,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku out.attribute(null, "pkg", p.info.provider.getPackageName()); out.attribute(null, "cl", p.info.provider.getClassName()); out.attribute(null, "tag", Integer.toHexString(p.tag)); if (!TextUtils.isEmpty(p.infoTag)) { out.attribute(null, "info_tag", p.infoTag); } out.endTag(null, "p"); } Loading Loading @@ -2422,17 +2476,33 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } @SuppressWarnings("deprecation") private Provider parseProviderInfoXml(ProviderId providerId, ResolveInfo ri) { Provider provider = null; ActivityInfo activityInfo = ri.activityInfo; XmlResourceParser parser = null; try { parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(), private Provider parseProviderInfoXml(ProviderId providerId, ResolveInfo ri, Provider oldProvider) { AppWidgetProviderInfo info = null; if (oldProvider != null && !TextUtils.isEmpty(oldProvider.infoTag)) { info = parseAppWidgetProviderInfo(providerId, ri.activityInfo, oldProvider.infoTag); } if (info == null) { info = parseAppWidgetProviderInfo(providerId, ri.activityInfo, AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); } if (info == null) { return null; } Provider provider = new Provider(); provider.id = providerId; provider.info = info; return provider; } private AppWidgetProviderInfo parseAppWidgetProviderInfo( ProviderId providerId, ActivityInfo activityInfo, String metadataKey) { try (XmlResourceParser parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(), metadataKey)) { if (parser == null) { Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for " + "AppWidget provider '" + providerId + '\''); Slog.w(TAG, "No " + metadataKey + " meta-data for AppWidget provider '" + providerId + '\''); return null; } Loading @@ -2452,9 +2522,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return null; } provider = new Provider(); provider.id = providerId; AppWidgetProviderInfo info = provider.info = new AppWidgetProviderInfo(); AppWidgetProviderInfo info = new AppWidgetProviderInfo(); info.provider = providerId.componentName; info.providerInfo = activityInfo; Loading Loading @@ -2501,7 +2569,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku className); } info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString(); info.icon = ri.getIconResource(); info.icon = activityInfo.getIconResource(); info.previewImage = sa.getResourceId( com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); info.autoAdvanceViewId = sa.getResourceId( Loading @@ -2516,6 +2584,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0); sa.recycle(); return info; } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) { // Ok to catch Exception here, because anything going wrong because // of what a client process passes to us should not be fatal for the Loading @@ -2523,12 +2592,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Slog.w(TAG, "XML parsing failed for AppWidget provider " + providerId.componentName + " for user " + providerId.uid, e); return null; } finally { if (parser != null) { parser.close(); } } return provider; } private int getUidForPackage(String packageName, int userId) { Loading Loading @@ -2891,7 +2955,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (provider.getUserId() != userId) { continue; } if (provider.widgets.size() > 0) { if (provider.shouldBePersisted()) { serializeProvider(out, provider); } } Loading Loading @@ -3000,6 +3064,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final int providerTag = !TextUtils.isEmpty(tagAttribute) ? Integer.parseInt(tagAttribute, 16) : legacyProviderIndex; provider.tag = providerTag; provider.infoTag = parser.getAttributeValue(null, "info_tag"); if (!TextUtils.isEmpty(provider.infoTag) && !mSafeMode) { AppWidgetProviderInfo info = parseAppWidgetProviderInfo( providerId, providerInfo, provider.infoTag); if (info != null) { provider.info = info; } } } else if ("h".equals(tag)) { legacyHostIndex++; Host host = new Host(); Loading Loading @@ -3254,7 +3327,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku providersUpdated = true; } } else { Provider parsed = parseProviderInfoXml(providerId, ri); Provider parsed = parseProviderInfoXml(providerId, ri, provider); if (parsed != null) { keep.add(providerId); // Use the new AppWidgetProviderInfo. Loading Loading @@ -3725,6 +3798,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku AppWidgetProviderInfo info; ArrayList<Widget> widgets = new ArrayList<>(); PendingIntent broadcast; String infoTag; boolean zombie; // if we're in safe mode, don't prune this just because nobody references it boolean maskedByLockedProfile; Loading Loading @@ -3784,6 +3858,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku public boolean isMaskedLocked() { return maskedByQuietProfile || maskedByLockedProfile || maskedBySuspendedPackage; } public boolean shouldBePersisted() { return !widgets.isEmpty() || !TextUtils.isEmpty(infoTag); } } private static final class ProviderId { Loading Loading @@ -4114,7 +4192,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku for (int i = 0; i < N; i++) { Provider provider = mProviders.get(i); if (!provider.widgets.isEmpty() if (provider.shouldBePersisted() && (provider.isInPackageForUser(backedupPackage, userId) || provider.hostedByPackageForUser(backedupPackage, userId))) { provider.tag = index; Loading Loading
api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -7362,6 +7362,7 @@ package android.appwidget { method public void updateAppWidget(int, android.widget.RemoteViews); method public void updateAppWidget(android.content.ComponentName, android.widget.RemoteViews); method public void updateAppWidgetOptions(int, android.os.Bundle); method public void updateAppWidgetProviderInfo(android.content.ComponentName, java.lang.String); field public static final java.lang.String ACTION_APPWIDGET_BIND = "android.appwidget.action.APPWIDGET_BIND"; field public static final java.lang.String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE"; field public static final java.lang.String ACTION_APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
core/java/android/appwidget/AppWidgetManager.java +28 −0 Original line number Diff line number Diff line Loading @@ -676,6 +676,34 @@ public class AppWidgetManager { } } /** * Updates the info for the supplied AppWidget provider. * * <p> * The manifest entry of the provider should contain an additional meta-data tag similar to * {@link #META_DATA_APPWIDGET_PROVIDER} which should point to any additional definitions for * the provider. * * <p> * This is persisted across device reboots and app updates. If this meta-data key is not * present in the manifest entry, the info reverts to default. * * @param provider {@link ComponentName} for the {@link * android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget. * @param metaDataKey key for the meta-data tag pointing to the new provider info. Use null * to reset any previously set info. */ public void updateAppWidgetProviderInfo(ComponentName provider, @Nullable String metaDataKey) { if (mService == null) { return; } try { mService.updateAppWidgetProviderInfo(provider, metaDataKey); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Notifies the specified collection view in all the specified AppWidget instances * to invalidate their data. Loading
core/java/com/android/internal/appwidget/IAppWidgetService.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ interface IAppWidgetService { void partiallyUpdateAppWidgetIds(String callingPackage, in int[] appWidgetIds, in RemoteViews views); void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views); void updateAppWidgetProviderInfo(in ComponentName provider, in String metadataKey); void notifyAppWidgetViewDataChanged(String packageName, in int[] appWidgetIds, int viewId); ParceledListSlice getInstalledProvidersForProfile(int categoryFilter, int profileId, String packageName); Loading
services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +101 −23 Original line number Diff line number Diff line Loading @@ -120,7 +120,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; Loading @@ -134,6 +133,7 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; Loading Loading @@ -1567,6 +1567,57 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } @Override public void updateAppWidgetProviderInfo(ComponentName componentName, String metadataKey) { final int userId = UserHandle.getCallingUserId(); if (DEBUG) { Slog.i(TAG, "updateAppWidgetProvider() " + userId); } // Make sure the package runs under the caller uid. mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName()); synchronized (mLock) { ensureGroupStateLoadedLocked(userId); // NOTE: The lookup is enforcing security across users by making // sure the caller can access only its providers. ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName); Provider provider = lookupProviderLocked(providerId); if (provider == null) { throw new IllegalArgumentException( componentName + " is not a valid AppWidget provider"); } if (Objects.equals(provider.infoTag, metadataKey)) { // No change return; } String keyToUse = metadataKey == null ? AppWidgetManager.META_DATA_APPWIDGET_PROVIDER : metadataKey; AppWidgetProviderInfo info = parseAppWidgetProviderInfo(providerId, provider.info.providerInfo, keyToUse); if (info == null) { throw new IllegalArgumentException("Unable to parse " + keyToUse + " meta-data to a valid AppWidget provider"); } provider.info = info; provider.infoTag = metadataKey; // Update all widgets for this provider final int N = provider.widgets.size(); for (int i = 0; i < N; i++) { Widget widget = provider.widgets.get(i); scheduleNotifyProviderChangedLocked(widget); updateAppWidgetInstanceLocked(widget, widget.views, false /* isPartialUpdate */); } saveGroupStateAsync(userId); scheduleNotifyGroupHostsForProvidersChangedLocked(userId); } } @Override public boolean isRequestPinAppWidgetSupported() { return LocalServices.getService(ShortcutServiceInternal.class) Loading Loading @@ -2168,7 +2219,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku ri.activityInfo.name); ProviderId providerId = new ProviderId(ri.activityInfo.applicationInfo.uid, componentName); Provider provider = parseProviderInfoXml(providerId, ri); Provider provider = parseProviderInfoXml(providerId, ri, null); if (provider != null) { // we might have an inactive entry for this provider already due to // a preceding restore operation. if so, fix it up in place; otherwise Loading Loading @@ -2362,6 +2413,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku out.attribute(null, "pkg", p.info.provider.getPackageName()); out.attribute(null, "cl", p.info.provider.getClassName()); out.attribute(null, "tag", Integer.toHexString(p.tag)); if (!TextUtils.isEmpty(p.infoTag)) { out.attribute(null, "info_tag", p.infoTag); } out.endTag(null, "p"); } Loading Loading @@ -2422,17 +2476,33 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } @SuppressWarnings("deprecation") private Provider parseProviderInfoXml(ProviderId providerId, ResolveInfo ri) { Provider provider = null; ActivityInfo activityInfo = ri.activityInfo; XmlResourceParser parser = null; try { parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(), private Provider parseProviderInfoXml(ProviderId providerId, ResolveInfo ri, Provider oldProvider) { AppWidgetProviderInfo info = null; if (oldProvider != null && !TextUtils.isEmpty(oldProvider.infoTag)) { info = parseAppWidgetProviderInfo(providerId, ri.activityInfo, oldProvider.infoTag); } if (info == null) { info = parseAppWidgetProviderInfo(providerId, ri.activityInfo, AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); } if (info == null) { return null; } Provider provider = new Provider(); provider.id = providerId; provider.info = info; return provider; } private AppWidgetProviderInfo parseAppWidgetProviderInfo( ProviderId providerId, ActivityInfo activityInfo, String metadataKey) { try (XmlResourceParser parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(), metadataKey)) { if (parser == null) { Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for " + "AppWidget provider '" + providerId + '\''); Slog.w(TAG, "No " + metadataKey + " meta-data for AppWidget provider '" + providerId + '\''); return null; } Loading @@ -2452,9 +2522,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return null; } provider = new Provider(); provider.id = providerId; AppWidgetProviderInfo info = provider.info = new AppWidgetProviderInfo(); AppWidgetProviderInfo info = new AppWidgetProviderInfo(); info.provider = providerId.componentName; info.providerInfo = activityInfo; Loading Loading @@ -2501,7 +2569,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku className); } info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString(); info.icon = ri.getIconResource(); info.icon = activityInfo.getIconResource(); info.previewImage = sa.getResourceId( com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); info.autoAdvanceViewId = sa.getResourceId( Loading @@ -2516,6 +2584,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0); sa.recycle(); return info; } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) { // Ok to catch Exception here, because anything going wrong because // of what a client process passes to us should not be fatal for the Loading @@ -2523,12 +2592,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Slog.w(TAG, "XML parsing failed for AppWidget provider " + providerId.componentName + " for user " + providerId.uid, e); return null; } finally { if (parser != null) { parser.close(); } } return provider; } private int getUidForPackage(String packageName, int userId) { Loading Loading @@ -2891,7 +2955,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (provider.getUserId() != userId) { continue; } if (provider.widgets.size() > 0) { if (provider.shouldBePersisted()) { serializeProvider(out, provider); } } Loading Loading @@ -3000,6 +3064,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final int providerTag = !TextUtils.isEmpty(tagAttribute) ? Integer.parseInt(tagAttribute, 16) : legacyProviderIndex; provider.tag = providerTag; provider.infoTag = parser.getAttributeValue(null, "info_tag"); if (!TextUtils.isEmpty(provider.infoTag) && !mSafeMode) { AppWidgetProviderInfo info = parseAppWidgetProviderInfo( providerId, providerInfo, provider.infoTag); if (info != null) { provider.info = info; } } } else if ("h".equals(tag)) { legacyHostIndex++; Host host = new Host(); Loading Loading @@ -3254,7 +3327,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku providersUpdated = true; } } else { Provider parsed = parseProviderInfoXml(providerId, ri); Provider parsed = parseProviderInfoXml(providerId, ri, provider); if (parsed != null) { keep.add(providerId); // Use the new AppWidgetProviderInfo. Loading Loading @@ -3725,6 +3798,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku AppWidgetProviderInfo info; ArrayList<Widget> widgets = new ArrayList<>(); PendingIntent broadcast; String infoTag; boolean zombie; // if we're in safe mode, don't prune this just because nobody references it boolean maskedByLockedProfile; Loading Loading @@ -3784,6 +3858,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku public boolean isMaskedLocked() { return maskedByQuietProfile || maskedByLockedProfile || maskedBySuspendedPackage; } public boolean shouldBePersisted() { return !widgets.isEmpty() || !TextUtils.isEmpty(infoTag); } } private static final class ProviderId { Loading Loading @@ -4114,7 +4192,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku for (int i = 0; i < N; i++) { Provider provider = mProviders.get(i); if (!provider.widgets.isEmpty() if (provider.shouldBePersisted() && (provider.isInPackageForUser(backedupPackage, userId) || provider.hostedByPackageForUser(backedupPackage, userId))) { provider.tag = index; Loading