1192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta/*
2192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * Copyright (C) 2014 The Android Open Source Project
3192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *
4192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * Licensed under the Apache License, Version 2.0 (the "License");
5192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * you may not use this file except in compliance with the License.
6192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * You may obtain a copy of the License at
7192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *
8192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *      http://www.apache.org/licenses/LICENSE-2.0
9192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta *
10192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * Unless required by applicable law or agreed to in writing, software
11192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * distributed under the License is distributed on an "AS IS" BASIS,
12192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * See the License for the specific language governing permissions and
14192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * limitations under the License.
15192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta */
16192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
17192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptapackage android.bluetooth.client.map;
18192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport android.util.Log;
19192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
20192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport org.json.JSONException;
21192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport org.json.JSONObject;
22192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport org.xmlpull.v1.XmlPullParser;
23192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport org.xmlpull.v1.XmlPullParserException;
24192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport org.xmlpull.v1.XmlPullParserFactory;
25192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
26192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport java.io.DataInputStream;
27192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport java.io.IOException;
28192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport java.math.BigInteger;
29192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptaimport java.util.HashMap;
30192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
31192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta/**
32192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * Object representation of event report received by MNS
33192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * <p>
34192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * This object will be received in {@link BluetoothMasClient#EVENT_EVENT_REPORT}
35192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta * callback message.
36192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta */
37192d793d2586b620027edd5b45ff4c72a86cc7beHemant Guptapublic class BluetoothMapEventReport {
38192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
39192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final static String TAG = "BluetoothMapEventReport";
40192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
41192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public enum Type {
42192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        NEW_MESSAGE("NewMessage"), DELIVERY_SUCCESS("DeliverySuccess"),
43192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        SENDING_SUCCESS("SendingSuccess"), DELIVERY_FAILURE("DeliveryFailure"),
44192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        SENDING_FAILURE("SendingFailure"), MEMORY_FULL("MemoryFull"),
45192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        MEMORY_AVAILABLE("MemoryAvailable"), MESSAGE_DELETED("MessageDeleted"),
46192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        MESSAGE_SHIFT("MessageShift");
47192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
48192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        private final String mSpecName;
49192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
50192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        private Type(String specName) {
51192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mSpecName = specName;
52192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
53192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
54192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        @Override
55192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        public String toString() {
56192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            return mSpecName;
57192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
58192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
59192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
60192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final Type mType;
61192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
62192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final String mHandle;
63192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
64192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final String mFolder;
65192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
66192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final String mOldFolder;
67192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
68192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private final BluetoothMapBmessage.Type mMsgType;
69192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
70192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private BluetoothMapEventReport(HashMap<String, String> attrs) throws IllegalArgumentException {
71192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        mType = parseType(attrs.get("type"));
72192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
73192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (mType != Type.MEMORY_FULL && mType != Type.MEMORY_AVAILABLE) {
74192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            String handle = attrs.get("handle");
75192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            try {
76192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                /* just to validate */
77192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                new BigInteger(attrs.get("handle"), 16);
78192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
79192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mHandle = attrs.get("handle");
80192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } catch (NumberFormatException e) {
81192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                throw new IllegalArgumentException("Invalid value for handle:" + handle);
82192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
83192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } else {
84192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mHandle = null;
85192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
86192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
87192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        mFolder = attrs.get("folder");
88192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
89192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        mOldFolder = attrs.get("old_folder");
90192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
91192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        if (mType != Type.MEMORY_FULL && mType != Type.MEMORY_AVAILABLE) {
92192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            String s = attrs.get("msg_type");
93192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
94192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            if ("".equals(s)) {
95192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                // Some phones (e.g. SGS3 for MessageDeleted) send empty
96192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                // msg_type, in such case leave it as null rather than throw
97192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                // parse exception
98192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mMsgType = null;
99192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            } else {
100192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                mMsgType = parseMsgType(s);
101192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
102192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } else {
103192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            mMsgType = null;
104192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
105192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
106192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
107192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private Type parseType(String type) throws IllegalArgumentException {
108192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        for (Type t : Type.values()) {
109192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            if (t.toString().equals(type)) {
110192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                return t;
111192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
112192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
113192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
114192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        throw new IllegalArgumentException("Invalid value for type: " + type);
115192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
116192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
117192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    private BluetoothMapBmessage.Type parseMsgType(String msgType) throws IllegalArgumentException {
118192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        for (BluetoothMapBmessage.Type t : BluetoothMapBmessage.Type.values()) {
119192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            if (t.name().equals(msgType)) {
120192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                return t;
121192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
122192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
123192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
124192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        throw new IllegalArgumentException("Invalid value for msg_type: " + msgType);
125192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
126192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
127192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    /**
128192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     * @return {@link BluetoothMapEventReport.Type} object corresponding to
129192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     *         <code>type</code> application parameter in MAP specification
130192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     */
131192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public Type getType() {
132192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return mType;
133192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
134192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
135192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    /**
136192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     * @return value corresponding to <code>handle</code> parameter in MAP
137192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     *         specification
138192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     */
139192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public String getHandle() {
140192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return mHandle;
141192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
142192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
143192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    /**
144192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     * @return value corresponding to <code>folder</code> parameter in MAP
145192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     *         specification
146192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     */
147192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public String getFolder() {
148192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return mFolder;
149192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
150192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
151192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    /**
152192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     * @return value corresponding to <code>old_folder</code> parameter in MAP
153192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     *         specification
154192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     */
155192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public String getOldFolder() {
156192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return mOldFolder;
157192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
158192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
159192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    /**
160192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     * @return {@link BluetoothMapBmessage.Type} object corresponding to
161192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     *         <code>msg_type</code> application parameter in MAP specification
162192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta     */
163192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public BluetoothMapBmessage.Type getMsgType() {
164192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return mMsgType;
165192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
166192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
167192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    @Override
168192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    public String toString() {
169192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        JSONObject json = new JSONObject();
170192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
171192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        try {
172192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            json.put("type", mType);
173192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            json.put("handle", mHandle);
174192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            json.put("folder", mFolder);
175192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            json.put("old_folder", mOldFolder);
176192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            json.put("msg_type", mMsgType);
177192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } catch (JSONException e) {
178192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            // do nothing
179192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
180192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
181192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return json.toString();
182192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
183192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
184192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    static BluetoothMapEventReport fromStream(DataInputStream in) {
185192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        BluetoothMapEventReport ev = null;
186192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
187192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        try {
188192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser();
189192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            xpp.setInput(in, "utf-8");
190192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
191192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            int event = xpp.getEventType();
192192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            while (event != XmlPullParser.END_DOCUMENT) {
193192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                switch (event) {
194192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                    case XmlPullParser.START_TAG:
195192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        if (xpp.getName().equals("event")) {
196192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                            HashMap<String, String> attrs = new HashMap<String, String>();
197192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
198192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                            for (int i = 0; i < xpp.getAttributeCount(); i++) {
199192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                                attrs.put(xpp.getAttributeName(i), xpp.getAttributeValue(i));
200192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                            }
201192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
202192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                            ev = new BluetoothMapEventReport(attrs);
203192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
204192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                            // return immediately, only one event should be here
205192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                            return ev;
206192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        }
207192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                        break;
208192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                }
209192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
210192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta                event = xpp.next();
211192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            }
212192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
213192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } catch (XmlPullParserException e) {
214192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            Log.e(TAG, "XML parser error when parsing XML", e);
215192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } catch (IOException e) {
216192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            Log.e(TAG, "I/O error when parsing XML", e);
217192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        } catch (IllegalArgumentException e) {
218192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta            Log.e(TAG, "Invalid event received", e);
219192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        }
220192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta
221192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta        return ev;
222192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta    }
223192d793d2586b620027edd5b45ff4c72a86cc7beHemant Gupta}
224