1 /* 2 * Copyright (C) 2014 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 18 import android.util.Log; 19 import org.xmlpull.v1.XmlSerializer; 20 21 import com.android.internal.util.FastXmlSerializer; 22 23 import java.io.IOException; 24 import java.io.StringWriter; 25 import java.io.UnsupportedEncodingException; 26 import java.util.ArrayList; 27 import java.util.Collection; 28 import java.util.HashMap; 29 import java.util.Locale; 30 import java.util.Map.Entry; 31 32 33 /** 34 * Class to contain a single folder element representation. 35 * 36 */ 37 public class BluetoothMapFolderElement { 38 private String mName; 39 private BluetoothMapFolderElement mParent = null; 40 private boolean mHasSmsMmsContent = false; 41 private long mEmailFolderId = -1; 42 private HashMap<String, BluetoothMapFolderElement> mSubFolders; 43 44 private static final boolean D = BluetoothMapService.DEBUG; 45 private static final boolean V = BluetoothMapService.VERBOSE; 46 47 private final static String TAG = "BluetoothMapFolderElement"; 48 BluetoothMapFolderElement( String name, BluetoothMapFolderElement parrent)49 public BluetoothMapFolderElement( String name, BluetoothMapFolderElement parrent){ 50 this.mName = name; 51 this.mParent = parrent; 52 mSubFolders = new HashMap<String, BluetoothMapFolderElement>(); 53 } 54 getName()55 public String getName() { 56 return mName; 57 } 58 hasSmsMmsContent()59 public boolean hasSmsMmsContent(){ 60 return mHasSmsMmsContent; 61 } 62 getEmailFolderId()63 public long getEmailFolderId(){ 64 return mEmailFolderId; 65 } 66 setEmailFolderId(long emailFolderId)67 public void setEmailFolderId(long emailFolderId) { 68 this.mEmailFolderId = emailFolderId; 69 } 70 setHasSmsMmsContent(boolean hasSmsMmsContent)71 public void setHasSmsMmsContent(boolean hasSmsMmsContent) { 72 this.mHasSmsMmsContent = hasSmsMmsContent; 73 } 74 75 /** 76 * Fetch the parent folder. 77 * @return the parent folder or null if we are at the root folder. 78 */ getParent()79 public BluetoothMapFolderElement getParent() { 80 return mParent; 81 } 82 83 /** 84 * Build the full path to this folder 85 * @return a string representing the full path. 86 */ getFullPath()87 public String getFullPath() { 88 StringBuilder sb = new StringBuilder(mName); 89 BluetoothMapFolderElement current = mParent; 90 while(current != null) { 91 if(current.getParent() != null) { 92 sb.insert(0, current.mName + "/"); 93 } 94 current = current.getParent(); 95 } 96 //sb.insert(0, "/"); Should this be included? The MAP spec. do not include it in examples. 97 return sb.toString(); 98 } 99 100 getEmailFolderByName(String name)101 public BluetoothMapFolderElement getEmailFolderByName(String name) { 102 BluetoothMapFolderElement folderElement = this.getRoot(); 103 folderElement = folderElement.getSubFolder("telecom"); 104 folderElement = folderElement.getSubFolder("msg"); 105 folderElement = folderElement.getSubFolder(name); 106 if (folderElement != null && folderElement.getEmailFolderId() == -1 ) 107 folderElement = null; 108 return folderElement; 109 } 110 getEmailFolderById(long id)111 public BluetoothMapFolderElement getEmailFolderById(long id) { 112 return getEmailFolderById(id, this); 113 } 114 getEmailFolderById(long id, BluetoothMapFolderElement folderStructure)115 public static BluetoothMapFolderElement getEmailFolderById(long id, 116 BluetoothMapFolderElement folderStructure) { 117 if(folderStructure == null) { 118 return null; 119 } 120 return findEmailFolderById(id, folderStructure.getRoot()); 121 } 122 findEmailFolderById(long id, BluetoothMapFolderElement folder)123 private static BluetoothMapFolderElement findEmailFolderById(long id, 124 BluetoothMapFolderElement folder) { 125 if(folder.getEmailFolderId() == id) { 126 return folder; 127 } 128 /* Else */ 129 for(BluetoothMapFolderElement subFolder : folder.mSubFolders.values().toArray( 130 new BluetoothMapFolderElement[folder.mSubFolders.size()])) 131 { 132 BluetoothMapFolderElement ret = findEmailFolderById(id, subFolder); 133 if(ret != null) { 134 return ret; 135 } 136 } 137 return null; 138 } 139 140 141 /** 142 * Fetch the root folder. 143 * @return the parent folder or null if we are at the root folder. 144 */ getRoot()145 public BluetoothMapFolderElement getRoot() { 146 BluetoothMapFolderElement rootFolder = this; 147 while(rootFolder.getParent() != null) 148 rootFolder = rootFolder.getParent(); 149 return rootFolder; 150 } 151 152 /** 153 * Add a virtual folder. 154 * @param name the name of the folder to add. 155 * @return the added folder element. 156 */ addFolder(String name)157 public BluetoothMapFolderElement addFolder(String name){ 158 name = name.toLowerCase(Locale.US); 159 BluetoothMapFolderElement newFolder = mSubFolders.get(name); 160 if(D) Log.i(TAG,"addFolder():" + name); 161 if(newFolder == null) { 162 newFolder = new BluetoothMapFolderElement(name, this); 163 mSubFolders.put(name, newFolder); 164 } 165 return newFolder; 166 } 167 168 /** 169 * Add a sms/mms folder. 170 * @param name the name of the folder to add. 171 * @return the added folder element. 172 */ addSmsMmsFolder(String name)173 public BluetoothMapFolderElement addSmsMmsFolder(String name){ 174 name = name.toLowerCase(Locale.US); 175 BluetoothMapFolderElement newFolder = mSubFolders.get(name); 176 if(D) Log.i(TAG,"addSmsMmsFolder():" + name); 177 if(newFolder == null) { 178 newFolder = new BluetoothMapFolderElement(name, this); 179 mSubFolders.put(name, newFolder); 180 } 181 newFolder.setHasSmsMmsContent(true); 182 return newFolder; 183 } 184 185 /** 186 * Add an Email folder. 187 * @param name the name of the folder to add. 188 * @return the added folder element. 189 */ addEmailFolder(String name, long emailFolderId)190 public BluetoothMapFolderElement addEmailFolder(String name, long emailFolderId){ 191 name = name.toLowerCase(); 192 BluetoothMapFolderElement newFolder = mSubFolders.get(name); 193 if(V) Log.v(TAG,"addEmailFolder(): name = " + name 194 + "id = " + emailFolderId); 195 if(newFolder == null) { 196 newFolder = new BluetoothMapFolderElement(name, this); 197 mSubFolders.put(name, newFolder); 198 } 199 newFolder.setEmailFolderId(emailFolderId); 200 return newFolder; 201 } 202 203 /** 204 * Fetch the number of sub folders. 205 * @return returns the number of sub folders. 206 */ getSubFolderCount()207 public int getSubFolderCount(){ 208 return mSubFolders.size(); 209 } 210 211 /** 212 * Returns the subFolder element matching the supplied folder name. 213 * @param folderName the name of the subFolder to find. 214 * @return the subFolder element if found {@code null} otherwise. 215 */ getSubFolder(String folderName)216 public BluetoothMapFolderElement getSubFolder(String folderName){ 217 return mSubFolders.get(folderName.toLowerCase()); 218 } 219 encode(int offset, int count)220 public byte[] encode(int offset, int count) throws UnsupportedEncodingException { 221 StringWriter sw = new StringWriter(); 222 XmlSerializer xmlMsgElement = new FastXmlSerializer(); 223 int i, stopIndex; 224 // We need index based access to the subFolders 225 BluetoothMapFolderElement[] folders = mSubFolders.values().toArray(new BluetoothMapFolderElement[mSubFolders.size()]); 226 227 if(offset > mSubFolders.size()) 228 throw new IllegalArgumentException("FolderListingEncode: offset > subFolders.size()"); 229 230 stopIndex = offset + count; 231 if(stopIndex > mSubFolders.size()) 232 stopIndex = mSubFolders.size(); 233 234 try { 235 xmlMsgElement.setOutput(sw); 236 xmlMsgElement.startDocument("UTF-8", true); 237 xmlMsgElement.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); 238 xmlMsgElement.startTag(null, "folder-listing"); 239 xmlMsgElement.attribute(null, "version", "1.0"); 240 for(i = offset; i<stopIndex; i++) 241 { 242 xmlMsgElement.startTag(null, "folder"); 243 xmlMsgElement.attribute(null, "name", folders[i].getName()); 244 xmlMsgElement.endTag(null, "folder"); 245 } 246 xmlMsgElement.endTag(null, "folder-listing"); 247 xmlMsgElement.endDocument(); 248 } catch (IllegalArgumentException e) { 249 if(D) Log.w(TAG,e); 250 throw new IllegalArgumentException("error encoding folderElement"); 251 } catch (IllegalStateException e) { 252 if(D) Log.w(TAG,e); 253 throw new IllegalArgumentException("error encoding folderElement"); 254 } catch (IOException e) { 255 if(D) Log.w(TAG,e); 256 throw new IllegalArgumentException("error encoding folderElement"); 257 } 258 return sw.toString().getBytes("UTF-8"); 259 } 260 } 261