/*
* Copyright (C) 2010 Google Inc. All rights reserved.
*
* 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.anymote.device;
import java.util.concurrent.atomic.AtomicInteger;
import com.google.anymote.Key.Action;
import com.google.anymote.Key.Code;
import com.google.anymote.Messages.Data;
import com.google.anymote.Messages.Fling;
import com.google.anymote.Messages.FlingResult;
import com.google.anymote.Messages.KeyEvent;
import com.google.anymote.Messages.MouseEvent;
import com.google.anymote.Messages.MouseWheel;
import com.google.anymote.Messages.RemoteMessage;
import com.google.anymote.Messages.RequestMessage;
import com.google.anymote.Messages.ResponseMessage;
import com.google.anymote.common.ConnectInfo;
import com.google.anymote.common.RemoteWireAdapter.IMessageListener;
import com.google.anymote.common.WireAdapter;
/**
* Manages messages on the device side.
*/
public final class DeviceMessageAdapter
implements DeviceAdapter, IMessageListener {
/**
* A remote message sender.
*/
private final WireAdapter mWireAdapter;
/**
* A message receiver.
*/
private final MessageReceiver mMessageReceiver;
/**
* Ping counter.
*/
private final AtomicInteger mPingCounter = new AtomicInteger();
public DeviceMessageAdapter(MessageReceiver receiver, WireAdapter sender) {
mWireAdapter = sender;
mMessageReceiver = receiver;
}
public void onMessage(RemoteMessage message) {
if (message.hasResponseMessage()) {
Integer sequenceNumber =
message.hasSequenceNumber() ? message.getSequenceNumber() : null;
interpretResponse(message.getResponseMessage(), sequenceNumber);
}
}
public WireAdapter getWireAdapter() {
return mWireAdapter;
}
/**
* Interprets a response message.
*
* @param message the received message
*/
private void interpretResponse(
ResponseMessage message, Integer sequenceNumber) {
boolean isEmpty = true;
if (message.hasDataMessage()) {
isEmpty = false;
onData(message.getDataMessage());
}
if (message.hasFlingResultMessage()) {
isEmpty = false;
onFlingResult(message.getFlingResultMessage(), sequenceNumber);
}
if (isEmpty && sequenceNumber != null) {
onAck();
}
}
private void onAck() {
mMessageReceiver.onAck();
}
private void onData(Data connectionReply) {
String type = connectionReply.getType();
String data = connectionReply.getData();
mMessageReceiver.onData(type, data);
}
private void onFlingResult(FlingResult flingResult, Integer sequenceNumber) {
mMessageReceiver.onFlingResult(flingResult, sequenceNumber);
}
public void sendPing() {
RequestMessage.Builder request = getRequestMessageBuilder();
sendRequest(request, mPingCounter.incrementAndGet());
}
public void sendConnect(ConnectInfo connectInfo) {
RequestMessage.Builder request = getRequestMessageBuilder();
request.setConnectMessage(connectInfo.getProto());
sendRequest(request);
}
public void sendData(String type, String data) {
Data.Builder builder = Data.newBuilder();
builder.setData(data);
builder.setType(type);
RequestMessage.Builder request = getRequestMessageBuilder();
request.setDataMessage(builder);
sendRequest(request);
}
public void sendKeyEvent(Code keycode, Action action) {
KeyEvent.Builder builder = KeyEvent.newBuilder();
builder.setKeycode(keycode);
builder.setAction(action);
RequestMessage.Builder request = getRequestMessageBuilder();
request.setKeyEventMessage(builder);
sendRequest(request);
}
public void sendMouseMove(int xDelta, int yDelta) {
MouseEvent.Builder builder = MouseEvent.newBuilder();
builder.setXDelta(xDelta);
builder.setYDelta(yDelta);
RequestMessage.Builder request = getRequestMessageBuilder();
request.setMouseEventMessage(builder);
sendRequest(request);
}
public void sendMouseWheel(int xScroll, int yScroll) {
MouseWheel.Builder builder = MouseWheel.newBuilder();
builder.setXScroll(xScroll);
builder.setYScroll(yScroll);
RequestMessage.Builder request = getRequestMessageBuilder();
request.setMouseWheelMessage(builder);
sendRequest(request);
}
public void sendFling(String uri, int sequenceNumber) {
Fling.Builder builder = Fling.newBuilder();
builder.setUri(uri);
RequestMessage.Builder request = getRequestMessageBuilder();
request.setFlingMessage(builder);
sendRequest(request, sequenceNumber);
}
/**
* Constructs an empty {@code RequestMessage}.
*
* @return a request message ready to be send
*/
private static RequestMessage.Builder getRequestMessageBuilder() {
return RequestMessage.newBuilder();
}
/**
* Sends a request message.
*
* @param requestBuilder the builder that contains the message to send
* @param sequenceNumber the sequence number associated with message
*/
private void sendRequest(
RequestMessage.Builder requestBuilder, Integer sequenceNumber) {
RemoteMessage.Builder messageBuilder = RemoteMessage.newBuilder()
.setRequestMessage(requestBuilder);
if (sequenceNumber != null) {
messageBuilder.setSequenceNumber(sequenceNumber);
}
mWireAdapter.sendRemoteMessage(messageBuilder.build());
}
private void sendRequest(RequestMessage.Builder requestBuilder) {
sendRequest(requestBuilder, null);
}
/**
* Stops messages reception.
* <p>
* The streams will not be closed by function.
*/
public void stop() {
mWireAdapter.stop();
}
}