Index: components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMMessage.java |
diff --git a/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMMessage.java b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMMessage.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..dcdd6266a62959eb030d13d881a7edda565e7d02 |
--- /dev/null |
+++ b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMMessage.java |
@@ -0,0 +1,176 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.components.gcm_driver; |
+ |
+import android.annotation.TargetApi; |
+import android.os.Build; |
+import android.os.Bundle; |
+import android.os.PersistableBundle; |
+ |
+import org.chromium.base.annotations.SuppressFBWarnings; |
+ |
+import java.util.ArrayList; |
+import java.util.List; |
+ |
+import javax.annotation.Nullable; |
+ |
+/** |
+ * Represents the contents of a GCM Message that is to be handled by the GCM Driver. Can be created |
+ * based on data received from GCM, or serialized and deserialized to and from a PersistableBundle. |
+ */ |
+public class GCMMessage { |
+ /** |
+ * Keys used to store information in the persistable bundle for serialization purposes. |
+ */ |
+ private static final String BUNDLE_KEY_APP_ID = "appId"; |
+ private static final String BUNDLE_KEY_COLLAPSE_KEY = "collapseKey"; |
+ private static final String BUNDLE_KEY_DATA = "data"; |
+ private static final String BUNDLE_KEY_RAW_DATA = "rawData"; |
+ private static final String BUNDLE_KEY_SENDER_ID = "senderId"; |
+ |
+ private String mSenderId; |
nyquist
2017/02/22 11:38:02
I think all these members can be final?
Peter Beverloo
2017/02/23 17:26:56
Yup. Done.
|
+ private String mAppId; |
+ |
+ @Nullable |
+ private String mCollapseKey; |
+ @Nullable |
+ private byte[] mRawData; |
+ |
+ /** |
+ * Array that contains pairs of entries in the format of {key, value}. |
+ */ |
+ private String[] mDataKeysAndValuesArray; |
+ |
+ /** |
+ * Validates that all required fields have been set in the given bundle. |
+ */ |
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP) |
+ public static boolean validatePersistableBundle(PersistableBundle persistableBundle) { |
+ return persistableBundle.containsKey(BUNDLE_KEY_APP_ID) |
+ && persistableBundle.containsKey(BUNDLE_KEY_COLLAPSE_KEY) |
+ && persistableBundle.containsKey(BUNDLE_KEY_DATA) |
+ && persistableBundle.containsKey(BUNDLE_KEY_RAW_DATA) |
+ && persistableBundle.containsKey(BUNDLE_KEY_SENDER_ID); |
+ } |
+ |
+ /** |
+ * Creates a GCMMessage object based on data received from GCM. The extras will be filtered. |
+ */ |
+ public GCMMessage(String senderId, Bundle extras) { |
+ final String bundleCollapseKey = "collapse_key"; |
nyquist
2017/02/22 11:38:02
Nit: Why are these final? I don't think we usually
Peter Beverloo
2017/02/23 17:26:55
Largely just copied, it doesn't really matter. Rem
|
+ final String bundleGcmplex = "com.google.ipc.invalidation.gcmmplex."; |
+ final String bundleRawData = "rawData"; |
+ final String bundleSenderId = "from"; |
+ final String bundleSubtype = "subtype"; |
+ |
+ if (!extras.containsKey(bundleSubtype)) { |
+ throw new IllegalArgumentException("Received push message with no subtype"); |
+ } |
+ |
+ mSenderId = senderId; |
+ mAppId = extras.getString(bundleSubtype); |
+ |
+ mCollapseKey = extras.getString(bundleCollapseKey); // May be null. |
nyquist
2017/02/22 11:38:02
The nittiest of nits: I think your formatted remov
Peter Beverloo
2017/02/23 17:26:56
`git cl format` warns if I add two spaces :/
nyquist
2017/02/24 08:22:39
I see. That's messed up. :-/
|
+ mRawData = extras.getByteArray(bundleRawData); // May be null. |
+ |
+ List<String> dataKeysAndValues = new ArrayList<String>(); |
+ for (String key : extras.keySet()) { |
+ if (key.equals(bundleSubtype) || key.equals(bundleSenderId) |
+ || key.equals(bundleCollapseKey) || key.equals(bundleRawData) |
+ || key.startsWith(bundleGcmplex)) { |
+ continue; |
+ } |
+ |
+ Object value = extras.get(key); |
+ if (!(value instanceof String)) { |
+ continue; |
+ } |
+ |
+ dataKeysAndValues.add(key); |
+ dataKeysAndValues.add((String) value); |
+ } |
+ |
+ mDataKeysAndValuesArray = dataKeysAndValues.toArray(new String[dataKeysAndValues.size()]); |
+ } |
+ |
+ /** |
+ * Creates a GCMMessage object based on the given bundle. Assumes that the bundle has previously |
+ * been created through {@link #toPersistableBundle}. |
+ */ |
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP) |
+ public GCMMessage(PersistableBundle persistableBundle) { |
+ mSenderId = persistableBundle.getString(BUNDLE_KEY_SENDER_ID); |
+ mAppId = persistableBundle.getString(BUNDLE_KEY_APP_ID); |
+ mCollapseKey = persistableBundle.getString(BUNDLE_KEY_COLLAPSE_KEY); |
+ |
+ // The rawData field needs to distinguish between {not set, set but empty, set with data}. |
+ String rawDataString = persistableBundle.getString(BUNDLE_KEY_RAW_DATA); |
+ if (rawDataString != null) { |
+ if (rawDataString.length() > 0) { |
+ mRawData = rawDataString.getBytes(); |
+ } else { |
+ mRawData = new byte[0]; |
+ } |
+ } |
+ |
+ mDataKeysAndValuesArray = persistableBundle.getStringArray(BUNDLE_KEY_DATA); |
+ } |
+ |
+ public String getSenderId() { |
+ return mSenderId; |
+ } |
+ |
+ public String getAppId() { |
+ return mAppId; |
+ } |
+ |
+ @Nullable |
+ public String getCollapseKey() { |
+ return mCollapseKey; |
+ } |
+ |
+ /** |
+ * Callers are expected to not modify values in the returned byte array. |
+ */ |
+ @Nullable |
+ @SuppressFBWarnings("EI_EXPOSE_REP") |
+ public byte[] getRawData() { |
+ return mRawData; |
+ } |
+ |
+ /** |
+ * Callers are expected to not modify values in the returned byte array. |
+ */ |
+ @SuppressFBWarnings("EI_EXPOSE_REP") |
+ public String[] getDataKeysAndValuesArray() { |
+ return mDataKeysAndValuesArray; |
+ } |
+ |
+ /** |
+ * Serializes the contents of this GCM Message to a new persistable bundle that can be stored, |
+ * for example for purposes of scheduling a job. |
+ */ |
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP) |
+ public PersistableBundle toPersistableBundle() { |
+ PersistableBundle persistableBundle = new PersistableBundle(); |
+ persistableBundle.putString(BUNDLE_KEY_SENDER_ID, mSenderId); |
+ persistableBundle.putString(BUNDLE_KEY_APP_ID, mAppId); |
+ persistableBundle.putString(BUNDLE_KEY_COLLAPSE_KEY, mCollapseKey); |
+ |
+ // The rawData field needs to distinguish between {not set, set but empty, set with data}. |
+ if (mRawData != null) { |
+ if (mRawData.length > 0) { |
+ persistableBundle.putString(BUNDLE_KEY_RAW_DATA, new String(mRawData)); |
+ } else { |
+ persistableBundle.putString(BUNDLE_KEY_RAW_DATA, ""); |
+ } |
+ } else { |
+ persistableBundle.putString(BUNDLE_KEY_RAW_DATA, null); |
+ } |
+ |
+ persistableBundle.putStringArray(BUNDLE_KEY_DATA, mDataKeysAndValuesArray); |
+ return persistableBundle; |
+ } |
+} |