diff options
author | khushalsagar <khushalsagar@chromium.org> | 2015-08-19 15:53:25 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-19 22:54:00 +0000 |
commit | 66b1bc2e00f04466babc450c7fed23e6c8dc43c5 (patch) | |
tree | e2205f1e12c589f1105c4fe030079270f7a61d09 | |
parent | 8e27e940555f57b24548a6c0954a186a8b484155 (diff) | |
download | chromium_src-66b1bc2e00f04466babc450c7fed23e6c8dc43c5.zip chromium_src-66b1bc2e00f04466babc450c7fed23e6c8dc43c5.tar.gz chromium_src-66b1bc2e00f04466babc450c7fed23e6c8dc43c5.tar.bz2 |
[Part 1/3] CacheInvalidation Library Update to use GCM in GMSCore.
Roll cacheinvalidation client update release 20150819.
With this update cacheinvalidation adds support for using GCM in GMSCore. The update is backwards compatible and will support the deprecated GCM client library.
BUG=397327, 477059
Review URL: https://codereview.chromium.org/1300923002
Cr-Commit-Position: refs/heads/master@{#344360}
19 files changed, 827 insertions, 26 deletions
diff --git a/third_party/cacheinvalidation/BUILD.gn b/third_party/cacheinvalidation/BUILD.gn index 5056841..dbcae8a 100644 --- a/third_party/cacheinvalidation/BUILD.gn +++ b/third_party/cacheinvalidation/BUILD.gn @@ -148,6 +148,7 @@ if (is_android) { ":cacheinvalidation_proto_java", "//third_party/android_protobuf:protobuf_nano_javalib", "//third_party/android_tools:android_gcm_java", + google_play_services_library, ] DEPRECATED_java_in_dir = "src/java" diff --git a/third_party/cacheinvalidation/README.chromium b/third_party/cacheinvalidation/README.chromium index 9d95754..f12419c 100644 --- a/third_party/cacheinvalidation/README.chromium +++ b/third_party/cacheinvalidation/README.chromium @@ -13,4 +13,5 @@ previously hosted at http://code.google.com/p/google-cache-invalidation-api/ but was merged into the Chromium repository at r342. 2015-07-21: merging client library version 20150720 -2015-08-17: merging bug fixes for client library version 20150720
\ No newline at end of file +2015-08-17: merging bug fixes for client library version 20150720 +2015-08-19: merging client library version 20150819 diff --git a/third_party/cacheinvalidation/cacheinvalidation.gyp b/third_party/cacheinvalidation/cacheinvalidation.gyp index 7755807..dea1f54 100644 --- a/third_party/cacheinvalidation/cacheinvalidation.gyp +++ b/third_party/cacheinvalidation/cacheinvalidation.gyp @@ -223,6 +223,7 @@ 'type': 'none', 'dependencies': [ '../../third_party/android_tools/android_tools.gyp:android_gcm', + '../../third_party/android_tools/android_tools.gyp:google_play_services_javalib', 'cacheinvalidation_proto_java', ], 'variables': { diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/common/BuildConstants.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/common/BuildConstants.java index 4bc9d50..9381668 100644 --- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/common/BuildConstants.java +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/common/BuildConstants.java @@ -33,5 +33,5 @@ package com.google.ipc.invalidation.common; /** Build constant definitions. */ class BuildConstants { - static final int BUILD_DATESTAMP = 20150720; + static final int BUILD_DATESTAMP = 20150819; } diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/common/GcmSharedConstants.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/common/GcmSharedConstants.java new file mode 100644 index 0000000..782ae5a --- /dev/null +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/common/GcmSharedConstants.java @@ -0,0 +1,46 @@ +/* + * Copyright 2011 Google Inc. + * + * 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.google.ipc.invalidation.common; + +/** + * Shared client server constants for the GCM Channel. + * + * <p>On the client side a data bundle is created and sent using gcm.send(). At the server the same + * key value pairs are received in the DataMessageProto added to the {@link DataMessageRequest}. + * + */ +public class GcmSharedConstants { + + /** + * The key used for the {@link ClientToServerMessage} added to the data bundle. + */ + public static final String CLIENT_TO_SERVER_MESSAGE_KEY = "client_to_server_message"; + + /** + * The key used for the {@link NetworkEndpointId} added to the data bundle. + */ + public static final String NETWORK_ENDPOINT_ID_KEY = "network_endpoint_id"; + + /** + * Value of the client key set in the android endpoint id when sending messages using updated GCM. + */ + public static final String ANDROID_ENDPOINT_ID_CLIENT_KEY = "ANDROID_GCM_UPDATED"; + + /** + * The sender id used when sending upstream messages using GCM. + */ + public static final String GCM_UPDATED_SENDER_ID = "548642380543"; +} diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/android2/AndroidManifest.xml b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/android2/AndroidManifest.xml index 840c41f..91d526f 100644 --- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/android2/AndroidManifest.xml +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/android2/AndroidManifest.xml @@ -8,9 +8,6 @@ <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> <!-- GCM connects to Google Services. --> <uses-permission android:name="android.permission.INTERNET" /> - <!-- GCM requires a Google account. --> - <uses-permission android:name="android.permission.GET_ACCOUNTS" /> - <uses-permission android:name="android.permission.USE_CREDENTIALS" /> <!-- Keeps the processor from sleeping when a message is received. --> <uses-permission android:name="android.permission.WAKE_LOCK" /> diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/android2/AndroidManifestUpdatedGcm.xml b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/android2/AndroidManifestUpdatedGcm.xml new file mode 100644 index 0000000..8a6f60c --- /dev/null +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/android2/AndroidManifestUpdatedGcm.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> + <!-- Copyright 2011 Google Inc. All Rights Reserved. --> + <!-- Common configuration settings for application using client invalidation library with GCM update. --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.google.ipc.invalidation.client2.android2"> + + <!-- App receives GCM messages. --> + <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> + <!-- GCM connects to Google Services. --> + <uses-permission android:name="android.permission.INTERNET" /> + <!-- Used by the GCMListenerService. --> + <uses-permission android:name="android.permission.WAKE_LOCK" /> + + <application> + <!-- Ticl service. --> + <service android:exported="false" + android:name="com.google.ipc.invalidation.ticl2.android2.TiclService"/> + + <!-- Ticl sender. --> + <service android:exported="false" + android:name="com.google.ipc.invalidation.ticl2.android2.channel.AndroidMessageSenderService"/> + + <!-- Receiver for scheduler alarms. --> + <receiver android:exported="false" + android:name="com.google.ipc.invalidation.ticl2.android2.AndroidInternalScheduler$AlarmReceiver"/> + + <!-- GCM Broadcast Receiver --> + <receiver android:exported="true" + android:name="com.google.android.gms.gcm.GcmReceiver" + android:permission="com.google.android.c2dm.permission.SEND"> + <intent-filter> + <action android:name="com.google.android.c2dm.intent.RECEIVE" /> + <action android:name="com.google.android.c2dm.intent.REGISTRATION" /> + <category android:name="com.google.ipc.invalidation.client2.android2"/> + </intent-filter> + </receiver> + + <!-- InstanceID Listener Service --> + <service android:exported="false" + android:name="com.google.ipc.invalidation.ticl2.android2.channel.AndroidInstanceIDListenerService"> + <intent-filter> + <action android:name="com.google.android.gms.iid.InstanceID"/> + </intent-filter> + </service> + + <!-- GcmTaskService for registration --> + <service android:name="com.google.ipc.invalidation.ticl2.android2.channel.GcmRegistrationTaskService" + android:exported="true" + android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE" > + <intent-filter> + <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" /> + </intent-filter> + </service> + </application> +</manifest> diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/MultiplexingGcmListener.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/MultiplexingGcmListener.java index 6520f44..5fb24d1 100644 --- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/MultiplexingGcmListener.java +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/MultiplexingGcmListener.java @@ -22,6 +22,8 @@ import com.google.android.gcm.GCMRegistrar; import com.google.ipc.invalidation.external.client.SystemResources.Logger; import com.google.ipc.invalidation.external.client.android.service.AndroidLogger; import com.google.ipc.invalidation.ticl.android2.WakeLockManager; +import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelPreferences; +import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelPreferences.GcmChannelType; import android.app.IntentService; import android.content.BroadcastReceiver; @@ -263,8 +265,12 @@ public class MultiplexingGcmListener extends GCMBaseIntentService { @Override protected void onMessage(Context context, Intent intent) { Intent newIntent = new Intent(); - newIntent.putExtras(intent); newIntent.putExtra(Intents.EXTRA_OP_MESSAGE, true); + + // Copy the extra keys containing the message payload into the new Intent. + for (String extraKey : intent.getExtras().keySet()) { + newIntent.putExtra(extraKey, intent.getStringExtra(extraKey)); + } rebroadcast(newIntent); } @@ -322,6 +328,7 @@ public class MultiplexingGcmListener extends GCMBaseIntentService { * @throws IllegalStateException if the manifest is not correctly configured */ public static String initializeGcm(Context context) { + AndroidChannelPreferences.setGcmChannelType(context, GcmChannelType.DEFAULT); GCMRegistrar.checkDevice(context); GCMRegistrar.checkManifest(context); final String regId = GCMRegistrar.getRegistrationId(context); diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidTiclManifest.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidTiclManifest.java index 1f4ab07..e47b889 100644 --- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidTiclManifest.java +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidTiclManifest.java @@ -70,6 +70,11 @@ public class AndroidTiclManifest { return metadata.backgroundInvalidationListenerServiceClass; } + + public String getGcmUpstreamServiceClass() { + return metadata.gcmUpstreamServiceClass; + } + /** * If it has not already been cached for the given {@code context}, creates and caches application * metadata from the manifest. @@ -115,6 +120,13 @@ public class AndroidTiclManifest { private static final String BACKGROUND_INVALIDATION_LISTENER_SERVICE_NAME_KEY = "ipc.invalidation.ticl.background_invalidation_listener_service_class"; + /** + * Name of the {@code <application>} metadata element whose value gives the Java class that + * implements the application's gcm upstream sender intent service. + */ + private static final String GCM_UPSTREAM_SERVICE_NAME_KEY = + "ipc.invalidation.ticl.gcm_upstream_service_class"; + /** Default values returned if not overriden by the manifest file. */ private static final Map<String, String> DEFAULTS = new HashMap<String, String>(); static { @@ -124,12 +136,14 @@ public class AndroidTiclManifest { DEFAULTS.put(LISTENER_SERVICE_NAME_KEY, "com.google.ipc.invalidation.ticl.android2.AndroidInvalidationListenerStub"); DEFAULTS.put(BACKGROUND_INVALIDATION_LISTENER_SERVICE_NAME_KEY, null); + DEFAULTS.put(GCM_UPSTREAM_SERVICE_NAME_KEY, null); } private final String ticlServiceClass; private final String listenerClass; private final String listenerServiceClass; private final String backgroundInvalidationListenerServiceClass; + private final String gcmUpstreamServiceClass; ApplicationMetadata(Context context) { ApplicationInfo appInfo; @@ -145,6 +159,7 @@ public class AndroidTiclManifest { listenerServiceClass = readApplicationMetadata(appInfo, LISTENER_SERVICE_NAME_KEY); backgroundInvalidationListenerServiceClass = readApplicationMetadata(appInfo, BACKGROUND_INVALIDATION_LISTENER_SERVICE_NAME_KEY); + gcmUpstreamServiceClass = readApplicationMetadata(appInfo, GCM_UPSTREAM_SERVICE_NAME_KEY); } /** diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelConstants.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelConstants.java index bc0f4c2..8ea9a4c 100644 --- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelConstants.java +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelConstants.java @@ -121,6 +121,9 @@ public final class AndroidChannelConstants { */ static final String MESSAGE_SENDER_SVC_GCM_REGID_CHANGE = "com.google.ipc.invalidation.channel.sender.gcm_regid_change"; + + /** Tag used by the GcmRegistrationTaskService. */ + static final String GCM_REGISTRATION_TASK_SERVICE_TAG = "gcm_registration_task_service"; private AndroidChannelConstants() { // Disallow instantiation. diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelPreferences.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelPreferences.java index 1dc4c92..2a2c2f8 100644 --- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelPreferences.java +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidChannelPreferences.java @@ -25,7 +25,28 @@ import android.util.Base64; /** Accessor class for shared preference entries used by the channel. */ - public class AndroidChannelPreferences { +public class AndroidChannelPreferences { + /** GCM Channel Configurations */ + public class GcmChannelType { + /** + * Uses {@link GcmRegistrar} for registration, {@link AndroidMessageReceiverService} for + * receiving downstream messages and {@link AndroidMessageSenderService} for upstream messages. + */ + public static final int DEFAULT = 0; + + /** + * Uses InstanceID for registration, AndroidGcmController#onMessageReceived for receiving + * downstream messages and AndroidMessageSenderService for upstream messages. + */ + public static final int UPDATED = 1; + + /** + * Uses InstanceID for registration and AndroidGcmController#onMessageReceived for receiving + * downstream messages and GcmUpstreamSenderService for upstream messages. + */ + public static final int GCM_UPSTREAM = 2; + } + /** Name of the preferences in which channel preferences are stored. */ private static final String PREFERENCES_NAME = "com.google.ipc.invalidation.gcmchannel"; @@ -35,6 +56,23 @@ import android.util.Base64; */ private static final String BUFFERED_MSG_PREF = "buffered-msg"; + /** + * Preferences entry used to store the sender id for registering with GCM. + */ + private static final String GCM_CHANNEL_TYPE_PREF = "gcm_channel_type"; + + /** + * Preferences entry used to store the registration token returned for the sender id stored + * against {@code GCM_SENDER_ID}. + */ + private static final String GCM_REGISTRATION_TOKEN_PREF = "gcm_registration_token"; + + /** + * Preferences entry used to store the client app version for the {@code GCM_REGISTRATION_TOKEN} + * since the current token is not guarenteed to work with an updated version. + */ + private static final String GCM_APP_VERSION_PREF = "gcm_app_version"; + private static final Logger logger = AndroidLogger.forTag("ChannelPrefs"); /** Sets the token echoed on subsequent HTTP requests. */ @@ -94,6 +132,71 @@ import android.util.Base64; return Base64.decode(message, Base64.URL_SAFE); } + /** + * Sets the registration token returned from GCM for the sender id stored against + * {@code GCM_SENDER_ID}. + */ + static void setRegistrationToken(Context context, String token) { + if (token == null) { + return; + } + SharedPreferences.Editor editor = getPreferences(context).edit(); + editor.putString(GCM_REGISTRATION_TOKEN_PREF, token); + if (!editor.commit()) { + logger.warning("Failed writing shared preferences for: setRegistrationToken"); + } + } + + /** + * Returns the registration token stored or an empty string if no token is found. + */ + static String getRegistrationToken(Context context) { + return getPreferences(context).getString(GCM_REGISTRATION_TOKEN_PREF, ""); + } + + /** + * Stores the sender id used for registering with GCM. + * If the sender id has changed from the current sender id stored then the registration token + * is cleared. + */ + public static void setGcmChannelType(Context context, int type) { + if (getGcmChannelType(context) == type) { + return; + } + SharedPreferences.Editor editor = getPreferences(context).edit(); + editor.putInt(GCM_CHANNEL_TYPE_PREF, type); + editor.putString(GCM_REGISTRATION_TOKEN_PREF, ""); + if (!editor.commit()) { + logger.warning("Failed writing shared preferences for: setGcmChannelType"); + } + } + + /** + * Returns the sender id stored or an empty string if no token is found. + */ + static int getGcmChannelType(Context context) { + return getPreferences(context).getInt(GCM_CHANNEL_TYPE_PREF, -1); + } + + /** + * Stores the client app version for the registration token stored against {@code GCM_APP_VERSION} + */ + static void setAppVersion(Context context, int version) { + SharedPreferences.Editor editor = getPreferences(context).edit(); + + editor.putInt(GCM_APP_VERSION_PREF, version); + if (!editor.commit()) { + logger.warning("Failed writing shared preferences for: setAppVersion"); + } + } + + /** + * Returns the client app version or -1 if no version is found. + */ + static int getAppVersion(Context context) { + return getPreferences(context).getInt(GCM_APP_VERSION_PREF, -1); + } + /** Returns whether a message has been buffered, for tests. */ public static boolean hasBufferedMessageForTest(Context context) { return getPreferences(context).contains(BUFFERED_MSG_PREF); diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidGcmController.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidGcmController.java new file mode 100644 index 0000000..d1fb1c0 --- /dev/null +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidGcmController.java @@ -0,0 +1,194 @@ +/* + * Copyright 2011 Google Inc. + * + * 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.google.ipc.invalidation.ticl.android2.channel; + +import com.google.android.gms.gcm.GcmNetworkManager; +import com.google.android.gms.gcm.OneoffTask; +import com.google.ipc.invalidation.common.GcmSharedConstants; +import com.google.ipc.invalidation.external.client.SystemResources.Logger; +import com.google.ipc.invalidation.external.client.android.service.AndroidLogger; +import com.google.ipc.invalidation.ticl.android2.AndroidTiclManifest; +import com.google.ipc.invalidation.ticl.android2.ProtocolIntents; +import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelConstants.C2dmConstants; +import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelPreferences.GcmChannelType; +import com.google.ipc.invalidation.ticl.proto.AndroidChannel.AddressedAndroidMessage; +import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.Base64; + + +/** + * A controller class used by the client to initialize the GCM channel and forward downstream + * messages received from GCM. + */ +public class AndroidGcmController { + private static final Logger logger = AndroidLogger.forTag("AndroidGcmController"); + + /** Package name for Google Play Services APK. */ + private static final String GOOGLE_PLAY_SERVICES_PACKAGE = "com.google.android.gms"; + + /** Google Play Services APK version for Queso. */ + private static final int QUESO_PLAY_SERVICES_VERSION = 7571000; + + private static final Object lock = new Object(); + + private static AndroidGcmController androidGcmController; + + private GcmNetworkManager gcmNetworkManager; + + private Context context; + + /** + * A getter method for AndroidGcmController singleton which also initializes it if it wasn't + * already initialized. + * + * @param context, the application context. + * @return a singleton instance of the AndroidGcmController + */ + public static AndroidGcmController get(Context context) { + synchronized (lock) { + if (androidGcmController == null) { + androidGcmController = + new AndroidGcmController(context, GcmNetworkManager.getInstance(context)); + } + } + return androidGcmController; + } + + /** + * Override AndroidGcmController with a custom GcmNetworkManager in tests. This overrides the + * existing instance of AndroidGcmController if any. + * + * @param context, the application context. + * @param gcmNetworkManager, the custom GcmNetworkManager to use. + */ + public static void overrideAndroidGcmControllerForTests( + Context context, GcmNetworkManager gcmNetworkManager) { + synchronized (lock) { + androidGcmController = new AndroidGcmController(context, gcmNetworkManager); + } + } + + private AndroidGcmController(Context context, GcmNetworkManager gcmNetworkManager) { + this.context = context; + this.gcmNetworkManager = gcmNetworkManager; + } + + /** + * Returns true if no registration token is stored or the current application version is higher + * than the version for the token stored. + */ + private boolean shouldFetchToken() { + String pkgName = context.getPackageName(); + return AndroidChannelPreferences.getRegistrationToken(context).isEmpty() + || AndroidChannelPreferences.getAppVersion(context) + < CommonUtils.getPackageVersion(context, pkgName); + } + + /** + * Analogous to the MultiplexingGcmListener#initializeGcm call but used to support the updated + * GCM channel. Sets the {@link AndroidChannelPreferences.GcmChannelType} and fetches the + * registration token from GCM if no token is stored or if the application has been updated. + * + * @param useGcmUpstream, if true, the upstream messages from the client to the data center are + * sent using GCM. + */ + public void initializeGcm(boolean useGcmUpstream) { + if (useGcmUpstream) { + logger.info("Initializing Gcm. Use Gcm Upstream Sender Service"); + AndroidChannelPreferences.setGcmChannelType(context, GcmChannelType.GCM_UPSTREAM); + } else { + logger.info("Initializing Gcm updated."); + AndroidChannelPreferences.setGcmChannelType(context, GcmChannelType.UPDATED); + } + if (shouldFetchToken()) { + fetchToken(); + } + } + + /** + * Clears the current registration token and schedules a {@link OneoffTask} to start the + * GcmRegistrationTaskService if Google Play Services is available. + * + * <p>Declared public to be used by the client to update the token if they define an + * implementation of InstanceIDListenerService. + */ + public void fetchToken() { + // Clear the current token. If the call to InstanceID#getToken fails a new token will be fetched + // on the next call to {@code initializeGcm}. + AndroidChannelPreferences.setRegistrationToken(context, ""); + + // The GMS client library requires the corresponding version of Google Play Services APK to be + // installed on the device. + if (CommonUtils.getPackageVersion(context, GOOGLE_PLAY_SERVICES_PACKAGE) + < QUESO_PLAY_SERVICES_VERSION) { + logger.warning("Google Play Services unavailable. Initialization failed."); + return; + } + + OneoffTask registrationTask = + new OneoffTask.Builder() + .setExecutionWindow(0, 1) + .setTag(AndroidChannelConstants.GCM_REGISTRATION_TASK_SERVICE_TAG) + .setService(GcmRegistrationTaskService.class) + .build(); + + gcmNetworkManager.schedule(registrationTask); + } + + /** + * Used by the client to get the sender id to filter the GCM downstream messages forwarded to + * {@code onMessageReceived}. + */ + public String getSenderId() { + return GcmSharedConstants.GCM_UPDATED_SENDER_ID; + } + + /** + * Used by the client to forward downstream messages received from GCM. + * + * @param data, the data bundle of the downstream message. + */ + public void onMessageReceived(Bundle data) { + String content = data.getString(C2dmConstants.CONTENT_PARAM); + if (content != null) { + byte[] msgBytes = Base64.decode(content, Base64.URL_SAFE); + try { + // Look up the name of the Ticl service class from the manifest. + String serviceClass = new AndroidTiclManifest(context).getTiclServiceClass(); + AddressedAndroidMessage addrMessage = AddressedAndroidMessage.parseFrom(msgBytes); + Intent msgIntent = + ProtocolIntents.InternalDowncalls.newServerMessageIntent(addrMessage.getMessage()); + msgIntent.setClassName(context, serviceClass); + context.startService(msgIntent); + } catch (ValidationException exception) { + logger.warning("Failed parsing inbound message: %s", exception); + } + } else { + logger.warning("GCM Intent has no message content: %s", data); + } + + // Store the echo token. + + String echoToken = data.getString(C2dmConstants.ECHO_PARAM); + if (echoToken != null) { + AndroidChannelPreferences.setEchoToken(context, echoToken); + } + } +} diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidInstanceIDListenerService.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidInstanceIDListenerService.java new file mode 100644 index 0000000..f96b8a2 --- /dev/null +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidInstanceIDListenerService.java @@ -0,0 +1,38 @@ +/* + * Copyright 2011 Google Inc. + * + * 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.google.ipc.invalidation.ticl.android2.channel; + +import com.google.android.gms.iid.InstanceIDListenerService; +import com.google.ipc.invalidation.external.client.SystemResources.Logger; +import com.google.ipc.invalidation.external.client.android.service.AndroidLogger; + +/** + * Implementation of {@link InstanceIDListenerService} to receive notifications from GCM to + * update the registration token. + */ +public class AndroidInstanceIDListenerService extends InstanceIDListenerService { + private static final Logger logger = AndroidLogger.forTag("InstanceIDListener"); + + /** + * Called when the token needs to updated. {@link AndroidGcmController#fetchToken} clears the + * current token and schedules a task to fetch a new token. + */ + @Override + public void onTokenRefresh() { + logger.info("Received token refresh request"); + AndroidGcmController.get(this).fetchToken(); + } +} diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java index 2dc4590..81882a7 100644 --- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java @@ -16,12 +16,14 @@ package com.google.ipc.invalidation.ticl.android2.channel; import com.google.android.gcm.GCMRegistrar; +import com.google.ipc.invalidation.common.GcmSharedConstants; import com.google.ipc.invalidation.external.client.SystemResources.Logger; import com.google.ipc.invalidation.external.client.android.service.AndroidLogger; import com.google.ipc.invalidation.ticl.android2.AndroidTiclManifest; import com.google.ipc.invalidation.ticl.android2.ProtocolIntents; import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelConstants.AuthTokenConstants; import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelConstants.HttpConstants; +import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelPreferences.GcmChannelType; import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidNetworkSendRequest; import com.google.ipc.invalidation.ticl.proto.ChannelCommon.NetworkEndpointId; import com.google.ipc.invalidation.ticl.proto.CommonProtos; @@ -63,12 +65,6 @@ public class AndroidMessageSenderService extends IntentService { */ private static final String OAUTH2_TOKEN_TYPE_PREFIX = "oauth2:"; - /** - * Client key used in network endpoint ids. We only have one client at present, so there is no - * need for a key. - */ - private static final String NO_CLIENT_KEY = ""; - /** An override of the URL, for testing. */ private static String channelUrlForTest = null; @@ -390,13 +386,23 @@ public class AndroidMessageSenderService extends IntentService { public static NetworkEndpointId getNetworkEndpointId(Context context, Logger logger) { String registrationId; - try { - registrationId = GCMRegistrar.getRegistrationId(context); - } catch (RuntimeException exception) { - // GCMRegistrar#getRegistrationId occasionally throws a runtime exception. Catching the - // exception rather than crashing. - logger.warning("Unable to get GCM registration id: %s", exception); - registrationId = null; + String clientKey; + + // Select the registration token to use. + if (AndroidChannelPreferences.getGcmChannelType(context) == GcmChannelType.UPDATED) { + registrationId = AndroidChannelPreferences.getRegistrationToken(context); + clientKey = GcmSharedConstants.ANDROID_ENDPOINT_ID_CLIENT_KEY; + } else { + // No client key when using old style registration id. + clientKey = ""; + try { + registrationId = GCMRegistrar.getRegistrationId(context); + } catch (RuntimeException exception) { + // GCMRegistrar#getRegistrationId occasionally throws a runtime exception. Catching the + // exception rather than crashing. + logger.warning("Unable to get GCM registration id: %s", exception); + registrationId = null; + } } if ((registrationId == null) || registrationId.isEmpty()) { // No registration with GCM; we cannot compute a network id. The GCM documentation says the @@ -405,7 +411,7 @@ public class AndroidMessageSenderService extends IntentService { "No GCM registration id; cannot determine our network endpoint id: %s", registrationId); return null; } - return CommonProtos.newAndroidEndpointId(registrationId, NO_CLIENT_KEY, + return CommonProtos.newAndroidEndpointId(registrationId, clientKey, context.getPackageName(), AndroidChannelConstants.CHANNEL_VERSION); } diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java index afce69c..4a3adef 100644 --- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java @@ -16,9 +16,13 @@ package com.google.ipc.invalidation.ticl.android2.channel; import com.google.ipc.invalidation.external.client.SystemResources; +import com.google.ipc.invalidation.external.client.SystemResources.Logger; +import com.google.ipc.invalidation.external.client.android.service.AndroidLogger; import com.google.ipc.invalidation.ticl.TestableNetworkChannel; +import com.google.ipc.invalidation.ticl.android2.AndroidTiclManifest; import com.google.ipc.invalidation.ticl.android2.ProtocolIntents; import com.google.ipc.invalidation.ticl.android2.ResourcesFactory.AndroidResources; +import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelPreferences.GcmChannelType; import com.google.ipc.invalidation.ticl.proto.ChannelCommon.NetworkEndpointId; import com.google.ipc.invalidation.util.Preconditions; @@ -31,6 +35,7 @@ import android.content.Intent; * */ public class AndroidNetworkChannel implements TestableNetworkChannel { + private static final Logger logger = AndroidLogger.forTag("AndroidNetworkChannel"); private final Context context; private AndroidResources resources; @@ -41,7 +46,18 @@ public class AndroidNetworkChannel implements TestableNetworkChannel { @Override public void sendMessage(byte[] outgoingMessage) { Intent intent = ProtocolIntents.newOutboundMessageIntent(outgoingMessage); - intent.setClassName(context, AndroidMessageSenderService.class.getName()); + + // Select the sender service to use for upstream message. + if (AndroidChannelPreferences.getGcmChannelType(context) == GcmChannelType.GCM_UPSTREAM){ + String upstreamServiceClass = new AndroidTiclManifest(context).getGcmUpstreamServiceClass(); + if (upstreamServiceClass == null || upstreamServiceClass.isEmpty()) { + logger.warning("GcmUpstreamSenderService class not found."); + return; + } + intent.setClassName(context, upstreamServiceClass); + } else { + intent.setClassName(context, AndroidMessageSenderService.class.getName()); + } context.startService(intent); } diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/CommonUtils.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/CommonUtils.java new file mode 100644 index 0000000..08b87e5 --- /dev/null +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/CommonUtils.java @@ -0,0 +1,39 @@ +/* + * Copyright 2011 Google Inc. + * + * 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.google.ipc.invalidation.ticl.android2.channel; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; + +/** Common utility functions for the channel. */ +public class CommonUtils { + /** Returns the package version for the given package name or -1 if the package is not found. */ + static int getPackageVersion(Context context, String packageName) { + int versionCode = -1; + PackageManager pm = context.getPackageManager(); + try { + PackageInfo packageInfo = pm.getPackageInfo(packageName, 0); + if (packageInfo != null) { + versionCode = packageInfo.versionCode; + } + } catch (PackageManager.NameNotFoundException e) { + // Do nothing, versionCode stays -1 + } + return versionCode; + } +} + diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/GcmRegistrationTaskService.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/GcmRegistrationTaskService.java new file mode 100644 index 0000000..dc614b0 --- /dev/null +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/GcmRegistrationTaskService.java @@ -0,0 +1,116 @@ +/* + * Copyright 2011 Google Inc. + * + * 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.google.ipc.invalidation.ticl.android2.channel; + +import com.google.android.gms.gcm.GcmNetworkManager; +import com.google.android.gms.gcm.GcmTaskService; +import com.google.android.gms.gcm.GoogleCloudMessaging; +import com.google.android.gms.gcm.TaskParams; +import com.google.android.gms.iid.InstanceID; +import com.google.ipc.invalidation.common.GcmSharedConstants; +import com.google.ipc.invalidation.external.client.SystemResources.Logger; +import com.google.ipc.invalidation.external.client.android.service.AndroidLogger; +import com.google.ipc.invalidation.ticl.android2.AndroidTiclManifest; +import com.google.ipc.invalidation.ticl.android2.ProtocolIntents; +import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelPreferences.GcmChannelType; + +import android.content.Context; +import android.content.Intent; + +import java.io.IOException; + +/** + * Implementation of {@link GcmTaskService} to fetch the registration token from GCM. The service is + * started by the {@link GcmNetworkManager} when a Task scheduled using the GcmNetworkManager is + * ready to be executed. The task to start this service is scheduled in + * {@link AndroidGcmController#fetchToken}. + * + * <p>The service fetches a token from GCM, stores it and sends an update to the server. In case of + * failure to fetch the token, the task is rescheduled using the GcmNetworkManager which uses + * exponential back-offs to control when the task is executed. + */ +public class GcmRegistrationTaskService extends GcmTaskService { + private static final Logger logger = AndroidLogger.forTag("RegistrationTaskService"); + + public InstanceID getInstanceID(Context context) { + return InstanceID.getInstance(context); + } + + /** + * Called when the task is ready to be executed. Registers with GCM using + * {@link InstanceID#getToken} and stores the registration token. + * + * <p>Returns {@link GcmNetworkManager#RESULT_SUCCESS} when the token is successfully retrieved. + * On failure {@link GcmNetworkManager#RESULT_RESCHEDULE} is used which reschedules the service + * to be executed again using exponential back-off. + */ + @Override + public int onRunTask(TaskParams params) { + if (!AndroidChannelConstants.GCM_REGISTRATION_TASK_SERVICE_TAG.equals(params.getTag())) { + logger.warning("Unknown task received with tag: %s", params.getTag()); + return GcmNetworkManager.RESULT_FAILURE; + } + + String senderId = GcmSharedConstants.GCM_UPDATED_SENDER_ID; + try { + String token = getInstanceID(this).getToken( + senderId, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); + storeToken(token); + return GcmNetworkManager.RESULT_SUCCESS; + } catch (IOException exception) { + logger.warning("Failed to get token for sender: %s. Exception : %s", senderId, exception); + return GcmNetworkManager.RESULT_RESCHEDULE; + } + } + + /** Stores the registration token and the current application version in Shared Preferences. */ + private void storeToken(String token) { + AndroidChannelPreferences.setRegistrationToken(this, token); + AndroidChannelPreferences.setAppVersion( + this, CommonUtils.getPackageVersion(this, getPackageName())); + // Send the updated token to the server. + updateServer(); + } + + /** Sends a message to the server to update the GCM registration token. */ + private void updateServer() { + // Inform the sender service that the registration token has changed. If the sender service + // had buffered a message because no registration token was previously available, this intent + // will cause it to send that message. + Intent sendBuffered = new Intent(); + final String ignoredData = ""; + sendBuffered.putExtra(AndroidChannelConstants.MESSAGE_SENDER_SVC_GCM_REGID_CHANGE, ignoredData); + + // Select the sender service to use for upstream message. + if (AndroidChannelPreferences.getGcmChannelType(this) == GcmChannelType.GCM_UPSTREAM) { + String upstreamServiceClass = new AndroidTiclManifest(this).getGcmUpstreamServiceClass(); + if (upstreamServiceClass == null) { + logger.warning("GcmUpstreamSenderService class not found."); + return; + } + sendBuffered.setClassName(this, upstreamServiceClass); + } else { + sendBuffered.setClass(this, AndroidMessageSenderService.class); + } + startService(sendBuffered); + + // Inform the Ticl service that the registration id has changed. This will cause it to send + // a message to the data center and update the GCM registration id stored at the data center. + Intent updateServer = ProtocolIntents.InternalDowncalls.newNetworkAddrChangeIntent(); + updateServer.setClassName(this, new AndroidTiclManifest(this).getTiclServiceClass()); + startService(updateServer); + } +} diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/GcmUpstreamSenderService.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/GcmUpstreamSenderService.java new file mode 100644 index 0000000..8be42ef4 --- /dev/null +++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/GcmUpstreamSenderService.java @@ -0,0 +1,167 @@ +/* + * Copyright 2011 Google Inc. + * + * 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.google.ipc.invalidation.ticl.android2.channel; + +import com.google.ipc.invalidation.common.GcmSharedConstants; +import com.google.ipc.invalidation.external.client.SystemResources.Logger; +import com.google.ipc.invalidation.external.client.android.service.AndroidLogger; +import com.google.ipc.invalidation.ticl.android2.ProtocolIntents; +import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelPreferences.GcmChannelType; +import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidNetworkSendRequest; +import com.google.ipc.invalidation.ticl.proto.ChannelCommon.NetworkEndpointId; +import com.google.ipc.invalidation.ticl.proto.CommonProtos; +import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException; + +import android.app.IntentService; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.Base64; + + +/** + * Base class to send upstream messages using the GCM channel. Creates the bundle to send using + * GoogleCloudMessaging#send. The client should add an OAuth2 token to bundle before sending + * the message. + * + * <p>A sample implementation of an {@link GcmUpstreamSenderService} is shown below: + * + * <p><code> + * class ExampleSenderService extends GcmUpstreamSenderService { + * @Override + * public void deliverMessage(String to, Bundle data) { + * String messageId = ...; + * String oAuth2Token = ...; + * data.putString("Authorization", "Bearer " + oAuth2Token); + * GoogleCloudMessaging.getInstance(this).send(to, messageId, data); + * } + * } + * </code> + */ +public abstract class GcmUpstreamSenderService extends IntentService { + + private static final Logger logger = AndroidLogger.forTag("GcmMsgSenderSvc"); + + public GcmUpstreamSenderService() { + super("GcmUpstreamService"); + setIntentRedelivery(true); + } + + @Override + protected void onHandleIntent(Intent intent) { + if (AndroidChannelPreferences.getGcmChannelType(this) != GcmChannelType.GCM_UPSTREAM) { + logger.warning("Incorrect channel type for using GCM Upstream"); + return; + } + if (intent == null) { + return; + } + + if (intent.hasExtra(ProtocolIntents.OUTBOUND_MESSAGE_KEY)) { + // Request from the Ticl service to send a message. + handleOutboundMessage(intent.getByteArrayExtra(ProtocolIntents.OUTBOUND_MESSAGE_KEY)); + } else if (intent.hasExtra(AndroidChannelConstants.MESSAGE_SENDER_SVC_GCM_REGID_CHANGE)) { + handleGcmRegIdChange(); + } else { + logger.warning("Ignoring intent: %s", intent); + } + } + + /** + * Handles a request to send a message to the data center. Validates the message and creates the + * Bundle to be sent in the upstream message. + */ + private void handleOutboundMessage(byte[] sendRequestBytes) { + // Parse and validate the send request. + final AndroidNetworkSendRequest sendRequest; + try { + sendRequest = AndroidNetworkSendRequest.parseFrom(sendRequestBytes); + } catch (ValidationException exception) { + logger.warning("Invalid AndroidNetworkSendRequest from %s: %s", + sendRequestBytes, exception); + return; + } + + byte[] message = sendRequest.getMessage().getByteArray(); + sendUpstreamMessage(message); + } + + /** + * Handles a change in the GCM registration token by sending the buffered client message (if any) + * to the data center. + */ + private void handleGcmRegIdChange() { + byte[] bufferedMessage = AndroidChannelPreferences.takeBufferedMessage(this); + if (bufferedMessage != null) { + sendUpstreamMessage(bufferedMessage); + } + } + + /** + * Creates the Bundle for sending the {@code message}. Encodes the message and the network + * endpoint id and adds it to the bundle. + */ + private void sendUpstreamMessage(byte[] message) { + NetworkEndpointId endpointId = getNetworkEndpointId(this); + if (endpointId == null) { + logger.info("Buffering message to the data center: no GCM registration id"); + AndroidChannelPreferences.bufferMessage(this, message); + return; + } + Bundle dataBundle = new Bundle(); + + // Add the encoded android endpoint id to the bundle + dataBundle.putString(GcmSharedConstants.NETWORK_ENDPOINT_ID_KEY, + base64Encode(endpointId.toByteArray())); + + // Add the encoded message to the bundle + dataBundle.putString(GcmSharedConstants.CLIENT_TO_SERVER_MESSAGE_KEY, + base64Encode(message)); + logger.info("Encoded message: %s", base64Encode(message)); + + // Currently we do not check for message size limits since this will be run as an experiment. + // Feedback from the experiment will be used to decide whether handling of message size + // limit is required. + deliverMessage(GcmSharedConstants.GCM_UPDATED_SENDER_ID + "@google.com", dataBundle); + } + + /** + * Implemented by the client to deliver the message using GCM. + */ + protected abstract void deliverMessage(String to, Bundle data); + + /** Returns the endpoint id for this channel, or {@code null} if one cannot be determined. */ + + + static NetworkEndpointId getNetworkEndpointId(Context context) { + String registrationToken = AndroidChannelPreferences.getRegistrationToken(context); + if (registrationToken == null || registrationToken.isEmpty()) { + logger.warning("No GCM registration token; cannot determine our network endpoint id: %s", + registrationToken); + return null; + } + return CommonProtos.newAndroidEndpointId(registrationToken, + GcmSharedConstants.ANDROID_ENDPOINT_ID_CLIENT_KEY, + context.getPackageName(), AndroidChannelConstants.CHANNEL_VERSION); + } + + /** Returns a base-64 encoded version of {@code bytes}. */ + private static String base64Encode(byte[] bytes) { + logger.info("Encoding message: %s", bytes); + return Base64.encodeToString(bytes, Base64.NO_WRAP); + } +} + diff --git a/third_party/cacheinvalidation/src/javaexample/com/google/ipc/invalidation/examples/android2/AndroidManifest.xml b/third_party/cacheinvalidation/src/javaexample/com/google/ipc/invalidation/examples/android2/AndroidManifest.xml index 4c0dce8..5e20f63 100644 --- a/third_party/cacheinvalidation/src/javaexample/com/google/ipc/invalidation/examples/android2/AndroidManifest.xml +++ b/third_party/cacheinvalidation/src/javaexample/com/google/ipc/invalidation/examples/android2/AndroidManifest.xml @@ -69,10 +69,6 @@ <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/> <!-- GCM connects to Google Services. --> <uses-permission android:name="android.permission.INTERNET"/> - <!-- GCM requires a Google account. --> - <uses-permission android:name="android.permission.GET_ACCOUNTS"/> - <!-- Merged from file: java/com/google/ipc/invalidation/external/client/android2/AndroidManifest.xml --> - <uses-permission android:name="android.permission.USE_CREDENTIALS"/> <!-- Keeps the processor from sleeping when a message is received. --> <uses-permission android:name="android.permission.WAKE_LOCK"/> </manifest> |