15a60e47497f21f64e6d79420dc4c56c1907df22akschulz/*
25a60e47497f21f64e6d79420dc4c56c1907df22akschulz* Copyright (C) 2015 Samsung System LSI
35a60e47497f21f64e6d79420dc4c56c1907df22akschulz* Licensed under the Apache License, Version 2.0 (the "License");
45a60e47497f21f64e6d79420dc4c56c1907df22akschulz* you may not use this file except in compliance with the License.
55a60e47497f21f64e6d79420dc4c56c1907df22akschulz* You may obtain a copy of the License at
65a60e47497f21f64e6d79420dc4c56c1907df22akschulz*
75a60e47497f21f64e6d79420dc4c56c1907df22akschulz*      http://www.apache.org/licenses/LICENSE-2.0
85a60e47497f21f64e6d79420dc4c56c1907df22akschulz*
95a60e47497f21f64e6d79420dc4c56c1907df22akschulz* Unless required by applicable law or agreed to in writing, software
105a60e47497f21f64e6d79420dc4c56c1907df22akschulz* distributed under the License is distributed on an "AS IS" BASIS,
115a60e47497f21f64e6d79420dc4c56c1907df22akschulz* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
125a60e47497f21f64e6d79420dc4c56c1907df22akschulz* See the License for the specific language governing permissions and
135a60e47497f21f64e6d79420dc4c56c1907df22akschulz* limitations under the License.
145a60e47497f21f64e6d79420dc4c56c1907df22akschulz*/
155a60e47497f21f64e6d79420dc4c56c1907df22akschulzpackage com.android.bluetooth.map;
165a60e47497f21f64e6d79420dc4c56c1907df22akschulz
175a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport java.io.IOException;
185a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport java.io.InputStream;
195a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport java.io.StringWriter;
205a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport java.io.UnsupportedEncodingException;
215a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport java.text.ParseException;
225a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport java.util.ArrayList;
235a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport java.util.Collections;
245a60e47497f21f64e6d79420dc4c56c1907df22akschulzimport java.util.List;
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;
355a60e47497f21f64e6d79420dc4c56c1907df22akschulz
365a60e47497f21f64e6d79420dc4c56c1907df22akschulzpublic class BluetoothMapConvoListing {
375a60e47497f21f64e6d79420dc4c56c1907df22akschulz    private boolean hasUnread = false;
385a60e47497f21f64e6d79420dc4c56c1907df22akschulz    private static final String TAG = "BluetoothMapConvoListing";
395a60e47497f21f64e6d79420dc4c56c1907df22akschulz    private static final boolean D = BluetoothMapService.DEBUG;
405a60e47497f21f64e6d79420dc4c56c1907df22akschulz    private static final String XML_TAG = "MAP-convo-listing";
415a60e47497f21f64e6d79420dc4c56c1907df22akschulz
425a60e47497f21f64e6d79420dc4c56c1907df22akschulz    private List<BluetoothMapConvoListingElement> mList;
435a60e47497f21f64e6d79420dc4c56c1907df22akschulz
445a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public BluetoothMapConvoListing(){
455a60e47497f21f64e6d79420dc4c56c1907df22akschulz     mList = new ArrayList<BluetoothMapConvoListingElement>();
465a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
475a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public void add(BluetoothMapConvoListingElement element) {
485a60e47497f21f64e6d79420dc4c56c1907df22akschulz        mList.add(element);
495a60e47497f21f64e6d79420dc4c56c1907df22akschulz        /* update info regarding whether the list contains unread conversations */
505a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if (element.getReadBool())
515a60e47497f21f64e6d79420dc4c56c1907df22akschulz        {
525a60e47497f21f64e6d79420dc4c56c1907df22akschulz            hasUnread = true;
535a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
545a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
555a60e47497f21f64e6d79420dc4c56c1907df22akschulz
565a60e47497f21f64e6d79420dc4c56c1907df22akschulz    /**
575a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * Used to fetch the number of BluetoothMapConvoListingElement elements in the list.
585a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @return the number of elements in the list.
595a60e47497f21f64e6d79420dc4c56c1907df22akschulz     */
605a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public int getCount() {
615a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if(mList != null)
625a60e47497f21f64e6d79420dc4c56c1907df22akschulz        {
635a60e47497f21f64e6d79420dc4c56c1907df22akschulz            return mList.size();
645a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
655a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return 0;
665a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
675a60e47497f21f64e6d79420dc4c56c1907df22akschulz
685a60e47497f21f64e6d79420dc4c56c1907df22akschulz    /**
695a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * does the list contain any unread messages
705a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @return true if unread messages have been added to the list, else false
715a60e47497f21f64e6d79420dc4c56c1907df22akschulz     */
725a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public boolean hasUnread()
735a60e47497f21f64e6d79420dc4c56c1907df22akschulz    {
745a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return hasUnread;
755a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
765a60e47497f21f64e6d79420dc4c56c1907df22akschulz
775a60e47497f21f64e6d79420dc4c56c1907df22akschulz
785a60e47497f21f64e6d79420dc4c56c1907df22akschulz    /**
795a60e47497f21f64e6d79420dc4c56c1907df22akschulz     *  returns the entire list as a list
805a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @return list
815a60e47497f21f64e6d79420dc4c56c1907df22akschulz     */
825a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public List<BluetoothMapConvoListingElement> getList(){
835a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return mList;
845a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
855a60e47497f21f64e6d79420dc4c56c1907df22akschulz
865a60e47497f21f64e6d79420dc4c56c1907df22akschulz    /**
875a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * Encode the list of BluetoothMapMessageListingElement(s) into a UTF-8
885a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * formatted XML-string in a trimmed byte array
895a60e47497f21f64e6d79420dc4c56c1907df22akschulz     *
905a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @return a reference to the encoded byte array.
915a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @throws UnsupportedEncodingException
925a60e47497f21f64e6d79420dc4c56c1907df22akschulz     *             if UTF-8 encoding is unsupported on the platform.
935a60e47497f21f64e6d79420dc4c56c1907df22akschulz     */
945a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public byte[] encode() throws UnsupportedEncodingException {
955a60e47497f21f64e6d79420dc4c56c1907df22akschulz        StringWriter sw = new StringWriter();
965a60e47497f21f64e6d79420dc4c56c1907df22akschulz        XmlSerializer xmlConvoElement = new FastXmlSerializer();
975a60e47497f21f64e6d79420dc4c56c1907df22akschulz        try {
985a60e47497f21f64e6d79420dc4c56c1907df22akschulz            xmlConvoElement.setOutput(sw);
995a60e47497f21f64e6d79420dc4c56c1907df22akschulz            xmlConvoElement.startDocument("UTF-8", true);
1005a60e47497f21f64e6d79420dc4c56c1907df22akschulz            xmlConvoElement.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
1015a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    true);
1025a60e47497f21f64e6d79420dc4c56c1907df22akschulz            xmlConvoElement.startTag(null, XML_TAG);
1035a60e47497f21f64e6d79420dc4c56c1907df22akschulz            xmlConvoElement.attribute(null, "version", "1.0");
1045a60e47497f21f64e6d79420dc4c56c1907df22akschulz            // Do the XML encoding of list
1055a60e47497f21f64e6d79420dc4c56c1907df22akschulz            for (BluetoothMapConvoListingElement element : mList) {
1065a60e47497f21f64e6d79420dc4c56c1907df22akschulz                element.encode(xmlConvoElement); // Append the list element
1075a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
1085a60e47497f21f64e6d79420dc4c56c1907df22akschulz            xmlConvoElement.endTag(null, XML_TAG);
1095a60e47497f21f64e6d79420dc4c56c1907df22akschulz            xmlConvoElement.endDocument();
1105a60e47497f21f64e6d79420dc4c56c1907df22akschulz        } catch (IllegalArgumentException e) {
1115a60e47497f21f64e6d79420dc4c56c1907df22akschulz            Log.w(TAG, e);
1125a60e47497f21f64e6d79420dc4c56c1907df22akschulz        } catch (IllegalStateException e) {
1135a60e47497f21f64e6d79420dc4c56c1907df22akschulz            Log.w(TAG, e);
1145a60e47497f21f64e6d79420dc4c56c1907df22akschulz        } catch (IOException e) {
1155a60e47497f21f64e6d79420dc4c56c1907df22akschulz            Log.w(TAG, e);
1165a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
1175a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return sw.toString().getBytes("UTF-8");
1185a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
1195a60e47497f21f64e6d79420dc4c56c1907df22akschulz
1205a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public void sort() {
1215a60e47497f21f64e6d79420dc4c56c1907df22akschulz        Collections.sort(mList);
1225a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
1235a60e47497f21f64e6d79420dc4c56c1907df22akschulz
1245a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public void segment(int count, int offset) {
1255a60e47497f21f64e6d79420dc4c56c1907df22akschulz        count = Math.min(count, mList.size() - offset);
1265a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if (count > 0) {
1275a60e47497f21f64e6d79420dc4c56c1907df22akschulz            mList = mList.subList(offset, offset + count);
1285a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if(mList == null) {
1295a60e47497f21f64e6d79420dc4c56c1907df22akschulz                mList = new ArrayList<BluetoothMapConvoListingElement>(); // Return an empty list
1305a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
1315a60e47497f21f64e6d79420dc4c56c1907df22akschulz        } else {
1325a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if(offset > mList.size()) {
1335a60e47497f21f64e6d79420dc4c56c1907df22akschulz               mList = new ArrayList<BluetoothMapConvoListingElement>();
1345a60e47497f21f64e6d79420dc4c56c1907df22akschulz               Log.d(TAG, "offset greater than list size. Returning empty list");
1355a60e47497f21f64e6d79420dc4c56c1907df22akschulz            } else {
1365a60e47497f21f64e6d79420dc4c56c1907df22akschulz               mList = mList.subList(offset, mList.size());
1375a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
1385a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
1395a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
1405a60e47497f21f64e6d79420dc4c56c1907df22akschulz
1415a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public void appendFromXml(InputStream xmlDocument)
1425a60e47497f21f64e6d79420dc4c56c1907df22akschulz            throws XmlPullParserException, IOException, ParseException {
1435a60e47497f21f64e6d79420dc4c56c1907df22akschulz        try {
1445a60e47497f21f64e6d79420dc4c56c1907df22akschulz            XmlPullParser parser = Xml.newPullParser();
1455a60e47497f21f64e6d79420dc4c56c1907df22akschulz            int type;
1465a60e47497f21f64e6d79420dc4c56c1907df22akschulz            parser.setInput(xmlDocument, "UTF-8");
1475a60e47497f21f64e6d79420dc4c56c1907df22akschulz
1485a60e47497f21f64e6d79420dc4c56c1907df22akschulz            // First find the folder-listing
1495a60e47497f21f64e6d79420dc4c56c1907df22akschulz            while((type=parser.next()) != XmlPullParser.END_TAG
1505a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    && type != XmlPullParser.END_DOCUMENT ) {
1515a60e47497f21f64e6d79420dc4c56c1907df22akschulz                // Skip until we get a start tag
1525a60e47497f21f64e6d79420dc4c56c1907df22akschulz                if (parser.getEventType() != XmlPullParser.START_TAG) {
1535a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    continue;
1545a60e47497f21f64e6d79420dc4c56c1907df22akschulz                }
1555a60e47497f21f64e6d79420dc4c56c1907df22akschulz                // Skip until we get a folder-listing tag
1565a60e47497f21f64e6d79420dc4c56c1907df22akschulz                String name = parser.getName();
1575a60e47497f21f64e6d79420dc4c56c1907df22akschulz                if(!name.equalsIgnoreCase(XML_TAG)) {
1585a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    if(D) Log.i(TAG,"Unknown XML tag: " + name);
1595a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    XmlUtils.skipCurrentTag(parser);
1605a60e47497f21f64e6d79420dc4c56c1907df22akschulz                }
1615a60e47497f21f64e6d79420dc4c56c1907df22akschulz                readConversations(parser);
1625a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
1635a60e47497f21f64e6d79420dc4c56c1907df22akschulz        } finally {
1645a60e47497f21f64e6d79420dc4c56c1907df22akschulz            xmlDocument.close();
1655a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
1665a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
1675a60e47497f21f64e6d79420dc4c56c1907df22akschulz
1685a60e47497f21f64e6d79420dc4c56c1907df22akschulz    /**
1695a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * Parses folder elements, and add to mSubFolders.
1705a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @param parser the Xml Parser currently pointing to an folder-listing tag.
1715a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @throws XmlPullParserException
1725a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @throws IOException
1735a60e47497f21f64e6d79420dc4c56c1907df22akschulz     * @throws
1745a60e47497f21f64e6d79420dc4c56c1907df22akschulz     */
1755a60e47497f21f64e6d79420dc4c56c1907df22akschulz    private void readConversations(XmlPullParser parser)
1765a60e47497f21f64e6d79420dc4c56c1907df22akschulz            throws XmlPullParserException, IOException, ParseException {
1775a60e47497f21f64e6d79420dc4c56c1907df22akschulz        int type;
1785a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if(D) Log.i(TAG,"readConversations(): ");
1795a60e47497f21f64e6d79420dc4c56c1907df22akschulz        while((type=parser.next()) != XmlPullParser.END_TAG
1805a60e47497f21f64e6d79420dc4c56c1907df22akschulz                && type != XmlPullParser.END_DOCUMENT ) {
1815a60e47497f21f64e6d79420dc4c56c1907df22akschulz            // Skip until we get a start tag
1825a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if (parser.getEventType() != XmlPullParser.START_TAG) {
1835a60e47497f21f64e6d79420dc4c56c1907df22akschulz                continue;
1845a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
1855a60e47497f21f64e6d79420dc4c56c1907df22akschulz            // Skip until we get a folder-listing tag
1865a60e47497f21f64e6d79420dc4c56c1907df22akschulz            String name = parser.getName();
1875a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if(name.trim().equalsIgnoreCase(BluetoothMapConvoListingElement.XML_TAG_CONVERSATION)
1885a60e47497f21f64e6d79420dc4c56c1907df22akschulz                    == false) {
1895a60e47497f21f64e6d79420dc4c56c1907df22akschulz                if(D) Log.i(TAG,"Unknown XML tag: " + name);
1905a60e47497f21f64e6d79420dc4c56c1907df22akschulz                XmlUtils.skipCurrentTag(parser);
1915a60e47497f21f64e6d79420dc4c56c1907df22akschulz                continue;
1925a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
1935a60e47497f21f64e6d79420dc4c56c1907df22akschulz            // Add a single conversation
1945a60e47497f21f64e6d79420dc4c56c1907df22akschulz            add(BluetoothMapConvoListingElement.createFromXml(parser));
1955a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
1965a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
1975a60e47497f21f64e6d79420dc4c56c1907df22akschulz
1985a60e47497f21f64e6d79420dc4c56c1907df22akschulz
1995a60e47497f21f64e6d79420dc4c56c1907df22akschulz    @Override
2005a60e47497f21f64e6d79420dc4c56c1907df22akschulz    public boolean equals(Object obj) {
2015a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if (this == obj) {
2025a60e47497f21f64e6d79420dc4c56c1907df22akschulz            return true;
2035a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
2045a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if (obj == null) {
2055a60e47497f21f64e6d79420dc4c56c1907df22akschulz            return false;
2065a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
2075a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if (getClass() != obj.getClass()) {
2085a60e47497f21f64e6d79420dc4c56c1907df22akschulz            return false;
2095a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
2105a60e47497f21f64e6d79420dc4c56c1907df22akschulz        BluetoothMapConvoListing other = (BluetoothMapConvoListing) obj;
2115a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if (hasUnread != other.hasUnread) {
2125a60e47497f21f64e6d79420dc4c56c1907df22akschulz            return false;
2135a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
2145a60e47497f21f64e6d79420dc4c56c1907df22akschulz        if (mList == null) {
2155a60e47497f21f64e6d79420dc4c56c1907df22akschulz            if (other.mList != null) {
2165a60e47497f21f64e6d79420dc4c56c1907df22akschulz                return false;
2175a60e47497f21f64e6d79420dc4c56c1907df22akschulz            }
2185a60e47497f21f64e6d79420dc4c56c1907df22akschulz        } else if (!mList.equals(other.mList)) {
2195a60e47497f21f64e6d79420dc4c56c1907df22akschulz            return false;
2205a60e47497f21f64e6d79420dc4c56c1907df22akschulz        }
2215a60e47497f21f64e6d79420dc4c56c1907df22akschulz        return true;
2225a60e47497f21f64e6d79420dc4c56c1907df22akschulz    }
2235a60e47497f21f64e6d79420dc4c56c1907df22akschulz
2245a60e47497f21f64e6d79420dc4c56c1907df22akschulz}
225