Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7878e736 authored by Svet Ganov's avatar Svet Ganov Committed by android-build-merger
Browse files

Merge \"Mark app pending intents in notification extras\" into nyc-dev

am: b2cd9c95

Change-Id: Idb515255f224c23d60a513713d9e4f93decd7a9c
parents 91df8559 b2cd9c95
Loading
Loading
Loading
Loading
+62 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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)}.
@@ -1573,7 +1587,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();

@@ -1728,6 +1751,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++) {
@@ -1843,8 +1870,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);
+35 −0
Original line number Diff line number Diff line
@@ -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)}.
@@ -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
+37 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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.
@@ -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) {
+26 −0
Original line number Diff line number Diff line
@@ -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.
+6 −33
Original line number Diff line number Diff line
@@ -2598,7 +2598,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);
        }
@@ -2615,43 +2614,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 {