Index: components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GoogleCloudMessagingV2.java |
diff --git a/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GoogleCloudMessagingV2.java b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GoogleCloudMessagingV2.java |
index d8a825340212511f064fb62e66500636bc976073..6840602663371ce6cce9144363659ea85ccf5943 100644 |
--- a/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GoogleCloudMessagingV2.java |
+++ b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GoogleCloudMessagingV2.java |
@@ -7,6 +7,9 @@ |
import android.app.PendingIntent; |
import android.content.Context; |
import android.content.Intent; |
+import android.content.pm.PackageInfo; |
+import android.content.pm.PackageManager; |
+import android.os.Bundle; |
import android.os.Handler; |
import android.os.Looper; |
import android.os.Message; |
@@ -19,29 +22,25 @@ |
/** |
- * Temporary code for sending subtypes when (un)registering with GCM. |
+ * Temporary code for sending subtypes when (un)subscribing with GCM. |
* Subtypes are experimental and may change without notice! |
* TODO(johnme): Remove this file, once we switch to the GMS client library. |
*/ |
public class GoogleCloudMessagingV2 { |
- // Inlined com.google.android.gms.common.GooglePlayServicesUtil.GOOGLE_PLAY_SERVICES_PACKAGE |
- // since this class mustn't depend on the GMS client library. |
private static final String GOOGLE_PLAY_SERVICES_PACKAGE = "com.google.android.gms"; |
private static final long REGISTER_TIMEOUT = 5000; |
- private static final String ACTION_C2DM_REGISTER = |
- "com.google.android.c2dm.intent.REGISTER"; |
- private static final String ACTION_C2DM_UNREGISTER = |
- "com.google.android.c2dm.intent.UNREGISTER"; |
+ private static final String ACTION_C2DM_REGISTER = "com.google.android.c2dm.intent.REGISTER"; |
private static final String C2DM_EXTRA_ERROR = "error"; |
private static final String INTENT_PARAM_APP = "app"; |
private static final String ERROR_MAIN_THREAD = "MAIN_THREAD"; |
private static final String ERROR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE"; |
+ private static final String EXTRA_DELETE = "delete"; |
private static final String EXTRA_REGISTRATION_ID = "registration_id"; |
- private static final String EXTRA_UNREGISTERED = "unregistered"; |
private static final String EXTRA_SENDER = "sender"; |
private static final String EXTRA_MESSENGER = "google.messenger"; |
private static final String EXTRA_SUBTYPE = "subtype"; |
+ private static final String EXTRA_SUBSCRIPTION = "subscription"; |
private Context mContext; |
private PendingIntent mAppPendingIntent = null; |
@@ -51,80 +50,132 @@ public GoogleCloudMessagingV2(Context context) { |
mContext = context; |
} |
+ public String subscribe(String source, String subtype, Bundle data) throws IOException { |
+ if (data == null) { |
+ data = new Bundle(); |
+ } |
+ data.putString(EXTRA_SUBTYPE, subtype); |
+ Bundle result = subscribe(source, data); |
+ return result.getString(EXTRA_REGISTRATION_ID); |
+ } |
+ |
+ public void unsubscribe(String source, String subtype, Bundle data) throws IOException { |
+ if (data == null) { |
+ data = new Bundle(); |
+ } |
+ data.putString(EXTRA_SUBTYPE, subtype); |
+ unsubscribe(source, data); |
+ return; |
+ } |
+ |
/** |
- * Register the application for GCM and return the registration ID. You must call this once, |
- * when your application is installed, and send the returned registration ID to the server. |
- * <p> |
- * This is a blocking call—you shouldn't call it from the UI thread. |
- * <p> |
- * Repeated calls to this method will return the original registration ID. |
+ * Subscribe to receive GCM messages from a specific source. |
* <p> |
- * If you want to modify the list of senders, you must call {@code unregister()} first. |
+ * Source Types: |
+ * <ul> |
+ * <li>Sender ID - if you have multiple senders you can call this method |
+ * for each additional sender. Each sender can use the corresponding |
+ * {@link #REGISTRATION_ID} returned in the bundle to send messages |
+ * from the server.</li> |
+ * <li>Cloud Pub/Sub topic - You can subscribe to a topic and receive |
+ * notifications from the owner of that topic, when something changes. |
+ * For more information see |
+ * <a href="https://cloud.google.com/pubsub">Cloud Pub/Sub</a>.</li> |
+ * </ul> |
+ * This function is blocking and should not be called on the main thread. |
+ * |
+ * @param source of the desired notifications. |
+ * @param data (optional) additional information. |
+ * @return Bundle containing subscription information including {@link #REGISTRATION_ID} |
+ * @throws IOException if the request fails. |
+ */ |
+ public Bundle subscribe(String source, Bundle data) throws IOException { |
+ if (data == null) { |
+ data = new Bundle(); |
+ } |
+ // Expected by older versions of GMS and servlet |
+ data.putString(EXTRA_SENDER, source); |
+ // New name of the sender parameter |
+ data.putString(EXTRA_SUBSCRIPTION, source); |
+ // DB buster for older versions of GCM. |
+ if (data.getString(EXTRA_SUBTYPE) == null) { |
+ data.putString(EXTRA_SUBTYPE, source); |
+ } |
+ |
+ Intent resultIntent = registerRpc(data); |
+ getExtraOrThrow(resultIntent, EXTRA_REGISTRATION_ID); |
+ return resultIntent.getExtras(); |
+ } |
+ |
+ /** |
+ * Unsubscribe from a source to stop receiving messages from it. |
* <p> |
- * Most applications use a single sender ID. You may use multiple senders if different |
- * servers may send messages to the app or for testing. |
+ * This function is blocking and should not be called on the main thread. |
* |
- * @param senderIds list of project numbers or Google accounts identifying who is allowed to |
- * send messages to this application. |
- * @return registration id |
+ * @param source to unsubscribe |
+ * @param data (optional) additional information. |
+ * @throws IOException if the request fails. |
*/ |
- public String register(String subtype, String... senderIds) throws IOException { |
+ public void unsubscribe(String source, Bundle data) throws IOException { |
+ if (data == null) { |
+ data = new Bundle(); |
+ } |
+ // Use the register servlet, with 'delete=true'. |
+ // Registration service returns a registration_id on success - or an error code. |
+ data.putString(EXTRA_DELETE, "1"); |
+ subscribe(source, data); |
+ } |
+ |
+ private Intent registerRpc(Bundle data) throws IOException { |
if (Looper.getMainLooper() == Looper.myLooper()) { |
throw new IOException(ERROR_MAIN_THREAD); |
} |
+ if (getGcmVersion() < 0) { |
+ throw new IOException("Google Play Services missing"); |
+ } |
+ if (data == null) { |
+ data = new Bundle(); |
+ } |
- final BlockingQueue<Intent> registerResult = new LinkedBlockingQueue<Intent>(); |
- Handler registrationHandler = new Handler(Looper.getMainLooper()) { |
+ final BlockingQueue<Intent> responseResult = new LinkedBlockingQueue<Intent>(); |
+ Handler responseHandler = new Handler(Looper.getMainLooper()) { |
@Override |
public void handleMessage(Message msg) { |
Intent res = (Intent) msg.obj; |
- registerResult.add(res); |
+ responseResult.add(res); |
} |
}; |
- Messenger messenger = new Messenger(registrationHandler); |
- |
- internalRegister(messenger, subtype, senderIds); |
+ Messenger responseMessenger = new Messenger(responseHandler); |
+ Intent intent = new Intent(ACTION_C2DM_REGISTER); |
+ intent.setPackage(GOOGLE_PLAY_SERVICES_PACKAGE); |
+ setPackageNameExtra(intent); |
+ intent.putExtras(data); |
+ intent.putExtra(EXTRA_MESSENGER, responseMessenger); |
+ mContext.startService(intent); |
try { |
- Intent regIntent = registerResult.poll(REGISTER_TIMEOUT, TimeUnit.MILLISECONDS); |
- if (regIntent == null) { |
- throw new IOException(ERROR_SERVICE_NOT_AVAILABLE); |
- } |
- String registrationId = regIntent.getStringExtra(EXTRA_REGISTRATION_ID); |
- // registration succeeded |
- if (registrationId != null) { |
- return registrationId; |
- } |
- String err = regIntent.getStringExtra(C2DM_EXTRA_ERROR); |
- if (err != null) { |
- throw new IOException(err); |
- } else { |
- throw new IOException(ERROR_SERVICE_NOT_AVAILABLE); |
- } |
+ return responseResult.poll(REGISTER_TIMEOUT, TimeUnit.MILLISECONDS); |
} catch (InterruptedException e) { |
throw new IOException(e.getMessage()); |
} |
} |
- private void internalRegister(Messenger messenger, String subtype, String... senderIds) { |
- Intent intent = new Intent(ACTION_C2DM_REGISTER); |
- intent.setPackage(GOOGLE_PLAY_SERVICES_PACKAGE); |
- if (subtype != null) intent.putExtra("subtype", subtype); |
- intent.putExtra(EXTRA_MESSENGER, messenger); |
- setPackageNameExtra(intent); |
- intent.putExtra(EXTRA_SENDER, getFlatSenderIds(senderIds)); |
- mContext.startService(intent); |
- } |
+ private String getExtraOrThrow(Intent intent, String extraKey) throws IOException { |
+ if (intent == null) { |
+ throw new IOException(ERROR_SERVICE_NOT_AVAILABLE); |
+ } |
- private String getFlatSenderIds(String... senderIds) { |
- if (senderIds == null || senderIds.length == 0) { |
- throw new IllegalArgumentException("No senderIds"); |
+ String extraValue = intent.getStringExtra(extraKey); |
+ if (extraValue != null) { |
+ return extraValue; |
} |
- StringBuilder builder = new StringBuilder(senderIds[0]); |
- for (int i = 1; i < senderIds.length; i++) { |
- builder.append(',').append(senderIds[i]); |
+ |
+ String err = intent.getStringExtra(C2DM_EXTRA_ERROR); |
+ if (err != null) { |
+ throw new IOException(err); |
+ } else { |
+ throw new IOException(ERROR_SERVICE_NOT_AVAILABLE); |
} |
- return builder.toString(); |
} |
private void setPackageNameExtra(Intent intent) { |
@@ -140,63 +191,14 @@ private void setPackageNameExtra(Intent intent) { |
intent.putExtra(INTENT_PARAM_APP, mAppPendingIntent); |
} |
- /** |
- * Unregister the application. Calling {@code unregister()} stops any |
- * messages from the server. |
- * <p> |
- * This is a blocking call—you shouldn't call it from the UI thread. |
- * <p> |
- * You should rarely (if ever) need to call this method. Not only is it |
- * expensive in terms of resources, but it invalidates your registration ID, |
- * which you should never change unnecessarily. A better approach is to simply |
- * have your server stop sending messages. Only use unregister if you want |
- * to change your sender ID. |
- * |
- * @throws IOException if we can't connect to server to unregister. |
- */ |
- public void unregister(String subtype) throws IOException { |
- if (Looper.getMainLooper() == Looper.myLooper()) { |
- throw new IOException(ERROR_MAIN_THREAD); |
- } |
- final BlockingQueue<Intent> registerResult = new LinkedBlockingQueue<Intent>(); |
- Handler registrationHandler = new Handler(Looper.getMainLooper()) { |
- @Override |
- public void handleMessage(Message msg) { |
- Intent res = (Intent) msg.obj; |
- registerResult.add(res); |
- } |
- }; |
- Messenger messenger = new Messenger(registrationHandler); |
- internalUnregister(messenger, subtype); |
+ private int getGcmVersion() { |
+ PackageManager pm = mContext.getPackageManager(); |
try { |
- Intent regIntent = registerResult.poll(REGISTER_TIMEOUT, TimeUnit.MILLISECONDS); |
- if (regIntent == null) { |
- throw new IOException(ERROR_SERVICE_NOT_AVAILABLE); |
- } |
- String unregistered = regIntent.getStringExtra(EXTRA_UNREGISTERED); |
- if (unregistered != null) { |
- // All done |
- return; |
- } |
- String err = regIntent.getStringExtra(C2DM_EXTRA_ERROR); |
- if (err != null) { |
- throw new IOException(err); |
- } else { |
- throw new IOException(ERROR_SERVICE_NOT_AVAILABLE); |
- } |
- } catch (InterruptedException e) { |
- throw new IOException(e.getMessage()); |
+ PackageInfo packageInfo = pm.getPackageInfo(GOOGLE_PLAY_SERVICES_PACKAGE, 0); |
+ return packageInfo.versionCode; |
+ } catch (PackageManager.NameNotFoundException e) { |
+ // No problem |
} |
- } |
- |
- private void internalUnregister(Messenger messenger, String subtype) { |
- Intent intent = new Intent(ACTION_C2DM_UNREGISTER); |
- intent.setPackage(GOOGLE_PLAY_SERVICES_PACKAGE); |
- if (subtype != null) { |
- intent.putExtra("subtype", subtype); |
- } |
- intent.putExtra(EXTRA_MESSENGER, messenger); |
- setPackageNameExtra(intent); |
- mContext.startService(intent); |
+ return -1; |
} |
} |