Loading core/java/android/app/Notification.java +62 −3 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.media.AudioManager; import android.media.session.MediaSession; import android.net.Uri; import android.os.BadParcelableException; import android.os.BaseBundle; import android.os.Build; import android.os.Bundle; import android.os.Parcel; Loading @@ -53,6 +54,7 @@ import android.text.style.AbsoluteSizeSpan; import android.text.style.CharacterStyle; import android.text.style.RelativeSizeSpan; import android.text.style.TextAppearanceSpan; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.view.Gravity; Loading @@ -63,6 +65,7 @@ import android.widget.ProgressBar; import android.widget.RemoteViews; import com.android.internal.R; import com.android.internal.util.ArrayUtils; import com.android.internal.util.NotificationColorUtil; import java.lang.annotation.Retention; Loading @@ -70,6 +73,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; Loading Loading @@ -757,6 +761,16 @@ public class Notification implements Parcelable */ public Bundle extras = new Bundle(); /** * All pending intents in the notification extras (notification extras, actions extras, * and remote input extras) as the system needs to be able to access them but touching * the extras bundle in the system process is not safe because the bundle may contain * custom parcelable objects. * * @hide */ public ArraySet<PendingIntent> extrasPendingIntents; /** * {@link #extras} key: this is the title of the notification, * as supplied to {@link Builder#setContentTitle(CharSequence)}. Loading Loading @@ -1549,7 +1563,16 @@ public class Notification implements Parcelable /** * Unflatten the notification from a parcel. */ public Notification(Parcel parcel) @SuppressWarnings("unchecked") public Notification(Parcel parcel) { // IMPORTANT: Add unmarshaling code in readFromParcel as the pending // intents in extras are always written as the last entry. readFromParcelImpl(parcel); // Must be read last! extrasPendingIntents = (ArraySet<PendingIntent>) parcel.readArraySet(null); } private void readFromParcelImpl(Parcel parcel) { int version = parcel.readInt(); Loading Loading @@ -1704,6 +1727,10 @@ public class Notification implements Parcelable } } if (!ArrayUtils.isEmpty(extrasPendingIntents)) { that.extrasPendingIntents = new ArraySet<>(extrasPendingIntents); } if (this.actions != null) { that.actions = new Action[this.actions.length]; for(int i=0; i<this.actions.length; i++) { Loading Loading @@ -1819,8 +1846,40 @@ public class Notification implements Parcelable /** * Flatten this notification into a parcel. */ public void writeToParcel(Parcel parcel, int flags) { public void writeToParcel(Parcel parcel, int flags) { // We need to mark all pending intents getting into the notification // system as being put there to later allow the notification ranker // to launch them and by doing so add the app to the battery saver white // list for a short period of time. The problem is that the system // cannot look into the extras as there may be parcelables there that // the platform does not know how to handle. To go around that we have // an explicit list of the pending intents in the extras bundle. final boolean collectPendingIntents = (extrasPendingIntents == null); if (collectPendingIntents) { PendingIntent.setOnMarshaledListener( (PendingIntent intent, Parcel out, int outFlags) -> { if (parcel == out) { if (extrasPendingIntents == null) { extrasPendingIntents = new ArraySet<>(); } extrasPendingIntents.add(intent); } }); } try { // IMPORTANT: Add marshaling code in writeToParcelImpl as we // want to intercept all pending events written to the pacel. writeToParcelImpl(parcel, flags); // Must be written last! parcel.writeArraySet(extrasPendingIntents); } finally { if (collectPendingIntents) { PendingIntent.setOnMarshaledListener(null); } } } private void writeToParcelImpl(Parcel parcel, int flags) { parcel.writeInt(1); parcel.writeLong(when); Loading core/java/android/app/PendingIntent.java +35 −0 Original line number Diff line number Diff line Loading @@ -241,6 +241,36 @@ public final class PendingIntent implements Parcelable { } } /** * Listener for observing when pending intents are written to a parcel. * * @hide */ public interface OnMarshaledListener { /** * Called when a pending intent is written to a parcel. * * @param intent The pending intent. * @param parcel The parcel to which it was written. * @param flags The parcel flags when it was written. */ void onMarshaled(PendingIntent intent, Parcel parcel, int flags); } private static final ThreadLocal<OnMarshaledListener> sOnMarshaledListener = new ThreadLocal<>(); /** * Registers an listener for pending intents being written to a parcel. * * @param listener The listener, null to clear. * * @hide */ public static void setOnMarshaledListener(OnMarshaledListener listener) { sOnMarshaledListener.set(listener); } /** * Retrieve a PendingIntent that will start a new activity, like calling * {@link Context#startActivity(Intent) Context.startActivity(Intent)}. Loading Loading @@ -1016,6 +1046,11 @@ public final class PendingIntent implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeStrongBinder(mTarget.asBinder()); OnMarshaledListener listener = sOnMarshaledListener.get(); if (listener != null) { listener.onMarshaled(this, out, flags); } } public static final Parcelable.Creator<PendingIntent> CREATOR Loading core/java/android/os/Parcel.java +37 −0 Original line number Diff line number Diff line Loading @@ -17,8 +17,10 @@ package android.os; import android.annotation.IntegerRes; import android.annotation.Nullable; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Size; import android.util.SizeF; Loading Loading @@ -733,6 +735,21 @@ public final class Parcel { writeArrayMapInternal(val); } /** * Write an array set to the parcel. * * @param val The array set to write. * * @hide */ public void writeArraySet(@Nullable ArraySet<? extends Object> val) { final int size = (val != null) ? val.size() : -1; writeInt(size); for (int i = 0; i < size; i++) { writeValue(val.valueAt(i)); } } /** * Flatten a Bundle into the parcel at the current dataPosition(), * growing dataCapacity() if needed. Loading Loading @@ -2735,6 +2752,26 @@ public final class Parcel { readArrayMapInternal(outVal, N, loader); } /** * Reads an array set. * * @param loader The class loader to use. * * @hide */ public @Nullable ArraySet<? extends Object> readArraySet(ClassLoader loader) { final int size = readInt(); if (size < 0) { return null; } ArraySet<Object> result = new ArraySet<>(size); for (int i = 0; i < size; i++) { Object value = readValue(loader); result.append(value); } return result; } private void readListInternal(List outVal, int N, ClassLoader loader) { while (N > 0) { Loading core/java/android/util/ArraySet.java +26 −0 Original line number Diff line number Diff line Loading @@ -389,6 +389,32 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { return true; } /** * Special fast path for appending items to the end of the array without validation. * The array must already be large enough to contain the item. * @hide */ public void append(E value) { final int index = mSize; final int hash = value == null ? 0 : (mIdentityHashCode ? System.identityHashCode(value) : value.hashCode()); if (index >= mHashes.length) { throw new IllegalStateException("Array is full"); } if (index > 0 && mHashes[index - 1] > hash) { RuntimeException e = new RuntimeException("here"); e.fillInStackTrace(); Log.w(TAG, "New hash " + hash + " is before end of array hash " + mHashes[index - 1] + " at index " + index, e); add(value); return; } mSize = index + 1; mHashes[index] = hash; mArray[index] = value; } /** * Perform a {@link #add(Object)} of all values in <var>array</var> * @param array The array whose contents are to be retrieved. Loading services/core/java/com/android/server/notification/NotificationManagerService.java +6 −33 Original line number Diff line number Diff line Loading @@ -2584,7 +2584,6 @@ public class NotificationManagerService extends SystemService { final long duration = LocalServices.getService(DeviceIdleController.LocalService.class) .getNotificationWhitelistDuration(); int size = 0; if (notification.contentIntent != null) { am.setPendingIntentWhitelistDuration(notification.contentIntent.getTarget(), duration); } Loading @@ -2601,43 +2600,17 @@ public class NotificationManagerService extends SystemService { continue; } am.setPendingIntentWhitelistDuration(action.actionIntent.getTarget(), duration); setPendingIntentWhitelistDuration(am, duration, action.getExtras()); final RemoteInput[] remoteInputs = action.getRemoteInputs(); if (remoteInputs != null) { for (RemoteInput remoteInput : remoteInputs) { setPendingIntentWhitelistDuration(am, duration, remoteInput.getExtras()); } } if (notification.extrasPendingIntents != null) { final int intentCount = notification.extrasPendingIntents.size(); for (int i = 0; i < intentCount; i++) { PendingIntent pendingIntent = notification.extrasPendingIntents.valueAt(i); if (pendingIntent != null) { am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration); } } } private static void setPendingIntentWhitelistDuration(ActivityManagerInternal am, long duration, Bundle extras) { for (String key : extras.keySet()) { final Object value = extras.get(key); if (value instanceof Parcelable) { setPendingIntentWhitelistDuration(am, duration, (Parcelable) value); } else if (value instanceof Parcelable[]) { for (Parcelable parcelable : (Parcelable[]) value) { setPendingIntentWhitelistDuration(am, duration, parcelable); } } else if (value instanceof List) { for (Object element : (List <?>) value) { if (element instanceof Parcelable) { setPendingIntentWhitelistDuration(am, duration, (Parcelable) element); } } } } } private static void setPendingIntentWhitelistDuration(ActivityManagerInternal am, long duration, Parcelable parcelable) { if (parcelable instanceof PendingIntent) { am.setPendingIntentWhitelistDuration(((PendingIntent) parcelable).getTarget(), duration); } } private class EnqueueNotificationRunnable implements Runnable { Loading Loading
core/java/android/app/Notification.java +62 −3 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.media.AudioManager; import android.media.session.MediaSession; import android.net.Uri; import android.os.BadParcelableException; import android.os.BaseBundle; import android.os.Build; import android.os.Bundle; import android.os.Parcel; Loading @@ -53,6 +54,7 @@ import android.text.style.AbsoluteSizeSpan; import android.text.style.CharacterStyle; import android.text.style.RelativeSizeSpan; import android.text.style.TextAppearanceSpan; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; import android.view.Gravity; Loading @@ -63,6 +65,7 @@ import android.widget.ProgressBar; import android.widget.RemoteViews; import com.android.internal.R; import com.android.internal.util.ArrayUtils; import com.android.internal.util.NotificationColorUtil; import java.lang.annotation.Retention; Loading @@ -70,6 +73,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; Loading Loading @@ -757,6 +761,16 @@ public class Notification implements Parcelable */ public Bundle extras = new Bundle(); /** * All pending intents in the notification extras (notification extras, actions extras, * and remote input extras) as the system needs to be able to access them but touching * the extras bundle in the system process is not safe because the bundle may contain * custom parcelable objects. * * @hide */ public ArraySet<PendingIntent> extrasPendingIntents; /** * {@link #extras} key: this is the title of the notification, * as supplied to {@link Builder#setContentTitle(CharSequence)}. Loading Loading @@ -1549,7 +1563,16 @@ public class Notification implements Parcelable /** * Unflatten the notification from a parcel. */ public Notification(Parcel parcel) @SuppressWarnings("unchecked") public Notification(Parcel parcel) { // IMPORTANT: Add unmarshaling code in readFromParcel as the pending // intents in extras are always written as the last entry. readFromParcelImpl(parcel); // Must be read last! extrasPendingIntents = (ArraySet<PendingIntent>) parcel.readArraySet(null); } private void readFromParcelImpl(Parcel parcel) { int version = parcel.readInt(); Loading Loading @@ -1704,6 +1727,10 @@ public class Notification implements Parcelable } } if (!ArrayUtils.isEmpty(extrasPendingIntents)) { that.extrasPendingIntents = new ArraySet<>(extrasPendingIntents); } if (this.actions != null) { that.actions = new Action[this.actions.length]; for(int i=0; i<this.actions.length; i++) { Loading Loading @@ -1819,8 +1846,40 @@ public class Notification implements Parcelable /** * Flatten this notification into a parcel. */ public void writeToParcel(Parcel parcel, int flags) { public void writeToParcel(Parcel parcel, int flags) { // We need to mark all pending intents getting into the notification // system as being put there to later allow the notification ranker // to launch them and by doing so add the app to the battery saver white // list for a short period of time. The problem is that the system // cannot look into the extras as there may be parcelables there that // the platform does not know how to handle. To go around that we have // an explicit list of the pending intents in the extras bundle. final boolean collectPendingIntents = (extrasPendingIntents == null); if (collectPendingIntents) { PendingIntent.setOnMarshaledListener( (PendingIntent intent, Parcel out, int outFlags) -> { if (parcel == out) { if (extrasPendingIntents == null) { extrasPendingIntents = new ArraySet<>(); } extrasPendingIntents.add(intent); } }); } try { // IMPORTANT: Add marshaling code in writeToParcelImpl as we // want to intercept all pending events written to the pacel. writeToParcelImpl(parcel, flags); // Must be written last! parcel.writeArraySet(extrasPendingIntents); } finally { if (collectPendingIntents) { PendingIntent.setOnMarshaledListener(null); } } } private void writeToParcelImpl(Parcel parcel, int flags) { parcel.writeInt(1); parcel.writeLong(when); Loading
core/java/android/app/PendingIntent.java +35 −0 Original line number Diff line number Diff line Loading @@ -241,6 +241,36 @@ public final class PendingIntent implements Parcelable { } } /** * Listener for observing when pending intents are written to a parcel. * * @hide */ public interface OnMarshaledListener { /** * Called when a pending intent is written to a parcel. * * @param intent The pending intent. * @param parcel The parcel to which it was written. * @param flags The parcel flags when it was written. */ void onMarshaled(PendingIntent intent, Parcel parcel, int flags); } private static final ThreadLocal<OnMarshaledListener> sOnMarshaledListener = new ThreadLocal<>(); /** * Registers an listener for pending intents being written to a parcel. * * @param listener The listener, null to clear. * * @hide */ public static void setOnMarshaledListener(OnMarshaledListener listener) { sOnMarshaledListener.set(listener); } /** * Retrieve a PendingIntent that will start a new activity, like calling * {@link Context#startActivity(Intent) Context.startActivity(Intent)}. Loading Loading @@ -1016,6 +1046,11 @@ public final class PendingIntent implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeStrongBinder(mTarget.asBinder()); OnMarshaledListener listener = sOnMarshaledListener.get(); if (listener != null) { listener.onMarshaled(this, out, flags); } } public static final Parcelable.Creator<PendingIntent> CREATOR Loading
core/java/android/os/Parcel.java +37 −0 Original line number Diff line number Diff line Loading @@ -17,8 +17,10 @@ package android.os; import android.annotation.IntegerRes; import android.annotation.Nullable; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Size; import android.util.SizeF; Loading Loading @@ -733,6 +735,21 @@ public final class Parcel { writeArrayMapInternal(val); } /** * Write an array set to the parcel. * * @param val The array set to write. * * @hide */ public void writeArraySet(@Nullable ArraySet<? extends Object> val) { final int size = (val != null) ? val.size() : -1; writeInt(size); for (int i = 0; i < size; i++) { writeValue(val.valueAt(i)); } } /** * Flatten a Bundle into the parcel at the current dataPosition(), * growing dataCapacity() if needed. Loading Loading @@ -2735,6 +2752,26 @@ public final class Parcel { readArrayMapInternal(outVal, N, loader); } /** * Reads an array set. * * @param loader The class loader to use. * * @hide */ public @Nullable ArraySet<? extends Object> readArraySet(ClassLoader loader) { final int size = readInt(); if (size < 0) { return null; } ArraySet<Object> result = new ArraySet<>(size); for (int i = 0; i < size; i++) { Object value = readValue(loader); result.append(value); } return result; } private void readListInternal(List outVal, int N, ClassLoader loader) { while (N > 0) { Loading
core/java/android/util/ArraySet.java +26 −0 Original line number Diff line number Diff line Loading @@ -389,6 +389,32 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { return true; } /** * Special fast path for appending items to the end of the array without validation. * The array must already be large enough to contain the item. * @hide */ public void append(E value) { final int index = mSize; final int hash = value == null ? 0 : (mIdentityHashCode ? System.identityHashCode(value) : value.hashCode()); if (index >= mHashes.length) { throw new IllegalStateException("Array is full"); } if (index > 0 && mHashes[index - 1] > hash) { RuntimeException e = new RuntimeException("here"); e.fillInStackTrace(); Log.w(TAG, "New hash " + hash + " is before end of array hash " + mHashes[index - 1] + " at index " + index, e); add(value); return; } mSize = index + 1; mHashes[index] = hash; mArray[index] = value; } /** * Perform a {@link #add(Object)} of all values in <var>array</var> * @param array The array whose contents are to be retrieved. Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +6 −33 Original line number Diff line number Diff line Loading @@ -2584,7 +2584,6 @@ public class NotificationManagerService extends SystemService { final long duration = LocalServices.getService(DeviceIdleController.LocalService.class) .getNotificationWhitelistDuration(); int size = 0; if (notification.contentIntent != null) { am.setPendingIntentWhitelistDuration(notification.contentIntent.getTarget(), duration); } Loading @@ -2601,43 +2600,17 @@ public class NotificationManagerService extends SystemService { continue; } am.setPendingIntentWhitelistDuration(action.actionIntent.getTarget(), duration); setPendingIntentWhitelistDuration(am, duration, action.getExtras()); final RemoteInput[] remoteInputs = action.getRemoteInputs(); if (remoteInputs != null) { for (RemoteInput remoteInput : remoteInputs) { setPendingIntentWhitelistDuration(am, duration, remoteInput.getExtras()); } } if (notification.extrasPendingIntents != null) { final int intentCount = notification.extrasPendingIntents.size(); for (int i = 0; i < intentCount; i++) { PendingIntent pendingIntent = notification.extrasPendingIntents.valueAt(i); if (pendingIntent != null) { am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration); } } } private static void setPendingIntentWhitelistDuration(ActivityManagerInternal am, long duration, Bundle extras) { for (String key : extras.keySet()) { final Object value = extras.get(key); if (value instanceof Parcelable) { setPendingIntentWhitelistDuration(am, duration, (Parcelable) value); } else if (value instanceof Parcelable[]) { for (Parcelable parcelable : (Parcelable[]) value) { setPendingIntentWhitelistDuration(am, duration, parcelable); } } else if (value instanceof List) { for (Object element : (List <?>) value) { if (element instanceof Parcelable) { setPendingIntentWhitelistDuration(am, duration, (Parcelable) element); } } } } } private static void setPendingIntentWhitelistDuration(ActivityManagerInternal am, long duration, Parcelable parcelable) { if (parcelable instanceof PendingIntent) { am.setPendingIntentWhitelistDuration(((PendingIntent) parcelable).getTarget(), duration); } } private class EnqueueNotificationRunnable implements Runnable { Loading