2 * Copyright 2011 Google Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.google.ipc.invalidation.external.client.contrib;
18 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
19 import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
20 import com.google.ipc.invalidation.external.client.contrib.AndroidListener.AlarmReceiver;
21 import com.google.ipc.invalidation.external.client.types.ObjectId;
22 import com.google.ipc.invalidation.ticl.android2.AndroidClock;
23 import com.google.ipc.invalidation.ticl.android2.AndroidTiclManifest;
24 import com.google.ipc.invalidation.ticl.android2.channel.AndroidChannelConstants.AuthTokenConstants;
25 import com.google.protobuf.ByteString;
26 import com.google.protobuf.InvalidProtocolBufferException;
27 import com.google.protos.ipc.invalidation.AndroidListenerProtocol.RegistrationCommand;
28 import com.google.protos.ipc.invalidation.AndroidListenerProtocol.StartCommand;
30 import android.app.AlarmManager;
31 import android.app.PendingIntent;
32 import android.app.PendingIntent.CanceledException;
33 import android.content.Context;
34 import android.content.Intent;
38 * Static helper class supporting construction and decoding of intents issued and handled by the
39 * {@link AndroidListener}.
42 class AndroidListenerIntents {
45 private static final Logger logger = AndroidLogger.forPrefix("");
47 /** Key of Intent byte[] holding a {@link RegistrationCommand} protocol buffer. */
48 static final String EXTRA_REGISTRATION =
49 "com.google.ipc.invalidation.android_listener.REGISTRATION";
51 /** Key of Intent byte[] holding a {@link StartCommand} protocol buffer. */
52 static final String EXTRA_START =
53 "com.google.ipc.invalidation.android_listener.START";
55 /** Key of Intent extra indicating that the client should stop. */
56 static final String EXTRA_STOP =
57 "com.google.ipc.invalidation.android_listener.STOP";
59 /** Key of Intent extra holding a byte[] that is ack handle data. */
60 static final String EXTRA_ACK =
61 "com.google.ipc.invalidation.android_listener.ACK";
64 * Issues the given {@code intent} to the TICL service class registered in the {@code context}.
66 static void issueTiclIntent(Context context, Intent intent) {
67 context.startService(intent.setClassName(context,
68 new AndroidTiclManifest(context).getTiclServiceClass()));
72 * Issues the given {@code intent} to the {@link AndroidListener} class registered in the
75 static void issueAndroidListenerIntent(Context context, Intent intent) {
76 context.startService(setAndroidListenerClass(context, intent));
80 * Returns the ack handle from the given intent if it has the appropriate extra. Otherwise,
81 * returns {@code null}.
83 static byte[] findAckHandle(Intent intent) {
84 return intent.getByteArrayExtra(EXTRA_ACK);
88 * Returns {@link RegistrationCommand} extra from the given intent or null if no valid
89 * registration command exists.
91 static RegistrationCommand findRegistrationCommand(Intent intent) {
92 // Check that the extra exists.
93 byte[] data = intent.getByteArrayExtra(EXTRA_REGISTRATION);
98 // Attempt to parse the extra.
100 return RegistrationCommand.parseFrom(data);
101 } catch (InvalidProtocolBufferException exception) {
102 logger.warning("Received invalid proto: %s", exception);
108 * Returns {@link StartCommand} extra from the given intent or null if no valid start command
111 static StartCommand findStartCommand(Intent intent) {
112 // Check that the extra exists.
113 byte[] data = intent.getByteArrayExtra(EXTRA_START);
118 // Attempt to parse the extra.
120 return StartCommand.parseFrom(data);
121 } catch (InvalidProtocolBufferException exception) {
122 logger.warning("Received invalid proto: %s", exception);
127 /** Returns {@code true} if the intent has the 'stop' extra. */
128 static boolean isStopIntent(Intent intent) {
129 return intent.hasExtra(EXTRA_STOP);
132 /** Issues a registration retry with delay. */
133 static void issueDelayedRegistrationIntent(Context context, AndroidClock clock,
134 ByteString clientId, ObjectId objectId, boolean isRegister, int delayMs, int requestCode) {
135 RegistrationCommand command = isRegister ?
136 AndroidListenerProtos.newDelayedRegisterCommand(clientId, objectId) :
137 AndroidListenerProtos.newDelayedUnregisterCommand(clientId, objectId);
138 Intent intent = new Intent()
139 .putExtra(EXTRA_REGISTRATION, command.toByteArray())
140 .setClass(context, AlarmReceiver.class);
142 // Create a pending intent that will cause the AlarmManager to fire the above intent.
143 PendingIntent pendingIntent = PendingIntent.getBroadcast(context, requestCode, intent,
144 PendingIntent.FLAG_ONE_SHOT);
146 // Schedule the pending intent after the appropriate delay.
147 AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
148 long executeMs = clock.nowMs() + delayMs;
149 alarmManager.set(AlarmManager.RTC, executeMs, pendingIntent);
152 /** Creates a 'start-client' intent. */
153 static Intent createStartIntent(Context context, int clientType, byte[] clientName,
154 boolean allowSuppression) {
155 Intent intent = new Intent();
156 // Create proto for the start command.
157 StartCommand command = AndroidListenerProtos.newStartCommand(clientType,
158 ByteString.copyFrom(clientName), allowSuppression);
159 intent.putExtra(EXTRA_START, command.toByteArray());
160 return setAndroidListenerClass(context, intent);
163 /** Creates a 'stop-client' intent. */
164 static Intent createStopIntent(Context context) {
165 // Stop command just has the extra (its content doesn't matter).
166 Intent intent = new Intent();
167 intent.putExtra(EXTRA_STOP, true);
168 return setAndroidListenerClass(context, intent);
171 /** Create an ack intent. */
172 static Intent createAckIntent(Context context, byte[] ackHandle) {
173 // Ack intent has an extra containing the ack handle data.
174 Intent intent = new Intent();
175 intent.putExtra(EXTRA_ACK, ackHandle);
176 return setAndroidListenerClass(context, intent);
179 /** Constructs an intent with {@link RegistrationCommand} proto. */
180 static Intent createRegistrationIntent(Context context, byte[] clientId,
181 Iterable<ObjectId> objectIds, boolean isRegister) {
182 // Registration intent has an extra containing the RegistrationCommand proto.
183 Intent intent = new Intent();
184 RegistrationCommand command = isRegister
185 ? AndroidListenerProtos.newRegisterCommand(ByteString.copyFrom(clientId), objectIds)
186 : AndroidListenerProtos.newUnregisterCommand(ByteString.copyFrom(clientId), objectIds);
187 intent.putExtra(EXTRA_REGISTRATION, command.toByteArray());
188 return setAndroidListenerClass(context, intent);
191 /** Sets the appropriate class for {@link AndroidListener} service intents. */
192 static Intent setAndroidListenerClass(Context context, Intent intent) {
193 String simpleListenerClass = new AndroidTiclManifest(context).getListenerServiceClass();
194 return intent.setClassName(context, simpleListenerClass);
197 /** Returns {@code true} iff the given intent is an authorization token request. */
198 static boolean isAuthTokenRequest(Intent intent) {
199 return AuthTokenConstants.ACTION_REQUEST_AUTH_TOKEN.equals(intent.getAction());
203 * Given an authorization token request intent and authorization information ({@code authToken}
204 * and {@code authType}) issues a response.
206 static void issueAuthTokenResponse(Context context, PendingIntent pendingIntent, String authToken,
208 Intent responseIntent = new Intent()
209 .putExtra(AuthTokenConstants.EXTRA_AUTH_TOKEN, authToken)
210 .putExtra(AuthTokenConstants.EXTRA_AUTH_TOKEN_TYPE, authType);
212 pendingIntent.send(context, 0, responseIntent);
213 } catch (CanceledException exception) {
214 logger.warning("Canceled auth request: %s", exception);
218 // Prevent instantiation.
219 private AndroidListenerIntents() {