1fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie/*
25a60e47497f21f64e6d79420dc4c56c1907df22akschulz* Copyright (C) 2015 Samsung System LSI
3fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* Licensed under the Apache License, Version 2.0 (the "License");
4fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* you may not use this file except in compliance with the License.
5fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* You may obtain a copy of the License at
6fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie*
7fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie*      http://www.apache.org/licenses/LICENSE-2.0
8fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie*
9fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* Unless required by applicable law or agreed to in writing, software
10fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* distributed under the License is distributed on an "AS IS" BASIS,
11fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* See the License for the specific language governing permissions and
13fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie* limitations under the License.
14fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie*/
15fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xiepackage com.android.bluetooth.map;
16fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
17326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
18fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport java.io.IOException;
195a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport java.io.InputStream;
20fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport java.io.StringWriter;
21fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xieimport java.io.UnsupportedEncodingException;
225a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport java.util.Arrays;
23326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.util.HashMap;
24326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bondeimport java.util.Locale;
255a60e47497f21f64e6d79420dc4c56c1907df22akschulz
265a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport org.xmlpull.v1.XmlPullParser;
275a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport org.xmlpull.v1.XmlPullParserException;
285a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport org.xmlpull.v1.XmlSerializer;
295a60e47497f21f64e6d79420dc4c56c1907df22akschulz
305a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport android.util.Log;
315a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport android.util.Xml;
325a60e47497f21f64e6d79420dc4c56c1907df22akschulz
335a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport com.android.internal.util.FastXmlSerializer;
345a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport com.android.internal.util.XmlUtils;
35fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
36fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
37fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie/**
38326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde * Class to contain a single folder element representation.
39fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie *
40fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie */
415a60e47497f21f64e6d79420dc4c56c1907df22akschulzpublic class BluetoothMapFolderElement implements Comparable<BluetoothMapFolderElement>{
42326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private String mName;
43326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private BluetoothMapFolderElement mParent = null;
445a60e47497f21f64e6d79420dc4c56c1907df22akschulz    private long mFolderId = -1;
45326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private boolean mHasSmsMmsContent = false;
465a60e47497f21f64e6d79420dc4c56c1907df22akschulz    private boolean mHasImContent = false;
470dcecb2cfd921916ed586183d64ec9fd250a6e4ckschulz    private boolean mHasEmailContent = false;
485a60e47497f21f64e6d79420dc4c56c1907df22akschulz
495a60e47497f21f64e6d79420dc4c56c1907df22akschulz    private boolean mIgnore = false;
505a60e47497f21f64e6d79420dc4c56c1907df22akschulz
51326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private HashMap<String, BluetoothMapFolderElement> mSubFolders;
52326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
53326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private static final boolean D = BluetoothMapService.DEBUG;
54326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private static final boolean V = BluetoothMapService.VERBOSE;
55326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
56326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    private final static String TAG = "BluetoothMapFolderElement";
57fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
58326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    public BluetoothMapFolderElement( String name, BluetoothMapFolderElement parrent){
59326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        this.mName = name;
60326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        this.mParent = parrent;
61326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        mSubFolders = new HashMap<String, BluetoothMapFolderElement>();
62fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
63fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
645a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public void setIngore(boolean ignore) {
655a60e47497f21f64e6d79420dc4c56c1907df22akschulz        mIgnore = ignore;
665a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
675a60e47497f21f64e6d79420dc4c56c1907df22akschulz
685a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public boolean shouldIgnore() {
695a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return mIgnore;
705a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
715a60e47497f21f64e6d79420dc4c56c1907df22akschulz
72fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    public String getName() {
73326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        return mName;
74326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
75326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
76326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    public boolean hasSmsMmsContent(){
77326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        return mHasSmsMmsContent;
78326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
79326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
805a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public long getFolderId(){
815a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return mFolderId;
82326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
830dcecb2cfd921916ed586183d64ec9fd250a6e4ckschulz    public boolean hasEmailContent(){
840dcecb2cfd921916ed586183d64ec9fd250a6e4ckschulz        return mHasEmailContent;
850dcecb2cfd921916ed586183d64ec9fd250a6e4ckschulz    }
86326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
875a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public void setFolderId(long folderId) {
885a60e47497f21f64e6d79420dc4c56c1907df22akschulz        this.mFolderId = folderId;
89326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
90326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    public void setHasSmsMmsContent(boolean hasSmsMmsContent) {
91326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        this.mHasSmsMmsContent = hasSmsMmsContent;
92fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
930dcecb2cfd921916ed586183d64ec9fd250a6e4ckschulz    public void setHasEmailContent(boolean hasEmailContent) {
940dcecb2cfd921916ed586183d64ec9fd250a6e4ckschulz        this.mHasEmailContent = hasEmailContent;
950dcecb2cfd921916ed586183d64ec9fd250a6e4ckschulz    }
965a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public void setHasImContent(boolean hasImContent) {
975a60e47497f21f64e6d79420dc4c56c1907df22akschulz        this.mHasImContent = hasImContent;
985a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
995a60e47497f21f64e6d79420dc4c56c1907df22akschulz
1005a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public boolean hasImContent(){
1015a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return mHasImContent;
1025a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
1030dcecb2cfd921916ed586183d64ec9fd250a6e4ckschulz
104fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    /**
105fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     * Fetch the parent folder.
106fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     * @return the parent folder or null if we are at the root folder.
107fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     */
108fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    public BluetoothMapFolderElement getParent() {
109326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        return mParent;
110fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
111fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
112fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    /**
113326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * Build the full path to this folder
114326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * @return a string representing the full path.
115326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     */
116326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    public String getFullPath() {
117326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        StringBuilder sb = new StringBuilder(mName);
118326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        BluetoothMapFolderElement current = mParent;
119326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        while(current != null) {
120326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            if(current.getParent() != null) {
121326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                sb.insert(0, current.mName + "/");
122326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            }
123326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            current = current.getParent();
124326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        }
125326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        //sb.insert(0, "/"); Should this be included? The MAP spec. do not include it in examples.
126326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        return sb.toString();
127326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
128326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
129326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
1305a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public BluetoothMapFolderElement getFolderByName(String name) {
131326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        BluetoothMapFolderElement folderElement = this.getRoot();
132326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        folderElement = folderElement.getSubFolder("telecom");
133326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        folderElement = folderElement.getSubFolder("msg");
134326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        folderElement = folderElement.getSubFolder(name);
1355a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if (folderElement != null && folderElement.getFolderId() == -1 )
136326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            folderElement = null;
137326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        return folderElement;
138326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
139326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
1405a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public BluetoothMapFolderElement getFolderById(long id) {
1415a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return getFolderById(id, this);
142326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
143326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
1445a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public static BluetoothMapFolderElement getFolderById(long id,
145326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            BluetoothMapFolderElement folderStructure) {
146326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        if(folderStructure == null) {
147326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            return null;
148326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        }
1495a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return findFolderById(id, folderStructure.getRoot());
150326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
151326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
1525a60e47497f21f64e6d79420dc4c56c1907df22akschulz    private static BluetoothMapFolderElement findFolderById(long id,
153326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            BluetoothMapFolderElement folder) {
1545a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if(folder.getFolderId() == id) {
155326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            return folder;
156326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        }
157326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        /* Else */
158326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        for(BluetoothMapFolderElement subFolder : folder.mSubFolders.values().toArray(
159326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                new BluetoothMapFolderElement[folder.mSubFolders.size()]))
160326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        {
1615a60e47497f21f64e6d79420dc4c56c1907df22akschulz            BluetoothMapFolderElement ret = findFolderById(id, subFolder);
162326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            if(ret != null) {
163326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                return ret;
164326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            }
165326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        }
166326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        return null;
167326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
168326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
169326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
170326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    /**
171fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     * Fetch the root folder.
1725a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @return the root folder.
173fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     */
174fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    public BluetoothMapFolderElement getRoot() {
175fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        BluetoothMapFolderElement rootFolder = this;
176fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        while(rootFolder.getParent() != null)
177fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            rootFolder = rootFolder.getParent();
178fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        return rootFolder;
179fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
180fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
181fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    /**
182326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * Add a virtual folder.
183fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     * @param name the name of the folder to add.
184fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     * @return the added folder element.
185fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     */
186fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    public BluetoothMapFolderElement addFolder(String name){
187326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        name = name.toLowerCase(Locale.US);
188326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        BluetoothMapFolderElement newFolder = mSubFolders.get(name);
189326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        if(newFolder == null) {
1905a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if(D) Log.i(TAG,"addFolder():" + name);
191326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            newFolder = new BluetoothMapFolderElement(name, this);
192326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            mSubFolders.put(name, newFolder);
1935a60e47497f21f64e6d79420dc4c56c1907df22akschulz        } else {
1945a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if(D) Log.i(TAG,"addFolder():" + name + " already added");
195326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        }
196326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        return newFolder;
197326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
198326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
199326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    /**
200326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * Add a sms/mms folder.
201326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * @param name the name of the folder to add.
202326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * @return the added folder element.
203326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     */
204326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    public BluetoothMapFolderElement addSmsMmsFolder(String name){
2055a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if(D) Log.i(TAG,"addSmsMmsFolder()");
2065a60e47497f21f64e6d79420dc4c56c1907df22akschulz        BluetoothMapFolderElement newFolder = addFolder(name);
207326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        newFolder.setHasSmsMmsContent(true);
208326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        return newFolder;
209326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    }
210326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
211326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    /**
2125a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * Add a im folder.
2135a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @param name the name of the folder to add.
2145a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @return the added folder element.
2155a60e47497f21f64e6d79420dc4c56c1907df22akschulz     */
2165a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public BluetoothMapFolderElement addImFolder(String name, long idFolder){
2175a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if(D) Log.i(TAG,"addImFolder() id = " + idFolder);
2185a60e47497f21f64e6d79420dc4c56c1907df22akschulz        BluetoothMapFolderElement newFolder = addFolder(name);
2195a60e47497f21f64e6d79420dc4c56c1907df22akschulz        newFolder.setHasImContent(true);
2205a60e47497f21f64e6d79420dc4c56c1907df22akschulz        newFolder.setFolderId(idFolder);
2215a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return newFolder;
2225a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
2235a60e47497f21f64e6d79420dc4c56c1907df22akschulz
2245a60e47497f21f64e6d79420dc4c56c1907df22akschulz    /**
225326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * Add an Email folder.
226326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * @param name the name of the folder to add.
227326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     * @return the added folder element.
228326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde     */
229326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde    public BluetoothMapFolderElement addEmailFolder(String name, long emailFolderId){
2305a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if(V) Log.v(TAG,"addEmailFolder() id = " + emailFolderId);
2315a60e47497f21f64e6d79420dc4c56c1907df22akschulz        BluetoothMapFolderElement newFolder = addFolder(name);
2325a60e47497f21f64e6d79420dc4c56c1907df22akschulz        newFolder.setFolderId(emailFolderId);
2335a60e47497f21f64e6d79420dc4c56c1907df22akschulz        newFolder.setHasEmailContent(true);
234fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        return newFolder;
235fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
236fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    /**
237fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     * Fetch the number of sub folders.
238fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     * @return returns the number of sub folders.
239fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     */
240fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    public int getSubFolderCount(){
241326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        return mSubFolders.size();
242fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
243fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
244fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    /**
245fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     * Returns the subFolder element matching the supplied folder name.
246fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     * @param folderName the name of the subFolder to find.
247fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     * @return the subFolder element if found {@code null} otherwise.
248fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie     */
249fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    public BluetoothMapFolderElement getSubFolder(String folderName){
250326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        return mSubFolders.get(folderName.toLowerCase());
251fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
252fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
253fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    public byte[] encode(int offset, int count) throws UnsupportedEncodingException {
254fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        StringWriter sw = new StringWriter();
255326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        XmlSerializer xmlMsgElement = new FastXmlSerializer();
256fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        int i, stopIndex;
257326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        // We need index based access to the subFolders
258326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        BluetoothMapFolderElement[] folders = mSubFolders.values().toArray(new BluetoothMapFolderElement[mSubFolders.size()]);
259326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde
260326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        if(offset > mSubFolders.size())
261fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            throw new IllegalArgumentException("FolderListingEncode: offset > subFolders.size()");
262fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
263fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        stopIndex = offset + count;
264326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde        if(stopIndex > mSubFolders.size())
265326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            stopIndex = mSubFolders.size();
266fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie
267fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        try {
268fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            xmlMsgElement.setOutput(sw);
269326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            xmlMsgElement.startDocument("UTF-8", true);
270326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            xmlMsgElement.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
271326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            xmlMsgElement.startTag(null, "folder-listing");
2725a60e47497f21f64e6d79420dc4c56c1907df22akschulz            xmlMsgElement.attribute(null, "version", BluetoothMapUtils.MAP_V10_STR);
273fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            for(i = offset; i<stopIndex; i++)
274fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            {
275326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                xmlMsgElement.startTag(null, "folder");
276326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                xmlMsgElement.attribute(null, "name", folders[i].getName());
277326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde                xmlMsgElement.endTag(null, "folder");
278fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            }
279326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            xmlMsgElement.endTag(null, "folder-listing");
280fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie            xmlMsgElement.endDocument();
281fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        } catch (IllegalArgumentException e) {
282326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            if(D) Log.w(TAG,e);
283326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            throw new IllegalArgumentException("error encoding folderElement");
284fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        } catch (IllegalStateException e) {
285326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            if(D) Log.w(TAG,e);
286326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            throw new IllegalArgumentException("error encoding folderElement");
287fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        } catch (IOException e) {
288326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            if(D) Log.w(TAG,e);
289326b5e610063ac24c0ba467ac585bd4c7f618a67Casper Bonde            throw new IllegalArgumentException("error encoding folderElement");
290fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        }
291fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie        return sw.toString().getBytes("UTF-8");
292fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie    }
2935a60e47497f21f64e6d79420dc4c56c1907df22akschulz
2945a60e47497f21f64e6d79420dc4c56c1907df22akschulz    /* The functions below are useful for implementing a MAP client, reusing the object.
2955a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * Currently they are only used for test purposes.
2965a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * */
2975a60e47497f21f64e6d79420dc4c56c1907df22akschulz
2985a60e47497f21f64e6d79420dc4c56c1907df22akschulz    /**
2995a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * Append sub folders from an XML document as specified in the MAP specification.
3005a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * Attributes will be inherited from parent folder - with regards to message types in the
3015a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * folder.
3025a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @param xmlDocument - InputStream with the document
3035a60e47497f21f64e6d79420dc4c56c1907df22akschulz     *
3045a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @throws XmlPullParserException
3055a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @throws IOException
3065a60e47497f21f64e6d79420dc4c56c1907df22akschulz     */
3075a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public void appendSubfolders(InputStream xmlDocument)
3085a60e47497f21f64e6d79420dc4c56c1907df22akschulz            throws XmlPullParserException, IOException {
3095a60e47497f21f64e6d79420dc4c56c1907df22akschulz        try {
3105a60e47497f21f64e6d79420dc4c56c1907df22akschulz            XmlPullParser parser = Xml.newPullParser();
3115a60e47497f21f64e6d79420dc4c56c1907df22akschulz            int type;
3125a60e47497f21f64e6d79420dc4c56c1907df22akschulz            parser.setInput(xmlDocument, "UTF-8");
3135a60e47497f21f64e6d79420dc4c56c1907df22akschulz
3145a60e47497f21f64e6d79420dc4c56c1907df22akschulz            // First find the folder-listing
3155a60e47497f21f64e6d79420dc4c56c1907df22akschulz            while((type=parser.next()) != XmlPullParser.END_TAG
3165a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    && type != XmlPullParser.END_DOCUMENT ) {
3175a60e47497f21f64e6d79420dc4c56c1907df22akschulz                // Skip until we get a start tag
3185a60e47497f21f64e6d79420dc4c56c1907df22akschulz                if (parser.getEventType() != XmlPullParser.START_TAG) {
3195a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    continue;
3205a60e47497f21f64e6d79420dc4c56c1907df22akschulz                }
3215a60e47497f21f64e6d79420dc4c56c1907df22akschulz                // Skip until we get a folder-listing tag
3225a60e47497f21f64e6d79420dc4c56c1907df22akschulz                String name = parser.getName();
3235a60e47497f21f64e6d79420dc4c56c1907df22akschulz                if(!name.equalsIgnoreCase("folder-listing")) {
3245a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    if(D) Log.i(TAG,"Unknown XML tag: " + name);
3255a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    XmlUtils.skipCurrentTag(parser);
3265a60e47497f21f64e6d79420dc4c56c1907df22akschulz                }
3275a60e47497f21f64e6d79420dc4c56c1907df22akschulz                readFolders(parser);
3285a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
3295a60e47497f21f64e6d79420dc4c56c1907df22akschulz        } finally {
3305a60e47497f21f64e6d79420dc4c56c1907df22akschulz            xmlDocument.close();
3315a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
3325a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
3335a60e47497f21f64e6d79420dc4c56c1907df22akschulz
3345a60e47497f21f64e6d79420dc4c56c1907df22akschulz    /**
3355a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * Parses folder elements, and add to mSubFolders.
3365a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @param parser the Xml Parser currently pointing to an folder-listing tag.
3375a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @throws XmlPullParserException
3385a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @throws IOException
3395a60e47497f21f64e6d79420dc4c56c1907df22akschulz     */
3405a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public void readFolders(XmlPullParser parser)
3415a60e47497f21f64e6d79420dc4c56c1907df22akschulz            throws XmlPullParserException, IOException {
3425a60e47497f21f64e6d79420dc4c56c1907df22akschulz        int type;
3435a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if(D) Log.i(TAG,"readFolders(): ");
3445a60e47497f21f64e6d79420dc4c56c1907df22akschulz        while((type=parser.next()) != XmlPullParser.END_TAG
3455a60e47497f21f64e6d79420dc4c56c1907df22akschulz                && type != XmlPullParser.END_DOCUMENT ) {
3465a60e47497f21f64e6d79420dc4c56c1907df22akschulz            // Skip until we get a start tag
3475a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if (parser.getEventType() != XmlPullParser.START_TAG) {
3485a60e47497f21f64e6d79420dc4c56c1907df22akschulz                continue;
3495a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
3505a60e47497f21f64e6d79420dc4c56c1907df22akschulz            // Skip until we get a folder-listing tag
3515a60e47497f21f64e6d79420dc4c56c1907df22akschulz            String name = parser.getName();
3525a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if(name.trim().equalsIgnoreCase("folder") == false) {
3535a60e47497f21f64e6d79420dc4c56c1907df22akschulz                if(D) Log.i(TAG,"Unknown XML tag: " + name);
3545a60e47497f21f64e6d79420dc4c56c1907df22akschulz                XmlUtils.skipCurrentTag(parser);
3555a60e47497f21f64e6d79420dc4c56c1907df22akschulz                continue;
3565a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
3575a60e47497f21f64e6d79420dc4c56c1907df22akschulz            int count = parser.getAttributeCount();
3585a60e47497f21f64e6d79420dc4c56c1907df22akschulz            for (int i = 0; i<count; i++) {
3595a60e47497f21f64e6d79420dc4c56c1907df22akschulz                if(parser.getAttributeName(i).trim().equalsIgnoreCase("name")) {
3605a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    // We found a folder, append to sub folders.
3615a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    BluetoothMapFolderElement element =
3625a60e47497f21f64e6d79420dc4c56c1907df22akschulz                            addFolder(parser.getAttributeValue(i).trim());
3635a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    element.setHasEmailContent(mHasEmailContent);
3645a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    element.setHasImContent(mHasImContent);
3655a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    element.setHasSmsMmsContent(mHasSmsMmsContent);
3665a60e47497f21f64e6d79420dc4c56c1907df22akschulz                } else {
3675a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    if(D) Log.i(TAG,"Unknown XML attribute: " + parser.getAttributeName(i));
3685a60e47497f21f64e6d79420dc4c56c1907df22akschulz                }
3695a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
3705a60e47497f21f64e6d79420dc4c56c1907df22akschulz            parser.nextTag();
3715a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
3725a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
3735a60e47497f21f64e6d79420dc4c56c1907df22akschulz
3745a60e47497f21f64e6d79420dc4c56c1907df22akschulz    /**
3755a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * Recursive compare of all folder names
3765a60e47497f21f64e6d79420dc4c56c1907df22akschulz     */
3775a60e47497f21f64e6d79420dc4c56c1907df22akschulz    @Override
3785a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public int compareTo(BluetoothMapFolderElement another) {
3795a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if(another == null) return 1;
3805a60e47497f21f64e6d79420dc4c56c1907df22akschulz        int ret = mName.compareToIgnoreCase(another.mName);
3815a60e47497f21f64e6d79420dc4c56c1907df22akschulz        // TODO: Do we want to add compare of folder type?
3825a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if(ret == 0) {
3835a60e47497f21f64e6d79420dc4c56c1907df22akschulz            ret = mSubFolders.size() - another.mSubFolders.size();
3845a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if(ret == 0) {
3855a60e47497f21f64e6d79420dc4c56c1907df22akschulz                // Compare all sub folder elements (will do nothing if mSubFolders is empty)
3865a60e47497f21f64e6d79420dc4c56c1907df22akschulz                for(BluetoothMapFolderElement subfolder : mSubFolders.values()) {
3875a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    BluetoothMapFolderElement subfolderAnother =
3885a60e47497f21f64e6d79420dc4c56c1907df22akschulz                            another.mSubFolders.get(subfolder.getName());
3895a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    if(subfolderAnother == null) {
3905a60e47497f21f64e6d79420dc4c56c1907df22akschulz                        if(D) Log.i(TAG, subfolder.getFullPath() + " not in another");
3915a60e47497f21f64e6d79420dc4c56c1907df22akschulz                        return 1;
3925a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    }
3935a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    ret = subfolder.compareTo(subfolderAnother);
3945a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    if(ret != 0) {
3955a60e47497f21f64e6d79420dc4c56c1907df22akschulz                        if(D) Log.i(TAG, subfolder.getFullPath() + " filed compareTo()");
3965a60e47497f21f64e6d79420dc4c56c1907df22akschulz                        return ret;
3975a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    }
3985a60e47497f21f64e6d79420dc4c56c1907df22akschulz                }
3995a60e47497f21f64e6d79420dc4c56c1907df22akschulz            } else {
4005a60e47497f21f64e6d79420dc4c56c1907df22akschulz                if(D) Log.i(TAG, "mSubFolders.size(): " + mSubFolders.size() +
4015a60e47497f21f64e6d79420dc4c56c1907df22akschulz                        " another.mSubFolders.size(): " + another.mSubFolders.size());
4025a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
4035a60e47497f21f64e6d79420dc4c56c1907df22akschulz        } else {
4045a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if(D) Log.i(TAG, "mName: " + mName + " another.mName: " + another.mName);
4055a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
4065a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return ret;
4075a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
408fd6603b8bf9ed72dcc8bd59aaef3209251b6e17cMatthew Xie}
409