Loading core/java/android/appwidget/AppWidgetManager.java +37 −0 Original line number Diff line number Diff line Loading @@ -42,12 +42,15 @@ import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.util.DisplayMetrics; import android.util.Log; import android.widget.RemoteViews; import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.os.BackgroundThread; import java.util.Collections; import java.util.List; import java.util.Objects; /** * Updates AppWidget state; gets information about installed AppWidget providers and other Loading @@ -63,6 +66,7 @@ import java.util.List; @RequiresFeature(PackageManager.FEATURE_APP_WIDGETS) public class AppWidgetManager { /** * Activity action to launch from your {@link AppWidgetHost} activity when you want to * pick an AppWidget to display. The AppWidget picker activity will be launched. Loading Loading @@ -331,6 +335,17 @@ public class AppWidgetManager { @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE"; /** * A combination broadcast of APPWIDGET_ENABLED and APPWIDGET_UPDATE. * Sent during boot time and when the host is binding the widget for the very first time * * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_ENABLE_AND_UPDATE = "android.appwidget.action" + ".APPWIDGET_ENABLE_AND_UPDATE"; /** * Sent when the custom extras for an AppWidget change. * Loading Loading @@ -456,6 +471,8 @@ public class AppWidgetManager { public static final String ACTION_APPWIDGET_HOST_RESTORED = "android.appwidget.action.APPWIDGET_HOST_RESTORED"; private static final String TAG = "AppWidgetManager"; /** * An intent extra that contains multiple appWidgetIds. These are id values as * they were provided to the application during a recent restore from backup. It is Loading Loading @@ -511,6 +528,26 @@ public class AppWidgetManager { mPackageName = context.getOpPackageName(); mService = service; mDisplayMetrics = context.getResources().getDisplayMetrics(); if (mService == null) { return; } BackgroundThread.getExecutor().execute(() -> { try { mService.notifyProviderInheritance(getInstalledProvidersForPackage(mPackageName, null) .stream().filter(Objects::nonNull) .map(info -> info.provider).filter(p -> { try { Class clazz = Class.forName(p.getClassName()); return AppWidgetProvider.class.isAssignableFrom(clazz); } catch (Exception e) { return false; } }).toArray(ComponentName[]::new)); } catch (Exception e) { Log.e(TAG, "Nofity service of inheritance info", e); } }); } /** Loading core/java/android/appwidget/AppWidgetProvider.java +6 −1 Original line number Diff line number Diff line Loading @@ -58,7 +58,12 @@ public class AppWidgetProvider extends BroadcastReceiver { // Protect against rogue update broadcasts (not really a security issue, // just filter bad broacasts out so subclasses are less likely to crash). String action = intent.getAction(); if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) { if (AppWidgetManager.ACTION_APPWIDGET_ENABLE_AND_UPDATE.equals(action)) { this.onReceive(context, new Intent(intent) .setAction(AppWidgetManager.ACTION_APPWIDGET_ENABLED)); this.onReceive(context, new Intent(intent) .setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE)); } else if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) { Bundle extras = intent.getExtras(); if (extras != null) { int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS); Loading core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +5 −0 Original line number Diff line number Diff line Loading @@ -578,6 +578,11 @@ public final class SystemUiDeviceConfigFlags { */ public static final String CLIPBOARD_OVERLAY_SHOW_ACTIONS = "clipboard_overlay_show_actions"; /** * (boolean) Whether to combine the broadcasts APPWIDGET_ENABLED and APPWIDGET_UPDATE */ public static final String COMBINED_BROADCAST_ENABLED = "combined_broadcast_enabled"; private SystemUiDeviceConfigFlags() { } } core/res/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,7 @@ <protected-broadcast android:name="android.appwidget.action.APPWIDGET_ENABLED" /> <protected-broadcast android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED" /> <protected-broadcast android:name="android.appwidget.action.APPWIDGET_RESTORED" /> <protected-broadcast android:name="android.appwidget.action.APPWIDGET_ENABLE_AND_UPDATE" /> <protected-broadcast android:name="android.os.action.SETTING_RESTORED" /> Loading services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +30 −10 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; Loading Loading @@ -254,11 +255,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private boolean mSafeMode; private int mMaxWidgetBitmapMemory; private boolean mIsProviderInfoPersisted; private boolean mIsCombinedBroadcastEnabled; AppWidgetServiceImpl(Context context) { mContext = context; } @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public void onStart() { mPackageManager = AppGlobals.getPackageManager(); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); Loading @@ -277,6 +280,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku mIsProviderInfoPersisted = !ActivityManager.isLowRamDeviceStatic() && DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.PERSISTS_WIDGET_PROVIDER_INFO, true); mIsCombinedBroadcastEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.COMBINED_BROADCAST_ENABLED, true); if (DEBUG_PROVIDER_INFO_CACHE && !mIsProviderInfoPersisted) { Slog.d(TAG, "App widget provider info will not be persisted on this device"); } Loading Loading @@ -1123,15 +1128,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final int widgetCount = provider.widgets.size(); if (widgetCount == 1) { // Tell the provider that it's ready. sendEnableIntentLocked(provider); } // Send an update now -- We need this update now, and just for this appWidgetId. // It's less critical when the next one happens, so when we schedule the next one, // we add updatePeriodMillis to its start time. That time will have some slop, // but that's okay. // If we are binding the very first widget from a provider, we will send // a combined broadcast or 2 separate broadcasts to tell the provider that // it's ready, and we need them to provide the update now. sendEnableAndUpdateIntentLocked(provider, new int[]{appWidgetId}); } else { // For any widget other then the first one, we just send update intent // as we normally would. sendUpdateIntentLocked(provider, new int[]{appWidgetId}); } // Schedule the future updates. registerForBroadcastsLocked(provider, getWidgetIds(provider.widgets)); Loading Loading @@ -2361,6 +2366,22 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku cancelBroadcastsLocked(provider); } private void sendEnableAndUpdateIntentLocked(@NonNull Provider p, int[] appWidgetIds) { final boolean canSendCombinedBroadcast = mIsCombinedBroadcastEnabled && p.info != null && p.info.isExtendedFromAppWidgetProvider; if (!canSendCombinedBroadcast) { // If this function is called by mistake, send two separate broadcasts instead sendEnableIntentLocked(p); sendUpdateIntentLocked(p, appWidgetIds); return; } Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLE_AND_UPDATE); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); intent.setComponent(p.id.componentName); sendBroadcastAsUser(intent, p.id.getProfile()); } private void sendEnableIntentLocked(Provider p) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); intent.setComponent(p.id.componentName); Loading Loading @@ -2852,7 +2873,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (provider.widgets.size() > 0) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "appwidget init " + provider.id.componentName.getPackageName()); sendEnableIntentLocked(provider); provider.widgets.forEach(widget -> { widget.trackingUpdate = true; Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, Loading @@ -2861,7 +2881,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Log.i(TAG, "Widget update scheduled on unlock " + widget.toString()); }); int[] appWidgetIds = getWidgetIds(provider.widgets); sendUpdateIntentLocked(provider, appWidgetIds); sendEnableAndUpdateIntentLocked(provider, appWidgetIds); registerForBroadcastsLocked(provider, appWidgetIds); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } Loading Loading
core/java/android/appwidget/AppWidgetManager.java +37 −0 Original line number Diff line number Diff line Loading @@ -42,12 +42,15 @@ import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.util.DisplayMetrics; import android.util.Log; import android.widget.RemoteViews; import com.android.internal.appwidget.IAppWidgetService; import com.android.internal.os.BackgroundThread; import java.util.Collections; import java.util.List; import java.util.Objects; /** * Updates AppWidget state; gets information about installed AppWidget providers and other Loading @@ -63,6 +66,7 @@ import java.util.List; @RequiresFeature(PackageManager.FEATURE_APP_WIDGETS) public class AppWidgetManager { /** * Activity action to launch from your {@link AppWidgetHost} activity when you want to * pick an AppWidget to display. The AppWidget picker activity will be launched. Loading Loading @@ -331,6 +335,17 @@ public class AppWidgetManager { @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE"; /** * A combination broadcast of APPWIDGET_ENABLED and APPWIDGET_UPDATE. * Sent during boot time and when the host is binding the widget for the very first time * * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @BroadcastBehavior(explicitOnly = true) public static final String ACTION_APPWIDGET_ENABLE_AND_UPDATE = "android.appwidget.action" + ".APPWIDGET_ENABLE_AND_UPDATE"; /** * Sent when the custom extras for an AppWidget change. * Loading Loading @@ -456,6 +471,8 @@ public class AppWidgetManager { public static final String ACTION_APPWIDGET_HOST_RESTORED = "android.appwidget.action.APPWIDGET_HOST_RESTORED"; private static final String TAG = "AppWidgetManager"; /** * An intent extra that contains multiple appWidgetIds. These are id values as * they were provided to the application during a recent restore from backup. It is Loading Loading @@ -511,6 +528,26 @@ public class AppWidgetManager { mPackageName = context.getOpPackageName(); mService = service; mDisplayMetrics = context.getResources().getDisplayMetrics(); if (mService == null) { return; } BackgroundThread.getExecutor().execute(() -> { try { mService.notifyProviderInheritance(getInstalledProvidersForPackage(mPackageName, null) .stream().filter(Objects::nonNull) .map(info -> info.provider).filter(p -> { try { Class clazz = Class.forName(p.getClassName()); return AppWidgetProvider.class.isAssignableFrom(clazz); } catch (Exception e) { return false; } }).toArray(ComponentName[]::new)); } catch (Exception e) { Log.e(TAG, "Nofity service of inheritance info", e); } }); } /** Loading
core/java/android/appwidget/AppWidgetProvider.java +6 −1 Original line number Diff line number Diff line Loading @@ -58,7 +58,12 @@ public class AppWidgetProvider extends BroadcastReceiver { // Protect against rogue update broadcasts (not really a security issue, // just filter bad broacasts out so subclasses are less likely to crash). String action = intent.getAction(); if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) { if (AppWidgetManager.ACTION_APPWIDGET_ENABLE_AND_UPDATE.equals(action)) { this.onReceive(context, new Intent(intent) .setAction(AppWidgetManager.ACTION_APPWIDGET_ENABLED)); this.onReceive(context, new Intent(intent) .setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE)); } else if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) { Bundle extras = intent.getExtras(); if (extras != null) { int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS); Loading
core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +5 −0 Original line number Diff line number Diff line Loading @@ -578,6 +578,11 @@ public final class SystemUiDeviceConfigFlags { */ public static final String CLIPBOARD_OVERLAY_SHOW_ACTIONS = "clipboard_overlay_show_actions"; /** * (boolean) Whether to combine the broadcasts APPWIDGET_ENABLED and APPWIDGET_UPDATE */ public static final String COMBINED_BROADCAST_ENABLED = "combined_broadcast_enabled"; private SystemUiDeviceConfigFlags() { } }
core/res/AndroidManifest.xml +1 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,7 @@ <protected-broadcast android:name="android.appwidget.action.APPWIDGET_ENABLED" /> <protected-broadcast android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED" /> <protected-broadcast android:name="android.appwidget.action.APPWIDGET_RESTORED" /> <protected-broadcast android:name="android.appwidget.action.APPWIDGET_ENABLE_AND_UPDATE" /> <protected-broadcast android:name="android.os.action.SETTING_RESTORED" /> Loading
services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +30 −10 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; Loading Loading @@ -254,11 +255,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private boolean mSafeMode; private int mMaxWidgetBitmapMemory; private boolean mIsProviderInfoPersisted; private boolean mIsCombinedBroadcastEnabled; AppWidgetServiceImpl(Context context) { mContext = context; } @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public void onStart() { mPackageManager = AppGlobals.getPackageManager(); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); Loading @@ -277,6 +280,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku mIsProviderInfoPersisted = !ActivityManager.isLowRamDeviceStatic() && DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.PERSISTS_WIDGET_PROVIDER_INFO, true); mIsCombinedBroadcastEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.COMBINED_BROADCAST_ENABLED, true); if (DEBUG_PROVIDER_INFO_CACHE && !mIsProviderInfoPersisted) { Slog.d(TAG, "App widget provider info will not be persisted on this device"); } Loading Loading @@ -1123,15 +1128,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final int widgetCount = provider.widgets.size(); if (widgetCount == 1) { // Tell the provider that it's ready. sendEnableIntentLocked(provider); } // Send an update now -- We need this update now, and just for this appWidgetId. // It's less critical when the next one happens, so when we schedule the next one, // we add updatePeriodMillis to its start time. That time will have some slop, // but that's okay. // If we are binding the very first widget from a provider, we will send // a combined broadcast or 2 separate broadcasts to tell the provider that // it's ready, and we need them to provide the update now. sendEnableAndUpdateIntentLocked(provider, new int[]{appWidgetId}); } else { // For any widget other then the first one, we just send update intent // as we normally would. sendUpdateIntentLocked(provider, new int[]{appWidgetId}); } // Schedule the future updates. registerForBroadcastsLocked(provider, getWidgetIds(provider.widgets)); Loading Loading @@ -2361,6 +2366,22 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku cancelBroadcastsLocked(provider); } private void sendEnableAndUpdateIntentLocked(@NonNull Provider p, int[] appWidgetIds) { final boolean canSendCombinedBroadcast = mIsCombinedBroadcastEnabled && p.info != null && p.info.isExtendedFromAppWidgetProvider; if (!canSendCombinedBroadcast) { // If this function is called by mistake, send two separate broadcasts instead sendEnableIntentLocked(p); sendUpdateIntentLocked(p, appWidgetIds); return; } Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLE_AND_UPDATE); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); intent.setComponent(p.id.componentName); sendBroadcastAsUser(intent, p.id.getProfile()); } private void sendEnableIntentLocked(Provider p) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); intent.setComponent(p.id.componentName); Loading Loading @@ -2852,7 +2873,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (provider.widgets.size() > 0) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "appwidget init " + provider.id.componentName.getPackageName()); sendEnableIntentLocked(provider); provider.widgets.forEach(widget -> { widget.trackingUpdate = true; Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, Loading @@ -2861,7 +2881,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Log.i(TAG, "Widget update scheduled on unlock " + widget.toString()); }); int[] appWidgetIds = getWidgetIds(provider.widgets); sendUpdateIntentLocked(provider, appWidgetIds); sendEnableAndUpdateIntentLocked(provider, appWidgetIds); registerForBroadcastsLocked(provider, appWidgetIds); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } Loading