• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2016, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.car.stream;
17 
18 import android.os.Bundle;
19 import android.os.Parcel;
20 import android.os.Parcelable;
21 import android.support.annotation.VisibleForTesting;
22 import android.util.Log;
23 
24 import java.lang.reflect.Array;
25 
26 /**
27  * Base class for Parcelable classes that serialize/deserialize themselves using Bundles for
28  * backward compatibility.
29  *
30  * <p>
31  * By using Bundles which require explicit key-value pairs, unknown fields can be handled
32  * gracefully. Also, by ensuring that custom classes are serialized to a Bundle containing
33  * primitives or system classes only, ClassNotFoundExceptions can be prevented when deserializing.
34  * </p>
35  *
36  * <p>
37  * Subclass must expose a default constructor, implement {@link #writeToBundle(Bundle)} and
38  * {@link #readFromBundle(Bundle)} instead of {@link #writeToParcel(Parcel, int)}.
39  * It should also define a CREATOR, as required of all Parcelables, by instantiating a
40  * {@link BundleableCreator}.
41  *
42  * Example:
43  *
44  * public static final Creator<MyClass> CREATOR = new BundleableCreator<>(MyClass.class);
45  *
46  * @Override
47  * protected void writeToBundle(Bundle bundle) {
48  *     bundle.putInt(FIRST_FIELD_KEY, mFirstField);
49  *     if (mCustomField != null) {
50  *         Bundle customFieldBundle = new Bundle();
51  *         mCustomField.writeToBundle(customFieldBundle);
52  *         bundle.putBundle(CUSTOM_FIELD_KEY, customFieldBundle);
53  *     }
54  *     bundle.putParcelable(INTENT_KEY, mIntent);
55  * }
56  *
57  * @Override
58  * protected void readFromBundle(Bundle bundle) {
59  *     mFirstField = bundle.getInt(FIRST_FIELD_KEY);
60  *     Bundle customFieldBundle = bundle.getBundle(CUSTOM_FIELD_KEY);
61  *     if (customFieldBundle != null) {
62  *         mCustomField = new CustomClass();
63  *         mCustomField.readFromBundle(customFieldBundle);
64  *     }
65  *     mIntent = bundle.getParcelable(INTENT_KEY);
66  * }
67  * </p>
68  *
69  * <p>
70  * All subclasses should be added to BundleableTest#BUNDLEABLE_CLASSES list to be tested.
71  * </p>
72  */
73 public abstract class AbstractBundleable implements Parcelable {
74     private static final String TAG = "Bundleable";
75 
76     /**
77      * Creator class for unmarshalling subclasses of {@link AbstractBundleable}.
78      */
79     @VisibleForTesting
80     public static class BundleableCreator<T extends AbstractBundleable>
81             implements Creator<T> {
82         private Class<T> clazz;
83 
BundleableCreator(Class<T> bundleableClazz)84         public BundleableCreator(Class<T> bundleableClazz) {
85             clazz = bundleableClazz;
86         }
87 
88         @Override
createFromParcel(Parcel source)89         public final T createFromParcel(Parcel source) {
90             T instance = null;
91             try {
92                 instance = clazz.newInstance();
93                 instance.readFromBundle(source.readBundle());
94             } catch (Exception e) {
95                 Log.e(TAG, "Failed to instantiate " + clazz.getSimpleName(), e);
96             }
97             return instance;
98         }
99 
100         @SuppressWarnings("unchecked")
101         @Override
newArray(int size)102         public final T[] newArray(int size) {
103             return (T[]) Array.newInstance(clazz, size);
104         }
105     }
106 
107     @Override
describeContents()108     public final int describeContents() {
109         return 0;
110     }
111 
112     @Override
writeToParcel(Parcel dest, int flags)113     public final void writeToParcel(Parcel dest, int flags) {
114         Bundle bundle = new Bundle();
115         writeToBundle(bundle);
116         dest.writeBundle(bundle);
117     }
118 
119     @Override
toString()120     public String toString() {
121         Bundle bundle = new Bundle();
122         writeToBundle(bundle);
123         return bundle.toString();
124     }
125 
126     /**
127      * Writes the states of the instance to the given Bundle. Only primitives or system classes
128      * can be written into the Bundle. If a field of a custom class needs to be serialized,
129      * serialize it into a new Bundle, and then write that Bundle into the outer Bundle. A list or
130      * array of custom class instances should similarly be converted into an array of Bundles first.
131      */
writeToBundle(Bundle bundle)132     protected abstract void writeToBundle(Bundle bundle);
133 
134     /**
135      * Reads the states saved in the Bundle into the current instance. The implementation should
136      * mirror that of {@link #writeToBundle(Bundle)}.
137      */
readFromBundle(Bundle bundle)138     protected abstract void readFromBundle(Bundle bundle);
139 }