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 ProtocolRole(int intVal)41 private ProtocolRole(int intVal) { 42 mIntVal = intVal; 43 } 44 fromIntVal(int intVal)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 getAsInt()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 OptionsMessage()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 setProtocolRolePreference(ProtocolRole pref)82 public void setProtocolRolePreference(ProtocolRole pref) { 83 mProtocolRolePreference = pref; 84 } 85 getProtocolRolePreference()86 public ProtocolRole getProtocolRolePreference() { 87 return mProtocolRolePreference; 88 } 89 addInputEncoding(EncodingOption encoding)90 public void addInputEncoding(EncodingOption encoding) { 91 mInputEncodings.add(encoding); 92 } 93 addOutputEncoding(EncodingOption encoding)94 public void addOutputEncoding(EncodingOption encoding) { 95 mOutputEncodings.add(encoding); 96 } 97 supportsInputEncoding(EncodingOption encoding)98 public boolean supportsInputEncoding(EncodingOption encoding) { 99 return mInputEncodings.contains(encoding); 100 } 101 supportsOutputEncoding(EncodingOption encoding)102 public boolean supportsOutputEncoding(EncodingOption encoding) { 103 return mOutputEncodings.contains(encoding); 104 } 105 getInputEncodingSet()106 public Set<EncodingOption> getInputEncodingSet() { 107 return new HashSet<EncodingOption>(mInputEncodings); 108 } 109 getOutputEncodingSet()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 */ getBestConfiguration( OptionsMessage otherOptions)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 toString()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 equals(Object obj)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