1 /* 2 * Copyright (C) 2015 Samsung System LSI 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 package com.android.bluetooth.map; 16 17 import android.util.Log; 18 19 import com.android.bluetooth.SignedLongLong; 20 21 import org.xmlpull.v1.XmlPullParser; 22 import org.xmlpull.v1.XmlPullParserException; 23 import org.xmlpull.v1.XmlSerializer; 24 25 import java.io.IOException; 26 import java.io.UnsupportedEncodingException; 27 import java.text.ParseException; 28 import java.text.SimpleDateFormat; 29 import java.util.Date; 30 31 public class BluetoothMapConvoContactElement 32 implements Comparable<BluetoothMapConvoContactElement> { 33 34 public static final long CONTACT_ID_TYPE_SMS_MMS = 1; 35 public static final long CONTACT_ID_TYPE_EMAIL = 2; 36 public static final long CONTACT_ID_TYPE_IM = 3; 37 38 private static final String XML_ATT_PRIORITY = "priority"; 39 private static final String XML_ATT_PRESENCE_STATUS = "presence_status"; 40 private static final String XML_ATT_PRESENCE_AVAILABILITY = "presence_availability"; 41 private static final String XML_ATT_X_BT_UID = "x_bt_uid"; 42 private static final String XML_ATT_LAST_ACTIVITY = "last_activity"; 43 private static final String XML_ATT_CHAT_STATE = "chat_state"; 44 private static final String XML_ATT_NAME = "name"; 45 private static final String XML_ATT_DISPLAY_NAME = "display_name"; 46 private static final String XML_ATT_UCI = "x_bt_uci"; 47 protected static final String XML_TAG_CONVOCONTACT = "convocontact"; 48 private static final String TAG = "BluetoothMapConvoContactElement"; 49 private static final boolean D = false; 50 private static final boolean V = false; 51 52 private String mUci = null; 53 private String mName = null; 54 private String mDisplayName = null; 55 private String mPresenceStatus = null; 56 private int mPresenceAvailability = -1; 57 private int mPriority = -1; 58 private long mLastActivity = -1; 59 private SignedLongLong mBtUid = null; 60 private int mChatState = -1; 61 createFromMapContact(MapContact contact, String address)62 public static BluetoothMapConvoContactElement createFromMapContact(MapContact contact, 63 String address) { 64 BluetoothMapConvoContactElement newElement = new BluetoothMapConvoContactElement(); 65 newElement.mUci = address; 66 // TODO: For now we use the ID as BT-UID 67 newElement.mBtUid = new SignedLongLong(contact.getId(), 0); 68 newElement.mDisplayName = contact.getName(); 69 return newElement; 70 } 71 BluetoothMapConvoContactElement(String uci, String name, String displayName, String presenceStatus, int presenceAvailability, long lastActivity, int chatState, int priority, String btUid)72 public BluetoothMapConvoContactElement(String uci, String name, String displayName, 73 String presenceStatus, int presenceAvailability, long lastActivity, int chatState, 74 int priority, String btUid) { 75 this.mUci = uci; 76 this.mName = name; 77 this.mDisplayName = displayName; 78 this.mPresenceStatus = presenceStatus; 79 this.mPresenceAvailability = presenceAvailability; 80 this.mLastActivity = lastActivity; 81 this.mChatState = chatState; 82 this.mPresenceStatus = presenceStatus; 83 this.mPriority = priority; 84 if (btUid != null) { 85 try { 86 this.mBtUid = SignedLongLong.fromString(btUid); 87 } catch (UnsupportedEncodingException e) { 88 Log.w(TAG, e); 89 } 90 } 91 } 92 BluetoothMapConvoContactElement()93 public BluetoothMapConvoContactElement() { 94 // TODO Auto-generated constructor stub 95 } 96 getPresenceStatus()97 public String getPresenceStatus() { 98 return mPresenceStatus; 99 } 100 getDisplayName()101 public String getDisplayName() { 102 return mDisplayName; 103 } 104 setDisplayName(String displayName)105 public void setDisplayName(String displayName) { 106 this.mDisplayName = displayName; 107 } 108 setPresenceStatus(String presenceStatus)109 public void setPresenceStatus(String presenceStatus) { 110 this.mPresenceStatus = presenceStatus; 111 } 112 getPresenceAvailability()113 public int getPresenceAvailability() { 114 return mPresenceAvailability; 115 } 116 setPresenceAvailability(int presenceAvailability)117 public void setPresenceAvailability(int presenceAvailability) { 118 this.mPresenceAvailability = presenceAvailability; 119 } 120 getPriority()121 public int getPriority() { 122 return mPriority; 123 } 124 setPriority(int priority)125 public void setPriority(int priority) { 126 this.mPriority = priority; 127 } 128 getName()129 public String getName() { 130 return mName; 131 } 132 setName(String name)133 public void setName(String name) { 134 this.mName = name; 135 } 136 getBtUid()137 public String getBtUid() { 138 return mBtUid.toHexString(); 139 } 140 setBtUid(SignedLongLong btUid)141 public void setBtUid(SignedLongLong btUid) { 142 this.mBtUid = btUid; 143 } 144 getChatState()145 public int getChatState() { 146 return mChatState; 147 } 148 setChatState(int chatState)149 public void setChatState(int chatState) { 150 this.mChatState = chatState; 151 } 152 setChatState(String chatState)153 public void setChatState(String chatState) { 154 this.mChatState = Integer.valueOf(chatState); 155 } 156 157 getLastActivityString()158 public String getLastActivityString() { 159 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); 160 Date date = new Date(mLastActivity); 161 return format.format(date); // Format to YYYYMMDDTHHMMSS local time 162 } 163 setLastActivity(long dateTime)164 public void setLastActivity(long dateTime) { 165 this.mLastActivity = dateTime; 166 } 167 setLastActivity(String lastActivity)168 public void setLastActivity(String lastActivity) throws ParseException { 169 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); 170 Date date = format.parse(lastActivity); 171 this.mLastActivity = date.getTime(); 172 } 173 setContactId(String uci)174 public void setContactId(String uci) { 175 this.mUci = uci; 176 } 177 getContactId()178 public String getContactId() { 179 return mUci; 180 } 181 182 @Override compareTo(BluetoothMapConvoContactElement e)183 public int compareTo(BluetoothMapConvoContactElement e) { 184 if (this.mLastActivity < e.mLastActivity) { 185 return 1; 186 } else if (this.mLastActivity > e.mLastActivity) { 187 return -1; 188 } else { 189 return 0; 190 } 191 } 192 193 /* Encode the MapConvoContactElement into the StringBuilder reference. 194 * Here we have taken the choice not to report empty attributes, to reduce the 195 * amount of data to be transfered over BT. */ encode(XmlSerializer xmlConvoElement)196 public void encode(XmlSerializer xmlConvoElement) 197 throws IllegalArgumentException, IllegalStateException, IOException { 198 // construct the XML tag for a single contact in the convolisting element. 199 xmlConvoElement.startTag(null, XML_TAG_CONVOCONTACT); 200 if (mUci != null) { 201 xmlConvoElement.attribute(null, XML_ATT_UCI, mUci); 202 } 203 if (mDisplayName != null) { 204 xmlConvoElement.attribute(null, XML_ATT_DISPLAY_NAME, 205 BluetoothMapUtils.stripInvalidChars(mDisplayName)); 206 } 207 if (mName != null) { 208 xmlConvoElement.attribute(null, XML_ATT_NAME, 209 BluetoothMapUtils.stripInvalidChars(mName)); 210 } 211 if (mChatState != -1) { 212 xmlConvoElement.attribute(null, XML_ATT_CHAT_STATE, String.valueOf(mChatState)); 213 } 214 if (mLastActivity != -1) { 215 xmlConvoElement.attribute(null, XML_ATT_LAST_ACTIVITY, this.getLastActivityString()); 216 } 217 if (mBtUid != null) { 218 xmlConvoElement.attribute(null, XML_ATT_X_BT_UID, mBtUid.toHexString()); 219 } 220 if (mPresenceAvailability != -1) { 221 xmlConvoElement.attribute(null, XML_ATT_PRESENCE_AVAILABILITY, 222 String.valueOf(mPresenceAvailability)); 223 } 224 if (mPresenceStatus != null) { 225 xmlConvoElement.attribute(null, XML_ATT_PRESENCE_STATUS, mPresenceStatus); 226 } 227 if (mPriority != -1) { 228 xmlConvoElement.attribute(null, XML_ATT_PRIORITY, String.valueOf(mPriority)); 229 } 230 231 xmlConvoElement.endTag(null, XML_TAG_CONVOCONTACT); 232 } 233 234 235 /** 236 * Call this function to create a BluetoothMapConvoContactElement. Will consume the end-tag. 237 * @param parser must point into XML_TAG_CONVERSATION tag, hence attributes can be read. 238 * @return 239 * @throws IOException 240 * @throws XmlPullParserException 241 */ createFromXml(XmlPullParser parser)242 public static BluetoothMapConvoContactElement createFromXml(XmlPullParser parser) 243 throws ParseException, XmlPullParserException, IOException { 244 int count = parser.getAttributeCount(); 245 BluetoothMapConvoContactElement newElement; 246 if (count < 1) { 247 throw new IllegalArgumentException( 248 XML_TAG_CONVOCONTACT + " is not decorated with attributes"); 249 } 250 newElement = new BluetoothMapConvoContactElement(); 251 for (int i = 0; i < count; i++) { 252 String attributeName = parser.getAttributeName(i).trim(); 253 String attributeValue = parser.getAttributeValue(i); 254 if (attributeName.equalsIgnoreCase(XML_ATT_UCI)) { 255 newElement.mUci = attributeValue; 256 } else if (attributeName.equalsIgnoreCase(XML_ATT_NAME)) { 257 newElement.mName = attributeValue; 258 } else if (attributeName.equalsIgnoreCase(XML_ATT_DISPLAY_NAME)) { 259 newElement.mDisplayName = attributeValue; 260 } else if (attributeName.equalsIgnoreCase(XML_ATT_CHAT_STATE)) { 261 newElement.setChatState(attributeValue); 262 } else if (attributeName.equalsIgnoreCase(XML_ATT_LAST_ACTIVITY)) { 263 newElement.setLastActivity(attributeValue); 264 } else if (attributeName.equalsIgnoreCase(XML_ATT_X_BT_UID)) { 265 newElement.setBtUid(SignedLongLong.fromString(attributeValue)); 266 } else if (attributeName.equalsIgnoreCase(XML_ATT_PRESENCE_AVAILABILITY)) { 267 newElement.mPresenceAvailability = Integer.parseInt(attributeValue); 268 } else if (attributeName.equalsIgnoreCase(XML_ATT_PRESENCE_STATUS)) { 269 newElement.setPresenceStatus(attributeValue); 270 } else if (attributeName.equalsIgnoreCase(XML_ATT_PRIORITY)) { 271 newElement.setPriority(Integer.parseInt(attributeValue)); 272 } else { 273 if (D) { 274 Log.i(TAG, "Unknown XML attribute: " + parser.getAttributeName(i)); 275 } 276 } 277 } 278 parser.nextTag(); // Consume the end-tag 279 return newElement; 280 } 281 282 @Override equals(Object obj)283 public boolean equals(Object obj) { 284 if (this == obj) { 285 return true; 286 } 287 if (obj == null) { 288 return false; 289 } 290 if (getClass() != obj.getClass()) { 291 return false; 292 } 293 BluetoothMapConvoContactElement other = (BluetoothMapConvoContactElement) obj; 294 /* As we use equals only for test, we don't compare auto assigned values 295 * if (mBtUid == null) { 296 if (other.mBtUid != null) { 297 return false; 298 } 299 } else if (!mBtUid.equals(other.mBtUid)) { 300 return false; 301 }*/ 302 if (mChatState != other.mChatState) { 303 return false; 304 } 305 if (mDisplayName == null) { 306 if (other.mDisplayName != null) { 307 return false; 308 } 309 } else if (!mDisplayName.equals(other.mDisplayName)) { 310 return false; 311 } 312 /* As we use equals only for test, we don't compare auto assigned values 313 * if (mId == null) { 314 if (other.mId != null) { 315 return false; 316 } 317 } else if (!mId.equals(other.mId)) { 318 return false; 319 }*/ 320 if (mLastActivity != other.mLastActivity) { 321 return false; 322 } 323 if (mName == null) { 324 if (other.mName != null) { 325 return false; 326 } 327 } else if (!mName.equals(other.mName)) { 328 return false; 329 } 330 if (mPresenceAvailability != other.mPresenceAvailability) { 331 return false; 332 } 333 if (mPresenceStatus == null) { 334 if (other.mPresenceStatus != null) { 335 return false; 336 } 337 } else if (!mPresenceStatus.equals(other.mPresenceStatus)) { 338 return false; 339 } 340 if (mPriority != other.mPriority) { 341 return false; 342 } 343 return true; 344 } 345 346 } 347 348 349