summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/protos
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/dialer/protos')
-rw-r--r--java/com/android/dialer/protos/ProtoParsers.java167
1 files changed, 167 insertions, 0 deletions
diff --git a/java/com/android/dialer/protos/ProtoParsers.java b/java/com/android/dialer/protos/ProtoParsers.java
new file mode 100644
index 000000000..7dfbc7c5e
--- /dev/null
+++ b/java/com/android/dialer/protos/ProtoParsers.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 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.android.dialer.protos;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.android.dialer.common.Assert;
+import com.google.protobuf.nano.CodedOutputByteBufferNano;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+import com.google.protobuf.nano.MessageNano;
+import java.io.IOException;
+
+/** Useful methods for using Protocol Buffers with Android. */
+public final class ProtoParsers {
+
+ private ProtoParsers() {}
+
+ /** Retrieve a proto from a Bundle */
+ @SuppressWarnings("unchecked") // We want to eventually optimize away parser classes, so cast
+ public static <T extends MessageNano> T get(Bundle bundle, String key, T defaultInstance)
+ throws InvalidProtocolBufferNanoException {
+ InternalDontUse parcelable = bundle.getParcelable(key);
+ return (T) parcelable.getMessageUnsafe(defaultInstance);
+ }
+
+ /**
+ * Retrieve a proto from a trusted bundle
+ *
+ * @throws RuntimeException if the proto cannot be parsed
+ */
+ public static <T extends MessageNano> T getFromInstanceState(
+ Bundle bundle, String key, T defaultInstance) {
+ try {
+ return get(bundle, key, defaultInstance);
+ } catch (InvalidProtocolBufferNanoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Stores a proto in a Bundle, for later retrieval by {@link #get(Bundle, String, MessageNano)} or
+ * {@link #getFromInstanceState(Bundle, String, MessageNano)}.
+ */
+ public static void put(Bundle bundle, String key, MessageNano message) {
+ bundle.putParcelable(key, new InternalDontUse<>(null, message));
+ }
+
+ /**
+ * Stores a proto in an Intent, for later retrieval by {@link #get(Bundle, String, MessageNano)}.
+ * Needs separate method because Intent has similar to but different API than Bundle.
+ */
+ public static void put(Intent intent, String key, MessageNano message) {
+ intent.putExtra(key, new InternalDontUse<>(null, message));
+ }
+
+ /** Returns a {@linkplain Parcelable} representation of this protobuf message. */
+ public static <T extends MessageNano> ParcelableProto<T> asParcelable(T message) {
+ return new InternalDontUse<>(null, message);
+ }
+
+ /**
+ * A protobuf message that can be stored in a {@link Parcel}.
+ *
+ * <p><b>Note:</b> This <code>Parcelable</code> can only be used in single app. Attempting to send
+ * it to another app through an <code>Intent</code> will result in an exception due to Proguard
+ * obfusation when the target application attempts to load the <code>ParcelableProto</code> class.
+ */
+ public interface ParcelableProto<T extends MessageNano> extends Parcelable {
+ /**
+ * @throws IllegalStateException if the parceled data does not correspond to the defaultInstance
+ * type.
+ */
+ T getMessage(T defaultInstance);
+ }
+
+ /** Public because of Parcelable requirements. Do not use. */
+ public static final class InternalDontUse<T extends MessageNano> implements ParcelableProto<T> {
+ /* One of these two fields is always populated - since the bytes field never escapes this
+ * object, there is no risk of concurrent modification by multiple threads, and volatile
+ * is sufficient to be thread-safe. */
+ private volatile byte[] bytes;
+ private volatile T message;
+
+ /**
+ * Ideally, we would have type safety here. However, a static field {@link Creator} is required
+ * by {@link Parcelable}. Static fields are inherently not type safe, since only 1 exists per
+ * class (rather than 1 per type).
+ */
+ public static final Parcelable.Creator<InternalDontUse<?>> CREATOR =
+ new Creator<InternalDontUse<?>>() {
+ @Override
+ public InternalDontUse<?> createFromParcel(Parcel parcel) {
+ int serializedSize = parcel.readInt();
+ byte[] array = new byte[serializedSize];
+ parcel.readByteArray(array);
+ return new InternalDontUse<>(array, null);
+ }
+
+ @Override
+ public InternalDontUse<?>[] newArray(int i) {
+ return new InternalDontUse[i];
+ }
+ };
+
+ private InternalDontUse(byte[] bytes, T message) {
+ Assert.checkArgument(bytes != null || message != null);
+ this.bytes = bytes;
+ this.message = message;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ if (bytes == null) {
+ final byte[] flatArray = new byte[message.getSerializedSize()];
+ try {
+ message.writeTo(CodedOutputByteBufferNano.newInstance(flatArray));
+ bytes = flatArray;
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+ parcel.writeInt(bytes.length);
+ parcel.writeByteArray(bytes);
+ }
+
+ @Override
+ public T getMessage(T defaultInstance) {
+ try {
+ // The proto should never be invalid if it came from our application, so if it is, throw.
+ return getMessageUnsafe(defaultInstance);
+ } catch (InvalidProtocolBufferNanoException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked") // We're being deserialized, so there's no real type safety
+ T getMessageUnsafe(T defaultInstance) throws InvalidProtocolBufferNanoException {
+ // There's a risk that we'll double-parse the bytes, but that's OK, because it'll end up
+ // as the same immutable object anyway.
+ if (message == null) {
+ message = MessageNano.mergeFrom(defaultInstance, bytes);
+ }
+ return message;
+ }
+ }
+}