cmsdk: Declare a parcelable header.
- This change forces that a parcelable header is written as the
first data positions in a parcel and defines a means to distinguish
between old sdk class versions vs new ones to do proper unraveling
of parcels.
Ticket: BAMBOO-152
Change-Id: I9cc762fe8a51cc527e85be7fe5de57e4613be019
diff --git a/src/java/cyanogenmod/app/CustomTile.java b/src/java/cyanogenmod/app/CustomTile.java
index 8f2f4bd..dc10d4a 100644
--- a/src/java/cyanogenmod/app/CustomTile.java
+++ b/src/java/cyanogenmod/app/CustomTile.java
@@ -23,6 +23,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import cyanogenmod.os.Build;
import java.util.ArrayList;
@@ -83,25 +84,38 @@
* Unflatten the CustomTile from a parcel.
*/
public CustomTile(Parcel parcel) {
- if (parcel.readInt() != 0) {
- this.onClick = PendingIntent.CREATOR.createFromParcel(parcel);
+ // Read parcelable version, make sure to define explicit changes
+ // within {@link Build.PARCELABLE_VERSION);
+ int parcelableVersion = parcel.readInt();
+ int parcelableSize = parcel.readInt();
+ int startPosition = parcel.dataPosition();
+
+ // Pattern here is that all new members should be added to the end of
+ // the writeToParcel method. Then we step through each version, until the latest
+ // API release to help unravel this parcel
+ if (parcelableVersion >= Build.CM_VERSION_CODES.APRICOT) {
+ if (parcel.readInt() != 0) {
+ this.onClick = PendingIntent.CREATOR.createFromParcel(parcel);
+ }
+ if (parcel.readInt() != 0) {
+ this.onSettingsClick = Intent.CREATOR.createFromParcel(parcel);
+ }
+ if (parcel.readInt() != 0) {
+ this.onClickUri = Uri.CREATOR.createFromParcel(parcel);
+ }
+ if (parcel.readInt() != 0) {
+ this.label = parcel.readString();
+ }
+ if (parcel.readInt() != 0) {
+ this.contentDescription = parcel.readString();
+ }
+ if (parcel.readInt() != 0) {
+ this.expandedStyle = ExpandedStyle.CREATOR.createFromParcel(parcel);
+ }
+ this.icon = parcel.readInt();
}
- if (parcel.readInt() != 0) {
- this.onSettingsClick = Intent.CREATOR.createFromParcel(parcel);
- }
- if (parcel.readInt() != 0) {
- this.onClickUri = Uri.CREATOR.createFromParcel(parcel);
- }
- if (parcel.readInt() != 0) {
- this.label = parcel.readString();
- }
- if (parcel.readInt() != 0) {
- this.contentDescription = parcel.readString();
- }
- if (parcel.readInt() != 0) {
- this.expandedStyle = ExpandedStyle.CREATOR.createFromParcel(parcel);
- }
- this.icon = parcel.readInt();
+
+ parcel.setDataPosition(startPosition + parcelableSize);
}
/**
@@ -167,6 +181,17 @@
@Override
public void writeToParcel(Parcel out, int flags) {
+ // Write parcelable version, make sure to define explicit changes
+ // within {@link Build.PARCELABLE_VERSION);
+ out.writeInt(Build.PARCELABLE_VERSION);
+
+ // Inject a placeholder that will store the parcel size from this point on
+ // (not including the size itself).
+ int sizePosition = out.dataPosition();
+ out.writeInt(0);
+ int startPosition = out.dataPosition();
+
+ // ==== APRICOT =====
if (onClick != null) {
out.writeInt(1);
onClick.writeToParcel(out, 0);
@@ -204,6 +229,12 @@
out.writeInt(0);
}
out.writeInt(icon);
+
+ // Go back and write size
+ int parcelableSize = out.dataPosition() - startPosition;
+ out.setDataPosition(sizePosition);
+ out.writeInt(parcelableSize);
+ out.setDataPosition(startPosition + parcelableSize);
}
/**
@@ -234,10 +265,23 @@
private int styleId;
private ExpandedStyle(Parcel parcel) {
- if (parcel.readInt() != 0) {
- expandedItems = parcel.createTypedArray(ExpandedItem.CREATOR);
+ // Read parcelable version, make sure to define explicit changes
+ // within {@link Build.PARCELABLE_VERSION);
+ int parcelableVersion = parcel.readInt();
+ int parcelableSize = parcel.readInt();
+ int startPosition = parcel.dataPosition();
+
+ // Pattern here is that all new members should be added to the end of
+ // the writeToParcel method. Then we step through each version, until the latest
+ // API release to help unravel this parcel
+ if (parcelableVersion >= Build.CM_VERSION_CODES.APRICOT) {
+ if (parcel.readInt() != 0) {
+ expandedItems = parcel.createTypedArray(ExpandedItem.CREATOR);
+ }
+ styleId = parcel.readInt();
}
- styleId = parcel.readInt();
+
+ parcel.setDataPosition(startPosition + parcelableSize);
}
/**
@@ -287,6 +331,17 @@
@Override
public void writeToParcel(Parcel parcel, int i) {
+ // Write parcelable version, make sure to define explicit changes
+ // within {@link Build.PARCELABLE_VERSION);
+ parcel.writeInt(Build.PARCELABLE_VERSION);
+
+ // Inject a placeholder that will store the parcel size from this point on
+ // (not including the size itself).
+ int sizePosition = parcel.dataPosition();
+ parcel.writeInt(0);
+ int startPosition = parcel.dataPosition();
+
+ // ==== APRICOT ====
if (expandedItems != null) {
parcel.writeInt(1);
parcel.writeTypedArray(expandedItems, 0);
@@ -294,6 +349,12 @@
parcel.writeInt(0);
}
parcel.writeInt(styleId);
+
+ // Go back and write size
+ int parcelableSize = parcel.dataPosition() - startPosition;
+ parcel.setDataPosition(sizePosition);
+ parcel.writeInt(parcelableSize);
+ parcel.setDataPosition(startPosition + parcelableSize);
}
@Override
@@ -433,16 +494,29 @@
* Unflatten the ExpandedItem from a parcel.
*/
protected ExpandedItem(Parcel parcel) {
- if (parcel.readInt() != 0) {
- onClickPendingIntent = PendingIntent.CREATOR.createFromParcel(parcel);
+ // Read parcelable version, make sure to define explicit changes
+ // within {@link Build.PARCELABLE_VERSION);
+ int parcelableVersion = parcel.readInt();
+ int parcelableSize = parcel.readInt();
+ int startPosition = parcel.dataPosition();
+
+ // Pattern here is that all new members should be added to the end of
+ // the writeToParcel method. Then we step through each version, until the latest
+ // API release to help unravel this parcel
+ if (parcelableVersion >= Build.CM_VERSION_CODES.APRICOT) {
+ if (parcel.readInt() != 0) {
+ onClickPendingIntent = PendingIntent.CREATOR.createFromParcel(parcel);
+ }
+ if (parcel.readInt() != 0) {
+ itemTitle = parcel.readString();
+ }
+ if (parcel.readInt() != 0) {
+ itemSummary = parcel.readString();
+ }
+ itemDrawableResourceId = parcel.readInt();
}
- if (parcel.readInt() != 0) {
- itemTitle = parcel.readString();
- }
- if (parcel.readInt() != 0) {
- itemSummary = parcel.readString();
- }
- itemDrawableResourceId = parcel.readInt();
+
+ parcel.setDataPosition(startPosition + parcelableSize);
}
@Override
@@ -452,6 +526,16 @@
@Override
public void writeToParcel(Parcel out, int flags) {
+ // Write parcelable version, make sure to define explicit changes
+ // within {@link Build.PARCELABLE_VERSION);
+ out.writeInt(Build.PARCELABLE_VERSION);
+
+ // Inject a placeholder that will store the parcel size from this point on
+ // (not including the size itself).
+ int sizePosition = out.dataPosition();
+ out.writeInt(0);
+ int startPosition = out.dataPosition();
+
if (onClickPendingIntent != null) {
out.writeInt(1);
onClickPendingIntent.writeToParcel(out, 0);
@@ -471,6 +555,12 @@
out.writeInt(0);
}
out.writeInt(itemDrawableResourceId);
+
+ // Go back and write size
+ int parcelableSize = out.dataPosition() - startPosition;
+ out.setDataPosition(sizePosition);
+ out.writeInt(parcelableSize);
+ out.setDataPosition(startPosition + parcelableSize);
}
@Override
diff --git a/src/java/cyanogenmod/app/StatusBarPanelCustomTile.java b/src/java/cyanogenmod/app/StatusBarPanelCustomTile.java
index 27d8151..cfdc153 100644
--- a/src/java/cyanogenmod/app/StatusBarPanelCustomTile.java
+++ b/src/java/cyanogenmod/app/StatusBarPanelCustomTile.java
@@ -19,6 +19,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import cyanogenmod.os.Build;
/**
* Class encapsulating a Custom Tile. Sent by the StatusBarManagerService to clients including
@@ -64,20 +65,56 @@
public StatusBarPanelCustomTile(Parcel in) {
- this.pkg = in.readString();
- this.opPkg = in.readString();
- this.id = in.readInt();
- if (in.readInt() != 0) {
- this.tag = in.readString();
- } else {
- this.tag = null;
+ // Read parcelable version, make sure to define explicit changes
+ // within {@link Build.PARCELABLE_VERSION);
+ int parcelableVersion = in.readInt();
+ int parcelableSize = in.readInt();
+ int startPosition = in.dataPosition();
+
+ // tmp variables for final
+ String tmpPkg = null;
+ String tmpOpPkg = null;
+ int tmpId = -1;
+ String tmpTag = null;
+ int tmpUid = -1;
+ int tmpPid = -1;
+ CustomTile tmpCustomTile = null;
+ UserHandle tmpUser = null;
+ long tmpPostTime = -1;
+
+ // Pattern here is that all new members should be added to the end of
+ // the writeToParcel method. Then we step through each version, until the latest
+ // API release to help unravel this parcel
+ if (parcelableVersion >= Build.CM_VERSION_CODES.APRICOT) {
+ // default
+ tmpPkg = in.readString();
+ tmpOpPkg = in.readString();
+ tmpId = in.readInt();
+ if (in.readInt() != 0) {
+ tmpTag = in.readString();
+ } else {
+ tmpTag = null;
+ }
+ tmpUid = in.readInt();
+ tmpPid = in.readInt();
+ tmpCustomTile = new CustomTile(in);
+ tmpUser = UserHandle.readFromParcel(in);
+ tmpPostTime = in.readLong();
}
- this.uid = in.readInt();
- this.initialPid = in.readInt();
- this.customTile = new CustomTile(in);
- this.user = UserHandle.readFromParcel(in);
- this.postTime = in.readLong();
+
+ // Assign finals
+ this.pkg = tmpPkg;
+ this.opPkg = tmpOpPkg;
+ this.id = tmpId;
+ this.tag = tmpTag;
+ this.uid = tmpUid;
+ this.initialPid = tmpPid;
+ this.customTile = tmpCustomTile;
+ this.user = tmpUser;
+ this.postTime = tmpPostTime;
this.key = key();
+
+ in.setDataPosition(startPosition + parcelableSize);
}
private String key() {
@@ -112,6 +149,17 @@
@Override
public void writeToParcel(Parcel out, int flags) {
+ // Write parcelable version, make sure to define explicit changes
+ // within {@link Build.PARCELABLE_VERSION);
+ out.writeInt(Build.PARCELABLE_VERSION);
+
+ // Inject a placeholder that will store the parcel size from this point on
+ // (not including the size itself).
+ int sizePosition = out.dataPosition();
+ out.writeInt(0);
+ int startPosition = out.dataPosition();
+
+ // ==== APRICOT ===
out.writeString(this.pkg);
out.writeString(this.opPkg);
out.writeInt(this.id);
@@ -126,6 +174,12 @@
this.customTile.writeToParcel(out, flags);
user.writeToParcel(out, flags);
out.writeLong(this.postTime);
+
+ // Go back and write size
+ int parcelableSize = out.dataPosition() - startPosition;
+ out.setDataPosition(sizePosition);
+ out.writeInt(parcelableSize);
+ out.setDataPosition(startPosition + parcelableSize);
}
@Override
diff --git a/src/java/cyanogenmod/os/Build.java b/src/java/cyanogenmod/os/Build.java
index 8fde45f..5ae1d97 100644
--- a/src/java/cyanogenmod/os/Build.java
+++ b/src/java/cyanogenmod/os/Build.java
@@ -26,6 +26,16 @@
/** Value used for when a build property is unknown. */
public static final String UNKNOWN = "unknown";
+ /**
+ * Since there might be a case where new versions of the cm framework use applications running
+ * old versions of the protocol (and thus old versions of this class), we need a versioning
+ * system for the parcels sent between the core framework and its sdk users.
+ *
+ * This parcelable version should be the latest version API version listed in
+ * {@link CM_VERSION_CODES}
+ */
+ public static final int PARCELABLE_VERSION = CM_VERSION_CODES.APRICOT;
+
private static final SparseArray<String> sdkMap;
static
{