• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.text.ParseException;
27 import java.text.SimpleDateFormat;
28 import java.util.Date;
29 import java.util.Locale;
30 import java.util.Objects;
31 
32 // Next tag value for ContentProfileErrorReportUtils.report(): 1
33 public class BluetoothMapConvoContactElement
34         implements Comparable<BluetoothMapConvoContactElement> {
35     private static final String TAG = BluetoothMapConvoContactElement.class.getSimpleName();
36 
37     public static final long CONTACT_ID_TYPE_SMS_MMS = 1;
38     public static final long CONTACT_ID_TYPE_EMAIL = 2;
39     public static final long CONTACT_ID_TYPE_IM = 3;
40 
41     private static final String XML_ATT_PRIORITY = "priority";
42     private static final String XML_ATT_PRESENCE_STATUS = "presence_status";
43     private static final String XML_ATT_PRESENCE_AVAILABILITY = "presence_availability";
44     private static final String XML_ATT_X_BT_UID = "x_bt_uid";
45     private static final String XML_ATT_LAST_ACTIVITY = "last_activity";
46     private static final String XML_ATT_CHAT_STATE = "chat_state";
47     private static final String XML_ATT_NAME = "name";
48     private static final String XML_ATT_DISPLAY_NAME = "display_name";
49     private static final String XML_ATT_UCI = "x_bt_uci";
50     protected static final String XML_TAG_CONVOCONTACT = "convocontact";
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(
63             MapContact contact, 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.id(), 0);
68         newElement.mDisplayName = contact.name();
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(
73             String uci,
74             String name,
75             String displayName,
76             String presenceStatus,
77             int presenceAvailability,
78             long lastActivity,
79             int chatState,
80             int priority,
81             String btUid) {
82         this.mUci = uci;
83         this.mName = name;
84         this.mDisplayName = displayName;
85         this.mPresenceStatus = presenceStatus;
86         this.mPresenceAvailability = presenceAvailability;
87         this.mLastActivity = lastActivity;
88         this.mChatState = chatState;
89         this.mPresenceStatus = presenceStatus;
90         this.mPriority = priority;
91         if (btUid != null) {
92             this.mBtUid = SignedLongLong.fromString(btUid);
93         }
94     }
95 
BluetoothMapConvoContactElement()96     public BluetoothMapConvoContactElement() {
97         // TODO Auto-generated constructor stub
98     }
99 
getPresenceStatus()100     public String getPresenceStatus() {
101         return mPresenceStatus;
102     }
103 
getDisplayName()104     public String getDisplayName() {
105         return mDisplayName;
106     }
107 
setDisplayName(String displayName)108     public void setDisplayName(String displayName) {
109         this.mDisplayName = displayName;
110     }
111 
setPresenceStatus(String presenceStatus)112     public void setPresenceStatus(String presenceStatus) {
113         this.mPresenceStatus = presenceStatus;
114     }
115 
getPresenceAvailability()116     public int getPresenceAvailability() {
117         return mPresenceAvailability;
118     }
119 
setPresenceAvailability(int presenceAvailability)120     public void setPresenceAvailability(int presenceAvailability) {
121         this.mPresenceAvailability = presenceAvailability;
122     }
123 
getPriority()124     public int getPriority() {
125         return mPriority;
126     }
127 
setPriority(int priority)128     public void setPriority(int priority) {
129         this.mPriority = priority;
130     }
131 
getName()132     public String getName() {
133         return mName;
134     }
135 
setName(String name)136     public void setName(String name) {
137         this.mName = name;
138     }
139 
getBtUid()140     public String getBtUid() {
141         return mBtUid.toHexString();
142     }
143 
setBtUid(SignedLongLong btUid)144     public void setBtUid(SignedLongLong btUid) {
145         this.mBtUid = btUid;
146     }
147 
getChatState()148     public int getChatState() {
149         return mChatState;
150     }
151 
setChatState(int chatState)152     public void setChatState(int chatState) {
153         this.mChatState = chatState;
154     }
155 
setChatState(String chatState)156     public void setChatState(String chatState) {
157         this.mChatState = Integer.valueOf(chatState);
158     }
159 
160     @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate
getLastActivityString()161     public String getLastActivityString() {
162         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT);
163         Date date = new Date(mLastActivity);
164         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
165     }
166 
setLastActivity(long dateTime)167     public void setLastActivity(long dateTime) {
168         this.mLastActivity = dateTime;
169     }
170 
171     @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate
setLastActivity(String lastActivity)172     public void setLastActivity(String lastActivity) throws ParseException {
173         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT);
174         Date date = format.parse(lastActivity);
175         this.mLastActivity = date.getTime();
176     }
177 
setContactId(String uci)178     public void setContactId(String uci) {
179         this.mUci = uci;
180     }
181 
getContactId()182     public String getContactId() {
183         return mUci;
184     }
185 
186     @Override
compareTo(BluetoothMapConvoContactElement e)187     public int compareTo(BluetoothMapConvoContactElement e) {
188         if (this.mLastActivity < e.mLastActivity) {
189             return 1;
190         } else if (this.mLastActivity > e.mLastActivity) {
191             return -1;
192         } else {
193             return 0;
194         }
195     }
196 
197     /* Encode the MapConvoContactElement into the StringBuilder reference.
198      * Here we have taken the choice not to report empty attributes, to reduce the
199      * amount of data to be transferred over BT. */
encode(XmlSerializer xmlConvoElement)200     public void encode(XmlSerializer xmlConvoElement)
201             throws IllegalArgumentException, IllegalStateException, IOException {
202         // construct the XML tag for a single contact in the convolisting element.
203         xmlConvoElement.startTag(null, XML_TAG_CONVOCONTACT);
204         if (mUci != null) {
205             xmlConvoElement.attribute(null, XML_ATT_UCI, mUci);
206         }
207         if (mDisplayName != null) {
208             xmlConvoElement.attribute(
209                     null, XML_ATT_DISPLAY_NAME, BluetoothMapUtils.stripInvalidChars(mDisplayName));
210         }
211         if (mName != null) {
212             xmlConvoElement.attribute(
213                     null, XML_ATT_NAME, BluetoothMapUtils.stripInvalidChars(mName));
214         }
215         if (mChatState != -1) {
216             xmlConvoElement.attribute(null, XML_ATT_CHAT_STATE, String.valueOf(mChatState));
217         }
218         if (mLastActivity != -1) {
219             xmlConvoElement.attribute(null, XML_ATT_LAST_ACTIVITY, this.getLastActivityString());
220         }
221         if (mBtUid != null) {
222             xmlConvoElement.attribute(null, XML_ATT_X_BT_UID, mBtUid.toHexString());
223         }
224         if (mPresenceAvailability != -1) {
225             xmlConvoElement.attribute(
226                     null, XML_ATT_PRESENCE_AVAILABILITY, String.valueOf(mPresenceAvailability));
227         }
228         if (mPresenceStatus != null) {
229             xmlConvoElement.attribute(null, XML_ATT_PRESENCE_STATUS, mPresenceStatus);
230         }
231         if (mPriority != -1) {
232             xmlConvoElement.attribute(null, XML_ATT_PRIORITY, String.valueOf(mPriority));
233         }
234 
235         xmlConvoElement.endTag(null, XML_TAG_CONVOCONTACT);
236     }
237 
238     /**
239      * Call this function to create a BluetoothMapConvoContactElement. Will consume the end-tag.
240      *
241      * @param parser must point into XML_TAG_CONVERSATION tag, hence attributes can be read.
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(
249                     XML_TAG_CONVOCONTACT + " 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                 Log.w(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 instanceof BluetoothMapConvoContactElement other)) {
287             return false;
288         }
289 
290         // Skip comparing auto assigned value `mBtUid`. Equals is only used for test
291 
292         if (mChatState != other.mChatState) {
293             return false;
294         }
295         if (!Objects.equals(mDisplayName, other.mDisplayName)) {
296             return false;
297         }
298 
299         // Skip comparing auto assigned value `mId`. Equals is only used for test
300 
301         if (mLastActivity != other.mLastActivity) {
302             return false;
303         }
304         if (!Objects.equals(mName, other.mName)) {
305             return false;
306         }
307         if (mPresenceAvailability != other.mPresenceAvailability) {
308             return false;
309         }
310         if (!Objects.equals(mPresenceStatus, other.mPresenceStatus)) {
311             return false;
312         }
313         if (mPriority != other.mPriority) {
314             return false;
315         }
316         return true;
317     }
318 
319     @Override
hashCode()320     public int hashCode() {
321         return Objects.hash(
322                 mChatState,
323                 mDisplayName,
324                 mLastActivity,
325                 mName,
326                 mPresenceAvailability,
327                 mPresenceStatus,
328                 mPriority);
329     }
330 }
331