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

Commit d3199a60 authored by Hao Ke's avatar Hao Ke Committed by Gerrit Code Review
Browse files

Merge "Adding typed Parcel read/write APIs."

parents fb7a6db2 8a86e7d5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -29998,12 +29998,15 @@ package android.os {
    method public int readInt();
    method public void readIntArray(@NonNull int[]);
    method public void readList(@NonNull java.util.List, @Nullable ClassLoader);
    method public <T> void readList(@NonNull java.util.List<? super T>, @Nullable ClassLoader, @NonNull Class<T>);
    method public long readLong();
    method public void readLongArray(@NonNull long[]);
    method public void readMap(@NonNull java.util.Map, @Nullable ClassLoader);
    method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader);
    method @Nullable public <T extends android.os.Parcelable> T readParcelable(@Nullable ClassLoader, @NonNull Class<T>);
    method @Nullable public android.os.Parcelable[] readParcelableArray(@Nullable ClassLoader);
    method @Nullable public android.os.Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader);
    method @Nullable public <T> android.os.Parcelable.Creator<T> readParcelableCreator(@Nullable ClassLoader, @NonNull Class<T>);
    method @NonNull public <T extends android.os.Parcelable> java.util.List<T> readParcelableList(@NonNull java.util.List<T>, @Nullable ClassLoader);
    method @Nullable public android.os.PersistableBundle readPersistableBundle();
    method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
+215 −82
Original line number Diff line number Diff line
@@ -2766,7 +2766,20 @@ public final class Parcel {
     */
    public final void readList(@NonNull List outVal, @Nullable ClassLoader loader) {
        int N = readInt();
        readListInternal(outVal, N, loader);
        readListInternal(outVal, N, loader, /* clazz */ null);
    }

    /**
     * Same as {@link #readList(List, ClassLoader)} but accepts {@code clazz} parameter as
     * the type required for each item. If the item to be deserialized is not an instance
     * of that class or any of its children class
     * a {@link BadParcelableException} will be thrown.
     */
    public <T> void readList(@NonNull List<? super T> outVal,
            @Nullable ClassLoader loader, @NonNull Class<T> clazz) {
        Objects.requireNonNull(clazz);
        int n = readInt();
        readListInternal(outVal, n, loader, clazz);
    }

    /**
@@ -2965,7 +2978,7 @@ public final class Parcel {
            return null;
        }
        ArrayList l = new ArrayList(N);
        readListInternal(l, N, loader);
        readListInternal(l, N, loader, /* clazz */ null);
        return l;
    }

