Index: chrome/android/java/src/org/chromium/chrome/browser/GcmPlatformImpl.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/GcmPlatformImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/GcmPlatformImpl.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..06e4367985f2f5a16cb985fa2c9800ff50c2f060 |
--- /dev/null |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/GcmPlatformImpl.java |
@@ -0,0 +1,200 @@ |
+// Copyright 2013 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.chrome.browser; |
+ |
+import android.content.Context; |
+import android.content.Intent; |
+import android.os.AsyncTask; |
+import android.util.Log; |
+ |
+import com.google.android.gcm.GCMRegistrar; |
+import com.google.ipc.invalidation.external.client.contrib.MultiplexingGcmListener; |
+ |
+import org.chromium.base.CalledByNative; |
+import org.chromium.base.ThreadUtils; |
+ |
+import java.io.IOException; |
+ |
+/** |
+ * This class is the Java counterpart to the C++ GcmPlatformImplAndroid class. |
+ * It implements GCM registration, and sends back GCM messages over JNI. |
+ * |
+ * Threading model note: all calls from C++ must happen on the UI thread. |
+ * Callbacks from Android may happen on a different thread, so we always |
+ * use ThreadUtils.runOnUiThread when calling back to C++. |
+ */ |
+class GcmPlatformImpl { |
+ private static final String TAG = "Chrome-GcmPlatformImpl"; |
+ |
+ private static GcmPlatformImpl sInstance = null; |
+ |
+ private long mNativeGcmPlatformImplAndroid; |
+ private Context mContext; |
+ |
+ private GcmPlatformImpl(long nativeGcmPlatformImplAndroid, Context context) { |
+ mNativeGcmPlatformImplAndroid = nativeGcmPlatformImplAndroid; |
+ mContext = context; |
+ sInstance = this; |
+ } |
+ |
+ /** |
+ * Create a GcmPlatformImpl object, which is owned by GcmPlatformImplAndroid |
+ * on the C++ side. |
+ * |
+ * @param nativeGcmPlatformImplAndroid The C++ object that owns us. |
+ * @param context The app context. |
+ */ |
+ @CalledByNative |
+ private static GcmPlatformImpl create(int nativeGcmPlatformImplAndroid, |
+ Context context) { |
+ if (sInstance != null) { |
+ throw new IllegalStateException("Already instantiated"); |
+ } |
+ return new GcmPlatformImpl(nativeGcmPlatformImplAndroid, context); |
+ } |
+ |
+ /** |
+ * Called when our C++ counterpart is deleted. Clear the handle to our |
+ * native C++ object, ensuring it's never called. |
+ */ |
+ @CalledByNative |
+ private void destroy() { |
+ mNativeGcmPlatformImplAndroid = 0; |
+ } |
+ |
+ /** |
+ * Registers the app with GCM servers asynchronously. Calls |
+ * nativeOnRegistrationFinished once this is done. |
+ * |
+ * @param appUniqueIdCurrentlyIgnored A unique string identifying the app. |
+ * Currently ignored. |
+ * @param senderIds List of project numbers or Google accounts identifying |
+ * who is allowed to send messages to this application. |
+ */ |
+ @CalledByNative |
+ private void registerApp(String appUniqueIdCurrentlyIgnored, String[] senderIds) { |
+ new AsyncTask<String, Void, String>() { |
+ @Override |
+ protected String doInBackground(String[] senderIds) { |
+ try { |
+ GCMRegistrar.checkDevice(mContext); |
+ } |
+ catch (UnsupportedOperationException ex) { |
+ return ""; // Indicates failure |
+ } |
+ GCMRegistrar.checkManifest(mContext); // TODO: Do I want this? |
+ String registrationId = GCMRegistrar.getRegistrationId(mContext); |
+ if (registrationId.equals("")) { |
+ GCMRegistrar.register(mContext, senderIds); |
+ return null; // Indicates pending result |
+ } else { |
+ return registrationId; |
+ } |
+ } |
+ |
+ @Override |
+ protected void onPostExecute(String registrationId) { |
+ if (registrationId != null) |
+ nativeOnRegistrationFinished(mNativeGcmPlatformImplAndroid, |
+ registrationId); |
+ } |
+ }.execute(senderIds); |
+ } |
+ |
+ // registrationId will be an empty string in case of failure. |
+ private native void nativeOnRegistrationFinished(long nativeGcmPlatformImplAndroid, |
+ String registrationId); |
+ private native void nativeOnMessageReceived(long nativeGcmPlatformImplAndroid, String data); |
+ private native void nativeOnMessagesDeletedByServer(long nativeGcmPlatformImplAndroid); |
+ |
+ /** |
+ * Receives GCM registration events and messages rebroadcast by MultiplexingGcmListener. |
+ */ |
+ public static class GcmListener extends MultiplexingGcmListener.AbstractListener { |
+ /** |
+ * Receiver for broadcasts by the multiplexed GCM service. It forwards them to |
+ * GcmListener. |
+ */ |
+ public static class Receiver extends MultiplexingGcmListener.AbstractListener.Receiver { |
+ /** |
+ * This class is public so that it can be instantiated by the Android runtime. |
+ */ |
+ @Override |
+ protected Class<?> getServiceClass() { |
+ return GcmListener.class; |
+ } |
+ } |
+ |
+ private static final String TAG = "GcmListener"; |
+ |
+ public GcmListener() { |
+ super(TAG); |
+ } |
+ |
+ @Override |
+ protected void onMessage(Intent intent) { |
+ final GcmPlatformImpl impl = GcmPlatformImpl.sInstance; |
+ // HACK FOR DEMO: Don't start Chrome if it's not already running. |
+ if (impl == null) |
+ return; |
+ |
+ final String DATA_KEY = "data"; |
+ if (!intent.hasExtra(DATA_KEY)) { |
+ // Not a GCM message for us (likely for sync or cloud print). |
+ return; |
+ } |
+ final String data = intent.getExtras().getString(DATA_KEY); |
+ |
+ ThreadUtils.runOnUiThread(new Runnable() { |
+ @Override |
+ public void run() { |
+ impl.nativeOnMessageReceived(impl.mNativeGcmPlatformImplAndroid, data); |
+ } |
+ }); |
+ } |
+ |
+ @Override |
+ public void onRegistered(final String registrationId) { |
+ final GcmPlatformImpl impl = GcmPlatformImpl.sInstance; |
+ // Drop this event if it arrives after Chrome gets killed. |
+ if (impl == null) |
+ return; |
+ |
+ // TODO: Check that this onRegistered event actually corresponds |
+ // to the current observer of GcmPlatformImplAndroid. Requires |
+ // changes to Android GCM API. |
+ |
+ ThreadUtils.runOnUiThread(new Runnable() { |
+ @Override |
+ public void run() { |
+ impl.nativeOnRegistrationFinished(impl.mNativeGcmPlatformImplAndroid, |
+ registrationId); |
+ } |
+ }); |
+ } |
+ |
+ @Override |
+ public void onUnregistered(String registrationId) { |
+ Log.e(TAG, "onUnregistered not implemented"); |
+ } |
+ |
+ @Override |
+ protected void onDeletedMessages(int total) { |
+ final GcmPlatformImpl impl = GcmPlatformImpl.sInstance; |
+ // HACK FOR DEMO: Don't start Chrome if it's not already running. |
+ if (impl == null) |
+ return; |
+ |
+ // FIXME: How do we know whether this message is for us, sync or cloud print? |
+ |
+ ThreadUtils.runOnUiThread(new Runnable() { |
+ @Override |
+ public void run() { |
+ impl.nativeOnMessagesDeletedByServer(impl.mNativeGcmPlatformImplAndroid); |
+ } |
+ }); |
+ } |
+ } |
+} |