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