Repo cloned
This commit is contained in:
commit
496ae75f58
7988 changed files with 1451097 additions and 0 deletions
7
core-gms/safeparcel/build.gradle.kts
Normal file
7
core-gms/safeparcel/build.gradle.kts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
plugins {
|
||||
id("signal-library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.google.android.gms.common.internal.safeparcel"
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.common.internal.safeparcel;
|
||||
|
||||
/**
|
||||
* Implements {@link SafeParcelable} and implements some default methods defined by {@link
|
||||
* android.os.Parcelable}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class AbstractSafeParcelable implements SafeParcelable {
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public final int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.common.internal.safeparcel;
|
||||
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* Interface for Parcelables that have the class name reflectively read as part of serialization.
|
||||
* This happens when when put into an Intent or Bundle, or in some Parcel write methods.
|
||||
*
|
||||
* <p>This interface is needed because the errorprone checker has some limitations on detecting
|
||||
* annotations (like {@code @KeepName}), where detecting inheritance is easier.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface ReflectedParcelable extends Parcelable {}
|
||||
|
|
@ -0,0 +1,930 @@
|
|||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.common.internal.safeparcel;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.SparseLongArray;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Functions to read in a safe parcel.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SafeParcelReader {
|
||||
/** class to parse the exception. */
|
||||
public static class ParseException extends RuntimeException {
|
||||
public ParseException(@NonNull String message, @NonNull Parcel p) {
|
||||
super(message + " Parcel: pos=" + p.dataPosition() + " size=" + p.dataSize());
|
||||
}
|
||||
}
|
||||
|
||||
private SafeParcelReader() {}
|
||||
|
||||
/** Reads the header. */
|
||||
public static int readHeader(@NonNull Parcel p) {
|
||||
return p.readInt();
|
||||
}
|
||||
|
||||
/** Gets the id for the field. */
|
||||
public static int getFieldId(int header) {
|
||||
return header & 0x0000ffff;
|
||||
}
|
||||
|
||||
/** Reads the size. */
|
||||
public static int readSize(@NonNull Parcel p, int header) {
|
||||
if ((header & 0xffff0000) != 0xffff0000) {
|
||||
return (header >> 16) & 0x0000ffff;
|
||||
} else {
|
||||
return p.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
/** Skips the unknown field. */
|
||||
public static void skipUnknownField(@NonNull Parcel p, int header) {
|
||||
int size = readSize(p, header);
|
||||
p.setDataPosition(p.dataPosition() + size);
|
||||
}
|
||||
|
||||
private static void readAndEnforceSize(@NonNull Parcel p, int header, int required) {
|
||||
final int size = readSize(p, header);
|
||||
if (size != required) {
|
||||
throw new ParseException(
|
||||
"Expected size "
|
||||
+ required
|
||||
+ " got "
|
||||
+ size
|
||||
+ " (0x"
|
||||
+ Integer.toHexString(size)
|
||||
+ ")",
|
||||
p);
|
||||
}
|
||||
}
|
||||
|
||||
private static void enforceSize(@NonNull Parcel p, int header, int size, int required) {
|
||||
if (size != required) {
|
||||
throw new ParseException(
|
||||
"Expected size "
|
||||
+ required
|
||||
+ " got "
|
||||
+ size
|
||||
+ " (0x"
|
||||
+ Integer.toHexString(size)
|
||||
+ ")",
|
||||
p);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the end position of the object in the parcel. */
|
||||
public static int validateObjectHeader(@NonNull Parcel p) {
|
||||
final int header = readHeader(p);
|
||||
final int size = readSize(p, header);
|
||||
final int start = p.dataPosition();
|
||||
if (getFieldId(header) != SafeParcelWriter.OBJECT_HEADER) {
|
||||
throw new ParseException(
|
||||
"Expected object header. Got 0x" + Integer.toHexString(header), p);
|
||||
}
|
||||
final int end = start + size;
|
||||
if (end < start || end > p.dataSize()) {
|
||||
throw new ParseException("Size read is invalid start=" + start + " end=" + end, p);
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
/** Reads a boolean. */
|
||||
public static boolean readBoolean(@NonNull Parcel p, int header) {
|
||||
readAndEnforceSize(p, header, 4);
|
||||
return p.readInt() != 0;
|
||||
}
|
||||
|
||||
/** Reads a {@link Boolean} object. */
|
||||
@Nullable
|
||||
public static Boolean readBooleanObject(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
if (size == 0) {
|
||||
return null;
|
||||
} else {
|
||||
enforceSize(p, header, size, 4);
|
||||
return p.readInt() != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Reads a byte. */
|
||||
public static byte readByte(@NonNull Parcel p, int header) {
|
||||
readAndEnforceSize(p, header, 4);
|
||||
return (byte) p.readInt();
|
||||
}
|
||||
|
||||
/** Reads a char. */
|
||||
public static char readChar(@NonNull Parcel p, int header) {
|
||||
readAndEnforceSize(p, header, 4);
|
||||
return (char) p.readInt();
|
||||
}
|
||||
|
||||
/** Reads a short. */
|
||||
public static short readShort(@NonNull Parcel p, int header) {
|
||||
readAndEnforceSize(p, header, 4);
|
||||
return (short) p.readInt();
|
||||
}
|
||||
|
||||
/** Reads an int. */
|
||||
public static int readInt(@NonNull Parcel p, int header) {
|
||||
readAndEnforceSize(p, header, 4);
|
||||
return p.readInt();
|
||||
}
|
||||
|
||||
/** Reads an {@link Integer} object. */
|
||||
@Nullable
|
||||
public static Integer readIntegerObject(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
if (size == 0) {
|
||||
return null;
|
||||
} else {
|
||||
enforceSize(p, header, size, 4);
|
||||
return p.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
/** Reads a long. */
|
||||
public static long readLong(@NonNull Parcel p, int header) {
|
||||
readAndEnforceSize(p, header, 8);
|
||||
return p.readLong();
|
||||
}
|
||||
|
||||
/** Reads a {@link Long} object. */
|
||||
@Nullable
|
||||
public static Long readLongObject(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
if (size == 0) {
|
||||
return null;
|
||||
} else {
|
||||
enforceSize(p, header, size, 8);
|
||||
return p.readLong();
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a {@link BigInteger}. */
|
||||
@Nullable
|
||||
public static BigInteger createBigInteger(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final byte[] val = p.createByteArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return new BigInteger(val);
|
||||
}
|
||||
|
||||
/** Reads a float. */
|
||||
public static float readFloat(@NonNull Parcel p, int header) {
|
||||
readAndEnforceSize(p, header, 4);
|
||||
return p.readFloat();
|
||||
}
|
||||
|
||||
/** Reads a {@link Float}. */
|
||||
@Nullable
|
||||
public static Float readFloatObject(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
if (size == 0) {
|
||||
return null;
|
||||
} else {
|
||||
enforceSize(p, header, size, 4);
|
||||
return p.readFloat();
|
||||
}
|
||||
}
|
||||
|
||||
/** Reads a double. */
|
||||
public static double readDouble(@NonNull Parcel p, int header) {
|
||||
readAndEnforceSize(p, header, 8);
|
||||
return p.readDouble();
|
||||
}
|
||||
|
||||
/** Reads a {@link Double}. */
|
||||
@Nullable
|
||||
public static Double readDoubleObject(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
if (size == 0) {
|
||||
return null;
|
||||
} else {
|
||||
enforceSize(p, header, size, 8);
|
||||
return p.readDouble();
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a {@link BigDecimal}. */
|
||||
@Nullable
|
||||
public static BigDecimal createBigDecimal(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final byte[] unscaledValue = p.createByteArray();
|
||||
final int scale = p.readInt();
|
||||
p.setDataPosition(pos + size);
|
||||
return new BigDecimal(new BigInteger(unscaledValue), scale);
|
||||
}
|
||||
|
||||
/** Creates a {@link String}. */
|
||||
@Nullable
|
||||
public static String createString(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final String result = p.readString();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Reads an {@link IBinder}. */
|
||||
@Nullable
|
||||
public static IBinder readIBinder(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final IBinder result = p.readStrongBinder();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Reads a {@link PendingIntent}. */
|
||||
@Nullable
|
||||
public static PendingIntent readPendingIntent(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final PendingIntent result = PendingIntent.readPendingIntentOrNullFromParcel(p);
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link Parcelable}. */
|
||||
@Nullable
|
||||
public static <T extends Parcelable> T createParcelable(
|
||||
@NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> creator) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final T result = creator.createFromParcel(p);
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link Bundle}. */
|
||||
@Nullable
|
||||
public static Bundle createBundle(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final Bundle result = p.readBundle();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a byte array. */
|
||||
@Nullable
|
||||
public static byte[] createByteArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final byte[] result = p.createByteArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a byte array array. */
|
||||
@Nullable
|
||||
public static byte[][] createByteArrayArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final int length = p.readInt();
|
||||
final byte[][] result = new byte[length][];
|
||||
for (int i = 0; i < length; i++) {
|
||||
result[i] = p.createByteArray();
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a boolean array array. */
|
||||
@Nullable
|
||||
public static boolean[] createBooleanArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final boolean[] result = p.createBooleanArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a char array. */
|
||||
@Nullable
|
||||
public static char[] createCharArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final char[] result = p.createCharArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates an int array. */
|
||||
@Nullable
|
||||
public static int[] createIntArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final int[] result = p.createIntArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a long array. */
|
||||
@Nullable
|
||||
public static long[] createLongArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final long[] result = p.createLongArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link BigInteger} array. */
|
||||
@Nullable
|
||||
public static BigInteger[] createBigIntegerArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final int length = p.readInt();
|
||||
final BigInteger[] result = new BigInteger[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
result[i] = new BigInteger(p.createByteArray());
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a float array. */
|
||||
@Nullable
|
||||
public static float[] createFloatArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final float[] result = p.createFloatArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a double array. */
|
||||
@Nullable
|
||||
public static double[] createDoubleArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final double[] result = p.createDoubleArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link BigDecimal} array. */
|
||||
@Nullable
|
||||
public static BigDecimal[] createBigDecimalArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final int length = p.readInt();
|
||||
final BigDecimal[] result = new BigDecimal[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
byte[] unscaledValue = p.createByteArray();
|
||||
int scale = p.readInt();
|
||||
result[i] = new BigDecimal(new BigInteger(unscaledValue), scale);
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link String} array. */
|
||||
@Nullable
|
||||
public static String[] createStringArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final String[] result = p.createStringArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link IBinder} array. */
|
||||
@Nullable
|
||||
public static IBinder[] createIBinderArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final IBinder[] result = p.createBinderArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link Boolean} list. */
|
||||
@Nullable
|
||||
public static ArrayList<Boolean> createBooleanList(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final ArrayList<Boolean> result = new ArrayList<Boolean>();
|
||||
final int count = p.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(p.readInt() != 0 ? true : false);
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link Integer} list. */
|
||||
@Nullable
|
||||
public static ArrayList<Integer> createIntegerList(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final ArrayList<Integer> result = new ArrayList<Integer>();
|
||||
final int count = p.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(p.readInt());
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link SparseBooleanArray}. */
|
||||
@Nullable
|
||||
public static SparseBooleanArray createSparseBooleanArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
SparseBooleanArray result = p.readSparseBooleanArray();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link SparseIntArray}. */
|
||||
@Nullable
|
||||
public static SparseIntArray createSparseIntArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final SparseIntArray result = new SparseIntArray();
|
||||
final int count = p.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int key = p.readInt();
|
||||
int value = p.readInt();
|
||||
result.append(key, value);
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link Float} {@link SparseArray}. */
|
||||
@Nullable
|
||||
public static SparseArray<Float> createFloatSparseArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final SparseArray<Float> result = new SparseArray<Float>();
|
||||
final int count = p.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int key = p.readInt();
|
||||
float value = p.readFloat();
|
||||
result.append(key, value);
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link Double} {@link SparseArray}. */
|
||||
@Nullable
|
||||
public static SparseArray<Double> createDoubleSparseArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final SparseArray<Double> result = new SparseArray<Double>();
|
||||
final int count = p.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int key = p.readInt();
|
||||
double value = p.readDouble();
|
||||
result.append(key, value);
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link SparseLongArray}. */
|
||||
@Nullable
|
||||
public static SparseLongArray createSparseLongArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final SparseLongArray result = new SparseLongArray();
|
||||
final int count = p.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int key = p.readInt();
|
||||
long value = p.readLong();
|
||||
result.append(key, value);
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link String} {@link SparseArray}. */
|
||||
@Nullable
|
||||
public static SparseArray<String> createStringSparseArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final SparseArray<String> result = new SparseArray<String>();
|
||||
final int count = p.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int key = p.readInt();
|
||||
String value = p.readString();
|
||||
result.append(key, value);
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates a {@link Parcel} {@link SparseArray}. */
|
||||
@Nullable
|
||||
public static SparseArray<Parcel> createParcelSparseArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final int count = p.readInt();
|
||||
final SparseArray<Parcel> result = new SparseArray<Parcel>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int key = p.readInt();
|
||||
// read in the flag of whether this element is null
|
||||
int parcelSize = p.readInt();
|
||||
if (parcelSize != 0) {
|
||||
// non-null
|
||||
int currentDataPosition = p.dataPosition();
|
||||
Parcel item = Parcel.obtain();
|
||||
item.appendFrom(p, currentDataPosition, parcelSize);
|
||||
result.append(key, item);
|
||||
|
||||
// move p's data position
|
||||
p.setDataPosition(currentDataPosition + parcelSize);
|
||||
} else {
|
||||
// is null
|
||||
result.append(key, null);
|
||||
}
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates typed {@link SparseArray}. */
|
||||
@Nullable
|
||||
public static <T> SparseArray<T> createTypedSparseArray(
|
||||
@NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final int count = p.readInt();
|
||||
final SparseArray<T> result = new SparseArray<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int key = p.readInt();
|
||||
T value;
|
||||
if (p.readInt() != 0) {
|
||||
value = c.createFromParcel(p);
|
||||
} else {
|
||||
value = null;
|
||||
}
|
||||
result.append(key, value);
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates {@link IBinder} {@link SparseArray}. */
|
||||
@Nullable
|
||||
public static SparseArray<IBinder> createIBinderSparseArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final int count = p.readInt();
|
||||
final SparseArray<IBinder> result = new SparseArray<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
int key = p.readInt();
|
||||
IBinder value = p.readStrongBinder();
|
||||
result.append(key, value);
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates byte array {@link SparseArray}. */
|
||||
@Nullable
|
||||
public static SparseArray<byte[]> createByteArraySparseArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final int count = p.readInt();
|
||||
final SparseArray<byte[]> result = new SparseArray<byte[]>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
int key = p.readInt();
|
||||
byte[] value = p.createByteArray();
|
||||
result.append(key, value);
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates {@link Long} {@link ArrayList}. */
|
||||
@Nullable
|
||||
public static ArrayList<Long> createLongList(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final ArrayList<Long> result = new ArrayList<Long>();
|
||||
final int count = p.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(p.readLong());
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates {@link Float} {@link ArrayList}. */
|
||||
@Nullable
|
||||
public static ArrayList<Float> createFloatList(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final ArrayList<Float> result = new ArrayList<Float>();
|
||||
final int count = p.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(p.readFloat());
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates {@link Double} {@link ArrayList}. */
|
||||
@Nullable
|
||||
public static ArrayList<Double> createDoubleList(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final ArrayList<Double> result = new ArrayList<Double>();
|
||||
final int count = p.readInt();
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(p.readDouble());
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates {@link String} {@link ArrayList}. */
|
||||
@Nullable
|
||||
public static ArrayList<String> createStringList(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final ArrayList<String> result = p.createStringArrayList();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates {@link IBinder} {@link ArrayList}. */
|
||||
@Nullable
|
||||
public static ArrayList<IBinder> createIBinderList(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final ArrayList<IBinder> result = p.createBinderArrayList();
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates typed array. */
|
||||
@Nullable
|
||||
public static <T> T[] createTypedArray(
|
||||
@NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final T[] result = p.createTypedArray(c);
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates typed {@link ArrayList}. */
|
||||
@Nullable
|
||||
public static <T> ArrayList<T> createTypedList(
|
||||
@NonNull Parcel p, int header, @NonNull Parcelable.Creator<T> c) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final ArrayList<T> result = p.createTypedArrayList(c);
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates {@link Parcel}. */
|
||||
@Nullable
|
||||
public static Parcel createParcel(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final Parcel result = Parcel.obtain();
|
||||
result.appendFrom(p, pos, size);
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates {@link Parcel} array. */
|
||||
@Nullable
|
||||
public static Parcel[] createParcelArray(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final int length = p.readInt();
|
||||
final Parcel[] result = new Parcel[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
int parcelSize = p.readInt();
|
||||
if (parcelSize != 0) {
|
||||
int currentDataPosition = p.dataPosition();
|
||||
Parcel item = Parcel.obtain();
|
||||
item.appendFrom(p, currentDataPosition, parcelSize);
|
||||
result[i] = item;
|
||||
|
||||
// move p's data position
|
||||
p.setDataPosition(currentDataPosition + parcelSize);
|
||||
} else {
|
||||
result[i] = null;
|
||||
}
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Creates {@link Parcel} {@link ArrayList}. */
|
||||
@Nullable
|
||||
public static ArrayList<Parcel> createParcelList(@NonNull Parcel p, int header) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return null;
|
||||
}
|
||||
final int length = p.readInt();
|
||||
final ArrayList<Parcel> result = new ArrayList<Parcel>();
|
||||
for (int i = 0; i < length; i++) {
|
||||
// read in the flag of whether this element is null
|
||||
int parcelSize = p.readInt();
|
||||
if (parcelSize != 0) {
|
||||
// non-null
|
||||
int currentDataPosition = p.dataPosition();
|
||||
Parcel item = Parcel.obtain();
|
||||
item.appendFrom(p, currentDataPosition, parcelSize);
|
||||
result.add(item);
|
||||
|
||||
// move p's data position
|
||||
p.setDataPosition(currentDataPosition + parcelSize);
|
||||
} else {
|
||||
// is null
|
||||
result.add(null);
|
||||
}
|
||||
}
|
||||
p.setDataPosition(pos + size);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Reads the list. */
|
||||
public static void readList(
|
||||
@NonNull Parcel p,
|
||||
int header,
|
||||
@SuppressWarnings("rawtypes") @NonNull List list,
|
||||
@Nullable ClassLoader loader) {
|
||||
final int size = readSize(p, header);
|
||||
final int pos = p.dataPosition();
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
p.readList(list, loader);
|
||||
p.setDataPosition(pos + size);
|
||||
}
|
||||
|
||||
/** Ensures at end. */
|
||||
public static void ensureAtEnd(@NonNull Parcel parcel, int end) {
|
||||
if (parcel.dataPosition() != end) {
|
||||
throw new ParseException("Overread allowed size end=" + end, parcel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,964 @@
|
|||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.common.internal.safeparcel;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.util.SparseLongArray;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Functions to write a safe parcel. A safe parcel consists of a sequence of header/payload bytes.
|
||||
*
|
||||
* <p>The header is 16 bits of size and 16 bits of field id. If the size in the header is 0xffff,
|
||||
* the next 4 bytes are the size field instead.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SafeParcelWriter {
|
||||
|
||||
static final int OBJECT_HEADER = 0x00004f45;
|
||||
|
||||
private SafeParcelWriter() {}
|
||||
|
||||
private static void writeHeader(Parcel p, int id, int size) {
|
||||
if (size >= 0x0000ffff) {
|
||||
p.writeInt(0xffff0000 | id);
|
||||
p.writeInt(size);
|
||||
} else {
|
||||
p.writeInt((size << 16) | id);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the cookie that should be passed to endVariableData. */
|
||||
private static int beginVariableData(Parcel p, int id) {
|
||||
// Since we don't know the size yet, assume it might be big and always use the
|
||||
// size overflow.
|
||||
p.writeInt(0xffff0000 | id);
|
||||
p.writeInt(0);
|
||||
return p.dataPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param start The result of the paired beginVariableData.
|
||||
*/
|
||||
private static void finishVariableData(Parcel p, int start) {
|
||||
int end = p.dataPosition();
|
||||
int size = end - start;
|
||||
// The size is one int before start.
|
||||
p.setDataPosition(start - 4);
|
||||
p.writeInt(size);
|
||||
p.setDataPosition(end);
|
||||
}
|
||||
|
||||
/** Begins the objects header. */
|
||||
public static int beginObjectHeader(@NonNull Parcel p) {
|
||||
return beginVariableData(p, OBJECT_HEADER);
|
||||
}
|
||||
|
||||
/** Finishes the objects header. */
|
||||
public static void finishObjectHeader(@NonNull Parcel p, int start) {
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a boolean. */
|
||||
public static void writeBoolean(@NonNull Parcel p, int id, boolean val) {
|
||||
writeHeader(p, id, 4);
|
||||
p.writeInt(val ? 1 : 0);
|
||||
}
|
||||
|
||||
/** Writes a {@link Boolean} object. */
|
||||
public static void writeBooleanObject(
|
||||
@NonNull Parcel p, int id, @Nullable Boolean val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
writeHeader(p, id, 4);
|
||||
p.writeInt(val ? 1 : 0);
|
||||
}
|
||||
|
||||
/** Writes a byte. */
|
||||
public static void writeByte(@NonNull Parcel p, int id, byte val) {
|
||||
writeHeader(p, id, 4);
|
||||
p.writeInt(val);
|
||||
}
|
||||
|
||||
/** Writes a char. */
|
||||
public static void writeChar(@NonNull Parcel p, int id, char val) {
|
||||
writeHeader(p, id, 4);
|
||||
p.writeInt(val);
|
||||
}
|
||||
|
||||
/** Writes a short. */
|
||||
public static void writeShort(@NonNull Parcel p, int id, short val) {
|
||||
writeHeader(p, id, 4);
|
||||
p.writeInt(val);
|
||||
}
|
||||
|
||||
/** Writes an int. */
|
||||
public static void writeInt(@NonNull Parcel p, int id, int val) {
|
||||
writeHeader(p, id, 4);
|
||||
p.writeInt(val);
|
||||
}
|
||||
|
||||
/** Writes an {@link Integer}. */
|
||||
public static void writeIntegerObject(
|
||||
@NonNull Parcel p, int id, @Nullable Integer val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
writeHeader(p, id, 4);
|
||||
p.writeInt(val);
|
||||
}
|
||||
|
||||
/** Writes a long. */
|
||||
public static void writeLong(@NonNull Parcel p, int id, long val) {
|
||||
writeHeader(p, id, 8);
|
||||
p.writeLong(val);
|
||||
}
|
||||
|
||||
/** Writes a {@link Long}. */
|
||||
public static void writeLongObject(
|
||||
@NonNull Parcel p, int id, @Nullable Long val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
writeHeader(p, id, 8);
|
||||
p.writeLong(val);
|
||||
}
|
||||
|
||||
/** Writes a {@link BigInteger}. */
|
||||
public static void writeBigInteger(
|
||||
@NonNull Parcel p, int id, @Nullable BigInteger val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeByteArray(val.toByteArray());
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a float. */
|
||||
public static void writeFloat(@NonNull Parcel p, int id, float val) {
|
||||
writeHeader(p, id, 4);
|
||||
p.writeFloat(val);
|
||||
}
|
||||
|
||||
/** Writes a {@link Float}. */
|
||||
public static void writeFloatObject(
|
||||
@NonNull Parcel p, int id, @Nullable Float val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
writeHeader(p, id, 4);
|
||||
p.writeFloat(val);
|
||||
}
|
||||
|
||||
/** Writes a double. */
|
||||
public static void writeDouble(@NonNull Parcel p, int id, double val) {
|
||||
writeHeader(p, id, 8);
|
||||
p.writeDouble(val);
|
||||
}
|
||||
|
||||
/** Writes a {@link Double} object. */
|
||||
public static void writeDoubleObject(
|
||||
@NonNull Parcel p, int id, @Nullable Double val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
writeHeader(p, id, 8);
|
||||
p.writeDouble(val);
|
||||
}
|
||||
|
||||
/** Writes a {@link BigDecimal}. */
|
||||
public static void writeBigDecimal(
|
||||
@NonNull Parcel p, int id, @Nullable BigDecimal val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeByteArray(val.unscaledValue().toByteArray());
|
||||
p.writeInt(val.scale());
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link String}. */
|
||||
public static void writeString(
|
||||
@NonNull Parcel p, int id, @Nullable String val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeString(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link IBinder}. */
|
||||
public static void writeIBinder(
|
||||
@NonNull Parcel p, int id, @Nullable IBinder val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// The size of the flat_binder_object in Parcel.cpp is not actually variable
|
||||
// but is not part of the CDD, so treat it as variable. It almost certainly
|
||||
// won't change between processes on a given device.
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeStrongBinder(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link Parcelable}. */
|
||||
public static void writeParcelable(
|
||||
@NonNull Parcel p,
|
||||
int id,
|
||||
@Nullable Parcelable val,
|
||||
int parcelableFlags,
|
||||
boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
val.writeToParcel(p, parcelableFlags);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link Bundle}. */
|
||||
public static void writeBundle(
|
||||
@NonNull Parcel p, int id, @Nullable Bundle val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeBundle(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a byte array. */
|
||||
public static void writeByteArray(
|
||||
@NonNull Parcel p, int id, @Nullable byte[] buf, boolean writeNull) {
|
||||
if (buf == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeByteArray(buf);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a byte array array. */
|
||||
public static void writeByteArrayArray(
|
||||
@NonNull Parcel p, int id, @Nullable byte[][] buf, boolean writeNull) {
|
||||
if (buf == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int length = buf.length;
|
||||
p.writeInt(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
p.writeByteArray(buf[i]);
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a boolean array. */
|
||||
public static void writeBooleanArray(
|
||||
@NonNull Parcel p, int id, @Nullable boolean[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeBooleanArray(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a char array. */
|
||||
public static void writeCharArray(
|
||||
@NonNull Parcel p, int id, @Nullable char[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeCharArray(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes an int array. */
|
||||
public static void writeIntArray(
|
||||
@NonNull Parcel p, int id, @Nullable int[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeIntArray(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a long array. */
|
||||
public static void writeLongArray(
|
||||
@NonNull Parcel p, int id, @Nullable long[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeLongArray(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link BigInteger} array. */
|
||||
public static void writeBigIntegerArray(
|
||||
@NonNull Parcel p, int id, @Nullable BigInteger[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int length = val.length;
|
||||
p.writeInt(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
p.writeByteArray(val[i].toByteArray());
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a float array. */
|
||||
public static void writeFloatArray(
|
||||
@NonNull Parcel p, int id, @Nullable float[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeFloatArray(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a double array. */
|
||||
public static void writeDoubleArray(
|
||||
@NonNull Parcel p, int id, @Nullable double[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeDoubleArray(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link BigDecimal} array. */
|
||||
public static void writeBigDecimalArray(
|
||||
@NonNull Parcel p, int id, @Nullable BigDecimal[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int length = val.length;
|
||||
p.writeInt(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
p.writeByteArray(val[i].unscaledValue().toByteArray());
|
||||
p.writeInt(val[i].scale());
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link String} array. */
|
||||
public static void writeStringArray(
|
||||
@NonNull Parcel p, int id, @Nullable String[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeStringArray(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link IBinder} array. */
|
||||
public static void writeIBinderArray(
|
||||
@NonNull Parcel p, int id, @Nullable IBinder[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeBinderArray(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a boolean list. */
|
||||
public static void writeBooleanList(
|
||||
@NonNull Parcel p, int id, @Nullable List<Boolean> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.get(i) ? 1 : 0);
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes an {@link Integer} list. */
|
||||
public static void writeIntegerList(
|
||||
@NonNull Parcel p, int id, @Nullable List<Integer> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.get(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link Long} list. */
|
||||
public static void writeLongList(
|
||||
@NonNull Parcel p, int id, @Nullable List<Long> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeLong(val.get(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link Float} list. */
|
||||
public static void writeFloatList(
|
||||
@NonNull Parcel p, int id, @Nullable List<Float> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeFloat(val.get(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link Double} list. */
|
||||
public static void writeDoubleList(
|
||||
@NonNull Parcel p, int id, @Nullable List<Double> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeDouble(val.get(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link String} list. */
|
||||
public static void writeStringList(
|
||||
@NonNull Parcel p, int id, @Nullable List<String> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeStringList(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link IBinder} list. */
|
||||
public static void writeIBinderList(
|
||||
@NonNull Parcel p, int id, @Nullable List<IBinder> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeBinderList(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a typed array. */
|
||||
public static <T extends Parcelable> void writeTypedArray(
|
||||
@NonNull Parcel p, int id, @Nullable T[] val, int parcelableFlags, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
// We need to customize the built-in Parcel.writeTypedArray() because we need to write
|
||||
// the sizes for each individual SafeParcelable objects since they can vary in size due
|
||||
// to supporting missing fields.
|
||||
final int length = val.length;
|
||||
p.writeInt(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
T item = val[i];
|
||||
if (item == null) {
|
||||
p.writeInt(0);
|
||||
} else {
|
||||
writeTypedItemWithSize(p, item, parcelableFlags);
|
||||
}
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a typed list. */
|
||||
public static <T extends Parcelable> void writeTypedList(
|
||||
@NonNull Parcel p, int id, @Nullable List<T> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
// We need to customize the built-in Parcel.writeTypedList() because we need to write
|
||||
// the sizes for each individual SafeParcelable objects since they can vary in size due
|
||||
// supporting missing fields.
|
||||
final int length = val.size();
|
||||
p.writeInt(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
T item = val.get(i);
|
||||
if (item == null) {
|
||||
p.writeInt(0);
|
||||
} else {
|
||||
writeTypedItemWithSize(p, item, 0);
|
||||
}
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a typed item with size. */
|
||||
private static <T extends Parcelable> void writeTypedItemWithSize(
|
||||
Parcel p, T item, int parcelableFlags) {
|
||||
// Just write a 1 as a placeholder since we don't know the exact size of item
|
||||
// yet, and save the data position in Parcel p.
|
||||
final int itemSizeDataPosition = p.dataPosition();
|
||||
p.writeInt(1);
|
||||
final int itemStartPosition = p.dataPosition();
|
||||
item.writeToParcel(p, parcelableFlags);
|
||||
final int currentDataPosition = p.dataPosition();
|
||||
|
||||
// go back and write the length in bytes
|
||||
p.setDataPosition(itemSizeDataPosition);
|
||||
p.writeInt(currentDataPosition - itemStartPosition);
|
||||
|
||||
// set the parcel data position to where it was before
|
||||
p.setDataPosition(currentDataPosition);
|
||||
}
|
||||
|
||||
/** Writes a parcel. */
|
||||
public static void writeParcel(
|
||||
@NonNull Parcel p, int id, @Nullable Parcel val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.appendFrom(val, 0, val.dataSize());
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is made to be compatible with writeTypedArray. See implementation of
|
||||
* Parcel.writeTypedArray(T[] val, parcelableFlags);
|
||||
*/
|
||||
public static void writeParcelArray(
|
||||
@NonNull Parcel p, int id, @Nullable Parcel[] val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int length = val.length;
|
||||
p.writeInt(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Parcel item = val[i];
|
||||
if (item != null) {
|
||||
p.writeInt(item.dataSize());
|
||||
// custom part
|
||||
p.appendFrom(item, 0, item.dataSize());
|
||||
} else {
|
||||
p.writeInt(0);
|
||||
}
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is made to be compatible with writeTypedList. See implementation of
|
||||
* Parce.writeTypedList(List<T> val).
|
||||
*/
|
||||
public static void writeParcelList(
|
||||
@NonNull Parcel p, int id, @Nullable List<Parcel> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Parcel item = val.get(i);
|
||||
if (item != null) {
|
||||
p.writeInt(item.dataSize());
|
||||
// custom part
|
||||
p.appendFrom(item, 0, item.dataSize());
|
||||
} else {
|
||||
p.writeInt(0);
|
||||
}
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link PendingIntent}. */
|
||||
public static void writePendingIntent(
|
||||
@NonNull Parcel p, int id, @Nullable PendingIntent val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
PendingIntent.writePendingIntentOrNullToParcel(val, p);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a list. */
|
||||
public static void writeList(
|
||||
@NonNull Parcel p,
|
||||
int id,
|
||||
@SuppressWarnings("rawtypes") @Nullable List list,
|
||||
boolean writeNull) {
|
||||
if (list == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeList(list);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link SparseBooleanArray}. */
|
||||
public static void writeSparseBooleanArray(
|
||||
@NonNull Parcel p, int id, @Nullable SparseBooleanArray val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
p.writeSparseBooleanArray(val);
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link Double} {@link SparseArray}. */
|
||||
public static void writeDoubleSparseArray(
|
||||
@NonNull Parcel p, int id, @Nullable SparseArray<Double> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.keyAt(i));
|
||||
p.writeDouble(val.valueAt(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link Float} {@link SparseArray}. */
|
||||
public static void writeFloatSparseArray(
|
||||
@NonNull Parcel p, int id, @Nullable SparseArray<Float> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.keyAt(i));
|
||||
p.writeFloat(val.valueAt(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link SparseIntArray}. */
|
||||
public static void writeSparseIntArray(
|
||||
@NonNull Parcel p, int id, @Nullable SparseIntArray val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.keyAt(i));
|
||||
p.writeInt(val.valueAt(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link SparseLongArray}. */
|
||||
public static void writeSparseLongArray(
|
||||
@NonNull Parcel p, int id, @Nullable SparseLongArray val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.keyAt(i));
|
||||
p.writeLong(val.valueAt(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link String} {@link SparseArray}. */
|
||||
public static void writeStringSparseArray(
|
||||
@NonNull Parcel p, int id, @Nullable SparseArray<String> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.keyAt(i));
|
||||
p.writeString(val.valueAt(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes a {@link Parcel} {@link SparseArray}. */
|
||||
public static void writeParcelSparseArray(
|
||||
@NonNull Parcel p, int id, @Nullable SparseArray<Parcel> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.keyAt(i));
|
||||
Parcel item = val.valueAt(i);
|
||||
if (item != null) {
|
||||
p.writeInt(item.dataSize());
|
||||
// custom part
|
||||
p.appendFrom(item, 0, item.dataSize());
|
||||
} else {
|
||||
p.writeInt(0);
|
||||
}
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes typed {@link SparseArray}. */
|
||||
public static <T extends Parcelable> void writeTypedSparseArray(
|
||||
@NonNull Parcel p, int id, @Nullable SparseArray<T> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
// We follow the same approach as writeTypedList().
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.keyAt(i));
|
||||
T item = val.valueAt(i);
|
||||
if (item == null) {
|
||||
p.writeInt(0);
|
||||
} else {
|
||||
writeTypedItemWithSize(p, item, 0);
|
||||
}
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes {@link IBinder} {@link SparseArray}. */
|
||||
public static void writeIBinderSparseArray(
|
||||
@NonNull Parcel p, int id, @Nullable SparseArray<IBinder> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.keyAt(i));
|
||||
p.writeStrongBinder(val.valueAt(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
|
||||
/** Writes byte array {@link SparseArray}. */
|
||||
public static void writeByteArraySparseArray(
|
||||
@NonNull Parcel p, int id, @Nullable SparseArray<byte[]> val, boolean writeNull) {
|
||||
if (val == null) {
|
||||
if (writeNull) {
|
||||
writeHeader(p, id, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int start = beginVariableData(p, id);
|
||||
final int size = val.size();
|
||||
p.writeInt(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
p.writeInt(val.keyAt(i));
|
||||
p.writeByteArray(val.valueAt(i));
|
||||
}
|
||||
finishVariableData(p, start);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.gms.common.internal.safeparcel;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* A SafeParcelable is a special {@link Parcelable} interface that marshalls its fields in a
|
||||
* protobuf-like manner into a {@link Parcel}. The marshalling encodes a unique id for each field
|
||||
* along with the size in bytes of the field. By doing this, older versions of a SafeParcelable can
|
||||
* skip over unknown fields, which enables backwards compatibility. Because SafeParcelable extends a
|
||||
* Parcelable, it is NOT safe for persistence.
|
||||
*
|
||||
* <p>To prevent the need to manually write code to marshall fields like in a Parcelable, a
|
||||
* SafeParcelable implementing class is annotated with several annotations so that a generated
|
||||
* "creator" class has the metadata it needs to automatically generate the boiler plate marshalling
|
||||
* and unmarshalling code.
|
||||
*
|
||||
* <p>The main annotations are the following:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link Class} - This annotates the SafeParcelable implementing class and indicates the name
|
||||
* of the generated "creator" class that has the boiler plate marshalling/unmarshalling code.
|
||||
* You can also specify whether to call a method named validateContents() after a new instance
|
||||
* of this class is constructed.
|
||||
* <li>{@link VersionField} - This annotation may be on one field in the SafeParcelable to
|
||||
* indicate the version number for this SafeParcelable. This is purely here for style reasons
|
||||
* in case it is necessary for code to be dependent on the version of the SafeParcelable. This
|
||||
* member field must be final.
|
||||
* <li>{@link Field} - This annotates fields that will be marshalled and unmarshalled by the
|
||||
* generated "creator" class. You must provide an integer "id" for each field. To ensure
|
||||
* backwards compatibility, these field id's should never be changed. It is okay to omit field
|
||||
* id's in future versions, but do not reuse old id's. Member fields annotated with {@link
|
||||
* Field} may be any visibility (private, protected, etc.) and may also be final. You will
|
||||
* have to specify the "getter" if member fields are not at least package visible. See details
|
||||
* in {@link Field}.
|
||||
* <li>{@link Constructor} - You must annotate one constructor with this annotation, which
|
||||
* indicates the constructor that the "creator" class will use to construct a new instance of
|
||||
* this class. Each parameter to this constructor must be annotated with the {@link Param} or
|
||||
* {@link RemovedParam} annotation indicating the field id that the parameter corresponds to.
|
||||
* Every {@link Param} must correspond to a {@link Field} or {@link VersionField}, and every
|
||||
* {@link RemovedParam} must correspond to a {@link Reserved} field. Note that this
|
||||
* constructor must have at least package visibility because the generated "creator" class
|
||||
* must be able to use this constructor. (The "creator" class is generated in the same package
|
||||
* as the SafeParcelable class.).
|
||||
* <li>{@link Indicator} - This is an annotation on a field that keeps track of which fields are
|
||||
* actually present in a Parcel that represents the marshalled version of a SafeParcelable.
|
||||
* This is used in the GMS Core Apiary model class code generation.
|
||||
* </ul>
|
||||
*
|
||||
* <p>Because a SafeParcelable extends Parcelable, you must have a public static final member named
|
||||
* CREATOR and override writeToParcel() and describeContents(). Here's a typical example.
|
||||
*
|
||||
* <pre>
|
||||
* @Class(creator="MySafeParcelableCreator", validate=true)
|
||||
* public class MySafeParcelable implements SafeParcelable {
|
||||
* public static final Parcelable.Creator<MySafeParcelable> CREATOR =
|
||||
* new MySafeParcelableCreator();
|
||||
*
|
||||
* @Field(id=1)
|
||||
* public final String myString;
|
||||
*
|
||||
* @Field(id=2, getter="getInteger")
|
||||
* private final int myInteger;
|
||||
*
|
||||
* @Constructor
|
||||
* MySafeParcelable(
|
||||
* @Param(id=1) String string,
|
||||
* @Param(id=2) int integer) {
|
||||
* myString = string;
|
||||
* myInteger = integer;
|
||||
* )
|
||||
*
|
||||
* // Example public constructor (not used by MySafeParcelableCreator)
|
||||
* public MySafeParcelable(String string, int integer) {
|
||||
* myString = string;
|
||||
* myInteger = integer;
|
||||
* }
|
||||
*
|
||||
* // This is only needed if validate=true in @Class annotation.
|
||||
* public void validateContents() {
|
||||
* // Add validation here.
|
||||
* }
|
||||
*
|
||||
* // This getter is needed because myInteger is private, and the generated creator class
|
||||
* // MySafeParcelableCreator can't access private member fields.
|
||||
* int getInteger() {
|
||||
* return myInteger;
|
||||
* }
|
||||
*
|
||||
* // This is necessary because SafeParcelable extends Parcelable.
|
||||
* // {@link AbstractSafeParcelable} implements this for you.
|
||||
* @Override
|
||||
* public int describeContents() {
|
||||
* return MySafeParcelableCreator.CONTENT_DESCRIPTION;
|
||||
* }
|
||||
*
|
||||
* // This is necessary because SafeParcelable extends Parcelable.
|
||||
* @Override
|
||||
* public void writeToParcel(Parcel out, int flags) {
|
||||
* // This invokes the generated MySafeParcelableCreator class's marshalling to a Parcel.
|
||||
* // In the event you need custom logic when writing to a Parcel, that logic can be
|
||||
* // inserted here.
|
||||
* MySafeParcelableCreator.writeToParcel(this, out, flags);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface SafeParcelable extends Parcelable {
|
||||
/** @hide */
|
||||
// Note: the field name and value are accessed using reflection for backwards compatibility, and
|
||||
// must not be changed.
|
||||
String NULL = "SAFE_PARCELABLE_NULL_STRING";
|
||||
|
||||
/**
|
||||
* This annotates your class and specifies the name of the generated "creator" class for
|
||||
* marshalling/unmarshalling a SafeParcelable to/from a {@link Parcel}. The "creator" class is
|
||||
* generated in the same package as the SafeParcelable class. You can also set "validate" to
|
||||
* true, which will cause the "creator" to invoke the method validateContents() on your class
|
||||
* after constructing an instance.
|
||||
*/
|
||||
@SuppressWarnings("JavaLangClash")
|
||||
@interface Class {
|
||||
/**
|
||||
* Simple name of the generated "creator" class generated in the same package as the
|
||||
* SafeParceable.
|
||||
*/
|
||||
String creator();
|
||||
|
||||
/** Whether the generated "creator" class is final. */
|
||||
boolean creatorIsFinal() default true;
|
||||
|
||||
/**
|
||||
* When set to true, invokes the validateContents() method in this SafeParcelable object
|
||||
* after constructing a new instance.
|
||||
*/
|
||||
boolean validate() default false;
|
||||
|
||||
/**
|
||||
* When set to true, it will not write type default values to the Parcel.
|
||||
*
|
||||
* <p>boolean: false byte/char/short/int/long: 0 float: 0.0f double: 0.0 Objects/arrays:
|
||||
* null
|
||||
*
|
||||
* <p>Cannot be used with Field(defaultValue)
|
||||
*/
|
||||
boolean doNotParcelTypeDefaultValues() default false;
|
||||
}
|
||||
|
||||
/** Use this annotation on members that you wish to be marshalled in the SafeParcelable. */
|
||||
@interface Field {
|
||||
/**
|
||||
* Valid values for id are between 1 and 65535. This field id is marshalled into a Parcel .
|
||||
* To maintain backwards compatibility, never reuse old id's. It is okay to no longer use
|
||||
* old id's and add new ones in subsequent versions of a SafeParcelable.
|
||||
*/
|
||||
int id();
|
||||
|
||||
/**
|
||||
* This specifies the name of the getter method for retrieving the value of this field. This
|
||||
* must be specified for fields that do not have at least package visibility because the
|
||||
* "creator" class will be unable to access the value when attempting to marshall this
|
||||
* field. The getter method should take no parameters and return the type of this field
|
||||
* (unless overridden by the "type" attribute below).
|
||||
*/
|
||||
String getter() default NULL;
|
||||
|
||||
/**
|
||||
* For advanced uses, this specifies the type for the field when marshalling and
|
||||
* unmarshalling by the "creator" class to be something different than the declared type of
|
||||
* the member variable. This is useful if you want to incorporate an object that is not
|
||||
* SafeParcelable (or a system Parcelable object). Be sure to enter the fully qualified name
|
||||
* for the class (i.e., android.os.Bundle and not Bundle). For example,
|
||||
*
|
||||
* <pre>
|
||||
* @Class(creator="MyAdvancedCreator")
|
||||
* public class MyAdvancedSafeParcelable implements SafeParcelable {
|
||||
* public static final Parcelable.Creator<MyAdvancedSafeParcelable> CREATOR =
|
||||
* new MyAdvancedCreator();
|
||||
*
|
||||
* @Field(id=1, getter="getObjectAsBundle", type="android.os.Bundle")
|
||||
* private final MyCustomObject myObject;
|
||||
*
|
||||
* @Constructor
|
||||
* MyAdvancedSafeParcelable(
|
||||
* @Param(id=1) Bundle objectAsBundle) {
|
||||
* myObject = myConvertFromBundleToObject(objectAsBundle);
|
||||
* }
|
||||
*
|
||||
* Bundle getObjectAsBundle() {
|
||||
* // The code here can convert your custom object to one that can be parcelled.
|
||||
* return myConvertFromObjectToBundle(myObject);
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
String type() default NULL;
|
||||
|
||||
/**
|
||||
* This can be used to specify the default value for primitive types (e.g., boolean, int,
|
||||
* long), primitive type object wrappers (e.g., Boolean, Integer, Long) and String in the
|
||||
* case a value for a field was not explicitly set in the marshalled Parcel. This performs
|
||||
* compile-time checks for the type of the field and inserts the appropriate quotes or
|
||||
* double quotes around strings and chars or removes them completely for booleans and
|
||||
* numbers. To insert a generic string for initializing field, use {@link
|
||||
* #defaultValueUnchecked()}. You can specify at most one of {@link #defaultValue()} or
|
||||
* {@link #defaultValueUnchecked()}. For example,
|
||||
*
|
||||
* <pre>
|
||||
* @Field(id=2, defaultValue="true")
|
||||
* boolean myBoolean;
|
||||
*
|
||||
* @Field(id=3, defaultValue="13")
|
||||
* Integer myInteger;
|
||||
*
|
||||
* @Field(id=4, defaultValue="foo")
|
||||
* String myString;
|
||||
* </pre>
|
||||
*/
|
||||
String defaultValue() default NULL;
|
||||
|
||||
/**
|
||||
* This can be used to specify the default value for any object and the string value is
|
||||
* literally added to the generated creator class code unchecked. You can specify at most
|
||||
* one of {@link #defaultValue()} or {@link #defaultValueUnchecked()}. You must fully
|
||||
* qualify any classes you reference within the string. For example,
|
||||
*
|
||||
* <pre>
|
||||
* @Field(id=2, defaultValueUnchecked="new android.os.Bundle()")
|
||||
* Bundle myBundle;
|
||||
* </pre>
|
||||
*/
|
||||
String defaultValueUnchecked() default NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* There may be exactly one member annotated with VersionField, which represents the version of
|
||||
* this safe parcelable. The attributes are the same as those of {@link Field}. Note you can use
|
||||
* any type you want for your version field, although most people use int's.
|
||||
*/
|
||||
@interface VersionField {
|
||||
int id();
|
||||
|
||||
String getter() default NULL;
|
||||
|
||||
String type() default NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to indicate the member field that holds whether a field was set or not. The member
|
||||
* field type currently supported is a HashSet<Integer> which is the set of safe
|
||||
* parcelable field id's that have been explicitly set.
|
||||
*
|
||||
* <p>This annotation should also be used to annotate one of the parameters to the constructor
|
||||
* annotated with @Constructor. Note that this annotation should either be present on
|
||||
* exactly one member field and one constructor parameter or left out completely.
|
||||
*/
|
||||
@interface Indicator {
|
||||
String getter() default NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to indicate the constructor that the creator should use. The constructor annotated
|
||||
* with this must be package or public visibility, so that the generated "creator" class can
|
||||
* invoke this.
|
||||
*/
|
||||
@interface Constructor {}
|
||||
|
||||
/**
|
||||
* Use this on each parameter passed in to the Constructor to indicate to which field id each
|
||||
* formal parameter corresponds.
|
||||
*/
|
||||
@interface Param {
|
||||
int id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this on a parameter passed in to the Constructor to indicate that a removed field should
|
||||
* be read on construction. If the field is not present when read, the default value will be
|
||||
* used instead.
|
||||
*/
|
||||
@interface RemovedParam {
|
||||
int id();
|
||||
|
||||
String defaultValue() default NULL;
|
||||
|
||||
String defaultValueUnchecked() default NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to mark tombstones for removed {@link Field Fields} or {@link VersionField
|
||||
* VersionFields}.
|
||||
*/
|
||||
@interface Reserved {
|
||||
int[] value();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue