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

Commit 58b4c573 authored by Bernardo Rufino's avatar Bernardo Rufino Committed by Gerrit Code Review
Browse files

Merge "Add @hide Bundle.getParcelable() with explicit type"

parents dd5a31eb 32b2842e
Loading
Loading
Loading
Loading
+34 −18
Original line number Original line Diff line number Diff line
@@ -31,7 +31,7 @@ import com.android.internal.util.IndentingPrintWriter;
import java.io.Serializable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Set;
import java.util.Set;
import java.util.function.Supplier;
import java.util.function.Function;


/**
/**
 * A mapping from String keys to values of various types. In most cases, you
 * A mapping from String keys to values of various types. In most cases, you
@@ -252,11 +252,10 @@ public class BaseBundle {
        if (size == 0) {
        if (size == 0) {
            return null;
            return null;
        }
        }
        Object o = getValueAt(0);
        try {
        try {
            return (String) o;
            return getValueAt(0, String.class);
        } catch (ClassCastException e) {
        } catch (ClassCastException | BadParcelableException e) {
            typeWarning("getPairValue()", o, "String", e);
            typeWarning("getPairValue()", /* value */ null, "String", e);
            return null;
            return null;
        }
        }
    }
    }
@@ -309,7 +308,7 @@ public class BaseBundle {
                }
                }
                for (int i = 0, n = mMap.size(); i < n; i++) {
                for (int i = 0, n = mMap.size(); i < n; i++) {
                    // Triggers deserialization of i-th item, if needed
                    // Triggers deserialization of i-th item, if needed
                    getValueAt(i);
                    getValueAt(i, /* clazz */ null);
                }
                }
            }
            }
        }
        }
