Home | History | Annotate | Download | only in message
      1 /*
      2  * Copyright (C) 2009 Google Inc.  All rights reserved.
      3  *
      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
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     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.
     15  */
     16 
     17 package com.google.polo.pairing.message;
     18 
     19 import java.util.HashSet;
     20 import java.util.Iterator;
     21 import java.util.Set;
     22 
     23 /**
     24  * Object implementing the internal representation of the protocol message
     25  * 'OPTIONS'.
     26  */
     27 public class OptionsMessage extends PoloMessage {
     28 
     29   /**
     30    * Representation of a specific role type. The numeric values
     31    * should be kept synchronized with the constants defined by
     32    * Options.Encoding.EncodingType in polo.proto.
     33    */
     34   public static enum ProtocolRole {
     35     UNKNOWN(0),
     36     INPUT_DEVICE(1),
     37     DISPLAY_DEVICE(2);
     38 
     39     private final int mIntVal;
     40 
     41     private ProtocolRole(int intVal) {
     42       mIntVal = intVal;
     43     }
     44 
     45     public static ProtocolRole fromIntVal(int intVal) {
     46       for (ProtocolRole role : ProtocolRole.values()) {
     47         if (role.getAsInt() == intVal) {
     48           return role;
     49         }
     50       }
     51       return ProtocolRole.UNKNOWN;
     52     }
     53 
     54     public int getAsInt() {
     55       return mIntVal;
     56     }
     57   }
     58 
     59   /**
     60    * The preferred protocol role of the sender.
     61    */
     62   private ProtocolRole mProtocolRolePreference;
     63 
     64   /**
     65    * Sender's supported input encodings.
     66    */
     67   private Set<EncodingOption> mInputEncodings;
     68 
     69   /**
     70    * Sender's supported output encodings.
     71    */
     72   private Set<EncodingOption> mOutputEncodings;
     73 
     74   public OptionsMessage() {
     75     super(PoloMessage.PoloMessageType.OPTIONS);
     76 
     77     mProtocolRolePreference = ProtocolRole.UNKNOWN;
     78     mInputEncodings = new HashSet<EncodingOption>();
     79     mOutputEncodings = new HashSet<EncodingOption>();
     80   }
     81 
     82   public void setProtocolRolePreference(ProtocolRole pref) {
     83     mProtocolRolePreference = pref;
     84   }
     85 
     86   public ProtocolRole getProtocolRolePreference() {
     87     return mProtocolRolePreference;
     88   }
     89 
     90   public void addInputEncoding(EncodingOption encoding) {
     91     mInputEncodings.add(encoding);
     92   }
     93 
     94   public void addOutputEncoding(EncodingOption encoding) {
     95     mOutputEncodings.add(encoding);
     96   }
     97 
     98   public boolean supportsInputEncoding(EncodingOption encoding) {
     99     return mInputEncodings.contains(encoding);
    100   }
    101 
    102   public boolean supportsOutputEncoding(EncodingOption encoding) {
    103     return mOutputEncodings.contains(encoding);
    104   }
    105 
    106   public Set<EncodingOption> getInputEncodingSet() {
    107     return new HashSet<EncodingOption>(mInputEncodings);
    108   }
    109 
    110   public Set<EncodingOption> getOutputEncodingSet() {
    111     return new HashSet<EncodingOption>(mOutputEncodings);
    112   }
    113 
    114   /**
    115    * Generates a ConfigurationMessage, or {@code null}, by intersecting the
    116    * local message with another message.
    117    */
    118   public ConfigurationMessage getBestConfiguration(
    119       OptionsMessage otherOptions) {
    120     Set<EncodingOption> peerOutputs = otherOptions.getOutputEncodingSet();
    121     peerOutputs.retainAll(mInputEncodings);
    122 
    123     Set<EncodingOption> peerInputs = otherOptions.getInputEncodingSet();
    124     peerInputs.retainAll(mOutputEncodings);
    125 
    126     if (peerOutputs.isEmpty() && peerInputs.isEmpty()) {
    127       // No configuration possible: no common encodings.
    128       return null;
    129     }
    130 
    131     EncodingOption encoding;
    132     ProtocolRole role;
    133 
    134     EncodingOption bestInput = null;
    135     if (!peerInputs.isEmpty()) {
    136       bestInput = peerInputs.iterator().next();
    137     }
    138     EncodingOption bestOutput = null;
    139     if (!peerOutputs.isEmpty()) {
    140       bestOutput = peerOutputs.iterator().next();
    141     }
    142 
    143     if (mProtocolRolePreference == ProtocolRole.DISPLAY_DEVICE) {
    144       // We prefer to be the display device
    145       if (bestInput != null) {
    146         encoding = bestInput;
    147         role = ProtocolRole.DISPLAY_DEVICE;
    148       } else {
    149         encoding = bestOutput;
    150         role = ProtocolRole.INPUT_DEVICE;
    151       }
    152     } else {
    153       // We prefer to be the input device, or have no preference
    154       if (!peerOutputs.isEmpty()) {
    155         encoding = bestOutput;
    156         role = ProtocolRole.INPUT_DEVICE;
    157       } else {
    158         encoding = bestInput;
    159         role = ProtocolRole.DISPLAY_DEVICE;
    160       }
    161     }
    162 
    163     return new ConfigurationMessage(encoding, role);
    164   }
    165 
    166   @Override
    167   public String toString() {
    168     StringBuilder ret = new StringBuilder();
    169     ret.append("[" + getType() + " ");
    170 
    171     ret.append("inputs=");
    172     Iterator<EncodingOption> inputIterator = mInputEncodings.iterator();
    173     while (inputIterator.hasNext()) {
    174       ret.append(inputIterator.next());
    175       if (inputIterator.hasNext()) {
    176         ret.append(",");
    177       }
    178     }
    179 
    180     ret.append(" outputs=");
    181     Iterator<EncodingOption> outputIterator = mOutputEncodings.iterator();
    182     while (outputIterator.hasNext()) {
    183       ret.append(outputIterator.next());
    184       if (outputIterator.hasNext()) {
    185         ret.append(",");
    186       }
    187     }
    188 
    189     ret.append(" pref=" + mProtocolRolePreference);
    190     ret.append("]");
    191     return ret.toString();
    192   }
    193 
    194   @Override
    195   public boolean equals(Object obj) {
    196     if (this == obj) {
    197       return true;
    198     }
    199 
    200     if (!(obj instanceof OptionsMessage)) {
    201       return false;
    202     }
    203 
    204     OptionsMessage other = (OptionsMessage) obj;
    205 
    206     if (mProtocolRolePreference == null) {
    207       if (other.mProtocolRolePreference != null) {
    208         return false;
    209       }
    210     } else if (!mProtocolRolePreference.equals(other.mProtocolRolePreference)) {
    211         return false;
    212     }
    213 
    214     return mInputEncodings.equals(other.mInputEncodings) &&
    215         mOutputEncodings.equals(other.mOutputEncodings);
    216   }
    217 
    218 }
    219