diff options
14 files changed, 67 insertions, 12 deletions
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 512b5e08bf31..c58e627425b7 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -879,6 +879,20 @@ public final class PendingIntent implements Parcelable { } /** + * Perform the operation associated with this PendingIntent, supplying additional + * options for the operation. + * + * @param options Additional options the caller would like to provide to modify the + * sending behavior. May be built from an {@link ActivityOptions} to apply to an + * activity start. + * + * @hide + */ + public void send(Bundle options) throws CanceledException { + send(null, 0, null, null, null, null, options); + } + + /** * Perform the operation associated with this PendingIntent, allowing the * caller to be notified when the send has completed. * diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index e0e13f59b706..fc199440e782 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -24,6 +24,7 @@ <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> <permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/> <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/> + <permission name="android.permission.COMPONENT_OPTION_INTERACTIVE"/> <permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/> <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/> <permission name="android.permission.CONTROL_VPN"/> diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 2c9dad96b076..4be1d30c8fe5 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -180,6 +180,9 @@ <!-- Doze mode temp whitelisting for notification dispatching. --> <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" /> + <!-- Tag user-initiated PendingIntent invocations as "interactive" when appropriate --> + <uses-permission android:name="android.permission.COMPONENT_OPTION_INTERACTIVE" /> + <!-- Listen for keyboard attachment / detachment --> <uses-permission android:name="android.permission.TABLET_MODE" /> diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java index d0694ab124c6..429458fe0704 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java @@ -17,6 +17,7 @@ package com.android.systemui.plugins; import android.annotation.Nullable; +import android.app.BroadcastOptions; import android.app.PendingIntent; import android.graphics.drawable.Drawable; import android.view.View; @@ -70,7 +71,9 @@ public interface GlobalActionsPanelPlugin extends Plugin { /** Starts a PendingIntent, dismissing the keyguard if necessary. */ default void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) { try { - pendingIntent.send(); + BroadcastOptions options = BroadcastOptions.makeBasic(); + options.setInteractive(true); + pendingIntent.send(options.toBundle()); } catch (PendingIntent.CanceledException e) { // no-op } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt index edd1c6891946..3d9eee4e9feb 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -156,6 +156,8 @@ class DetailDialog( // Remove the task explicitly, since onRelease() callback will be executed after // startActivity() below is called. broadcastSender.closeSystemDialogs() + // not sent as interactive, lest the higher-importance activity launch + // be impacted pendingIntent.send() false } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt index 2dd339d409a6..1cc8a1353a34 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt @@ -16,6 +16,7 @@ package com.android.systemui.media.controls.pipeline +import android.app.BroadcastOptions import android.app.Notification import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME import android.app.PendingIntent @@ -1165,7 +1166,9 @@ class MediaDataManager( private fun sendPendingIntent(intent: PendingIntent): Boolean { return try { - intent.send() + val options = BroadcastOptions.makeBasic() + options.setInteractive(true) + intent.send(options.toBundle()) true } catch (e: PendingIntent.CanceledException) { Log.d(TAG, "Intent canceled", e) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java index 15c34430f455..ee0147f55536 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java @@ -23,6 +23,7 @@ import static com.android.systemui.media.controls.models.recommendation.Smartspa import android.animation.Animator; import android.animation.AnimatorInflater; import android.animation.AnimatorSet; +import android.app.BroadcastOptions; import android.app.PendingIntent; import android.app.WallpaperColors; import android.app.smartspace.SmartspaceAction; @@ -113,6 +114,8 @@ import com.android.systemui.util.ColorUtilKt; import com.android.systemui.util.animation.TransitionLayout; import com.android.systemui.util.time.SystemClock; +import dagger.Lazy; + import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; @@ -120,7 +123,6 @@ import java.util.concurrent.Executor; import javax.inject.Inject; -import dagger.Lazy; import kotlin.Unit; /** @@ -625,7 +627,9 @@ public class MediaControlPanel { device.getIntent().getIntent(), true); } else { try { - device.getIntent().send(); + BroadcastOptions options = BroadcastOptions.makeBasic(); + options.setInteractive(true); + device.getIntent().send(options.toBundle()); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Device pending intent was canceled"); } diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java index b8684ee30b9a..431b28fb7f28 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java @@ -16,12 +16,14 @@ package com.android.systemui.screenrecord; +import android.app.BroadcastOptions; import android.app.Dialog; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.Bundle; import android.os.CountDownTimer; import android.os.UserHandle; import android.util.Log; @@ -57,6 +59,7 @@ public class RecordingController private boolean mIsStarting; private boolean mIsRecording; private PendingIntent mStopIntent; + private final Bundle mInteractiveBroadcastOption; private CountDownTimer mCountDownTimer = null; private final Executor mMainExecutor; private final BroadcastDispatcher mBroadcastDispatcher; @@ -106,6 +109,10 @@ public class RecordingController mBroadcastDispatcher = broadcastDispatcher; mUserContextProvider = userContextProvider; mUserTracker = userTracker; + + BroadcastOptions options = BroadcastOptions.makeBasic(); + options.setInteractive(true); + mInteractiveBroadcastOption = options.toBundle(); } /** Create a dialog to show screen recording options to the user. */ @@ -148,7 +155,7 @@ public class RecordingController cb.onCountdownEnd(); } try { - startIntent.send(); + startIntent.send(mInteractiveBroadcastOption); mUserTracker.addCallback(mUserChangedCallback, mMainExecutor); IntentFilter stateFilter = new IntentFilter(INTENT_UPDATE_STATE); @@ -202,7 +209,7 @@ public class RecordingController public void stopRecording() { try { if (mStopIntent != null) { - mStopIntent.send(); + mStopIntent.send(mInteractiveBroadcastOption); } else { Log.e(TAG, "Stop intent was null"); } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java index c4ea67e0f79e..860bfe37aee2 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java @@ -18,6 +18,7 @@ package com.android.systemui.screenshot; import static java.util.Objects.requireNonNull; +import android.app.BroadcastOptions; import android.app.PendingIntent; import android.content.Context; import android.graphics.drawable.Icon; @@ -96,7 +97,9 @@ public class OverlayActionChip extends FrameLayout { public void setPendingIntent(PendingIntent intent, Runnable finisher) { setOnClickListener(v -> { try { - intent.send(); + BroadcastOptions options = BroadcastOptions.makeBasic(); + options.setInteractive(true); + intent.send(options.toBundle()); finisher.run(); } catch (PendingIntent.CanceledException e) { Log.e(TAG, "Intent cancelled", e); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index e8ceb521b6b0..736b892beff7 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -34,6 +34,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.app.ActivityManager; +import android.app.BroadcastOptions; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; @@ -53,6 +54,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.graphics.drawable.InsetDrawable; import android.graphics.drawable.LayerDrawable; +import android.os.Bundle; import android.os.Looper; import android.os.RemoteException; import android.util.AttributeSet; @@ -169,6 +171,7 @@ public class ScreenshotView extends FrameLayout implements private long mDefaultTimeoutOfTimeoutHandler; private ActionIntentExecutor mActionExecutor; private FeatureFlags mFlags; + private final Bundle mInteractiveBroadcastOption; private enum PendingInteraction { PREVIEW, @@ -195,6 +198,10 @@ public class ScreenshotView extends FrameLayout implements mResources = mContext.getResources(); mInteractionJankMonitor = getInteractionJankMonitorInstance(); + BroadcastOptions options = BroadcastOptions.makeBasic(); + options.setInteractive(true); + mInteractiveBroadcastOption = options.toBundle(); + mFixedSize = mResources.getDimensionPixelSize(R.dimen.overlay_x_scale); // standard material ease @@ -1105,7 +1112,7 @@ public class ScreenshotView extends FrameLayout implements private void startSharedTransition(ActionTransition transition) { try { mPendingSharedTransition = true; - transition.action.actionIntent.send(); + transition.action.actionIntent.send(mInteractiveBroadcastOption); // fade out non-preview UI createScreenshotFadeDismissAnimation().start(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index cf2f7742dc59..8dcfec71b68e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -122,6 +122,7 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn options.setLaunchDisplayId(displayId); options.setCallerDisplayId(displayId); options.setPendingIntentBackgroundActivityLaunchAllowed(true); + options.setInteractive(true); return options.toBundle(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java index 3b1a4db067a3..33620979d681 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/notifications/TvNotificationAdapter.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.tv.notifications; +import android.app.BroadcastOptions; import android.app.Notification; import android.app.PendingIntent; import android.service.notification.StatusBarNotification; @@ -100,7 +101,9 @@ public class TvNotificationAdapter extends RecyclerView.Adapter<RecyclerView.Vie public void onClick(View v) { try { if (mPendingIntent != null) { - mPendingIntent.send(); + BroadcastOptions options = BroadcastOptions.makeBasic(); + options.setInteractive(true); + mPendingIntent.send(options.toBundle()); } } catch (PendingIntent.CanceledException e) { Log.d(TAG, "Pending intent canceled for : " + mPendingIntent); diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java index 1243c4718229..dfc6392404a4 100644 --- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java +++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java @@ -20,6 +20,7 @@ import static com.android.systemui.wallet.ui.WalletCardCarousel.CARD_ANIM_ALPHA_ import static com.android.systemui.wallet.ui.WalletCardCarousel.CARD_ANIM_ALPHA_DURATION; import android.annotation.Nullable; +import android.app.BroadcastOptions; import android.app.PendingIntent; import android.content.Context; import android.content.res.Configuration; @@ -303,7 +304,10 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard ? mDeviceLockedActionOnClickListener : v -> { try { - walletCard.getPendingIntent().send(); + + BroadcastOptions options = BroadcastOptions.makeBasic(); + options.setInteractive(true); + walletCard.getPendingIntent().send(options.toBundle()); } catch (PendingIntent.CanceledException e) { Log.w(TAG, "Error sending pending intent for wallet card."); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java index 69f3e987ec1d..8127ccca3f3f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java @@ -107,7 +107,7 @@ public class RecordingControllerTest extends SysuiTestCase { mController.startCountdown(0, 0, startIntent, null); verify(mCallback).onCountdownEnd(); - verify(startIntent).send(); + verify(startIntent).send(any()); } // Test that when recording is stopped, the stop intent is sent and listeners are notified. @@ -125,7 +125,7 @@ public class RecordingControllerTest extends SysuiTestCase { assertFalse(mController.isStarting()); assertFalse(mController.isRecording()); - verify(stopIntent).send(); + verify(stopIntent).send(any()); verify(mCallback).onRecordingEnd(); } |