@@ -324,8 +323,21 @@ public class BaseBundle {
     * @hide
     * @hide
     */
     */
    final Object getValue(String key) {
    final Object getValue(String key) {
        return getValue(key, /* clazz */ null);
    }

    /**
     * Returns the value for key {@code key} for expected return type {@param clazz} (or {@code
     * null} for no type check).
     *
     * This call should always be made after {@link #unparcel()} or inside a lock after making sure
     * {@code mMap} is not null.
     *
     * @hide
     */
    final <T> T getValue(String key, @Nullable Class<T> clazz) {
        int i = mMap.indexOfKey(key);
        int i = mMap.indexOfKey(key);
        return (i >= 0) ? getValueAt(i) : null;
        return (i >= 0) ? getValueAt(i, clazz) : null;
    }
    }


    /**
    /**
@@ -336,11 +348,12 @@ public class BaseBundle {
     *
     *
     * @hide
     * @hide
     */
     */
    final Object getValueAt(int i) {
    @SuppressWarnings("unchecked")
    final <T> T getValueAt(int i, @Nullable Class<T> clazz) {
        Object object = mMap.valueAt(i);
        Object object = mMap.valueAt(i);
        if (object instanceof Supplier<?>) {
        if (object instanceof Function<?, ?>) {
            try {
            try {
                object = ((Supplier<?>) object).get();
                object = ((Function<Class<?>, ?>) object).apply(clazz);
            } catch (BadParcelableException e) {
            } catch (BadParcelableException e) {
                if (sShouldDefuse) {
                if (sShouldDefuse) {
                    Log.w(TAG, "Failed to parse item " + mMap.keyAt(i) + ", returning null.", e);
                    Log.w(TAG, "Failed to parse item " + mMap.keyAt(i) + ", returning null.", e);
@@ -351,7 +364,7 @@ public class BaseBundle {
            }
            }
            mMap.setValueAt(i, object);
            mMap.setValueAt(i, object);
        }
        }
        return object;
        return (clazz != null) ? clazz.cast(object) : (T) object;
    }
    }


    private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel,
    private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel,
@@ -528,7 +541,7 @@ public class BaseBundle {
        } else {
        } else {
            // Following semantic above of failing in case we get a serialized value vs a
            // Following semantic above of failing in case we get a serialized value vs a
            // deserialized one, we'll compare the map. If a certain element hasn't been
            // deserialized one, we'll compare the map. If a certain element hasn't been
            // deserialized yet, it's a Supplier (or more specifically a LazyValue, but let's
            // deserialized yet, it's a function object (or more specifically a LazyValue, but let's
            // pretend we don't know that here :P), we'll use that element's equality comparison as
            // pretend we don't know that here :P), we'll use that element's equality comparison as
            // map naturally does. That will takes care of comparing the payload if needed (see
            // map naturally does. That will takes care of comparing the payload if needed (see
            // Parcel.readLazyValue() for details).
            // Parcel.readLazyValue() for details).
@@ -982,15 +995,19 @@ public class BaseBundle {
    }
    }


    // Log a message if the value was non-null but not of the expected type
    // Log a message if the value was non-null but not of the expected type
    void typeWarning(String key, Object value, String className,
    void typeWarning(String key, @Nullable Object value, String className,
            Object defaultValue, ClassCastException e) {
            Object defaultValue, RuntimeException e) {
        StringBuilder sb = new StringBuilder();
        StringBuilder sb = new StringBuilder();
        sb.append("Key ");
        sb.append("Key ");
        sb.append(key);
        sb.append(key);
        sb.append(" expected ");
        sb.append(" expected ");
        sb.append(className);
        sb.append(className);
        if (value != null) {
            sb.append(" but value was a ");
            sb.append(" but value was a ");
            sb.append(value.getClass().getName());
            sb.append(value.getClass().getName());
        } else {
            sb.append(" but value was of a different type ");
        }
        sb.append(".  The default value ");
        sb.append(".  The default value ");
        sb.append(defaultValue);
        sb.append(defaultValue);
        sb.append(" was returned.");
        sb.append(" was returned.");
@@ -998,8 +1015,7 @@ public class BaseBundle {
        Log.w(TAG, "Attempt to cast generated internal exception:", e);
        Log.w(TAG, "Attempt to cast generated internal exception:", e);
    }
    }


    void typeWarning(String key, Object value, String className,
    void typeWarning(String key, @Nullable Object value, String className, RuntimeException e) {
            ClassCastException e) {
        typeWarning(key, value, className, "<null>", e);
        typeWarning(key, value, className, "<null>", e);
    }
    }


+30 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,9 @@


package android.os;
package android.os;


import static java.util.Objects.requireNonNull;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import android.util.ArrayMap;
@@ -912,6 +915,33 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        }
        }
    }
    }


    /**
     * Returns the value associated with the given key, or {@code null} if
     * no mapping of the desired type exists for the given key or a {@code null}
     * value is explicitly associated with the key.
     *
     * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
     * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
     * Otherwise, this method might throw an exception or return {@code null}.
     *
     * @param key a String, or {@code null}
     * @param clazz The type of the object expected or {@code null} for performing no checks.
     * @return a Parcelable value, or {@code null}
     *
     * @hide
     */
    @SuppressWarnings("unchecked")
    @Nullable
    public <T> T getParcelable(@Nullable String key, @NonNull Class<T> clazz) {
        unparcel();
        try {
            return getValue(key, requireNonNull(clazz));
        } catch (ClassCastException | BadParcelableException e) {
            typeWarning(key, /* value */ null, "Parcelable", e);
            return null;
        }
    }

    /**
    /**
     * Returns the value associated with the given key, or {@code null} if
     * Returns the value associated with the given key, or {@code null} if
     * no mapping of the desired type exists for the given key or a null
     * no mapping of the desired type exists for the given key or a null
+12 −11
Original line number Original line Diff line number Diff line
@@ -4312,18 +4312,19 @@ public final class Parcel {
    }
    }


    /**
    /**
     * This will return a {@link Supplier} for length-prefixed types that deserializes the object
     * This will return a {@link Function} for length-prefixed types that deserializes the object
     * when {@link Supplier#get()} is called, for other types it will return the object itself.
     * when {@link Function#apply} is called with the expected class of the return object (or {@code
     * null} for no type check), for other types it will return the object itself.
     *
     *
     * <p>After calling {@link Supplier#get()} the parcel cursor will not change. Note that you
     * <p>After calling {@link Function#apply(Object)} the parcel cursor will not change. Note that
     * shouldn't recycle the parcel, not at least until all objects have been retrieved. No
     * you shouldn't recycle the parcel, not at least until all objects have been retrieved. No
     * synchronization attempts are made.
     * synchronization attempts are made.
     *
     *
     * </p>The supplier returned implements {@link #equals(Object)} and {@link #hashCode()}. Two
     * </p>The function returned implements {@link #equals(Object)} and {@link #hashCode()}. Two
     * suppliers are equal if either of the following is true:
     * function objects are equal if either of the following is true:
     * <ul>
     * <ul>
     *   <li>{@link Supplier#get()} has been called on both and both objects returned are equal.
     *   <li>{@link Function#apply} has been called on both and both objects returned are equal.
     *   <li>{@link Supplier#get()} hasn't been called on either one and everything below is true:
     *   <li>{@link Function#apply} hasn't been called on either one and everything below is true:
     *   <ul>
     *   <ul>
     *       <li>The {@code loader} parameters used to retrieve each are equal.
     *       <li>The {@code loader} parameters used to retrieve each are equal.
     *       <li>They both have the same type.
     *       <li>They both have the same type.
@@ -4350,7 +4351,7 @@ public final class Parcel {
    }
    }




    private static final class LazyValue implements Supplier<Object> {
    private static final class LazyValue implements Function<Class<?>, Object> {
        /**
        /**
         *                      |   4B   |   4B   |
         *                      |   4B   |   4B   |
         * mSource = Parcel{... |  type  | length | object | ...}
         * mSource = Parcel{... |  type  | length | object | ...}
@@ -4382,7 +4383,7 @@ public final class Parcel {
        }
        }


        @Override
        @Override
        public Object get() {
        public Object apply(@Nullable Class<?> clazz) {
            Parcel source = mSource;
            Parcel source = mSource;
            if (source != null) {
            if (source != null) {
                synchronized (source) {
                synchronized (source) {
@@ -4391,7 +4392,7 @@ public final class Parcel {
                        int restore = source.dataPosition();
                        int restore = source.dataPosition();
                        try {
                        try {
                            source.setDataPosition(mPosition);
                            source.setDataPosition(mPosition);
                            mObject = source.readValue(mLoader);
                            mObject = source.readValue(mLoader, clazz);
                        } finally {
                        } finally {
                            source.setDataPosition(restore);
                            source.setDataPosition(restore);
                        }
                        }