17c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/*
27c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Copyright (C) 2009 Google Inc.  All rights reserved.
37c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
47c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Licensed under the Apache License, Version 2.0 (the "License");
57c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * you may not use this file except in compliance with the License.
67c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * You may obtain a copy of the License at
77c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
87c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *      http://www.apache.org/licenses/LICENSE-2.0
97c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet *
107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Unless required by applicable law or agreed to in writing, software
117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * distributed under the License is distributed on an "AS IS" BASIS,
127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * See the License for the specific language governing permissions and
147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * limitations under the License.
157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */
167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetpackage com.google.polo.wire.protobuf;
187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.exception.BadSecretException;
207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.exception.NoConfigurationException;
217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.exception.PoloException;
227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.exception.ProtocolErrorException;
237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.PairingContext;
247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.PoloUtil;
257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.message.ConfigurationAckMessage;
267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.message.ConfigurationMessage;
277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.message.EncodingOption;
287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.message.OptionsMessage;
297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.message.PairingRequestAckMessage;
307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.message.PairingRequestMessage;
317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.message.PoloMessage;
327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.message.SecretAckMessage;
337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.pairing.message.SecretMessage;
347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.wire.PoloWireInterface;
357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.polo.wire.protobuf.PoloProto.OuterMessage;
367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport com.google.protobuf.nano.MessageNano;
377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.io.IOException;
397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.io.InputStream;
407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetimport java.io.OutputStream;
417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet/**
437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * Implementation of {@link PoloWireInterface} that uses Protocol Buffers for
447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * the data representation.
457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * <p/>
467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * The primary work of this class is to translate Protocol Buffer messages
477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * instances (derived from {@link MessageNano} to an internal message
487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * instance (derived from {@link PoloMessage}, and vice versa.
497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * <p/>
507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * The reason we are going through all this trouble, and not using protocol
517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * buffer objects directly, is that we'd like to limit the scope of protocol
527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * buffers to the wire protocol only.  Some applications may prefer to use
537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * a different wire format, where the requirement of adding the protobuf library
547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet * could be an impediment.
557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet */
567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichetpublic class ProtobufWireAdapter implements PoloWireInterface {
577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * The output coming from the peer.
607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private final InputStream mInputStream;
627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * The input going to the peer.
647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private final OutputStream mOutputStream;
667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Constructor.
697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *
707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @param input  the {@link InputStream} from the peer
717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @param output the {@link OutputStream} to the peer
727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public ProtobufWireAdapter(InputStream input, OutputStream output) {
747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        mInputStream = input;
757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        mOutputStream = output;
767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Generates a new instance from a {@link PairingContext}.
807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *
817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @param context the {@link PairingContext}
827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @return the new instance
837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public static ProtobufWireAdapter fromContext(PairingContext context) {
857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return new ProtobufWireAdapter(context.getPeerInputStream(),
867c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                context.getPeerOutputStream());
877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Returns the next message sent over the wire, blocking as necessary.
917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public PoloMessage getNextMessage() throws IOException, PoloException {
937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return protoToPoloMessage(readNextInnerMessage());
947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Returns the next message read over the wire, requiring it to be a certain
987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * type.
997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *
1007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @param type the required message type
1017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @throws IOException   on error during read
1027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @throws PoloException if the wrong message type was read, or on protocol
1037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *                       error
1047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
1057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public PoloMessage getNextMessage(PoloMessage.PoloMessageType type)
1067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            throws IOException, PoloException {
1077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        PoloMessage message = getNextMessage();
1087c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (message.getType() != type) {
1097c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            throw new PoloException("Wrong message type (wanted " + type +
1107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                    ", got " + message.getType() + ")");
1117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
1127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return message;
1137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
1147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
1167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Returns the next message seen on the input stream.
1177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *
1187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @return the next OuterMessage read from the wire
1197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @throws IOException on error during read
1207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
1217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private OuterMessage readNextOuterMessage() throws IOException, PoloException {
1227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // Read the preamble (length of payload)
1237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        byte[] preambleBuffer = readBytesBlocking(4);
1247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int messageLen = (int) PoloUtil.intBigEndianBytesToLong(preambleBuffer);
1257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // Read the payload (serialized PoloMessage)
1277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        byte[] messageBuffer = readBytesBlocking(messageLen);
1287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // Decode and return the payload
1307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        OuterMessage message = OuterMessage.parseFrom(messageBuffer);
1317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (message.status != OuterMessage.STATUS_OK) {
1337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            throw new ProtocolErrorException();
1347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
1357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return message;
1377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
1387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
1407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Reads the next inner message from the wire, decoding and handling the outer
1417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * message in the process.
1427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *
1437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @return a protocol buffer message
1447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @throws IOException   on error during read
1457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @throws PoloException on protocol error
1467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
1477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private MessageNano readNextInnerMessage()
1487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            throws IOException, PoloException {
1497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        OuterMessage message = readNextOuterMessage();
1507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        byte[] payload = message.payload;
1527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (message.type == OuterMessage.MESSAGE_TYPE_OPTIONS) {
1547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return PoloProto.Options.parseFrom(payload);
1557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message.type == OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST) {
1567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return PoloProto.PairingRequest.parseFrom(payload);
1577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message.type == OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST_ACK) {
1587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return PoloProto.PairingRequestAck.parseFrom(payload);
1597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message.type == OuterMessage.MESSAGE_TYPE_CONFIGURATION) {
1607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return PoloProto.Configuration.parseFrom(payload);
1617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message.type == OuterMessage.MESSAGE_TYPE_CONFIGURATION_ACK) {
1627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return PoloProto.ConfigurationAck.parseFrom(payload);
1637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message.type == OuterMessage.MESSAGE_TYPE_SECRET) {
1647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return PoloProto.Secret.parseFrom(payload);
1657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message.type == OuterMessage.MESSAGE_TYPE_SECRET_ACK) {
1667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return PoloProto.SecretAck.parseFrom(payload);
1677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
1687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        throw new IOException("Could not unparse message");
1707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
1717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
1737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Convenience method to read a fixed number of bytes from the client
1747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * InputStream, blocking if necessary.
1757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *
1767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @param numBytes the number of bytes to read
1777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @return the bytes read
1787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @throws IOException on error during read
1797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
1807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private byte[] readBytesBlocking(int numBytes) throws IOException {
1817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        byte[] buf = new byte[numBytes];
1827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int bytesRead = 0;
1837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // For an SSLSocket, read() can frequently return zero bytes,
1857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // or fewer bytes than desired, due to SSL unwrapping and other
1867c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // non-application-data events.
1877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        while (bytesRead < numBytes) {
1887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            int inc = mInputStream.read(buf, bytesRead, numBytes - bytesRead);
1897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            if (inc < 0) {
1907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                throw new IOException("Stream closed while reading.");
1917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            }
1927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            bytesRead += inc;
1937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
1947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return buf;
1957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
1967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
1977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
1987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Wraps an outer message in an inner message.
1997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *
2007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @param message the {@link MessageNano} to wrap
2017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @throws PoloException if the message was not well formed
2027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
2037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private OuterMessage wrapInnerMessage(MessageNano message)
2047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            throws PoloException {
2057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int type;
2067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (message instanceof PoloProto.Options) {
2077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            type = OuterMessage.MESSAGE_TYPE_OPTIONS;
2087c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message instanceof PoloProto.PairingRequest) {
2097c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            type = OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST;
2107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message instanceof PoloProto.PairingRequestAck) {
2117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            type = OuterMessage.MESSAGE_TYPE_PAIRING_REQUEST_ACK;
2127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message instanceof PoloProto.Configuration) {
2137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            type = OuterMessage.MESSAGE_TYPE_CONFIGURATION;
2147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message instanceof PoloProto.ConfigurationAck) {
2157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            type = OuterMessage.MESSAGE_TYPE_CONFIGURATION_ACK;
2167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message instanceof PoloProto.Secret) {
2177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            type = OuterMessage.MESSAGE_TYPE_SECRET;
2187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (message instanceof PoloProto.SecretAck) {
2197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            type = OuterMessage.MESSAGE_TYPE_SECRET_ACK;
2207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else {
2217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            throw new PoloException("Bad inner message type.");
2227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
2237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        // compose outer message
2257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        OuterMessage outerMessage = new OuterMessage();
2267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        outerMessage.status = OuterMessage.STATUS_OK;
2277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        outerMessage.protocolVersion = 1;
2287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        outerMessage.type = type;
2297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        outerMessage.payload = MessageNano.toByteArray(message);
2307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return outerMessage;
2317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
2327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
2347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Writes an {@link OuterMessage} to the wire.
2357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *
2367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @param message the message
2377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @throws IOException on error during write
2387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
2397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private void writeMessage(OuterMessage message) throws IOException {
2407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        byte[] messageBytes = message.payload;
2417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int messageLength = messageBytes.length;
2427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        mOutputStream.write(PoloUtil.intToBigEndianIntBytes(messageLength));
2447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        mOutputStream.write(messageBytes);
2457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
2467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
2487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Writes a new message to the wire.
2497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
2507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public void sendMessage(PoloMessage message)
2517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            throws IOException, PoloException {
2527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        MessageNano pb = poloMessageToProto(message);
2537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        OuterMessage outerMessage = wrapInnerMessage(pb);
2547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        writeMessage(outerMessage);
2557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
2567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
2587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Sends a new error message to the wire.
2597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
2607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    public void sendErrorMessage(Exception e) throws IOException {
2617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        OuterMessage outerMessage = new OuterMessage();
2627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        outerMessage.protocolVersion = 1;
2637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (e instanceof NoConfigurationException) {
2657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            outerMessage.status = OuterMessage.STATUS_BAD_CONFIGURATION;
2667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (e instanceof BadSecretException) {
2677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            outerMessage.status = OuterMessage.STATUS_BAD_SECRET;
2687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else {
2697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            outerMessage.status = OuterMessage.STATUS_ERROR;
2707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
2717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        writeMessage(outerMessage);
2737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
2747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
2757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
2767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts an internal message to the corresponding protocol buffer message.
2777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *
2787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @param poloMessage the internal message
2797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @return a new {@link MessageNano} instance
2807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
2817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private MessageNano poloMessageToProto(PoloMessage poloMessage) {
2827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (poloMessage instanceof PairingRequestMessage) {
2837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return toProto((PairingRequestMessage) poloMessage);
2847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (poloMessage instanceof PairingRequestAckMessage) {
2857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return toProto((PairingRequestAckMessage) poloMessage);
2867c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (poloMessage instanceof OptionsMessage) {
2877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return toProto((OptionsMessage) poloMessage);
2887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (poloMessage instanceof ConfigurationMessage) {
2897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return toProto((ConfigurationMessage) poloMessage);
2907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (poloMessage instanceof ConfigurationAckMessage) {
2917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return toProto((ConfigurationAckMessage) poloMessage);
2927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (poloMessage instanceof SecretMessage) {
2937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return toProto((SecretMessage) poloMessage);
2947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (poloMessage instanceof SecretAckMessage) {
2957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return toProto((SecretAckMessage) poloMessage);
2967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
2977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return null;
2987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
2997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
3017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link PairingRequestMessage} to a
3027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * {@link PoloProto.PairingRequest}.
3037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
3047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PoloProto.PairingRequest toProto(PairingRequestMessage poloMessage) {
3057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        PoloProto.PairingRequest pairingRequest = new PoloProto.PairingRequest();
3067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        pairingRequest.serviceName = poloMessage.getServiceName();
3077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3087c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (poloMessage.hasClientName()) {
3097c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            pairingRequest.clientName = poloMessage.getClientName();
3107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
3117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return pairingRequest;
3127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
3137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
3157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link PairingRequestAckMessage} to a
3167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * {@link PoloProto.PairingRequestAck}.
3177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
3187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PoloProto.PairingRequestAck toProto(PairingRequestAckMessage poloMessage) {
3197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        PoloProto.PairingRequestAck pairingRequestAck = new PoloProto.PairingRequestAck();
3207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (poloMessage.hasServerName()) {
3217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            pairingRequestAck.serverName = poloMessage.getServerName();
3227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
3237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return pairingRequestAck;
3247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
3257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
3277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link OptionsMessage} to a {@link PoloProto.Options}.
3287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
3297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PoloProto.Options toProto(OptionsMessage poloMessage) {
3307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        PoloProto.Options options = new PoloProto.Options();
3317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        switch (poloMessage.getProtocolRolePreference()) {
3337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case DISPLAY_DEVICE:
3347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                options.preferredRole = PoloProto.Options.ROLE_TYPE_INPUT;
3357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
3367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case INPUT_DEVICE:
3377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                options.preferredRole = PoloProto.Options.ROLE_TYPE_OUTPUT;
3387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
3397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
3407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        int i = 0, n = poloMessage.getOutputEncodingSet().size();
3427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        options.outputEncodings = new PoloProto.Options.Encoding[n];
3437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        for (EncodingOption enc : poloMessage.getOutputEncodingSet()) {
3447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            options.outputEncodings[i++] = toProto(enc);
3457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
3467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        i = 0;
3487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        n = poloMessage.getInputEncodingSet().size();
3497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        options.inputEncodings = new PoloProto.Options.Encoding[n];
3507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        for (EncodingOption enc : poloMessage.getInputEncodingSet()) {
3517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            options.inputEncodings[i++] = toProto(enc);
3527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
3537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return options;
3557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
3567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
3587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link ConfigurationMessage} to a
3597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * {@link PoloProto.Configuration}.
3607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
3617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PoloProto.Configuration toProto(ConfigurationMessage poloMessage) {
3627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        PoloProto.Configuration configuration = new PoloProto.Configuration();
3637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        configuration.encoding = toProto(poloMessage.getEncoding());
3647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        configuration.clientRole = toProto(poloMessage.getClientRole());
3657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return configuration;
3667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
3677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
3697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link EncodingOption} to a {@link PoloProto.Options.Encoding}.
3707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
3717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PoloProto.Options.Encoding toProto(EncodingOption enc) {
3727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        PoloProto.Options.Encoding encoding = new PoloProto.Options.Encoding();
3737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        switch (enc.getType()) {
3757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case ENCODING_ALPHANUMERIC:
3767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_ALPHANUMERIC;
3777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
3787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case ENCODING_HEXADECIMAL:
3797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_HEXADECIMAL;
3807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
3817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case ENCODING_NUMERIC:
3827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_NUMERIC;
3837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
3847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case ENCODING_QRCODE:
3857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_QRCODE;
3867c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
3877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            default:
3887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                encoding.type = PoloProto.Options.Encoding.ENCODING_TYPE_UNKNOWN;
3897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
3907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
3917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        encoding.symbolLength = enc.getSymbolLength();
3937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return encoding;
3947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
3957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
3967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
3977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link OptionsMessage.ProtocolRole} to a
3987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * {@link PoloProto.Options}.
3997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
4007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private int toProto(OptionsMessage.ProtocolRole role) {
4017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        switch (role) {
4027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case DISPLAY_DEVICE:
4037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                return PoloProto.Options.ROLE_TYPE_OUTPUT;
4047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case INPUT_DEVICE:
4057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                return PoloProto.Options.ROLE_TYPE_INPUT;
4067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            default:
4077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                return PoloProto.Options.ROLE_TYPE_UNKNOWN;
4087c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
4097c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
4107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
4117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
4127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link ConfigurationAckMessage} to a
4137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * {@link PoloProto.ConfigurationAck}.
4147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
4157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PoloProto.ConfigurationAck toProto(ConfigurationAckMessage poloMessage) {
4167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        PoloProto.ConfigurationAck configurationAck = new PoloProto.ConfigurationAck();
4177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return configurationAck;
4187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
4197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
4207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
4217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link SecretMessage} to a {@link PoloProto.Secret}.
4227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
4237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PoloProto.Secret toProto(SecretMessage poloMessage) {
4247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        PoloProto.Secret secret = new PoloProto.Secret();
4257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        secret.secret = poloMessage.getSecret();
4267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return secret;
4277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
4287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
4297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
4307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link SecretAckMessage} to a {@link PoloProto.SecretAck}.
4317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
4327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PoloProto.SecretAck toProto(SecretAckMessage poloMessage) {
4337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        PoloProto.SecretAck secretAck = new PoloProto.SecretAck();
4347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        secretAck.secret = poloMessage.getSecret();
4357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return secretAck;
4367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
4377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
4387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    //
4397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    // polo -> protocol buffer routines
4407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    //
4417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
4427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
4437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a protocol buffer message to the corresponding internal
4447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * message.
4457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     *
4467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @param protoMessage the protobuf message to convert
4477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * @return the new {@link PoloMessage}
4487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
4497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PoloMessage protoToPoloMessage(MessageNano protoMessage) {
4507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        if (protoMessage instanceof PoloProto.PairingRequest) {
4517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return fromProto((PoloProto.PairingRequest) protoMessage);
4527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (protoMessage instanceof PoloProto.PairingRequestAck) {
4537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return fromProto((PoloProto.PairingRequestAck) protoMessage);
4547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (protoMessage instanceof PoloProto.Options) {
4557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return fromProto((PoloProto.Options) protoMessage);
4567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (protoMessage instanceof PoloProto.Configuration) {
4577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return fromProto((PoloProto.Configuration) protoMessage);
4587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (protoMessage instanceof PoloProto.ConfigurationAck) {
4597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return fromProto((PoloProto.ConfigurationAck) protoMessage);
4607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (protoMessage instanceof PoloProto.Secret) {
4617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return fromProto((PoloProto.Secret) protoMessage);
4627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        } else if (protoMessage instanceof PoloProto.SecretAck) {
4637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            return fromProto((PoloProto.SecretAck) protoMessage);
4647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
4657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return null;
4667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
4677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
4687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
4697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link PoloProto.PairingRequest} to a
4707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * {@link PairingRequestMessage}.
4717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
4727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PairingRequestMessage fromProto(PoloProto.PairingRequest protoMessage) {
4737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return new PairingRequestMessage(protoMessage.serviceName, protoMessage.clientName);
4747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
4757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
4767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
4777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link PoloProto.PairingRequestAck} to a
4787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * {@link PairingRequestAckMessage}.
4797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
4807c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private PairingRequestAckMessage fromProto(PoloProto.PairingRequestAck protoMessage) {
4817c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return new PairingRequestAckMessage(protoMessage.serverName);
4827c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
4837c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
4847c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
4857c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link PoloProto.Options} to a {@link OptionsMessage}.
4867c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
4877c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private OptionsMessage fromProto(PoloProto.Options protoMessage) {
4887c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        OptionsMessage optionsMessage = new OptionsMessage();
4897c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
4907c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        switch (protoMessage.preferredRole) {
4917c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case PoloProto.Options.ROLE_TYPE_INPUT:
4927c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                optionsMessage.setProtocolRolePreference(OptionsMessage.ProtocolRole.INPUT_DEVICE);
4937c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
4947c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case PoloProto.Options.ROLE_TYPE_OUTPUT:
4957c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                optionsMessage.setProtocolRolePreference(OptionsMessage.ProtocolRole.DISPLAY_DEVICE);
4967c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
4977c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
4987c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
4997c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        for (PoloProto.Options.Encoding e : protoMessage.inputEncodings) {
5007c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            optionsMessage.addInputEncoding(fromProto(e));
5017c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
5027c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5037c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        for (PoloProto.Options.Encoding e : protoMessage.outputEncodings) {
5047c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            optionsMessage.addOutputEncoding(fromProto(e));
5057c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
5067c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5077c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return optionsMessage;
5087c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
5097c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5107c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
5117c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link PoloProto.Configuration} to a
5127c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * {@link ConfigurationMessage}.
5137c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
5147c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private ConfigurationMessage fromProto(PoloProto.Configuration protoMessage) {
5157c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        EncodingOption enc = fromProto(protoMessage.encoding);
5167c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        OptionsMessage.ProtocolRole role = OptionsMessage.ProtocolRole.UNKNOWN;
5177c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5187c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        switch (protoMessage.clientRole) {
5197c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case PoloProto.Options.ROLE_TYPE_INPUT:
5207c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                role = OptionsMessage.ProtocolRole.INPUT_DEVICE;
5217c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
5227c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case PoloProto.Options.ROLE_TYPE_OUTPUT:
5237c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                role = OptionsMessage.ProtocolRole.DISPLAY_DEVICE;
5247c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
5257c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
5267c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5277c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return new ConfigurationMessage(enc, role);
5287c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
5297c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5307c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
5317c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link PoloProto.ConfigurationAck} to a
5327c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * {@link ConfigurationAckMessage}.
5337c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
5347c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private ConfigurationAckMessage fromProto(PoloProto.ConfigurationAck protoMessage) {
5357c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return new ConfigurationAckMessage();
5367c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
5377c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5387c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
5397c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link PoloProto.Secret} to a {@link SecretMessage}.
5407c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
5417c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private SecretMessage fromProto(PoloProto.Secret protoMessage) {
5427c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return new SecretMessage(protoMessage.secret);
5437c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
5447c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5457c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
5467c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link PoloProto.SecretAck} to a {@link SecretAckMessage}.
5477c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
5487c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private SecretAckMessage fromProto(PoloProto.SecretAck protoMessage) {
5497c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return new SecretAckMessage(protoMessage.secret);
5507c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
5517c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5527c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    /**
5537c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     * Converts a {@link PoloProto.Options.Encoding} to a {@link EncodingOption}.
5547c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet     */
5557c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    private EncodingOption fromProto(PoloProto.Options.Encoding enc) {
5567c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        EncodingOption.EncodingType type;
5577c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5587c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        switch (enc.type) {
5597c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case PoloProto.Options.Encoding.ENCODING_TYPE_ALPHANUMERIC:
5607c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                type = EncodingOption.EncodingType.ENCODING_ALPHANUMERIC;
5617c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
5627c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case PoloProto.Options.Encoding.ENCODING_TYPE_HEXADECIMAL:
5637c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                type = EncodingOption.EncodingType.ENCODING_HEXADECIMAL;
5647c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
5657c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case PoloProto.Options.Encoding.ENCODING_TYPE_NUMERIC:
5667c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                type = EncodingOption.EncodingType.ENCODING_NUMERIC;
5677c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
5687c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            case PoloProto.Options.Encoding.ENCODING_TYPE_QRCODE:
5697c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                type = EncodingOption.EncodingType.ENCODING_QRCODE;
5707c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                break;
5717c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet            default:
5727c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet                type = EncodingOption.EncodingType.ENCODING_UNKNOWN;
5737c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        }
5747c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5757c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet        return new EncodingOption(type, enc.symbolLength);
5767c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5777c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet    }
5787c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet
5797c9978567a202d6aa98beac5da5e1b3b34792862Jerome Poichet}
580