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