@@ -3365,12 +3378,21 @@ public final class Parcel {
     */
    @Nullable
    public final Object readValue(@Nullable ClassLoader loader) {
        return readValue(loader, /* clazz */ null);
    }


    /**
     * @param clazz The type of the object expected or {@code null} for performing no checks.
     */
    @Nullable
    private <T> T readValue(@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
        int type = readInt();
        final Object object;
        final T object;
        if (isLengthPrefixed(type)) {
            int length = readInt();
            int start = dataPosition();
            object = readValue(type, loader);
            object = readValue(type, loader, clazz);
            int actual = dataPosition() - start;
            if (actual != length) {
                Slog.wtfStack(TAG,
@@ -3378,7 +3400,7 @@ public final class Parcel {
                                + "  consumed " + actual + " bytes, but " + length + " expected.");
            }
        } else {
            object = readValue(type, loader);
            object = readValue(type, loader, clazz);
        }
        return object;
    }
@@ -3415,7 +3437,7 @@ public final class Parcel {
            setDataPosition(MathUtils.addOrThrow(dataPosition(), length));
            return new LazyValue(this, start, length, type, loader);
        } else {
            return readValue(type, loader);
            return readValue(type, loader, /* clazz */ null);
        }
    }

@@ -3547,105 +3569,145 @@ public final class Parcel {
    /**
     * Reads a value from the parcel of type {@code type}. Does NOT read the int representing the
     * type first.
     * @param clazz The type of the object expected or {@code null} for performing no checks.
     */
    @SuppressWarnings("unchecked")
    @Nullable
    private Object readValue(int type, @Nullable ClassLoader loader) {
    private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz) {
        final Object object;
        switch (type) {
            case VAL_NULL:
            return null;
                object = null;
                break;

            case VAL_STRING:
            return readString();
                object = readString();
                break;

            case VAL_INTEGER:
            return readInt();
                object = readInt();
                break;

            case VAL_MAP:
            return readHashMap(loader);
                object = readHashMap(loader);
                break;

            case VAL_PARCELABLE:
            return readParcelable(loader);
                object = readParcelableInternal(loader, clazz);
                break;

            case VAL_SHORT:
            return (short) readInt();
                object = (short) readInt();
                break;

            case VAL_LONG:
            return readLong();
                object = readLong();
                break;

            case VAL_FLOAT:
            return readFloat();
                object = readFloat();
                break;

            case VAL_DOUBLE:
            return readDouble();
                object = readDouble();
                break;

            case VAL_BOOLEAN:
            return readInt() == 1;
                object = readInt() == 1;
                break;

            case VAL_CHARSEQUENCE:
            return readCharSequence();
                object = readCharSequence();
                break;

            case VAL_LIST:
            return readArrayList(loader);
                object = readArrayList(loader);
                break;

            case VAL_BOOLEANARRAY:
            return createBooleanArray();
                object = createBooleanArray();
                break;

            case VAL_BYTEARRAY:
            return createByteArray();
                object = createByteArray();
                break;

            case VAL_STRINGARRAY:
            return readStringArray();
                object = readStringArray();
                break;

            case VAL_CHARSEQUENCEARRAY:
            return readCharSequenceArray();
                object = readCharSequenceArray();
                break;

            case VAL_IBINDER:
            return readStrongBinder();
                object = readStrongBinder();
                break;

            case VAL_OBJECTARRAY:
            return readArray(loader);
                object = readArray(loader);
                break;

            case VAL_INTARRAY:
            return createIntArray();
                object = createIntArray();
                break;

            case VAL_LONGARRAY:
            return createLongArray();
                object = createLongArray();
                break;

            case VAL_BYTE:
            return readByte();
                object = readByte();
                break;

            case VAL_SERIALIZABLE:
            return readSerializable(loader);
                object = readSerializable(loader);
                break;

            case VAL_PARCELABLEARRAY:
            return readParcelableArray(loader);
                object = readParcelableArray(loader);
                break;

            case VAL_SPARSEARRAY:
            return readSparseArray(loader);
                object = readSparseArray(loader);
                break;

            case VAL_SPARSEBOOLEANARRAY:
            return readSparseBooleanArray();
                object = readSparseBooleanArray();
                break;

            case VAL_BUNDLE:
            return readBundle(loader); // loading will be deferred
                object = readBundle(loader); // loading will be deferred
                break;

            case VAL_PERSISTABLEBUNDLE:
            return readPersistableBundle(loader);
                object = readPersistableBundle(loader);
                break;

            case VAL_SIZE:
            return readSize();
                object = readSize();
                break;

            case VAL_SIZEF:
            return readSizeF();
                object = readSizeF();
                break;

            case VAL_DOUBLEARRAY:
            return createDoubleArray();
                object = createDoubleArray();
                break;

            default:
                int off = dataPosition() - 4;
                throw new RuntimeException(
                "Parcel " + this + ": Unmarshalling unknown type code " + type + " at offset " + off);
                    "Parcel " + this + ": Unmarshalling unknown type code " + type
                            + " at offset " + off);
        }
        if (clazz != null && !clazz.isInstance(object)) {
            throw new BadParcelableException("Unparcelled object " + object
                    + " is not an instance of required class " + clazz.getName()
                    + " provided in the parameter");
        }
        return (T) object;
    }

    private boolean isLengthPrefixed(int type) {
@@ -3673,10 +3735,35 @@ public final class Parcel {
     * @throws BadParcelableException Throws BadParcelableException if there
     * was an error trying to instantiate the Parcelable.
     */
    @SuppressWarnings("unchecked")
    @Nullable
    public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) {
        Parcelable.Creator<?> creator = readParcelableCreator(loader);
        return readParcelableInternal(loader, /* clazz */ null);
    }

    /**
     * Same as {@link #readParcelable(ClassLoader)} but accepts {@code clazz} parameter as the type
     * required for each item. If the item to be deserialized is not an instance of that class or
     * any of its children classes a {@link BadParcelableException} will be thrown.
     */
    @Nullable
    public <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader,
            @NonNull Class<T> clazz) {
        Objects.requireNonNull(clazz);
        return readParcelableInternal(loader, clazz);
    }

    /**
     *
     * @param clazz The type of the parcelable expected or {@code null} for performing no checks.
     */
    @SuppressWarnings("unchecked")
    @Nullable
    private <T> T readParcelableInternal(@Nullable ClassLoader loader, @Nullable Class<T> clazz) {
        if (clazz != null && !Parcelable.class.isAssignableFrom(clazz)) {
            throw new BadParcelableException("About to unparcel a parcelable object "
                    + " but class required " + clazz.getName() + " is not Parcelable");
        }
        Parcelable.Creator<?> creator = readParcelableCreatorInternal(loader, clazz);
        if (creator == null) {
            return null;
        }
@@ -3717,6 +3804,28 @@ public final class Parcel {
     */
    @Nullable
    public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
        return readParcelableCreatorInternal(loader, /* clazz */ null);
    }

    /**
     * Same as {@link #readParcelableCreator(ClassLoader)} but accepts {@code clazz} parameter
     * as the required type. If the item to be deserialized is not an instance of that class
     * or any of its children classes a {@link BadParcelableException} will be thrown.
     */
    @Nullable
    public <T> Parcelable.Creator<T> readParcelableCreator(
            @Nullable ClassLoader loader, @NonNull Class<T> clazz) {
        Objects.requireNonNull(clazz);
        return readParcelableCreatorInternal(loader, clazz);
    }

    /**
     * @param clazz The type of the parcelable expected or {@code null} for performing no checks.
     */
    @SuppressWarnings("unchecked")
    @Nullable
    private <T> Parcelable.Creator<T> readParcelableCreatorInternal(
            @Nullable ClassLoader loader, @Nullable Class<T> clazz) {
        String name = readString();
        if (name == null) {
            return null;
@@ -3732,7 +3841,15 @@ public final class Parcel {
            creator = map.get(name);
        }
        if (creator != null) {
            return creator;
            if (clazz != null) {
                Class<?> parcelableClass = creator.getClass().getEnclosingClass();
                if (!clazz.isAssignableFrom(parcelableClass)) {
                    throw new BadParcelableException("Parcelable creator " + name + " is not "
                            + "a subclass of required class " + clazz.getName()
                            + " provided in the parameter");
                }
            }
            return (Parcelable.Creator<T>) creator;
        }

        try {
@@ -3748,6 +3865,14 @@ public final class Parcel {
                throw new BadParcelableException("Parcelable protocol requires subclassing "
                        + "from Parcelable on class " + name);
            }
            if (clazz != null) {
                if (!clazz.isAssignableFrom(parcelableClass)) {
                    throw new BadParcelableException("Parcelable creator " + name + " is not "
                            + "a subclass of required class " + clazz.getName()
                            + " provided in the parameter");
                }
            }

            Field f = parcelableClass.getField("CREATOR");
            if ((f.getModifiers() & Modifier.STATIC) == 0) {
                throw new BadParcelableException("Parcelable protocol requires "
@@ -3785,7 +3910,7 @@ public final class Parcel {
            map.put(name, creator);
        }

        return creator;
        return (Parcelable.Creator<T>) creator;
    }

    /**
@@ -4031,13 +4156,21 @@ public final class Parcel {
        return result;
    }

    private void readListInternal(@NonNull List outVal, int N,
    private void readListInternal(@NonNull List outVal, int n,
            @Nullable ClassLoader loader) {
        while (N > 0) {
            Object value = readValue(loader);
        readListInternal(outVal, n, loader, null);
    }

    /**
     * @param clazz The type of the object expected or {@code null} for performing no checks.
     */
    private <T> void readListInternal(@NonNull List<? super T> outVal, int n,
            @Nullable ClassLoader loader, @Nullable Class<T> clazz) {
        while (n > 0) {
            T value = readValue(loader, clazz);
            //Log.d(TAG, "Unmarshalling value=" + value);
            outVal.add(value);
            N--;
            n--;
        }
    }