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 import android.util.Xml; 19 20 import com.android.bluetooth.Utils; 21 import com.android.internal.util.FastXmlSerializer; 22 23 import org.xmlpull.v1.XmlPullParser; 24 import org.xmlpull.v1.XmlPullParserException; 25 import org.xmlpull.v1.XmlSerializer; 26 27 import java.io.IOException; 28 import java.io.InputStream; 29 import java.io.StringWriter; 30 import java.io.UnsupportedEncodingException; 31 import java.text.ParseException; 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.List; 35 36 public class BluetoothMapConvoListing { 37 private boolean mHasUnread = false; 38 private static final String TAG = "BluetoothMapConvoListing"; 39 private static final boolean D = BluetoothMapService.DEBUG; 40 private static final String XML_TAG = "MAP-convo-listing"; 41 42 private List<BluetoothMapConvoListingElement> mList; 43 BluetoothMapConvoListing()44 public BluetoothMapConvoListing() { 45 mList = new ArrayList<BluetoothMapConvoListingElement>(); 46 } 47 add(BluetoothMapConvoListingElement element)48 public void add(BluetoothMapConvoListingElement element) { 49 mList.add(element); 50 /* update info regarding whether the list contains unread conversations */ 51 if (element.getReadBool()) { 52 mHasUnread = true; 53 } 54 } 55 56 /** 57 * Used to fetch the number of BluetoothMapConvoListingElement elements in the list. 58 * @return the number of elements in the list. 59 */ getCount()60 public int getCount() { 61 if (mList != null) { 62 return mList.size(); 63 } 64 return 0; 65 } 66 67 /** 68 * does the list contain any unread messages 69 * @return true if unread messages have been added to the list, else false 70 */ hasUnread()71 public boolean hasUnread() { 72 return mHasUnread; 73 } 74 75 76 /** 77 * returns the entire list as a list 78 * @return list 79 */ getList()80 public List<BluetoothMapConvoListingElement> getList() { 81 return mList; 82 } 83 84 /** 85 * Encode the list of BluetoothMapMessageListingElement(s) into a UTF-8 86 * formatted XML-string in a trimmed byte array 87 * 88 * @return a reference to the encoded byte array. 89 * @throws UnsupportedEncodingException 90 * if UTF-8 encoding is unsupported on the platform. 91 */ encode()92 public byte[] encode() throws UnsupportedEncodingException { 93 StringWriter sw = new StringWriter(); 94 XmlSerializer xmlConvoElement = new FastXmlSerializer(0); 95 try { 96 xmlConvoElement.setOutput(sw); 97 xmlConvoElement.startDocument("UTF-8", true); 98 xmlConvoElement.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", 99 true); 100 xmlConvoElement.startTag(null, XML_TAG); 101 xmlConvoElement.attribute(null, "version", "1.0"); 102 // Do the XML encoding of list 103 for (BluetoothMapConvoListingElement element : mList) { 104 element.encode(xmlConvoElement); // Append the list element 105 } 106 xmlConvoElement.endTag(null, XML_TAG); 107 xmlConvoElement.endDocument(); 108 } catch (IllegalArgumentException e) { 109 Log.w(TAG, e); 110 } catch (IllegalStateException e) { 111 Log.w(TAG, e); 112 } catch (IOException e) { 113 Log.w(TAG, e); 114 } 115 return sw.toString().getBytes("UTF-8"); 116 } 117 sort()118 public void sort() { 119 Collections.sort(mList); 120 } 121 segment(int count, int offset)122 public void segment(int count, int offset) { 123 count = Math.min(count, mList.size() - offset); 124 if (count > 0) { 125 mList = mList.subList(offset, offset + count); 126 if (mList == null) { 127 mList = new ArrayList<BluetoothMapConvoListingElement>(); // Return an empty list 128 } 129 } else { 130 if (offset > mList.size()) { 131 mList = new ArrayList<BluetoothMapConvoListingElement>(); 132 Log.d(TAG, "offset greater than list size. Returning empty list"); 133 } else { 134 mList = mList.subList(offset, mList.size()); 135 } 136 } 137 } 138 appendFromXml(InputStream xmlDocument)139 public void appendFromXml(InputStream xmlDocument) 140 throws XmlPullParserException, IOException, ParseException { 141 try { 142 XmlPullParser parser = Xml.newPullParser(); 143 int type; 144 parser.setInput(xmlDocument, "UTF-8"); 145 146 // First find the folder-listing 147 while ((type = parser.next()) != XmlPullParser.END_TAG 148 && type != XmlPullParser.END_DOCUMENT) { 149 // Skip until we get a start tag 150 if (parser.getEventType() != XmlPullParser.START_TAG) { 151 continue; 152 } 153 // Skip until we get a folder-listing tag 154 String name = parser.getName(); 155 if (!name.equalsIgnoreCase(XML_TAG)) { 156 if (D) { 157 Log.i(TAG, "Unknown XML tag: " + name); 158 } 159 Utils.skipCurrentTag(parser); 160 } 161 readConversations(parser); 162 } 163 } finally { 164 xmlDocument.close(); 165 } 166 } 167 168 /** 169 * Parses folder elements, and add to mSubFolders. 170 * @param parser the Xml Parser currently pointing to an folder-listing tag. 171 * @throws XmlPullParserException 172 * @throws IOException 173 * @throws 174 */ readConversations(XmlPullParser parser)175 private void readConversations(XmlPullParser parser) 176 throws XmlPullParserException, IOException, ParseException { 177 int type; 178 if (D) { 179 Log.i(TAG, "readConversations(): "); 180 } 181 while ((type = parser.next()) != XmlPullParser.END_TAG 182 && type != XmlPullParser.END_DOCUMENT) { 183 // Skip until we get a start tag 184 if (parser.getEventType() != XmlPullParser.START_TAG) { 185 continue; 186 } 187 // Skip until we get a folder-listing tag 188 String name = parser.getName(); 189 if (!name.trim() 190 .equalsIgnoreCase(BluetoothMapConvoListingElement.XML_TAG_CONVERSATION)) { 191 if (D) { 192 Log.i(TAG, "Unknown XML tag: " + name); 193 } 194 Utils.skipCurrentTag(parser); 195 continue; 196 } 197 // Add a single conversation 198 add(BluetoothMapConvoListingElement.createFromXml(parser)); 199 } 200 } 201 202 203 @Override equals(Object obj)204 public boolean equals(Object obj) { 205 if (this == obj) { 206 return true; 207 } 208 if (obj == null) { 209 return false; 210 } 211 if (getClass() != obj.getClass()) { 212 return false; 213 } 214 BluetoothMapConvoListing other = (BluetoothMapConvoListing) obj; 215 if (mHasUnread != other.mHasUnread) { 216 return false; 217 } 218 if (mList == null) { 219 if (other.mList != null) { 220 return false; 221 } 222 } else if (!mList.equals(other.mList)) { 223 return false; 224 } 225 return true; 226 } 227 228 } 229