1fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang/*
2fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang * Copyright 2018 The Android Open Source Project
3fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang *
4fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang * Licensed under the Apache License, Version 2.0 (the "License");
5fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang * you may not use this file except in compliance with the License.
6fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang * You may obtain a copy of the License at
7fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang *
8fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang *      http://www.apache.org/licenses/LICENSE-2.0
9fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang *
10fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang * Unless required by applicable law or agreed to in writing, software
11fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang * distributed under the License is distributed on an "AS IS" BASIS,
12fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang * See the License for the specific language governing permissions and
14fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang * limitations under the License.
15fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang */
16fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
17fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangpackage androidx.media;
18fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
19fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
2046a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moonimport static androidx.media.MediaConstants2.ARGUMENT_EXTRAS;
2103c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moonimport static androidx.media.MediaConstants2.ARGUMENT_PAGE;
2203c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moonimport static androidx.media.MediaConstants2.ARGUMENT_PAGE_SIZE;
23fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
24fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport android.content.Context;
25c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kimimport android.os.BadParcelableException;
26fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport android.os.Bundle;
27fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport android.support.v4.media.MediaBrowserCompat;
28fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport android.support.v4.media.MediaBrowserCompat.ItemCallback;
29fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport android.support.v4.media.MediaBrowserCompat.MediaItem;
30fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport android.support.v4.media.MediaBrowserCompat.SubscriptionCallback;
3103c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moonimport android.util.Log;
32fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
33fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport androidx.annotation.GuardedBy;
34fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport androidx.annotation.NonNull;
35fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport androidx.annotation.Nullable;
36fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport androidx.annotation.RestrictTo;
37fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport androidx.media.MediaLibraryService2.MediaLibrarySession;
38fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport androidx.media.MediaSession2.ControllerInfo;
39fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
40fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport java.util.ArrayList;
41fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport java.util.HashMap;
42fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport java.util.List;
43fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangimport java.util.concurrent.Executor;
44fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
45fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang/**
46fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang * Browses media content offered by a {@link MediaLibraryService2}.
47fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang */
48fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kangpublic class MediaBrowser2 extends MediaController2 {
4903c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon    static final String TAG = "MediaBrowser2";
5003c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
5103c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon
52fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    /**
53fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @hide
54fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     */
55fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    @RestrictTo(LIBRARY_GROUP)
56fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    public static final String EXTRA_ITEM_COUNT = "android.media.browse.extra.ITEM_COUNT";
57fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
5846a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon    /**
5946a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon     * @hide
6046a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon     */
6146a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon    @RestrictTo(LIBRARY_GROUP)
6246a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon    public static final String MEDIA_BROWSER2_SUBSCRIBE = "androidx.media.MEDIA_BROWSER2_SUBSCRIBE";
6346a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon
64fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    private final Object mLock = new Object();
65fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    @GuardedBy("mLock")
66fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    private final HashMap<Bundle, MediaBrowserCompat> mBrowserCompats = new HashMap<>();
67fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    @GuardedBy("mLock")
68fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    private final HashMap<String, List<SubscribeCallback>> mSubscribeCallbacks = new HashMap<>();
69fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
70fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    /**
71fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * Callback to listen events from {@link MediaLibraryService2}.
72fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     */
73fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    public static class BrowserCallback extends MediaController2.ControllerCallback {
74fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        /**
75fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * Called with the result of {@link #getLibraryRoot(Bundle)}.
76fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * <p>
77fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * {@code rootMediaId} and {@code rootExtra} can be {@code null} if the library root isn't
78fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * available.
79fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *
80fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param browser the browser for this event
81fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param rootHints rootHints that you previously requested.
82fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param rootMediaId media id of the library root. Can be {@code null}
83fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param rootExtra extra of the library root. Can be {@code null}
84fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         */
85fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onGetLibraryRootDone(@NonNull MediaBrowser2 browser, @Nullable Bundle rootHints,
86fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                @Nullable String rootMediaId, @Nullable Bundle rootExtra) { }
87fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
88fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        /**
89fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * Called when there's change in the parent's children.
90fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * <p>
91fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * This API is called when the library service called
92fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * {@link MediaLibrarySession#notifyChildrenChanged(ControllerInfo, String, int, Bundle)} or
93fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * {@link MediaLibrarySession#notifyChildrenChanged(String, int, Bundle)} for the parent.
94fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *
95fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param browser the browser for this event
96fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param parentId parent id that you've specified with {@link #subscribe(String, Bundle)}
97fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param itemCount number of children
98fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param extras extra bundle from the library service. Can be differ from extras that
99fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *               you've specified with {@link #subscribe(String, Bundle)}.
100fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         */
101fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onChildrenChanged(@NonNull MediaBrowser2 browser, @NonNull String parentId,
102fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                int itemCount, @Nullable Bundle extras) { }
103fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
104fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        /**
105fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * Called when the list of items has been returned by the library service for the previous
106fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * {@link MediaBrowser2#getChildren(String, int, int, Bundle)}.
107fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *
108fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param browser the browser for this event
109fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param parentId parent id
110fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param page page number that you've specified with
111fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *             {@link #getChildren(String, int, int, Bundle)}
112fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param pageSize page size that you've specified with
113fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *                 {@link #getChildren(String, int, int, Bundle)}
114fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param result result. Can be {@code null}
115fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param extras extra bundle from the library service
116fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         */
117fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onGetChildrenDone(@NonNull MediaBrowser2 browser, @NonNull String parentId,
118fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                int page, int pageSize, @Nullable List<MediaItem2> result,
119fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                @Nullable Bundle extras) { }
120fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
121fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        /**
122fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * Called when the item has been returned by the library service for the previous
123fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * {@link MediaBrowser2#getItem(String)} call.
124fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * <p>
125fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * Result can be null if there had been error.
126fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *
127fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param browser the browser for this event
128fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param mediaId media id
129fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param result result. Can be {@code null}
130fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         */
131fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onGetItemDone(@NonNull MediaBrowser2 browser, @NonNull String mediaId,
132fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                @Nullable MediaItem2 result) { }
133fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
134fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        /**
135fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * Called when there's change in the search result requested by the previous
136fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * {@link MediaBrowser2#search(String, Bundle)}.
137fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *
138fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param browser the browser for this event
139fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param query search query that you've specified with {@link #search(String, Bundle)}
140fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param itemCount The item count for the search result
141fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param extras extra bundle from the library service
142fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         */
143fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onSearchResultChanged(@NonNull MediaBrowser2 browser, @NonNull String query,
144fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                int itemCount, @Nullable Bundle extras) { }
145fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
146fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        /**
147fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * Called when the search result has been returned by the library service for the previous
148fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * {@link MediaBrowser2#getSearchResult(String, int, int, Bundle)}.
149fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * <p>
150fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * Result can be null if there had been error.
151fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *
152fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param browser the browser for this event
153fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param query search query that you've specified with
154fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *              {@link #getSearchResult(String, int, int, Bundle)}
155fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param page page number that you've specified with
156fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *             {@link #getSearchResult(String, int, int, Bundle)}
157fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param pageSize page size that you've specified with
158fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         *                 {@link #getSearchResult(String, int, int, Bundle)}
159fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param result result. Can be {@code null}.
160fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         * @param extras extra bundle from the library service
161fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang         */
162fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onGetSearchResultDone(@NonNull MediaBrowser2 browser, @NonNull String query,
163fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                int page, int pageSize, @Nullable List<MediaItem2> result,
164fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                @Nullable Bundle extras) { }
165fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
166fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
167fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    public MediaBrowser2(@NonNull Context context, @NonNull SessionToken2 token,
168fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            @NonNull /*@CallbackExecutor*/ Executor executor, @NonNull BrowserCallback callback) {
169fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        super(context, token, executor, callback);
170fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
171fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
172fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    @Override
173fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    public void close() {
174fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        synchronized (mLock) {
175fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            for (MediaBrowserCompat browser : mBrowserCompats.values()) {
176fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                browser.disconnect();
177fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            }
178fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            mBrowserCompats.clear();
1792bab996996ef62c0feba30576a580d3cb33bca30Jaewan Kim            // Ensure that ControllerCallback#onDisconnected() is called by super.close().
180fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            super.close();
181fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
182fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
183fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
184fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    /**
185fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * Get the library root. Result would be sent back asynchronously with the
186fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * {@link BrowserCallback#onGetLibraryRootDone(MediaBrowser2, Bundle, String, Bundle)}.
187fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     *
188fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param extras extras for getting root
189fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @see BrowserCallback#onGetLibraryRootDone(MediaBrowser2, Bundle, String, Bundle)
190fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     */
191fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    public void getLibraryRoot(@Nullable final Bundle extras) {
192fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        final MediaBrowserCompat browser = getBrowserCompat(extras);
193fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        if (browser != null) {
194fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            // Already connected with the given extras.
195fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            getCallbackExecutor().execute(new Runnable() {
196fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                @Override
197fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                public void run() {
198fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    getCallback().onGetLibraryRootDone(MediaBrowser2.this, extras,
199fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                            browser.getRoot(), browser.getExtras());
200fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                }
201fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            });
202fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        } else {
203c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            getCallbackExecutor().execute(new Runnable() {
204c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                @Override
205c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                public void run() {
206c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                    // Do this on the callback executor to set the looper of MediaBrowserCompat's
207c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                    // callback handler to this looper.
208c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                    MediaBrowserCompat newBrowser = new MediaBrowserCompat(getContext(),
209c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                            getSessionToken().getComponentName(),
210c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                            new GetLibraryRootCallback(extras), extras);
211c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                    synchronized (mLock) {
212c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                        mBrowserCompats.put(extras, newBrowser);
213c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                    }
214c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                    newBrowser.connect();
215c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                }
216c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            });
217fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
218fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
219fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
220fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    /**
221fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * Subscribe to a parent id for the change in its children. When there's a change,
222fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * {@link BrowserCallback#onChildrenChanged(MediaBrowser2, String, int, Bundle)} will be called
223fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * with the bundle that you've specified. You should call
224fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * {@link #getChildren(String, int, int, Bundle)} to get the actual contents for the parent.
225fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     *
226fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param parentId parent id
227fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param extras extra bundle
228fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     */
229fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    public void subscribe(@NonNull String parentId, @Nullable Bundle extras) {
230fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        if (parentId == null) {
231fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            throw new IllegalArgumentException("parentId shouldn't be null");
232fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
233c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        MediaBrowserCompat browser = getBrowserCompat();
234c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        if (browser == null) {
235c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            return;
236fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
237fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        SubscribeCallback callback = new SubscribeCallback();
238fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        synchronized (mLock) {
239fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            List<SubscribeCallback> list = mSubscribeCallbacks.get(parentId);
240fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            if (list == null) {
241fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                list = new ArrayList<>();
242fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                mSubscribeCallbacks.put(parentId, list);
243fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            }
244fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            list.add(callback);
245fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
24646a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon
24746a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon        Bundle options = new Bundle();
24846a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon        options.putBundle(ARGUMENT_EXTRAS, extras);
24946a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon        options.putBoolean(MEDIA_BROWSER2_SUBSCRIBE, true);
25046a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon        browser.subscribe(parentId, options, callback);
251fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
252fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
253fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    /**
254fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * Unsubscribe for changes to the children of the parent, which was previously subscribed with
255fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * {@link #subscribe(String, Bundle)}.
256fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * <p>
257fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * This unsubscribes all previous subscription with the parent id, regardless of the extra
258fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * that was previously sent to the library service.
259fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     *
260fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param parentId parent id
261fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     */
262fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    public void unsubscribe(@NonNull String parentId) {
263fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        if (parentId == null) {
264fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            throw new IllegalArgumentException("parentId shouldn't be null");
265fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
266c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        MediaBrowserCompat browser = getBrowserCompat();
267c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        if (browser == null) {
268c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            return;
269c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        }
270fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        // Note: don't use MediaBrowserCompat#unsubscribe(String) here, to keep the subscription
271fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        // callback for getChildren.
272fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        synchronized (mLock) {
273fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            List<SubscribeCallback> list = mSubscribeCallbacks.get(parentId);
274fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            if (list == null) {
275fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                return;
276fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            }
277fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            for (int i = 0; i < list.size(); i++) {
278fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                browser.unsubscribe(parentId, list.get(i));
279fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            }
280fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
281fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
282fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
283fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    /**
284fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * Get list of children under the parent. Result would be sent back asynchronously with the
285fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * {@link BrowserCallback#onGetChildrenDone(MediaBrowser2, String, int, int, List, Bundle)}.
286fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     *
287fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param parentId parent id for getting the children.
288fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param page page number to get the result. Starts from {@code 1}
289fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param pageSize page size. Should be greater or equal to {@code 1}
290fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param extras extra bundle
291fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     */
292fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    public void getChildren(@NonNull String parentId, int page, int pageSize,
293fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            @Nullable Bundle extras) {
294fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        if (parentId == null) {
295fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            throw new IllegalArgumentException("parentId shouldn't be null");
296fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
297fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        if (page < 1 || pageSize < 1) {
298fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            throw new IllegalArgumentException("Neither page nor pageSize should be less than 1");
299fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
300c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        MediaBrowserCompat browser = getBrowserCompat();
301c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        if (browser == null) {
302c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            return;
303c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        }
304c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim
305c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        Bundle options = MediaUtils2.createBundle(extras);
306fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        options.putInt(MediaBrowserCompat.EXTRA_PAGE, page);
307fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        options.putInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, pageSize);
308c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        browser.subscribe(parentId, options, new GetChildrenCallback(parentId, page, pageSize));
309fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
310fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
311fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    /**
312fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * Get the media item with the given media id. Result would be sent back asynchronously with the
313fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * {@link BrowserCallback#onGetItemDone(MediaBrowser2, String, MediaItem2)}.
314fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     *
315fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param mediaId media id for specifying the item
316fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     */
317fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    public void getItem(@NonNull final String mediaId) {
318c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        MediaBrowserCompat browser = getBrowserCompat();
319c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        if (browser == null) {
320c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            return;
321c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        }
322c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        browser.getItem(mediaId, new ItemCallback() {
323fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            @Override
324fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            public void onItemLoaded(final MediaItem item) {
325fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                getCallbackExecutor().execute(new Runnable() {
326fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    @Override
327fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    public void run() {
328fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                        getCallback().onGetItemDone(MediaBrowser2.this, mediaId,
329fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                                MediaUtils2.createMediaItem2(item));
330fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    }
331fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                });
332fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            }
333fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
334fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            @Override
335fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            public void onError(String itemId) {
336fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                getCallbackExecutor().execute(new Runnable() {
337fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    @Override
338fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    public void run() {
339fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                        getCallback().onGetItemDone(MediaBrowser2.this, mediaId, null);
340fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    }
341fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                });
342fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            }
343fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        });
344fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
345fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
346fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    /**
347fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * Send a search request to the library service. When the search result is changed,
348fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * {@link BrowserCallback#onSearchResultChanged(MediaBrowser2, String, int, Bundle)} will be
349fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * called. You should call {@link #getSearchResult(String, int, int, Bundle)} to get the actual
350fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * search result.
351fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     *
352fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param query search query. Should not be an empty string.
353fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param extras extra bundle
354fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     */
355fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    public void search(@NonNull String query, @Nullable Bundle extras) {
35603c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        MediaBrowserCompat browser = getBrowserCompat();
35703c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        if (browser == null) {
35803c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            return;
35903c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        }
36003c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        browser.search(query, extras, new MediaBrowserCompat.SearchCallback() {
36103c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            @Override
36203c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            public void onSearchResult(final String query, final Bundle extras,
36303c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    final List<MediaItem> items) {
36403c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                getCallbackExecutor().execute(new Runnable() {
36503c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    @Override
36603c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    public void run() {
36703c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                        getCallback().onSearchResultChanged(
36803c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                                MediaBrowser2.this, query, items.size(), extras);
36903c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    }
37003c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                });
37103c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            }
37203c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon
37303c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            @Override
37403c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            public void onError(final String query, final Bundle extras) {
37503c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                // Currently no way to tell failures in MediaBrowser2#search().
37603c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            }
37703c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        });
378fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
379fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
380fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    /**
381fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * Get the search result from lhe library service. Result would be sent back asynchronously with
382fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * the
383fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * {@link BrowserCallback#onGetSearchResultDone(MediaBrowser2, String, int, int, List, Bundle)}.
384fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     *
385fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param query search query that you've specified with {@link #search(String, Bundle)}
386fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param page page number to get search result. Starts from {@code 1}
387fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param pageSize page size. Should be greater or equal to {@code 1}
388fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     * @param extras extra bundle
389fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang     */
39003c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon    public void getSearchResult(final @NonNull String query, final int page, final int pageSize,
39103c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            final @Nullable Bundle extras) {
39203c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        MediaBrowserCompat browser = getBrowserCompat();
39303c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        if (browser == null) {
39403c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            return;
39503c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        }
39603c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        Bundle options = MediaUtils2.createBundle(extras);
39703c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        options.putInt(ARGUMENT_PAGE, page);
39803c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        options.putInt(ARGUMENT_PAGE_SIZE, pageSize);
39903c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        browser.search(query, options, new MediaBrowserCompat.SearchCallback() {
40003c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            @Override
40103c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            public void onSearchResult(final String query, final Bundle extrasSent,
40203c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    final List<MediaItem> items) {
40303c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                getCallbackExecutor().execute(new Runnable() {
40403c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    @Override
40503c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    public void run() {
40603c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                        List<MediaItem2> item2List = MediaUtils2.toMediaItem2List(items);
40703c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                        getCallback().onGetSearchResultDone(
40803c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                                MediaBrowser2.this, query, page, pageSize, item2List, extras);
40903c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    }
41003c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                });
41103c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            }
41203c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon
41303c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            @Override
41403c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            public void onError(final String query, final Bundle extrasSent) {
41503c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                getCallbackExecutor().execute(new Runnable() {
41603c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    @Override
41703c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    public void run() {
41803c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                        getCallback().onGetSearchResultDone(
41903c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                                MediaBrowser2.this, query, page, pageSize, null, extras);
42003c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                    }
42103c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon                });
42203c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon            }
42303c696e779afb0f54668a8f76b0944ab3f1c9a29Hyundo Moon        });
424fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
425fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
426fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    @Override
427fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    BrowserCallback getCallback() {
428fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        return (BrowserCallback) super.getCallback();
429fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
430fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
431fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    private MediaBrowserCompat getBrowserCompat(Bundle extras) {
432e57a84cc8a3c62a777d4dcf48d1c7f6e58657bf6Jaewan Kim        synchronized (mLock) {
433e57a84cc8a3c62a777d4dcf48d1c7f6e58657bf6Jaewan Kim            return mBrowserCompats.get(extras);
434fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
435fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
436fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
437c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim    private Bundle getExtrasWithoutPagination(Bundle extras) {
438c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        if (extras == null) {
439c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            return null;
440c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        }
441c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        extras.setClassLoader(getContext().getClassLoader());
442c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        try {
443c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            extras.remove(MediaBrowserCompat.EXTRA_PAGE);
444c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            extras.remove(MediaBrowserCompat.EXTRA_PAGE_SIZE);
445c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        } catch (BadParcelableException e) {
446c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            // Pass through...
447c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        }
448c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim        return extras;
449c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim    }
450c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim
451fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    private class GetLibraryRootCallback extends MediaBrowserCompat.ConnectionCallback {
452fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        private final Bundle mExtras;
453fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
454fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        GetLibraryRootCallback(Bundle extras) {
455fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            super();
456fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            mExtras = extras;
457fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
458fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
459fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
460fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onConnected() {
461fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            getCallbackExecutor().execute(new Runnable() {
462fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                @Override
463fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                public void run() {
464fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    MediaBrowserCompat browser;
465fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    synchronized (mLock) {
466fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                        browser = mBrowserCompats.get(mExtras);
467fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    }
468fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    if (browser == null) {
469fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                        // Shouldn't be happen.
470fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                        return;
471fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    }
472fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    getCallback().onGetLibraryRootDone(MediaBrowser2.this,
473fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                            mExtras, browser.getRoot(), browser.getExtras());
474fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                }
475fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            });
476fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
477fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
478fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
479fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onConnectionSuspended() {
480fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            close();
481fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
482fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
483fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
484fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onConnectionFailed() {
485fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            close();
486fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
487fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
488fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
489fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    private class SubscribeCallback extends SubscriptionCallback {
490fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
491fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onError(String parentId) {
492fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            onChildrenLoaded(parentId, null, null);
493fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
494fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
495fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
496fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onError(String parentId, Bundle options) {
497fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            onChildrenLoaded(parentId, null, options);
498fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
499fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
500fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
501fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onChildrenLoaded(String parentId, List<MediaItem> children) {
502fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            onChildrenLoaded(parentId, children, null);
503fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
504fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
505fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
506fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onChildrenLoaded(final String parentId, List<MediaItem> children,
507fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                final Bundle options) {
508fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            final int itemCount;
509fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            if (options != null && options.containsKey(EXTRA_ITEM_COUNT)) {
510fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                itemCount = options.getInt(EXTRA_ITEM_COUNT);
511fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            } else if (children != null) {
512fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                itemCount = children.size();
513fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            } else {
514fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                // Currently no way to tell failures in MediaBrowser2#subscribe().
515fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                return;
516fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            }
51746a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon
51846a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon            final Bundle notifyChildrenChangedOptions =
51946a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon                    getBrowserCompat().getNotifyChildrenChangedOptions();
520fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            getCallbackExecutor().execute(new Runnable() {
521fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                @Override
522fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                public void run() {
523fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    getCallback().onChildrenChanged(MediaBrowser2.this, parentId, itemCount,
52446a5d0ff57a61f4e91b568f20b2df8e035de765eHyundo Moon                            notifyChildrenChangedOptions);
525fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                }
526fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            });
527fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
528fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
529fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
530fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    private class GetChildrenCallback extends SubscriptionCallback {
531fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        private final String mParentId;
532fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        private final int mPage;
533fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        private final int mPageSize;
534fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
535fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        GetChildrenCallback(String parentId, int page, int pageSize) {
536fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            super();
537fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            mParentId = parentId;
538fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            mPage = page;
539fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            mPageSize = pageSize;
540fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
541fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
542fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
543fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onError(String parentId) {
544fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            onChildrenLoaded(parentId, null, null);
545fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
546fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
547fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
548fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onError(String parentId, Bundle options) {
549fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            onChildrenLoaded(parentId, null, options);
550fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
551fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
552fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
553fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onChildrenLoaded(String parentId, List<MediaItem> children) {
554fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            onChildrenLoaded(parentId, children, null);
555fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
556fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang
557fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        @Override
558fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        public void onChildrenLoaded(final String parentId, List<MediaItem> children,
559c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                Bundle options) {
560fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            final List<MediaItem2> items;
561fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            if (children == null) {
562fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                items = null;
563fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            } else {
564fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                items = new ArrayList<>();
565fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                for (int i = 0; i < children.size(); i++) {
566fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    items.add(MediaUtils2.createMediaItem2(children.get(i)));
567fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                }
568fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            }
569c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim            final Bundle extras = getExtrasWithoutPagination(options);
570fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            getCallbackExecutor().execute(new Runnable() {
571fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                @Override
572fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                public void run() {
573c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                    MediaBrowserCompat browser = getBrowserCompat();
574c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                    if (browser == null) {
575c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                        return;
576c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                    }
577fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                    getCallback().onGetChildrenDone(MediaBrowser2.this, parentId, mPage, mPageSize,
578c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                            items, extras);
579c000096702ed479f7aa922176851fe98cfa6a154Jaewan Kim                    browser.unsubscribe(mParentId, GetChildrenCallback.this);
580fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang                }
581fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang            });
582fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang        }
583fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang    }
584fbbf807584a0fbe7a01a0aa9920330cad45689aaInsun Kang}
585