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 import android.util.Log; 28 29 import com.android.bluetooth.SignedLongLong; 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 compareTo(BluetoothMapConvoContactElement e)182 public int compareTo(BluetoothMapConvoContactElement e) { 183 if (this.mLastActivity < e.mLastActivity) { 184 return 1; 185 } else if (this.mLastActivity > e.mLastActivity) { 186 return -1; 187 } else { 188 return 0; 189 } 190 } 191 192 /* Encode the MapConvoContactElement into the StringBuilder reference. 193 * Here we have taken the choice not to report empty attributes, to reduce the 194 * amount of data to be transfered over BT. */ encode(XmlSerializer xmlConvoElement)195 public void encode(XmlSerializer xmlConvoElement) 196 throws IllegalArgumentException, IllegalStateException, IOException 197 { 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, 216 this.getLastActivityString()); 217 } 218 if(mBtUid != null) { 219 xmlConvoElement.attribute(null, XML_ATT_X_BT_UID, mBtUid.toHexString()); 220 } 221 if(mPresenceAvailability != -1) { 222 xmlConvoElement.attribute(null, XML_ATT_PRESENCE_AVAILABILITY, 223 String.valueOf(mPresenceAvailability)); 224 } 225 if(mPresenceStatus != null) { 226 xmlConvoElement.attribute(null, XML_ATT_PRESENCE_STATUS, mPresenceStatus); 227 } 228 if(mPriority != -1) { 229 xmlConvoElement.attribute(null, XML_ATT_PRIORITY, String.valueOf(mPriority)); 230 } 231 232 xmlConvoElement.endTag(null, XML_TAG_CONVOCONTACT); 233 } 234 235 236 /** 237 * Call this function to create a BluetoothMapConvoContactElement. Will consume the end-tag. 238 * @param parser must point into XML_TAG_CONVERSATION tag, hence attributes can be read. 239 * @return 240 * @throws IOException 241 * @throws XmlPullParserException 242 */ createFromXml(XmlPullParser parser)243 public static BluetoothMapConvoContactElement createFromXml(XmlPullParser parser) 244 throws ParseException, XmlPullParserException, IOException { 245 int count = parser.getAttributeCount(); 246 BluetoothMapConvoContactElement newElement; 247 if(count<1) { 248 throw new IllegalArgumentException(XML_TAG_CONVOCONTACT + 249 " is not decorated with attributes"); 250 } 251 newElement = new BluetoothMapConvoContactElement(); 252 for (int i = 0; i<count; i++) { 253 String attributeName = parser.getAttributeName(i).trim(); 254 String attributeValue = parser.getAttributeValue(i); 255 if(attributeName.equalsIgnoreCase(XML_ATT_UCI)) { 256 newElement.mUci = attributeValue; 257 } else if(attributeName.equalsIgnoreCase(XML_ATT_NAME)) { 258 newElement.mName = attributeValue; 259 } else if(attributeName.equalsIgnoreCase(XML_ATT_DISPLAY_NAME)) { 260 newElement.mDisplayName = attributeValue; 261 } else if(attributeName.equalsIgnoreCase(XML_ATT_CHAT_STATE)) { 262 newElement.setChatState(attributeValue); 263 } else if(attributeName.equalsIgnoreCase(XML_ATT_LAST_ACTIVITY)) { 264 newElement.setLastActivity(attributeValue); 265 } else if(attributeName.equalsIgnoreCase(XML_ATT_X_BT_UID)) { 266 newElement.setBtUid(SignedLongLong.fromString(attributeValue)); 267 } else if(attributeName.equalsIgnoreCase(XML_ATT_PRESENCE_AVAILABILITY)) { 268 newElement.mPresenceAvailability = Integer.parseInt(attributeValue); 269 } else if(attributeName.equalsIgnoreCase(XML_ATT_PRESENCE_STATUS)) { 270 newElement.setPresenceStatus(attributeValue); 271 } else if(attributeName.equalsIgnoreCase(XML_ATT_PRIORITY)) { 272 newElement.setPriority(Integer.parseInt(attributeValue)); 273 } else { 274 if(D) Log.i(TAG,"Unknown XML attribute: " + parser.getAttributeName(i)); 275 } 276 } 277 parser.nextTag(); // Consume the end-tag 278 return newElement; 279 } 280 281 @Override equals(Object obj)282 public boolean equals(Object obj) { 283 if (this == obj) { 284 return true; 285 } 286 if (obj == null) { 287 return false; 288 } 289 if (getClass() != obj.getClass()) { 290 return false; 291 } 292 BluetoothMapConvoContactElement other = (BluetoothMapConvoContactElement) obj; 293 /* As we use equals only for test, we don't compare auto assigned values 294 * if (mBtUid == null) { 295 if (other.mBtUid != null) { 296 return false; 297 } 298 } else if (!mBtUid.equals(other.mBtUid)) { 299 return false; 300 }*/ 301 if (mChatState != other.mChatState) { 302 return false; 303 } 304 if (mDisplayName == null) { 305 if (other.mDisplayName != null) { 306 return false; 307 } 308 } else if (!mDisplayName.equals(other.mDisplayName)) { 309 return false; 310 } 311 /* As we use equals only for test, we don't compare auto assigned values 312 * if (mId == null) { 313 if (other.mId != null) { 314 return false; 315 } 316 } else if (!mId.equals(other.mId)) { 317 return false; 318 }*/ 319 if (mLastActivity != other.mLastActivity) { 320 return false; 321 } 322 if (mName == null) { 323 if (other.mName != null) { 324 return false; 325 } 326 } else if (!mName.equals(other.mName)) { 327 return false; 328 } 329 if (mPresenceAvailability != other.mPresenceAvailability) { 330 return false; 331 } 332 if (mPresenceStatus == null) { 333 if (other.mPresenceStatus != null) { 334 return false; 335 } 336 } else if (!mPresenceStatus.equals(other.mPresenceStatus)) { 337 return false; 338 } 339 if (mPriority != other.mPriority) { 340 return false; 341 } 342 return true; 343 } 344 345 } 346 347 348