12df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal/*
22df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal * Copyright (C) 2016 The Android Open Source Project
32df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal *
42df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal * Licensed under the Apache License, Version 2.0 (the "License");
52df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal * you may not use this file except in compliance with the License.
62df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal * You may obtain a copy of the License at
72df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal *
82df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal *      http://www.apache.org/licenses/LICENSE-2.0
92df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal *
102df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal * Unless required by applicable law or agreed to in writing, software
112df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal * distributed under the License is distributed on an "AS IS" BASIS,
122df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal * See the License for the specific language governing permissions and
142df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal * limitations under the License.
152df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal */
162df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
172df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwalpackage com.android.bluetooth.avrcpcontroller;
182df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
19c4fbd756e2645147470c486ae96f2253f5e13a52Jack Heimport android.media.MediaDescription;
202df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwalimport android.media.browse.MediaBrowser;
212df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwalimport android.media.browse.MediaBrowser.MediaItem;
222df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwalimport android.os.Bundle;
232df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwalimport android.service.media.MediaBrowserService.Result;
242df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwalimport android.util.Log;
252df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
262df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwalimport java.util.ArrayList;
272df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwalimport java.util.HashMap;
282df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwalimport java.util.List;
292df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
302df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal// Browsing hierarchy.
312df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal// Root:
322df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal//      Player1:
332df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal//        Now_Playing:
342df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal//          MediaItem1
352df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal//          MediaItem2
362df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal//        Folder1
372df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal//        Folder2
382df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal//        ....
392df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal//      Player2
402df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal//      ....
412df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwalpublic class BrowseTree {
422df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    private static final String TAG = "BrowseTree";
43a016a2a7ece99211165717d01401a5c1a4c4ac3bJoseph Pirozzo    private static final boolean DBG = false;
44a016a2a7ece99211165717d01401a5c1a4c4ac3bJoseph Pirozzo    private static final boolean VDBG = false;
452df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
462df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    public static final int DIRECTION_DOWN = 0;
472df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    public static final int DIRECTION_UP = 1;
488e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal    public static final int DIRECTION_SAME = 2;
492df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    public static final int DIRECTION_UNKNOWN = -1;
502df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
512df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    public static final String ROOT = "__ROOT__";
522df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    public static final String NOW_PLAYING_PREFIX = "NOW_PLAYING";
532df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    public static final String PLAYER_PREFIX = "PLAYER";
542df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
552df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    // Static instance of Folder ID <-> Folder Instance (for navigation purposes)
562df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    private final HashMap<String, BrowseNode> mBrowseMap = new HashMap<String, BrowseNode>();
572df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    private BrowseNode mCurrentBrowseNode;
58a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal    private BrowseNode mCurrentBrowsedPlayer;
59a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal    private BrowseNode mCurrentAddressedPlayer;
602df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
612df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    BrowseTree() {
628e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal    }
638e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal
648e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal    public void init() {
652df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        MediaDescription.Builder mdb = new MediaDescription.Builder();
662df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        mdb.setMediaId(ROOT);
672df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        mdb.setTitle(ROOT);
682df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        Bundle mdBundle = new Bundle();
692df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        mdBundle.putString(AvrcpControllerService.MEDIA_ITEM_UID_KEY, ROOT);
702df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        mdb.setExtras(mdBundle);
712df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        mBrowseMap.put(ROOT, new BrowseNode(new MediaItem(mdb.build(), MediaItem.FLAG_BROWSABLE)));
722df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        mCurrentBrowseNode = mBrowseMap.get(ROOT);
732df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
742df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
758e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal    public void clear() {
768e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        // Clearing the map should garbage collect everything.
778e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        mBrowseMap.clear();
788e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal    }
798e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal
802df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    // Each node of the tree is represented by Folder ID, Folder Name and the children.
812df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    class BrowseNode {
822df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // MediaItem to store the media related details.
832df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        MediaItem mItem;
842df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
852df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // Type of this browse node.
862df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // Since Media APIs do not define the player separately we define that
872df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // distinction here.
882df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        boolean mIsPlayer = false;
892df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
908e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        // If this folder is currently cached, can be useful to return the contents
918e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        // without doing another fetch.
928e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        boolean mCached = false;
938e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal
942df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // Result object if this node is not loaded yet. This result object will be used
952df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // once loading is finished.
962df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        Result<List<MediaItem>> mResult = null;
972df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
982df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // List of children.
992df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        final List<BrowseNode> mChildren = new ArrayList<BrowseNode>();
1002df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1012df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        BrowseNode(MediaItem item) {
1022df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            mItem = item;
1032df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1042df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1052df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        BrowseNode(AvrcpPlayer player) {
1062df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            mIsPlayer = true;
1072df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1082df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            // Transform the player into a item.
1092df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            MediaDescription.Builder mdb = new MediaDescription.Builder();
1102df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            Bundle mdExtra = new Bundle();
1112df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            String playerKey = PLAYER_PREFIX + player.getId();
1122df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            mdExtra.putString(AvrcpControllerService.MEDIA_ITEM_UID_KEY, playerKey);
1132df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            mdb.setExtras(mdExtra);
1142df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            mdb.setMediaId(playerKey);
1152df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            mdb.setTitle(player.getName());
1162df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            mItem = new MediaBrowser.MediaItem(mdb.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE);
1172df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1182df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1192df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        synchronized List<BrowseNode> getChildren() {
1202df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return mChildren;
1212df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1222df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1232df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        synchronized boolean isChild(BrowseNode node) {
1242df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            for (BrowseNode bn : mChildren) {
1252df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal                if (bn.equals(node)) {
1262df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal                    return true;
1272df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal                }
1282df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            }
1292df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return false;
1302df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1312df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1328e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        synchronized boolean isCached() {
1338e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal            return mCached;
1348e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        }
1358e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal
1368e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        synchronized void setCached(boolean cached) {
1378e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal            mCached = cached;
1388e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        }
1398e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal
1402df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // Fetch the Unique UID for this item, this is unique across all elements in the tree.
1412df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        synchronized String getID() {
1422df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return mItem.getDescription().getMediaId();
1432df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1442df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1452df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // Get the BT Player ID associated with this node.
1462df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        synchronized int getPlayerID() {
1472df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return Integer.parseInt(getID().replace(PLAYER_PREFIX, ""));
1482df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1492df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1502df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // Fetch the Folder UID that can be used to fetch folder listing via bluetooth.
1512df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // This may not be unique hence this combined with direction will define the
1522df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // browsing here.
1532df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        synchronized String getFolderUID() {
154c4fbd756e2645147470c486ae96f2253f5e13a52Jack He            return mItem.getDescription()
155c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    .getExtras()
156c4fbd756e2645147470c486ae96f2253f5e13a52Jack He                    .getString(AvrcpControllerService.MEDIA_ITEM_UID_KEY);
1572df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1582df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1592df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        synchronized MediaItem getMediaItem() {
1602df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return mItem;
1612df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1622df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1632df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        synchronized boolean isPlayer() {
1642df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return mIsPlayer;
1652df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1662df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1672df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        synchronized boolean isNowPlaying() {
1682df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return getID().startsWith(NOW_PLAYING_PREFIX);
1692df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1702df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1712df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        @Override
1722df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        public boolean equals(Object other) {
1732df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            if (!(other instanceof BrowseNode)) {
1742df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal                return false;
1752df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            }
1762df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            BrowseNode otherNode = (BrowseNode) other;
1772df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return getID().equals(otherNode.getID());
1782df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1792df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1802df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        @Override
1812df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        public String toString() {
182a016a2a7ece99211165717d01401a5c1a4c4ac3bJoseph Pirozzo            if (VDBG) {
183a016a2a7ece99211165717d01401a5c1a4c4ac3bJoseph Pirozzo                return "ID: " + getID() + " desc: " + mItem;
184a016a2a7ece99211165717d01401a5c1a4c4ac3bJoseph Pirozzo            } else {
185a016a2a7ece99211165717d01401a5c1a4c4ac3bJoseph Pirozzo                return "ID: " + getID();
186a016a2a7ece99211165717d01401a5c1a4c4ac3bJoseph Pirozzo            }
1872df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1882df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
1892df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1902df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    synchronized <E> void refreshChildren(String parentID, List<E> children) {
1912df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        BrowseNode parent = findFolderByIDLocked(parentID);
1922df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        if (parent == null) {
1932df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            Log.w(TAG, "parent not found for parentID " + parentID);
1942df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return;
1952df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
1962df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        refreshChildren(parent, children);
1972df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
1982df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
1992df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    synchronized <E> void refreshChildren(BrowseNode parent, List<E> children) {
2002df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        if (children == null) {
2012df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            Log.e(TAG, "children cannot be null ");
2022df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return;
2032df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
2042df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2052df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        List<BrowseNode> bnList = new ArrayList<BrowseNode>();
2062df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        for (E child : children) {
2072df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            if (child instanceof MediaItem) {
2082df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal                bnList.add(new BrowseNode((MediaItem) child));
2092df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            } else if (child instanceof AvrcpPlayer) {
2102df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal                bnList.add(new BrowseNode((AvrcpPlayer) child));
2112df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            }
2122df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
2132df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2142df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        String parentID = parent.getID();
2152df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // Make sure that the child list is clean.
216a016a2a7ece99211165717d01401a5c1a4c4ac3bJoseph Pirozzo        if (VDBG) {
2172df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            Log.d(TAG, "parent " + parentID + " child list " + parent.getChildren());
2182df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
2192df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2202df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        addChildrenLocked(parent, bnList);
2212df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        List<MediaItem> childrenList = new ArrayList<MediaItem>();
2222df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        for (BrowseNode bn : parent.getChildren()) {
2232df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            childrenList.add(bn.getMediaItem());
2242df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
2258e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal
2268e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        parent.setCached(true);
2272df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
2282df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2292df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    synchronized BrowseNode findBrowseNodeByID(String parentID) {
2302df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        BrowseNode bn = mBrowseMap.get(parentID);
2312df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        if (bn == null) {
2322df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            Log.e(TAG, "folder " + parentID + " not found!");
2332df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return null;
2342df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
235a016a2a7ece99211165717d01401a5c1a4c4ac3bJoseph Pirozzo        if (VDBG) {
2362df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            Log.d(TAG, "Browse map: " + mBrowseMap);
2372df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
2382df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        return bn;
2392df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
2402df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2412df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    BrowseNode findFolderByIDLocked(String parentID) {
2422df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        return mBrowseMap.get(parentID);
2432df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
2442df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2452df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    void addChildrenLocked(BrowseNode parent, List<BrowseNode> items) {
2462df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // Remove existing children and then add the new children.
2472df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        for (BrowseNode c : parent.getChildren()) {
2482df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            mBrowseMap.remove(c.getID());
2492df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
2502df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        parent.getChildren().clear();
2512df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2522df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        for (BrowseNode bn : items) {
2532df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            parent.getChildren().add(bn);
2542df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            mBrowseMap.put(bn.getID(), bn);
2552df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
2562df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
2572df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2582df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    synchronized int getDirection(String toUID) {
2592df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        BrowseNode fromFolder = mCurrentBrowseNode;
2602df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        BrowseNode toFolder = findFolderByIDLocked(toUID);
2612df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        if (fromFolder == null || toFolder == null) {
2622df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            Log.e(TAG, "from folder " + mCurrentBrowseNode + " or to folder " + toUID + " null!");
2632df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
2642df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2652df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        // Check the relationship.
2662df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        if (fromFolder.isChild(toFolder)) {
2672df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return DIRECTION_DOWN;
2682df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        } else if (toFolder.isChild(fromFolder)) {
2692df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return DIRECTION_UP;
2708e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        } else if (fromFolder.equals(toFolder)) {
2718e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal            return DIRECTION_SAME;
2722df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        } else {
273a016a2a7ece99211165717d01401a5c1a4c4ac3bJoseph Pirozzo            Log.w(TAG, "from folder " + mCurrentBrowseNode + "to folder " + toUID);
2742df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return DIRECTION_UNKNOWN;
2752df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
2762df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
2772df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2782df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    synchronized boolean setCurrentBrowsedFolder(String uid) {
2792df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        BrowseNode bn = findFolderByIDLocked(uid);
2802df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        if (bn == null) {
2812df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            Log.e(TAG, "Setting an unknown browsed folder, ignoring bn " + uid);
2822df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal            return false;
2832df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        }
2848e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal
2858e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal        // Set the previous folder as not cached so that we fetch the contents again.
286609f94bb870727471a8c571ede2aa8cbbaf70f76Sanket Agarwal        if (!bn.equals(mCurrentBrowseNode)) {
287609f94bb870727471a8c571ede2aa8cbbaf70f76Sanket Agarwal            Log.d(TAG, "Set cache false " + bn + " curr " + mCurrentBrowseNode);
288609f94bb870727471a8c571ede2aa8cbbaf70f76Sanket Agarwal            mCurrentBrowseNode.setCached(false);
289609f94bb870727471a8c571ede2aa8cbbaf70f76Sanket Agarwal        }
2908e509db28e65be858598365b3ad25d08532a32f9Sanket Agarwal
2912df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        mCurrentBrowseNode = bn;
2922df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        return true;
2932df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
2942df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
2952df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    synchronized BrowseNode getCurrentBrowsedFolder() {
2962df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        return mCurrentBrowseNode;
2972df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
2982df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal
299a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal    synchronized boolean setCurrentBrowsedPlayer(String uid) {
300a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        BrowseNode bn = findFolderByIDLocked(uid);
301a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        if (bn == null) {
302a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal            Log.e(TAG, "Setting an unknown browsed player, ignoring bn " + uid);
303a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal            return false;
304a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        }
305a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        mCurrentBrowsedPlayer = bn;
306a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        return true;
307a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal    }
308a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal
309a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal    synchronized BrowseNode getCurrentBrowsedPlayer() {
310a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        return mCurrentBrowsedPlayer;
311a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal    }
312a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal
313a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal    synchronized boolean setCurrentAddressedPlayer(String uid) {
314a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        BrowseNode bn = findFolderByIDLocked(uid);
315a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        if (bn == null) {
316a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal            Log.e(TAG, "Setting an unknown addressed player, ignoring bn " + uid);
317a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal            return false;
318a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        }
319a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        mCurrentAddressedPlayer = bn;
320a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        return true;
321a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal    }
322a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal
323a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal    synchronized BrowseNode getCurrentAddressedPlayer() {
324a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal        return mCurrentAddressedPlayer;
325a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal    }
326a7c3906cd449598a2960f9574a79edbadb96f034Sanket Agarwal
3272df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    @Override
3282df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    public String toString() {
3292df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal        return mBrowseMap.toString();
3302df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal    }
3312df89213f063ef9d38f1531253299f80fdb0739dSanket Agarwal}
332