Add inheritance support for parcelable dataclasses

We don't want to recommend this, but some legacy framework classes use
inheritance, and it's easy enough to support

Fixes: 142081378
Test: . frameworks/base/tests/Codegen/runTest.sh
Change-Id: Ifb7f34abf1dfb871ac01b9a9a38dfee144e5f49a
diff --git a/tests/Codegen/runTest.sh b/tests/Codegen/runTest.sh
index 01522735..bb3f5b2 100755
--- a/tests/Codegen/runTest.sh
+++ b/tests/Codegen/runTest.sh
@@ -14,6 +14,8 @@
         header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java && \
         header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java && \
         header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java && \
+        header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java && \
+        header_and_eval codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java && \
         cd $ANDROID_BUILD_TOP &&
         header_and_eval mmma -j16 frameworks/base/tests/Codegen && \
         header_and_eval adb install -r -t $ANDROID_PRODUCT_OUT/testcases/CodegenTests/arm64/CodegenTests.apk && \
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.aidl b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.aidl
new file mode 100644
index 0000000..ab62c83
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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.codegentest;
+
+parcelable HierrarchicalDataClassBase;
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
new file mode 100644
index 0000000..9e9ddae4
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 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.codegentest;
+
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * @see HierrarchicalDataClassChild
+ */
+@DataClass(
+        genConstructor = false,
+        genSetters = true)
+public class HierrarchicalDataClassBase implements Parcelable {
+
+    private int mBaseData;
+
+
+
+    // Code below generated by codegen v1.0.5.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java
+
+
+    @DataClass.Generated.Member
+    public int getBaseData() {
+        return mBaseData;
+    }
+
+    @DataClass.Generated.Member
+    public HierrarchicalDataClassBase setBaseData(int value) {
+        mBaseData = value;
+        return this;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeInt(mBaseData);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected HierrarchicalDataClassBase(android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        int baseData = in.readInt();
+
+        this.mBaseData = baseData;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @android.annotation.NonNull Parcelable.Creator<HierrarchicalDataClassBase> CREATOR
+            = new Parcelable.Creator<HierrarchicalDataClassBase>() {
+        @Override
+        public HierrarchicalDataClassBase[] newArray(int size) {
+            return new HierrarchicalDataClassBase[size];
+        }
+
+        @Override
+        public HierrarchicalDataClassBase createFromParcel(android.os.Parcel in) {
+            return new HierrarchicalDataClassBase(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1570231100269L,
+            codegenVersion = "1.0.5",
+            sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassBase.java",
+            inputSignatures = "private  int mBaseData\nclass HierrarchicalDataClassBase extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genSetters=true)")
+    @Deprecated
+    private void __metadata() {}
+
+}
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.aidl b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.aidl
new file mode 100644
index 0000000..a099722
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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.codegentest;
+
+parcelable HierrarchicalDataClassChild;
diff --git a/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
new file mode 100644
index 0000000..27a6933
--- /dev/null
+++ b/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 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.codegentest;
+
+import android.annotation.NonNull;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * An example of data classes that extend one another.
+ *
+ * Note that some features like constructor generation might not work well due to lack of
+ * information about the superclass when generating code for subclass.
+ *
+ * It is recommended to avoid inheritance in favor of composition for new data classes,
+ * particularly parcelable ones.
+ *
+ * However for legacy classes or where inheritance is desired for allocation efficiency,
+ * you can either use a technique from this example, opting for mutability/setters, or just write
+ * constructors by hand.
+ *
+ * @see HierrarchicalDataClassBase
+ */
+@DataClass(
+        genParcelable = true,
+        genConstructor = false,
+        genSetters = true)
+public class HierrarchicalDataClassChild extends HierrarchicalDataClassBase {
+
+    private @NonNull String mChildData;
+
+
+
+    // Code below generated by codegen v1.0.5.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java
+
+
+    @DataClass.Generated.Member
+    public @NonNull String getChildData() {
+        return mChildData;
+    }
+
+    @DataClass.Generated.Member
+    public HierrarchicalDataClassChild setChildData(@NonNull String value) {
+        mChildData = value;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mChildData);
+        return this;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        super.writeToParcel(dest, flags);
+
+        dest.writeString(mChildData);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected HierrarchicalDataClassChild(android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        super(in);
+
+        String childData = in.readString();
+
+        this.mChildData = childData;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mChildData);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<HierrarchicalDataClassChild> CREATOR
+            = new Parcelable.Creator<HierrarchicalDataClassChild>() {
+        @Override
+        public HierrarchicalDataClassChild[] newArray(int size) {
+            return new HierrarchicalDataClassChild[size];
+        }
+
+        @Override
+        public HierrarchicalDataClassChild createFromParcel(android.os.Parcel in) {
+            return new HierrarchicalDataClassChild(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1570231101208L,
+            codegenVersion = "1.0.5",
+            sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/HierrarchicalDataClassChild.java",
+            inputSignatures = "private @android.annotation.NonNull java.lang.String mChildData\nclass HierrarchicalDataClassChild extends com.android.codegentest.HierrarchicalDataClassBase implements []\n@com.android.internal.util.DataClass(genParcelable=true, genConstructor=false, genSetters=true)")
+    @Deprecated
+    private void __metadata() {}
+
+}
diff --git a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
index 2d41257..dafece1 100644
--- a/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java
@@ -48,7 +48,7 @@
 
 
 
-    // Code below generated by codegen v1.0.4.
+    // Code below generated by codegen v1.0.5.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -162,6 +162,49 @@
     @DataClass.Generated.Member
     public int describeContents() { return 0; }
 
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected ParcelAllTheThingsDataClass(Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        String[] stringArray = in.createStringArray();
+        int[] intArray = in.createIntArray();
+        List<String> stringList = new java.util.ArrayList<>();
+        in.readStringList(stringList);
+        Map<String,SampleWithCustomBuilder> map = new java.util.LinkedHashMap<>();
+        in.readMap(map, SampleWithCustomBuilder.class.getClassLoader());
+        Map<String,String> stringMap = new java.util.LinkedHashMap<>();
+        in.readMap(stringMap, String.class.getClassLoader());
+        SparseArray<SampleWithCustomBuilder> sparseArray = (SparseArray) in.readSparseArray(SampleWithCustomBuilder.class.getClassLoader());
+        SparseIntArray sparseIntArray = (SparseIntArray) in.readSparseIntArray();
+
+        this.mStringArray = stringArray;
+        AnnotationValidations.validate(
+                NonNull.class, null, mStringArray);
+        this.mIntArray = intArray;
+        AnnotationValidations.validate(
+                NonNull.class, null, mIntArray);
+        this.mStringList = stringList;
+        AnnotationValidations.validate(
+                NonNull.class, null, mStringList);
+        this.mMap = map;
+        AnnotationValidations.validate(
+                NonNull.class, null, mMap);
+        this.mStringMap = stringMap;
+        AnnotationValidations.validate(
+                NonNull.class, null, mStringMap);
+        this.mSparseArray = sparseArray;
+        AnnotationValidations.validate(
+                NonNull.class, null, mSparseArray);
+        this.mSparseIntArray = sparseIntArray;
+        AnnotationValidations.validate(
+                NonNull.class, null, mSparseIntArray);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
     @DataClass.Generated.Member
     public static final @NonNull Parcelable.Creator<ParcelAllTheThingsDataClass> CREATOR
             = new Parcelable.Creator<ParcelAllTheThingsDataClass>() {
@@ -171,29 +214,8 @@
         }
 
         @Override
-        @SuppressWarnings({"unchecked", "RedundantCast"})
         public ParcelAllTheThingsDataClass createFromParcel(Parcel in) {
-            // You can override field unparcelling by defining methods like:
-            // static FieldType unparcelFieldName(Parcel in) { ... }
-
-            String[] stringArray = in.createStringArray();
-            int[] intArray = in.createIntArray();
-            List<String> stringList = new java.util.ArrayList<>();
-            in.readStringList(stringList);
-            Map<String,SampleWithCustomBuilder> map = new java.util.LinkedHashMap<>();
-            in.readMap(map, SampleWithCustomBuilder.class.getClassLoader());
-            Map<String,String> stringMap = new java.util.LinkedHashMap<>();
-            in.readMap(stringMap, String.class.getClassLoader());
-            SparseArray<SampleWithCustomBuilder> sparseArray = (SparseArray) in.readSparseArray(SampleWithCustomBuilder.class.getClassLoader());
-            SparseIntArray sparseIntArray = (SparseIntArray) in.readSparseIntArray();
-            return new ParcelAllTheThingsDataClass(
-                    stringArray,
-                    intArray,
-                    stringList,
-                    map,
-                    stringMap,
-                    sparseArray,
-                    sparseIntArray);
+            return new ParcelAllTheThingsDataClass(in);
         }
     };
 
@@ -352,8 +374,8 @@
     }
 
     @DataClass.Generated(
-            time = 1570139502128L,
-            codegenVersion = "1.0.4",
+            time = 1570231099316L,
+            codegenVersion = "1.0.5",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/ParcelAllTheThingsDataClass.java",
             inputSignatures = " @android.annotation.NonNull java.lang.String[] mStringArray\n @android.annotation.NonNull int[] mIntArray\n @android.annotation.NonNull java.util.List<java.lang.String> mStringList\n @android.annotation.NonNull java.util.Map<java.lang.String,com.android.codegentest.SampleWithCustomBuilder> mMap\n @android.annotation.NonNull java.util.Map<java.lang.String,java.lang.String> mStringMap\n @android.annotation.NonNull android.util.SparseArray<com.android.codegentest.SampleWithCustomBuilder> mSparseArray\n @android.annotation.NonNull android.util.SparseIntArray mSparseIntArray\nclass ParcelAllTheThingsDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index 0631f7d..1d73736 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -342,7 +342,7 @@
 
 
 
-    // Code below generated by codegen v1.0.4.
+    // Code below generated by codegen v1.0.5.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -1290,6 +1290,123 @@
     @DataClass.Generated.Member
     public int describeContents() { return 0; }
 
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ SampleDataClass(Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        long flg = in.readLong();
+        int num = in.readInt();
+        int num2 = in.readInt();
+        int num4 = in.readInt();
+        String name = (flg & 0x8) == 0 ? null : in.readString();
+        String name2 = in.readString();
+        String name4 = in.readString();
+        AccessibilityNodeInfo otherParcelable = (flg & 0x40) == 0 ? null : (AccessibilityNodeInfo) in.readTypedObject(AccessibilityNodeInfo.CREATOR);
+        Date date = sParcellingForDate.unparcel(in);
+        Pattern pattern = sParcellingForPattern.unparcel(in);
+        List<LinkAddress> linkAddresses2 = new ArrayList<>();
+        in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader());
+        ArrayList<LinkAddress> linkAddresses = new ArrayList<>();
+        in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader());
+        LinkAddress[] linkAddresses4 = (flg & 0x800) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
+        String stateName = in.readString();
+        int flags = in.readInt();
+        int state = in.readInt();
+        CharSequence _charSeq = (CharSequence) in.readCharSequence();
+        LinkAddress[] linkAddresses5 = (flg & 0x10000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
+        int stringRes = in.readInt();
+        int dayOfWeek = in.readInt();
+        float[] coords = in.createFloatArray();
+
+        this.mNum = num;
+        this.mNum2 = num2;
+        this.mNum4 = num4;
+        this.mName = name;
+        this.mName2 = name2;
+        AnnotationValidations.validate(
+                NonNull.class, null, mName2);
+        this.mName4 = name4;
+        AnnotationValidations.validate(
+                NonNull.class, null, mName4);
+        this.mOtherParcelable = otherParcelable;
+        this.mDate = date;
+        AnnotationValidations.validate(
+                NonNull.class, null, mDate);
+        this.mPattern = pattern;
+        AnnotationValidations.validate(
+                NonNull.class, null, mPattern);
+        this.mLinkAddresses2 = linkAddresses2;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses2);
+        this.mLinkAddresses = linkAddresses;
+        AnnotationValidations.validate(
+                NonNull.class, null, mLinkAddresses);
+        this.mLinkAddresses4 = linkAddresses4;
+        this.mStateName = stateName;
+
+        if (!(Objects.equals(mStateName, STATE_NAME_UNDEFINED))
+                && !(Objects.equals(mStateName, STATE_NAME_ON))
+                && !(Objects.equals(mStateName, STATE_NAME_OFF))) {
+            throw new java.lang.IllegalArgumentException(
+                    "stateName was " + mStateName + " but must be one of: "
+                            + "STATE_NAME_UNDEFINED(" + STATE_NAME_UNDEFINED + "), "
+                            + "STATE_NAME_ON(" + STATE_NAME_ON + "), "
+                            + "STATE_NAME_OFF(" + STATE_NAME_OFF + ")");
+        }
+
+        AnnotationValidations.validate(
+                NonNull.class, null, mStateName);
+        this.mFlags = flags;
+
+        Preconditions.checkFlagsArgument(
+                mFlags,
+                FLAG_MANUAL_REQUEST
+                        | FLAG_COMPATIBILITY_MODE_REQUEST
+                        | FLAG_AUGMENTED_REQUEST);
+        this.mState = state;
+
+        if (!(mState == STATE_UNDEFINED)
+                && !(mState == STATE_ON)
+                && !(mState == STATE_OFF)) {
+            throw new java.lang.IllegalArgumentException(
+                    "state was " + mState + " but must be one of: "
+                            + "STATE_UNDEFINED(" + STATE_UNDEFINED + "), "
+                            + "STATE_ON(" + STATE_ON + "), "
+                            + "STATE_OFF(" + STATE_OFF + ")");
+        }
+
+        this.charSeq = _charSeq;
+        AnnotationValidations.validate(
+                NonNull.class, null, charSeq);
+        this.mLinkAddresses5 = linkAddresses5;
+        this.mStringRes = stringRes;
+        AnnotationValidations.validate(
+                StringRes.class, null, mStringRes);
+        this.mDayOfWeek = dayOfWeek;
+        AnnotationValidations.validate(
+                android.annotation.IntRange.class, null, mDayOfWeek,
+                "from", 0,
+                "to", 6);
+        this.mCoords = coords;
+        AnnotationValidations.validate(
+                Size.class, null, mCoords.length,
+                "value", 2);
+        AnnotationValidations.validate(
+                NonNull.class, null, mCoords);
+        int coordsSize = mCoords.length;
+        for (int i = 0; i < coordsSize; i++) {
+            AnnotationValidations.validate(
+                    FloatRange.class, null, mCoords[i],
+                    "from", 0f);
+        }
+
+
+        onConstructed();
+    }
+
     @DataClass.Generated.Member
     public static final @NonNull Parcelable.Creator<SampleDataClass> CREATOR
             = new Parcelable.Creator<SampleDataClass>() {
@@ -1299,55 +1416,8 @@
         }
 
         @Override
-        @SuppressWarnings({"unchecked", "RedundantCast"})
         public SampleDataClass createFromParcel(Parcel in) {
-            // You can override field unparcelling by defining methods like:
-            // static FieldType unparcelFieldName(Parcel in) { ... }
-
-            long flg = in.readLong();
-            int num = in.readInt();
-            int num2 = in.readInt();
-            int num4 = in.readInt();
-            String name = (flg & 0x8) == 0 ? null : in.readString();
-            String name2 = in.readString();
-            String name4 = in.readString();
-            AccessibilityNodeInfo otherParcelable = (flg & 0x40) == 0 ? null : (AccessibilityNodeInfo) in.readTypedObject(AccessibilityNodeInfo.CREATOR);
-            Date date = sParcellingForDate.unparcel(in);
-            Pattern pattern = sParcellingForPattern.unparcel(in);
-            List<LinkAddress> linkAddresses2 = new ArrayList<>();
-            in.readParcelableList(linkAddresses2, LinkAddress.class.getClassLoader());
-            ArrayList<LinkAddress> linkAddresses = new ArrayList<>();
-            in.readParcelableList(linkAddresses, LinkAddress.class.getClassLoader());
-            LinkAddress[] linkAddresses4 = (flg & 0x800) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
-            String stateName = in.readString();
-            int flags = in.readInt();
-            int state = in.readInt();
-            CharSequence _charSeq = (CharSequence) in.readCharSequence();
-            LinkAddress[] linkAddresses5 = (flg & 0x10000) == 0 ? null : (LinkAddress[]) in.createTypedArray(LinkAddress.CREATOR);
-            int stringRes = in.readInt();
-            int dayOfWeek = in.readInt();
-            float[] coords = in.createFloatArray();
-            return new SampleDataClass(
-                    num,
-                    num2,
-                    num4,
-                    name,
-                    name2,
-                    name4,
-                    otherParcelable,
-                    date,
-                    pattern,
-                    linkAddresses2,
-                    linkAddresses,
-                    linkAddresses4,
-                    stateName,
-                    flags,
-                    state,
-                    _charSeq,
-                    linkAddresses5,
-                    stringRes,
-                    dayOfWeek,
-                    coords);
+            return new SampleDataClass(in);
         }
     };
 
@@ -1798,8 +1868,8 @@
     }
 
     @DataClass.Generated(
-            time = 1570139500112L,
-            codegenVersion = "1.0.4",
+            time = 1570231097226L,
+            codegenVersion = "1.0.5",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
             inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_UNDEFINED\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static  java.lang.String defaultName4()\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index 0f8c663..2efa193 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -85,7 +85,7 @@
 
 
 
-    // Code below generated by codegen v1.0.4.
+    // Code below generated by codegen v1.0.5.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -151,6 +151,26 @@
     @DataClass.Generated.Member
     public int describeContents() { return 0; }
 
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected SampleWithCustomBuilder(Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        long _delayAmount = in.readLong();
+        TimeUnit _delayUnit = unparcelDelayUnit(in);
+        long _creationTimestamp = in.readLong();
+
+        this.delayAmount = _delayAmount;
+        this.delayUnit = _delayUnit;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, delayUnit);
+        this.creationTimestamp = _creationTimestamp;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
     @DataClass.Generated.Member
     public static final @NonNull Parcelable.Creator<SampleWithCustomBuilder> CREATOR
             = new Parcelable.Creator<SampleWithCustomBuilder>() {
@@ -160,18 +180,8 @@
         }
 
         @Override
-        @SuppressWarnings({"unchecked", "RedundantCast"})
         public SampleWithCustomBuilder createFromParcel(Parcel in) {
-            // You can override field unparcelling by defining methods like:
-            // static FieldType unparcelFieldName(Parcel in) { ... }
-
-            long _delayAmount = in.readLong();
-            TimeUnit _delayUnit = unparcelDelayUnit(in);
-            long _creationTimestamp = in.readLong();
-            return new SampleWithCustomBuilder(
-                    _delayAmount,
-                    _delayUnit,
-                    _creationTimestamp);
+            return new SampleWithCustomBuilder(in);
         }
     };
 
@@ -239,8 +249,8 @@
     }
 
     @DataClass.Generated(
-            time = 1570139501160L,
-            codegenVersion = "1.0.4",
+            time = 1570231098303L,
+            codegenVersion = "1.0.5",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
             inputSignatures = "  long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n  long creationTimestamp\nprivate static  java.util.concurrent.TimeUnit unparcelDelayUnit(android.os.Parcel)\nprivate  void parcelDelayUnit(android.os.Parcel,int)\nclass SampleWithCustomBuilder extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genAidl=false, genToString=true)\nabstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic  com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
diff --git a/tools/codegen/src/com/android/codegen/ClassInfo.kt b/tools/codegen/src/com/android/codegen/ClassInfo.kt
index 5061be2..92da9da 100644
--- a/tools/codegen/src/com/android/codegen/ClassInfo.kt
+++ b/tools/codegen/src/com/android/codegen/ClassInfo.kt
@@ -38,6 +38,11 @@
     val superInterfaces = (fileAst.types[0] as ClassOrInterfaceDeclaration)
             .implementedTypes.map { it.asString() }
 
+    val superClass = run {
+        val superClasses = (fileAst.types[0] as ClassOrInterfaceDeclaration).extendedTypes
+        if (superClasses.isNonEmpty) superClasses[0] else null
+    }
+
     val ClassName = classAst.nameAsString
     private val genericArgsAst = classAst.typeParameters
     val genericArgs = if (genericArgsAst.isEmpty()) "" else {
diff --git a/tools/codegen/src/com/android/codegen/ClassPrinter.kt b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
index 1f0d4b8..bd72d9e 100644
--- a/tools/codegen/src/com/android/codegen/ClassPrinter.kt
+++ b/tools/codegen/src/com/android/codegen/ClassPrinter.kt
@@ -1,6 +1,7 @@
 package com.android.codegen
 
 import com.github.javaparser.ast.Modifier
+import com.github.javaparser.ast.body.CallableDeclaration
 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
 import com.github.javaparser.ast.body.TypeDeclaration
 import com.github.javaparser.ast.expr.*
@@ -37,6 +38,7 @@
     val GeneratedMember by lazy { classRef("com.android.internal.util.DataClass.Generated.Member") }
     val Parcelling by lazy { classRef("com.android.internal.util.Parcelling") }
     val Parcelable by lazy { classRef("android.os.Parcelable") }
+    val Parcel by lazy { classRef("android.os.Parcel") }
     val UnsupportedAppUsage by lazy { classRef("android.annotation.UnsupportedAppUsage") }
 
     init {
@@ -354,7 +356,9 @@
     }
 
     fun hasMethod(name: String, vararg argTypes: String): Boolean {
-        return classAst.methods.any {
+        val members: List<CallableDeclaration<*>> =
+                if (name == ClassName) classAst.constructors else classAst.methods
+        return members.any {
             it.name.asString() == name &&
                     it.parameters.map { it.type.asString() } == argTypes.toList()
         }
@@ -365,6 +369,10 @@
             .mapIndexed { i, node -> FieldInfo(index = i, fieldAst = node, classInfo = this) }
             .filter { hasMethod("lazyInit${it.NameUpperCamel}") }
 
+    val extendsParcelableClass by lazy {
+        Parcelable !in superInterfaces && superClass != null
+    }
+
     init {
         val builderFactoryOverride = classAst.methods.find {
             it.isStatic && it.nameAsString == "builder"
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 8653405..5a95676 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -422,6 +422,10 @@
             +"// void parcelFieldName(Parcel dest, int flags) { ... }"
             +""
 
+            if (extendsParcelableClass) {
+                +"super.writeToParcel(dest, flags);\n"
+            }
+
             if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) {
                 +"$flagStorageType flg = 0;"
                 booleanFields.forEachApply {
@@ -463,6 +467,123 @@
         +""
     }
 
+    if (!hasMethod(ClassName, Parcel)) {
+        val visibility = if (classAst.isFinal) "/* package-private */" else "protected"
+
+        +"/** @hide */"
+        +"@SuppressWarnings({\"unchecked\", \"RedundantCast\"})"
+        +GENERATED_MEMBER_HEADER
+        "$visibility $ClassName($Parcel in) {" {
+            +"// You can override field unparcelling by defining methods like:"
+            +"// static FieldType unparcelFieldName(Parcel in) { ... }"
+            +""
+
+            if (extendsParcelableClass) {
+                +"super(in);\n"
+            }
+
+            if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) {
+                +"$flagStorageType flg = in.read$FlagStorageType();"
+            }
+            booleanFields.forEachApply {
+                +"$Type $_name = (flg & $fieldBit) != 0;"
+            }
+            nonBooleanFields.forEachApply {
+
+                // Handle customized parceling
+                val customParcellingMethod = "unparcel$NameUpperCamel"
+                if (hasMethod(customParcellingMethod, Parcel)) {
+                    +"$Type $_name = $customParcellingMethod(in);"
+                } else if (customParcellingClass != null) {
+                    +"$Type $_name = $sParcelling.unparcel(in);"
+                } else if (hasAnnotation("@$DataClassEnum")) {
+                    val ordinal = "${_name}Ordinal"
+                    +"int $ordinal = in.readInt();"
+                    +"$Type $_name = $ordinal < 0 ? null : $FieldClass.values()[$ordinal];"
+                } else {
+                    val methodArgs = mutableListOf<String>()
+
+                    // Create container if any
+                    val containerInitExpr = when {
+                        FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()"
+                        FieldClass == "List" || FieldClass == "ArrayList" ->
+                            "new ${classRef("java.util.ArrayList")}<>()"
+                        else -> ""
+                    }
+                    val passContainer = containerInitExpr.isNotEmpty()
+
+                    // nullcheck +
+                    // "FieldType fieldName = (FieldType)"
+                    if (passContainer) {
+                        methodArgs.add(_name)
+                        !"$Type $_name = "
+                        if (mayBeNull) {
+                            +"null;"
+                            !"if ((flg & $fieldBit) != 0) {"
+                            pushIndent()
+                            +""
+                            !"$_name = "
+                        }
+                        +"$containerInitExpr;"
+                    } else {
+                        !"$Type $_name = "
+                        if (mayBeNull) !"(flg & $fieldBit) == 0 ? null : "
+                        if (ParcelMethodsSuffix == "StrongInterface") {
+                            !"$FieldClass.Stub.asInterface("
+                        } else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" &&
+                                (!isArray || FieldInnerType !in PRIMITIVE_TYPES + "String") &&
+                                ParcelMethodsSuffix != "Parcelable") {
+                            !"($FieldClass) "
+                        }
+                    }
+
+                    // Determine method args
+                    when {
+                        ParcelMethodsSuffix == "Parcelable" ->
+                            methodArgs += "$FieldClass.class.getClassLoader()"
+                        ParcelMethodsSuffix == "SparseArray" ->
+                            methodArgs += "$FieldInnerClass.class.getClassLoader()"
+                        ParcelMethodsSuffix == "TypedObject" ->
+                            methodArgs += "$FieldClass.CREATOR"
+                        ParcelMethodsSuffix == "TypedArray" ->
+                            methodArgs += "$FieldInnerClass.CREATOR"
+                        ParcelMethodsSuffix == "Map" ->
+                            methodArgs += "${fieldTypeGenegicArgs[1].substringBefore("<")}.class.getClassLoader()"
+                        ParcelMethodsSuffix.startsWith("Parcelable")
+                                || (isList || isArray)
+                                && FieldInnerType !in PRIMITIVE_TYPES + "String" ->
+                            methodArgs += "$FieldInnerClass.class.getClassLoader()"
+                    }
+
+                    // ...in.readFieldType(args...);
+                    when {
+                        ParcelMethodsSuffix == "StrongInterface" -> !"in.readStrongBinder"
+                        isArray -> !"in.create$ParcelMethodsSuffix"
+                        else -> !"in.read$ParcelMethodsSuffix"
+                    }
+                    !"(${methodArgs.joinToString(", ")})"
+                    if (ParcelMethodsSuffix == "StrongInterface") !")"
+                    +";"
+
+                    // Cleanup if passContainer
+                    if (passContainer && mayBeNull) {
+                        popIndent()
+                        rmEmptyLine()
+                        +"\n}"
+                    }
+                }
+            }
+
+            +""
+            fields.forEachApply {
+                !"this."
+                generateSetFrom(_name)
+            }
+
+            generateOnConstructedCallback()
+        }
+    }
+
     if (classAst.fields.none { it.variables[0].nameAsString == "CREATOR" }) {
         val Creator = classRef("android.os.Parcelable.Creator")
 
@@ -477,107 +598,8 @@
             }
 
             +"@Override"
-            +"@SuppressWarnings({\"unchecked\", \"RedundantCast\"})"
             "public $ClassName createFromParcel($Parcel in)" {
-                +"// You can override field unparcelling by defining methods like:"
-                +"// static FieldType unparcelFieldName(Parcel in) { ... }"
-                +""
-                if (booleanFields.isNotEmpty() || nullableFields.isNotEmpty()) {
-                    +"$flagStorageType flg = in.read$FlagStorageType();"
-                }
-                booleanFields.forEachApply {
-                    +"$Type $_name = (flg & $fieldBit) != 0;"
-                }
-                nonBooleanFields.forEachApply {
-
-                    // Handle customized parceling
-                    val customParcellingMethod = "unparcel$NameUpperCamel"
-                    if (hasMethod(customParcellingMethod, Parcel)) {
-                        +"$Type $_name = $customParcellingMethod(in);"
-                    } else if (customParcellingClass != null) {
-                        +"$Type $_name = $sParcelling.unparcel(in);"
-                    } else if (hasAnnotation("@$DataClassEnum")) {
-                        val ordinal = "${_name}Ordinal"
-                        +"int $ordinal = in.readInt();"
-                        +"$Type $_name = $ordinal < 0 ? null : $FieldClass.values()[$ordinal];"
-                    } else {
-                        val methodArgs = mutableListOf<String>()
-
-                        // Create container if any
-                        val containerInitExpr = when {
-                            FieldClass.endsWith("Map") -> "new $LinkedHashMap<>()"
-                            FieldClass == "List" || FieldClass == "ArrayList" ->
-                                "new ${classRef("java.util.ArrayList")}<>()"
-                            else -> ""
-                        }
-                        val passContainer = containerInitExpr.isNotEmpty()
-
-                        // nullcheck +
-                        // "FieldType fieldName = (FieldType)"
-                        if (passContainer) {
-                            methodArgs.add(_name)
-                            !"$Type $_name = "
-                            if (mayBeNull) {
-                                +"null;"
-                                !"if ((flg & $fieldBit) != 0) {"
-                                pushIndent()
-                                +""
-                                !"$_name = "
-                            }
-                            +"$containerInitExpr;"
-                        } else {
-                            !"$Type $_name = "
-                            if (mayBeNull) !"(flg & $fieldBit) == 0 ? null : "
-                            if (ParcelMethodsSuffix == "StrongInterface") {
-                                !"$FieldClass.Stub.asInterface("
-                            } else if (Type !in PRIMITIVE_TYPES + "String" + "Bundle" &&
-                                    (!isArray || FieldInnerType !in PRIMITIVE_TYPES + "String") &&
-                                    ParcelMethodsSuffix != "Parcelable") {
-                                !"($FieldClass) "
-                            }
-                        }
-
-                        // Determine method args
-                        when {
-                            ParcelMethodsSuffix == "Parcelable" ->
-                                methodArgs += "$FieldClass.class.getClassLoader()"
-                            ParcelMethodsSuffix == "SparseArray" ->
-                                methodArgs += "$FieldInnerClass.class.getClassLoader()"
-                            ParcelMethodsSuffix == "TypedObject" ->
-                                methodArgs += "$FieldClass.CREATOR"
-                            ParcelMethodsSuffix == "TypedArray" ->
-                                methodArgs += "$FieldInnerClass.CREATOR"
-                            ParcelMethodsSuffix == "Map" ->
-                                methodArgs += "${fieldTypeGenegicArgs[1].substringBefore("<")}.class.getClassLoader()"
-                            ParcelMethodsSuffix.startsWith("Parcelable")
-                                    || (isList || isArray)
-                                    && FieldInnerType !in PRIMITIVE_TYPES + "String" ->
-                                methodArgs += "$FieldInnerClass.class.getClassLoader()"
-                        }
-
-                        // ...in.readFieldType(args...);
-                        when {
-                            ParcelMethodsSuffix == "StrongInterface" -> !"in.readStrongBinder"
-                            isArray -> !"in.create$ParcelMethodsSuffix"
-                            else -> !"in.read$ParcelMethodsSuffix"
-                        }
-                        !"(${methodArgs.joinToString(", ")})"
-                        if (ParcelMethodsSuffix == "StrongInterface") !")"
-                        +";"
-
-                        // Cleanup if passContainer
-                        if (passContainer && mayBeNull) {
-                            popIndent()
-                            rmEmptyLine()
-                            +"\n}"
-                        }
-                    }
-                }
-                "return new $ClassType(" {
-                    fields.forEachTrimmingTrailingComma {
-                        +"$_name,"
-                    }
-                } + ";"
+                +"return new $ClassName(in);"
             }
             rmEmptyLine()
         } + ";"
diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt
index 5804674..c91eca9 100755
--- a/tools/codegen/src/com/android/codegen/Main.kt
+++ b/tools/codegen/src/com/android/codegen/Main.kt
@@ -146,8 +146,7 @@
             generateConstructor("public")
         } else if (FeatureFlag.BUILDER()
                 || FeatureFlag.COPY_CONSTRUCTOR()
-                || FeatureFlag.WITHERS()
-                || FeatureFlag.PARCELABLE()) {
+                || FeatureFlag.WITHERS()) {
             generateConstructor("/* package-private */")
         }
         if (FeatureFlag.COPY_CONSTRUCTOR()) generateCopyConstructor()
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 1cc7ef3..a36f2c83 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
 package com.android.codegen
 
 const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.4"
+const val CODEGEN_VERSION = "1.0.5"
 
 const val CANONICAL_BUILDER_CLASS = "Builder"
 const val BASE_BUILDER_CLASS = "BaseBuilder"