blob: ed1ec514cf64acfc2ee119c3fd431c0190afbb70 [file] [log] [blame]
/*
* 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;
import com.google.ipc.invalidation.external.client.InvalidationClient;
import com.google.ipc.invalidation.external.client.InvalidationListener;
import com.google.ipc.invalidation.external.client.InvalidationListener.RegistrationState;
import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
import com.google.ipc.invalidation.external.client.types.AckHandle;
import com.google.ipc.invalidation.external.client.types.ErrorInfo;
import com.google.ipc.invalidation.ticl.ProtoWrapperConverter;
import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall;
import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ErrorUpcall;
import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.InvalidateUpcall;
import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationFailureUpcall;
import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.RegistrationStatusUpcall;
import com.google.ipc.invalidation.ticl.proto.AndroidService.ListenerUpcall.ReissueRegistrationsUpcall;
import com.google.ipc.invalidation.util.ProtoWrapper.ValidationException;
import android.content.Context;
import android.content.Intent;
import java.util.Arrays;
/**
* Routes intents to the appropriate methods in {@link InvalidationListener}. Typically, an instance
* of the mapper should be created in {@code IntentService#onCreate} and the {@link #handleIntent}
* method called in {@code IntentService#onHandleIntent}.
*
*/
public final class AndroidInvalidationListenerIntentMapper {
/** The logger. */
private final AndroidLogger logger = AndroidLogger.forPrefix("");
/** Client passed to the listener (supports downcalls). */
public final InvalidationClient client;
/** Listener to which intents are routed. */
private final InvalidationListener listener;
/**
* Initializes
*
* @param listener the listener to which intents should be routed
* @param context the context used by the listener to issue downcalls to the TICL
*/
public AndroidInvalidationListenerIntentMapper(InvalidationListener listener, Context context) {
client = new AndroidInvalidationClientStub(context, logger);
this.listener = listener;
}
/**
* Handles a listener upcall by decoding the protocol buffer in {@code intent} and dispatching
* to the appropriate method on the {@link #listener}.
*/
public void handleIntent(Intent intent) {
// TODO: use wakelocks
// Unmarshall the arguments from the Intent and make the appropriate call on the listener.
ListenerUpcall upcall = tryParseIntent(intent);
if (upcall == null) {
return;
}
if (upcall.hasReady()) {
listener.ready(client);
} else if (upcall.getNullableInvalidate() != null) {
// Handle all invalidation-related upcalls on a common path, since they require creating
// an AckHandleP.
onInvalidateUpcall(upcall.getNullableInvalidate(), listener);
} else if (upcall.getNullableRegistrationStatus() != null) {
RegistrationStatusUpcall regStatus = upcall.getNullableRegistrationStatus();
listener.informRegistrationStatus(client,
ProtoWrapperConverter.convertFromObjectIdProto(regStatus.getObjectId()),
regStatus.getIsRegistered() ?
RegistrationState.REGISTERED : RegistrationState.UNREGISTERED);
} else if (upcall.getNullableRegistrationFailure() != null) {
RegistrationFailureUpcall failure = upcall.getNullableRegistrationFailure();
listener.informRegistrationFailure(client,
ProtoWrapperConverter.convertFromObjectIdProto(failure.getObjectId()),
failure.getTransient(),
failure.getMessage());
} else if (upcall.getNullableReissueRegistrations() != null) {
ReissueRegistrationsUpcall reissueRegs = upcall.getNullableReissueRegistrations();
listener.reissueRegistrations(client, reissueRegs.getPrefix().getByteArray(),
reissueRegs.getLength());
} else if (upcall.getNullableError() != null) {
ErrorUpcall error = upcall.getNullableError();
ErrorInfo errorInfo = ErrorInfo.newInstance(error.getErrorCode(), error.getIsTransient(),
error.getErrorMessage(), null);
listener.informError(client, errorInfo);
} else {
logger.warning("Dropping listener Intent with unknown call: %s", upcall);
}
}
/**
* Handles an invalidation-related listener {@code upcall} by dispatching to the appropriate
* method on an instance of {@link InvalidationListener}.
*/
private void onInvalidateUpcall(InvalidateUpcall invalidate, InvalidationListener listener) {
AckHandle ackHandle = AckHandle.newInstance(invalidate.getAckHandle().getByteArray());
if (invalidate.getNullableInvalidation() != null) {
listener.invalidate(client,
ProtoWrapperConverter.convertFromInvalidationProto(invalidate.getNullableInvalidation()),
ackHandle);
} else if (invalidate.hasInvalidateAll()) {
listener.invalidateAll(client, ackHandle);
} else if (invalidate.getNullableInvalidateUnknown() != null) {
listener.invalidateUnknownVersion(client,
ProtoWrapperConverter.convertFromObjectIdProto(invalidate.getNullableInvalidateUnknown()),
ackHandle);
} else {
throw new RuntimeException("Invalid invalidate upcall: " + invalidate);
}
}
/**
* Returns a valid {@link ListenerUpcall} from {@code intent}, or {@code null} if one
* could not be parsed.
*/
private ListenerUpcall tryParseIntent(Intent intent) {
if (intent == null) {
return null;
}
byte[] upcallBytes = intent.getByteArrayExtra(ProtocolIntents.LISTENER_UPCALL_KEY);
if (upcallBytes == null) {
return null;
}
try {
ListenerUpcall upcall = ListenerUpcall.parseFrom(upcallBytes);
return upcall;
} catch (ValidationException exception) {
logger.severe("Could not parse listener upcall from %s", Arrays.toString(upcallBytes));
return null;
}
}
}