• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.bluetooth.mapclient;
18 
19 import android.annotation.Nullable;
20 import android.util.Log;
21 
22 import com.android.internal.annotations.VisibleForTesting;
23 
24 import org.json.JSONException;
25 import org.json.JSONObject;
26 import org.xmlpull.v1.XmlPullParser;
27 import org.xmlpull.v1.XmlPullParserException;
28 import org.xmlpull.v1.XmlPullParserFactory;
29 
30 import java.io.DataInputStream;
31 import java.io.IOException;
32 import java.math.BigInteger;
33 import java.util.HashMap;
34 import java.util.Map;
35 
36 /**
37  * Object representation of event report received by MNS
38  *
39  * <p>This object will be received in {@link Client#EVENT_EVENT_REPORT} callback message.
40  */
41 public class EventReport {
42     private static final String TAG = EventReport.class.getSimpleName();
43 
44     private final Type mType;
45     private final String mDateTime;
46     private final String mHandle;
47     private final String mFolder;
48     private final String mOldFolder;
49     private final Bmessage.Type mMsgType;
50 
51     @VisibleForTesting
EventReport(Map<String, String> attrs)52     EventReport(Map<String, String> attrs) throws IllegalArgumentException {
53         mType = parseType(attrs.get("type"));
54 
55         if (mType != Type.MEMORY_FULL && mType != Type.MEMORY_AVAILABLE) {
56             String handle = attrs.get("handle");
57             try {
58                 /* just to validate */
59                 new BigInteger(attrs.get("handle"), 16);
60 
61                 mHandle = attrs.get("handle");
62             } catch (NumberFormatException e) {
63                 throw new IllegalArgumentException("Invalid value for handle:" + handle);
64             }
65         } else {
66             mHandle = null;
67         }
68 
69         mFolder = attrs.get("folder");
70 
71         mOldFolder = attrs.get("old_folder");
72 
73         mDateTime = attrs.get("datetime");
74 
75         if (mType != Type.MEMORY_FULL && mType != Type.MEMORY_AVAILABLE) {
76             String s = attrs.get("msg_type");
77 
78             if (s != null && s.isEmpty()) {
79                 // Some phones (e.g. SGS3 for MessageDeleted) send empty
80                 // msg_type, in such case leave it as null rather than throw
81                 // parse exception
82                 mMsgType = null;
83             } else {
84                 mMsgType = parseMsgType(s);
85             }
86         } else {
87             mMsgType = null;
88         }
89     }
90 
fromStream(DataInputStream in)91     static EventReport fromStream(DataInputStream in) {
92         EventReport ev = null;
93 
94         try {
95             XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
96             xpp.setInput(in, "utf-8");
97 
98             int event = xpp.getEventType();
99             while (event != XmlPullParser.END_DOCUMENT) {
100                 switch (event) {
101                     case XmlPullParser.START_TAG:
102                         if (xpp.getName().equals("event")) {
103                             HashMap<String, String> attrs = new HashMap<String, String>();
104 
105                             for (int i = 0; i < xpp.getAttributeCount(); i++) {
106                                 attrs.put(xpp.getAttributeName(i), xpp.getAttributeValue(i));
107                             }
108 
109                             ev = new EventReport(attrs);
110 
111                             // return immediately, only one event should be here
112                             return ev;
113                         }
114                         break;
115                 }
116 
117                 event = xpp.next();
118             }
119 
120         } catch (XmlPullParserException e) {
121             Log.e(TAG, "XML parser error when parsing XML", e);
122         } catch (IOException e) {
123             Log.e(TAG, "I/O error when parsing XML", e);
124         } catch (IllegalArgumentException e) {
125             Log.e(TAG, "Invalid event received", e);
126         }
127 
128         return ev;
129     }
130 
parseType(String type)131     private static Type parseType(String type) throws IllegalArgumentException {
132         for (Type t : Type.values()) {
133             if (t.toString().equals(type)) {
134                 return t;
135             }
136         }
137 
138         throw new IllegalArgumentException("Invalid value for type: " + type);
139     }
140 
parseMsgType(String msgType)141     private static Bmessage.Type parseMsgType(String msgType) throws IllegalArgumentException {
142         for (Bmessage.Type t : Bmessage.Type.values()) {
143             if (t.name().equals(msgType)) {
144                 return t;
145             }
146         }
147 
148         throw new IllegalArgumentException("Invalid value for msg_type: " + msgType);
149     }
150 
151     /**
152      * @return {@link EventReport.Type} object corresponding to <code>type</code> application
153      *     parameter in MAP specification
154      */
getType()155     public Type getType() {
156         return mType;
157     }
158 
159     /**
160      * @return value corresponding to <code>handle</code> parameter in MAP specification
161      */
getHandle()162     public String getHandle() {
163         return mHandle;
164     }
165 
166     /**
167      * @return value corresponding to <code>folder</code> parameter in MAP specification
168      */
getFolder()169     public String getFolder() {
170         return mFolder;
171     }
172 
173     /**
174      * @return value corresponding to <code>old_folder</code> parameter in MAP specification
175      */
getOldFolder()176     public String getOldFolder() {
177         return mOldFolder;
178     }
179 
180     /**
181      * @return {@link Bmessage.Type} object corresponding to <code>msg_type</code> application
182      *     parameter in MAP specification
183      */
getMsgType()184     public Bmessage.Type getMsgType() {
185         return mMsgType;
186     }
187 
188     /**
189      * @return value corresponding to <code>datetime</code> parameter in MAP specification for
190      *     NEW_MESSAGE (can be null)
191      */
192     @Nullable
getDateTime()193     public String getDateTime() {
194         return mDateTime;
195     }
196 
197     /**
198      * @return timestamp from the value corresponding to <code>datetime</code> parameter in MAP
199      *     specification for NEW_MESSAGE (can be null)
200      */
201     @Nullable
getTimestamp()202     public Long getTimestamp() {
203         if (mDateTime != null) {
204             ObexTime obexTime = new ObexTime(mDateTime);
205             if (obexTime != null) {
206                 return obexTime.getInstant().toEpochMilli();
207             }
208         }
209         return null;
210     }
211 
212     @Override
toString()213     public String toString() {
214         JSONObject json = new JSONObject();
215 
216         try {
217             json.put("type", mType);
218             if (mDateTime != null) {
219                 json.put("datetime", mDateTime);
220             }
221             json.put("handle", mHandle);
222             json.put("folder", mFolder);
223             json.put("old_folder", mOldFolder);
224             json.put("msg_type", mMsgType);
225         } catch (JSONException e) {
226             // do nothing
227         }
228 
229         return json.toString();
230     }
231 
232     public enum Type {
233         NEW_MESSAGE("NewMessage"),
234         DELIVERY_SUCCESS("DeliverySuccess"),
235         SENDING_SUCCESS("SendingSuccess"),
236         DELIVERY_FAILURE("DeliveryFailure"),
237         SENDING_FAILURE("SendingFailure"),
238         MEMORY_FULL("MemoryFull"),
239         MEMORY_AVAILABLE("MemoryAvailable"),
240         MESSAGE_DELETED("MessageDeleted"),
241         MESSAGE_SHIFT("MessageShift"),
242         READ_STATUS_CHANGED("ReadStatusChanged"),
243         MESSAGE_REMOVED("MessageRemoved"),
244         MESSAGE_EXTENDED_DATA_CHANGED("MessageExtendedDataChanged"),
245         PARTICIPANT_PRESENCE_CHANGED("ParticipantPresenceChanged"),
246         PARTICIPANT_CHAT_STATE_CHANGED("ParticipantChatStateChanged"),
247         CONVERSATION_CHANGED("ConversationChanged");
248         private final String mSpecName;
249 
Type(String specName)250         Type(String specName) {
251             mSpecName = specName;
252         }
253 
254         @Override
toString()255         public String toString() {
256             return mSpecName;
257         }
258     }
259 }
260