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 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 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 94 public BluetoothMapConvoContactElement() { 95 // TODO Auto-generated constructor stub 96 } 97 98 public String getPresenceStatus() { 99 return mPresenceStatus; 100 } 101 102 public String getDisplayName() { 103 return mDisplayName; 104 } 105 106 public void setDisplayName(String displayName) { 107 this.mDisplayName = displayName; 108 } 109 110 public void setPresenceStatus(String presenceStatus) { 111 this.mPresenceStatus = presenceStatus; 112 } 113 114 public int getPresenceAvailability() { 115 return mPresenceAvailability; 116 } 117 118 public void setPresenceAvailability(int presenceAvailability) { 119 this.mPresenceAvailability = presenceAvailability; 120 } 121 122 public int getPriority() { 123 return mPriority; 124 } 125 126 public void setPriority(int priority) { 127 this.mPriority = priority; 128 } 129 130 public String getName() { 131 return mName; 132 } 133 134 public void setName(String name) { 135 this.mName = name; 136 } 137 138 public String getBtUid() { 139 return mBtUid.toHexString(); 140 } 141 142 public void setBtUid(SignedLongLong btUid) { 143 this.mBtUid = btUid; 144 } 145 146 public int getChatState() { 147 return mChatState; 148 } 149 150 public void setChatState(int chatState) { 151 this.mChatState = chatState; 152 } 153 154 public void setChatState(String chatState) { 155 this.mChatState = Integer.valueOf(chatState); 156 } 157 158 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 165 public void setLastActivity(long dateTime) { 166 this.mLastActivity = dateTime; 167 } 168 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 175 public void setContactId(String uci) { 176 this.mUci = uci; 177 } 178 179 public String getContactId(){ 180 return mUci; 181 } 182 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. */ 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 */ 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 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