1 /* 2 * Copyright (C) 2013 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.DeviceWorkArounds; 21 import com.android.internal.util.FastXmlSerializer; 22 23 import org.xmlpull.v1.XmlSerializer; 24 25 import java.io.IOException; 26 import java.io.StringWriter; 27 import java.io.UnsupportedEncodingException; 28 import java.util.ArrayList; 29 import java.util.Collections; 30 import java.util.List; 31 32 public class BluetoothMapMessageListing { 33 private boolean mHasUnread = false; 34 private static final String TAG = "BluetoothMapMessageListing"; 35 private static final boolean D = BluetoothMapService.DEBUG; 36 37 private List<BluetoothMapMessageListingElement> mList; 38 BluetoothMapMessageListing()39 public BluetoothMapMessageListing() { 40 mList = new ArrayList<BluetoothMapMessageListingElement>(); 41 } 42 add(BluetoothMapMessageListingElement element)43 public void add(BluetoothMapMessageListingElement element) { 44 mList.add(element); 45 /* update info regarding whether the list contains unread messages */ 46 if (!element.getReadBool()) { 47 mHasUnread = true; 48 } 49 } 50 51 /** 52 * Used to fetch the number of BluetoothMapMessageListingElement elements in the list. 53 * @return the number of elements in the list. 54 */ getCount()55 public int getCount() { 56 if (mList != null) { 57 return mList.size(); 58 } 59 return 0; 60 } 61 62 /** 63 * does the list contain any unread messages 64 * @return true if unread messages have been added to the list, else false 65 */ hasUnread()66 public boolean hasUnread() { 67 return mHasUnread; 68 } 69 70 71 /** 72 * returns the entire list as a list 73 * @return list 74 */ getList()75 public List<BluetoothMapMessageListingElement> getList() { 76 return mList; 77 } 78 79 /** 80 * Encode the list of BluetoothMapMessageListingElement(s) into a UTF-8 81 * formatted XML-string in a trimmed byte array 82 * 83 * @param version the version as a string. 84 * Set the listing version to e.g. "1.0" or "1.1". 85 * To make this future proof, no check is added to validate the value, hence be careful. 86 * @return a reference to the encoded byte array. 87 * @throws UnsupportedEncodingException 88 * if UTF-8 encoding is unsupported on the platform. 89 */ 90 // TODO: Remove includeThreadId when MAP-IM is adopted encode(boolean includeThreadId, String version)91 public byte[] encode(boolean includeThreadId, String version) 92 throws UnsupportedEncodingException { 93 StringWriter sw = new StringWriter(); 94 XmlSerializer xmlMsgElement = null; 95 boolean isBenzCarkit = DeviceWorkArounds.addressStartsWith( 96 BluetoothMapService.getRemoteDevice().getAddress(), 97 DeviceWorkArounds.MERCEDES_BENZ_CARKIT); 98 try { 99 if (isBenzCarkit) { 100 Log.d(TAG, "java_interop: Remote is Mercedes Benz, " 101 + "using Xml Workaround."); 102 xmlMsgElement = Xml.newSerializer(); 103 xmlMsgElement.setOutput(sw); 104 xmlMsgElement.text("\n"); 105 } else { 106 xmlMsgElement = new FastXmlSerializer(); 107 xmlMsgElement.setOutput(sw); 108 xmlMsgElement.startDocument("UTF-8", true); 109 xmlMsgElement.setFeature( 110 "http://xmlpull.org/v1/doc/features.html#indent-output", true); 111 } 112 xmlMsgElement.startTag(null, "MAP-msg-listing"); 113 xmlMsgElement.attribute(null, "version", version); 114 // Do the XML encoding of list 115 for (BluetoothMapMessageListingElement element : mList) { 116 element.encode(xmlMsgElement, includeThreadId); // Append the list element 117 } 118 xmlMsgElement.endTag(null, "MAP-msg-listing"); 119 xmlMsgElement.endDocument(); 120 } catch (IllegalArgumentException e) { 121 Log.w(TAG, e); 122 } catch (IllegalStateException e) { 123 Log.w(TAG, e); 124 } catch (IOException e) { 125 Log.w(TAG, e); 126 } 127 /* Fix IOT issue to replace '&' by '&', < by < and '> by '>' in MessageListing */ 128 if (DeviceWorkArounds.addressStartsWith(BluetoothMapService.getRemoteDevice().getAddress(), 129 DeviceWorkArounds.BREZZA_ZDI_CARKIT)) { 130 return sw.toString() 131 .replaceAll("&", "&") 132 .replaceAll("<", "<") 133 .replaceAll(">", ">") 134 .getBytes("UTF-8"); 135 } 136 return sw.toString().getBytes("UTF-8"); 137 } 138 sort()139 public void sort() { 140 Collections.sort(mList); 141 } 142 segment(int count, int offset)143 public void segment(int count, int offset) { 144 count = Math.min(count, mList.size() - offset); 145 if (count > 0) { 146 mList = mList.subList(offset, offset + count); 147 if (mList == null) { 148 mList = new ArrayList<BluetoothMapMessageListingElement>(); // Return an empty list 149 } 150 } else { 151 if (offset > mList.size()) { 152 mList = new ArrayList<BluetoothMapMessageListingElement>(); 153 Log.d(TAG, "offset greater than list size. Returning empty list"); 154 } else { 155 mList = mList.subList(offset, mList.size()); 156 } 157 } 158 } 159 } 160