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 java.io.IOException; 18 import java.io.UnsupportedEncodingException; 19 import java.text.ParseException; 20 import java.text.SimpleDateFormat; 21 import java.util.Date; 22 23 import org.xmlpull.v1.XmlPullParser; 24 import org.xmlpull.v1.XmlPullParserException; 25 import org.xmlpull.v1.XmlSerializer; 26 27 28 import android.util.Log; 29 30 import com.android.bluetooth.SignedLongLong; 31 32 public class BluetoothMapConvoContactElement 33 implements Comparable<BluetoothMapConvoContactElement> { 34 35 public static final long CONTACT_ID_TYPE_SMS_MMS = 1; 36 public static final long CONTACT_ID_TYPE_EMAIL = 2; 37 public static final long CONTACT_ID_TYPE_IM = 3; 38 39 private static final String XML_ATT_PRIORITY = "priority"; 40 private static final String XML_ATT_PRESENCE_STATUS = "presence_status"; 41 private static final String XML_ATT_PRESENCE_AVAILABILITY = "presence_availability"; 42 private static final String XML_ATT_X_BT_UID = "x_bt_uid"; 43 private static final String XML_ATT_LAST_ACTIVITY = "last_activity"; 44 private static final String XML_ATT_CHAT_STATE = "chat_state"; 45 private static final String XML_ATT_NAME = "name"; 46 private static final String XML_ATT_DISPLAY_NAME = "display_name"; 47 private static final String XML_ATT_UCI = "x_bt_uci"; 48 protected static final String XML_TAG_CONVOCONTACT = "convocontact"; 49 private static final String TAG = "BluetoothMapConvoContactElement"; 50 private static final boolean D = false; 51 private static final boolean V = false; 52 53 private String mUci = null; 54 private String mName = null; 55 private String mDisplayName = null; 56 private String mPresenceStatus = null; 57 private int mPresenceAvailability = -1; 58 private int mPriority = -1; 59 private long mLastActivity = -1; 60 private SignedLongLong mBtUid = null; 61 private int mChatState = -1; 62 createFromMapContact(MapContact contact, String address)63 public static BluetoothMapConvoContactElement createFromMapContact(MapContact contact, 64 String address) { 65 BluetoothMapConvoContactElement newElement = new BluetoothMapConvoContactElement(); 66 newElement.mUci = address; 67 // TODO: For now we use the ID as BT-UID 68 newElement.mBtUid = new SignedLongLong(contact.getId(),0); 69 newElement.mDisplayName = contact.getName(); 70 return newElement; 71 } 72 BluetoothMapConvoContactElement(String uci, String name, String displayName, String presenceStatus, int presenceAvailability, long lastActivity, int chatState, int priority, String btUid)73 public BluetoothMapConvoContactElement(String uci, String name, String displayName, 74 String presenceStatus, int presenceAvailability, long lastActivity, int chatState, 75 int priority, String btUid) { 76 this.mUci = uci; 77 this.mName = name; 78 this.mDisplayName = displayName; 79 this.mPresenceStatus = presenceStatus; 80 this.mPresenceAvailability = presenceAvailability; 81 this.mLastActivity = lastActivity; 82 this.mChatState = chatState; 83 this.mPresenceStatus = presenceStatus; 84 this.mPriority = priority; 85 if(btUid != null) { 86 try { 87 this.mBtUid = SignedLongLong.fromString(btUid); 88 } catch (UnsupportedEncodingException e) { 89 Log.w(TAG,e); 90 } 91 } 92 } 93 BluetoothMapConvoContactElement()94 public BluetoothMapConvoContactElement() { 95 // TODO Auto-generated constructor stub 96 } 97 getPresenceStatus()98 public String getPresenceStatus() { 99 return mPresenceStatus; 100 } 101 getDisplayName()102 public String getDisplayName() { 103 return mDisplayName; 104 } 105 setDisplayName(String displayName)106 public void setDisplayName(String displayName) { 107 this.mDisplayName = displayName; 108 } 109 setPresenceStatus(String presenceStatus)110 public void setPresenceStatus(String presenceStatus) { 111 this.mPresenceStatus = presenceStatus; 112 } 113 getPresenceAvailability()114 public int getPresenceAvailability() { 115 return mPresenceAvailability; 116 } 117 setPresenceAvailability(int presenceAvailability)118 public void setPresenceAvailability(int presenceAvailability) { 119 this.mPresenceAvailability = presenceAvailability; 120 } 121 getPriority()122 public int getPriority() { 123 return mPriority; 124 } 125 setPriority(int priority)126 public void setPriority(int priority) { 127 this.mPriority = priority; 128 } 129 getName()130 public String getName() { 131 return mName; 132 } 133 setName(String name)134 public void setName(String name) { 135 this.mName = name; 136 } 137 getBtUid()138 public String getBtUid() { 139 return mBtUid.toHexString(); 140 } 141 setBtUid(SignedLongLong btUid)142 public void setBtUid(SignedLongLong btUid) { 143 this.mBtUid = btUid; 144 } 145 getChatState()146 public int getChatState() { 147 return mChatState; 148 } 149 setChatState(int chatState)150 public void setChatState(int chatState) { 151 this.mChatState = chatState; 152 } 153 setChatState(String chatState)154 public void setChatState(String chatState) { 155 this.mChatState = Integer.valueOf(chatState); 156 } 157 158 getLastActivityString()159 public String getLastActivityString() { 160 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); 161 Date date = new Date(mLastActivity); 162 return format.format(date); // Format to YYYYMMDDTHHMMSS local time 163 } 164 setLastActivity(long dateTime)165 public void setLastActivity(long dateTime) { 166 this.mLastActivity = dateTime; 167 } 168 setLastActivity(String lastActivity)169 public void setLastActivity(String lastActivity) throws ParseException { 170 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); 171 Date date = format.parse(lastActivity); 172 this.mLastActivity = date.getTime(); 173 } 174 setContactId(String uci)175 public void setContactId(String uci) { 176 this.mUci = uci; 177 } 178 getContactId()179 public String getContactId(){ 180 return mUci; 181 } 182 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 { 199 // construct the XML tag for a single contact in the convolisting element. 200 xmlConvoElement.startTag(null, XML_TAG_CONVOCONTACT); 201 if(mUci != null) { 202 xmlConvoElement.attribute(null, XML_ATT_UCI, mUci); 203 } 204 if(mDisplayName != null) { 205 xmlConvoElement.attribute(null, XML_ATT_DISPLAY_NAME, 206 BluetoothMapUtils.stripInvalidChars(mDisplayName)); 207 } 208 if(mName != null) { 209 xmlConvoElement.attribute(null, XML_ATT_NAME, 210 BluetoothMapUtils.stripInvalidChars(mName)); 211 } 212 if(mChatState != -1) { 213 xmlConvoElement.attribute(null, XML_ATT_CHAT_STATE, String.valueOf(mChatState)); 214 } 215 if(mLastActivity != -1) { 216 xmlConvoElement.attribute(null, XML_ATT_LAST_ACTIVITY, 217 this.getLastActivityString()); 218 } 219 if(mBtUid != null) { 220 xmlConvoElement.attribute(null, XML_ATT_X_BT_UID, mBtUid.toHexString()); 221 } 222 if(mPresenceAvailability != -1) { 223 xmlConvoElement.attribute(null, XML_ATT_PRESENCE_AVAILABILITY, 224 String.valueOf(mPresenceAvailability)); 225 } 226 if(mPresenceStatus != null) { 227 xmlConvoElement.attribute(null, XML_ATT_PRESENCE_STATUS, mPresenceStatus); 228 } 229 if(mPriority != -1) { 230 xmlConvoElement.attribute(null, XML_ATT_PRIORITY, String.valueOf(mPriority)); 231 } 232 233 xmlConvoElement.endTag(null, XML_TAG_CONVOCONTACT); 234 } 235 236 237 /** 238 * Call this function to create a BluetoothMapConvoContactElement. Will consume the end-tag. 239 * @param parser must point into XML_TAG_CONVERSATION tag, hence attributes can be read. 240 * @return 241 * @throws IOException 242 * @throws XmlPullParserException 243 */ createFromXml(XmlPullParser parser)244 public static BluetoothMapConvoContactElement createFromXml(XmlPullParser parser) 245 throws ParseException, XmlPullParserException, IOException { 246 int count = parser.getAttributeCount(); 247 BluetoothMapConvoContactElement newElement; 248 if(count<1) { 249 throw new IllegalArgumentException(XML_TAG_CONVOCONTACT + 250 " is not decorated with attributes"); 251 } 252 newElement = new BluetoothMapConvoContactElement(); 253 for (int i = 0; i<count; i++) { 254 String attributeName = parser.getAttributeName(i).trim(); 255 String attributeValue = parser.getAttributeValue(i); 256 if(attributeName.equalsIgnoreCase(XML_ATT_UCI)) { 257 newElement.mUci = attributeValue; 258 } else if(attributeName.equalsIgnoreCase(XML_ATT_NAME)) { 259 newElement.mName = attributeValue; 260 } else if(attributeName.equalsIgnoreCase(XML_ATT_DISPLAY_NAME)) { 261 newElement.mDisplayName = attributeValue; 262 } else if(attributeName.equalsIgnoreCase(XML_ATT_CHAT_STATE)) { 263 newElement.setChatState(attributeValue); 264 } else if(attributeName.equalsIgnoreCase(XML_ATT_LAST_ACTIVITY)) { 265 newElement.setLastActivity(attributeValue); 266 } else if(attributeName.equalsIgnoreCase(XML_ATT_X_BT_UID)) { 267 newElement.setBtUid(SignedLongLong.fromString(attributeValue)); 268 } else if(attributeName.equalsIgnoreCase(XML_ATT_PRESENCE_AVAILABILITY)) { 269 newElement.mPresenceAvailability = Integer.parseInt(attributeValue); 270 } else if(attributeName.equalsIgnoreCase(XML_ATT_PRESENCE_STATUS)) { 271 newElement.setPresenceStatus(attributeValue); 272 } else if(attributeName.equalsIgnoreCase(XML_ATT_PRIORITY)) { 273 newElement.setPriority(Integer.parseInt(attributeValue)); 274 } else { 275 if(D) Log.i(TAG,"Unknown XML attribute: " + parser.getAttributeName(i)); 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