1e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo/*
2e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Copyright (C) 2015 The Android Open Source Project
3e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo *
4e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Licensed under the Apache License, Version 2.0 (the "License");
5e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * you may not use this file except in compliance with the License.
6e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * You may obtain a copy of the License at
7e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo *
8e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo *      http://www.apache.org/licenses/LICENSE-2.0
9e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo *
10e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Unless required by applicable law or agreed to in writing, software
11e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * distributed under the License is distributed on an "AS IS" BASIS,
12e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * See the License for the specific language governing permissions and
14e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * limitations under the License.
15e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */
16e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seopackage android.support.v4.media;
17e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
18e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.content.ComponentName;
19e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.content.Context;
20e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.content.Intent;
21e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.content.ServiceConnection;
227a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Limimport android.os.Binder;
23a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Limimport android.os.Build;
24e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Bundle;
25e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Handler;
26e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.IBinder;
273f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Limimport android.os.Message;
283f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Limimport android.os.Messenger;
29e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Parcel;
30e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Parcelable;
31e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.RemoteException;
32e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.IntDef;
33e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.NonNull;
34e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.Nullable;
3582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Limimport android.support.v4.app.BundleCompat;
362490f437a4111d64520f891b2c81685f8fae323cJae Seoimport android.support.v4.media.session.MediaControllerCompat;
37e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.media.session.MediaSessionCompat;
38ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Limimport android.support.v4.os.BuildCompat;
39e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.os.ResultReceiver;
40e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.util.ArrayMap;
41e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.text.TextUtils;
42e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.util.Log;
43e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
44e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.lang.annotation.Retention;
45e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.lang.annotation.RetentionPolicy;
4616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Limimport java.lang.ref.WeakReference;
476b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Limimport java.util.ArrayList;
48ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Limimport java.util.Collections;
49e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.util.List;
5082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport java.util.Map;
51e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
5282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Limimport static android.support.v4.media.MediaBrowserProtocol.*;
5382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
54e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo/**
55096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * Browses media content offered by a {@link MediaBrowserServiceCompat}.
56e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p>
57e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * This object is not thread-safe. All calls should happen on the thread on which the browser
58e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * was constructed.
59e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p>
60e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */
61096f2531cb790bc1106377d2da344614a3b88d39Jae Seopublic final class MediaBrowserCompat {
6282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim    private static final String TAG = "MediaBrowserCompat";
637a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
643f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim
6582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    /**
6682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * Used as an int extra field to denote the page number to subscribe.
6782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * The value of {@code EXTRA_PAGE} should be greater than or equal to 1.
6882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *
6982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @see android.service.media.MediaBrowserService.BrowserRoot
7082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @see #EXTRA_PAGE_SIZE
7182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     */
7282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
7382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
7482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    /**
7582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * Used as an int extra field to denote the number of media items in a page.
7682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * The value of {@code EXTRA_PAGE_SIZE} should be greater than or equal to 1.
7782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *
7882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @see android.service.media.MediaBrowserService.BrowserRoot
7982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @see #EXTRA_PAGE
8082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     */
8182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
8282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
836b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim    private final MediaBrowserImpl mImpl;
84e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
85e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
86e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Creates a media browser for the specified media browse service.
87e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
88e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param context The context.
89e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param serviceComponent The component name of the media browse service.
90e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param callback The connection callback.
91e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param rootHints An optional bundle of service-specific arguments to send
92e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * to the media browse service when connecting and retrieving the root id
9382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * for browsing, or null if none. The contents of this bundle may affect
94e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * the information returned when browsing.
9526e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo     * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_RECENT
9626e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo     * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_OFFLINE
9726e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo     * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_SUGGESTED
98e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
99096f2531cb790bc1106377d2da344614a3b88d39Jae Seo    public MediaBrowserCompat(Context context, ComponentName serviceComponent,
100e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            ConnectionCallback callback, Bundle rootHints) {
101ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim        if (Build.VERSION.SDK_INT >= 24 || BuildCompat.isAtLeastN()) {
10201b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            mImpl = new MediaBrowserImplApi24(context, serviceComponent, callback, rootHints);
10301b922eddadab50910ce289921001a63855e1f8eSungsoo Lim        } else if (Build.VERSION.SDK_INT >= 23) {
10482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            mImpl = new MediaBrowserImplApi23(context, serviceComponent, callback, rootHints);
105a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim        } else if (Build.VERSION.SDK_INT >= 21) {
1066b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            mImpl = new MediaBrowserImplApi21(context, serviceComponent, callback, rootHints);
1076b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        } else {
10899f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim            mImpl = new MediaBrowserImplBase(context, serviceComponent, callback, rootHints);
1096b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
110e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
111e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
112e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
113e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Connects to the media browse service.
114e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
115e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * The connection callback specified in the constructor will be invoked
116e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * when the connection completes or fails.
117e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
118e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
119e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public void connect() {
120e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        mImpl.connect();
121e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
122e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
123e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
124e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Disconnects from the media browse service.
125e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * After this, no more callbacks will be received.
126e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
127e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public void disconnect() {
128e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        mImpl.disconnect();
129e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
130e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
131e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
132e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Returns whether the browser is connected to the service.
133e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
134e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public boolean isConnected() {
135e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        return mImpl.isConnected();
136e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
137e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
138e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
139e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Gets the service component that the media browser is connected to.
140e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
141e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public @NonNull
142e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    ComponentName getServiceComponent() {
143e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        return mImpl.getServiceComponent();
144e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
145e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
146e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
147e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Gets the root id.
148e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
149e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Note that the root id may become invalid or change when when the
150e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * browser is disconnected.
151e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
152e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
153e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @throws IllegalStateException if not connected.
154e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
155e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public @NonNull String getRoot() {
156e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        return mImpl.getRoot();
157e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
158e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
159e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
160e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Gets any extras for the media service.
161e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
162e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @throws IllegalStateException if not connected.
163e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
164e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public @Nullable
165e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    Bundle getExtras() {
166e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        return mImpl.getExtras();
167e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
168e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
169e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
170e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Gets the media session token associated with the media browser.
171e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
172e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Note that the session token may become invalid or change when when the
173e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * browser is disconnected.
174e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
175e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
176e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @return The session token for the browser, never null.
177e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
178e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @throws IllegalStateException if not connected.
179e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
180a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim    public @NonNull MediaSessionCompat.Token getSessionToken() {
181e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        return mImpl.getSessionToken();
182e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
183e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
184e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
185e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Queries for information about the media items that are contained within
186e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * the specified id and subscribes to receive updates when they change.
187e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
188e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * The list of subscriptions is maintained even when not connected and is
18982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * restored after the reconnection. It is ok to subscribe while not connected
190e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * but the results will not be returned until the connection completes.
191e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
192e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
193e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * If the id is already subscribed with a different callback then the new
194e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * callback will replace the previous one and the child data will be
195e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * reloaded.
196e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
197e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
198e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param parentId The id of the parent media item whose list of children
199e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *            will be subscribed.
200e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param callback The callback to receive the list of children.
201e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
202e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
2037a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        // Check arguments.
2047a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        if (TextUtils.isEmpty(parentId)) {
2057a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            throw new IllegalArgumentException("parentId is empty");
2067a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        }
2077a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        if (callback == null) {
2087a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            throw new IllegalArgumentException("callback is null");
2097a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        }
21082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        mImpl.subscribe(parentId, null, callback);
21182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    }
21282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
21382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    /**
21482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * Queries with service-specific arguments for information about the media items
21582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * that are contained within the specified id and subscribes to receive updates
21682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * when they change.
21782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * <p>
21882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * The list of subscriptions is maintained even when not connected and is
21982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * restored after the reconnection. It is ok to subscribe while not connected
22082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * but the results will not be returned until the connection completes.
22182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * </p>
22282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * <p>
22382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * If the id is already subscribed with a different callback then the new
22482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * callback will replace the previous one and the child data will be
22582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * reloaded.
22682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * </p>
22782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *
22882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @param parentId The id of the parent media item whose list of children
22982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *            will be subscribed.
23082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @param options A bundle of service-specific arguments to send to the media
23182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *            browse service. The contents of this bundle may affect the
23282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *            information returned when browsing.
23382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @param callback The callback to receive the list of children.
23482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     */
23582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    public void subscribe(@NonNull String parentId, @NonNull Bundle options,
23682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            @NonNull SubscriptionCallback callback) {
2377a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        // Check arguments.
2387a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        if (TextUtils.isEmpty(parentId)) {
2397a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            throw new IllegalArgumentException("parentId is empty");
2407a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        }
2417a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        if (callback == null) {
2427a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            throw new IllegalArgumentException("callback is null");
2437a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        }
24482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        if (options == null) {
24582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            throw new IllegalArgumentException("options are null");
24682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        }
24782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        mImpl.subscribe(parentId, options, callback);
248e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
249e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
250e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
251e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Unsubscribes for changes to the children of the specified media id.
252e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
253e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * The query callback will no longer be invoked for results associated with
254e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * this id once this method returns.
255e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
256e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
257e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param parentId The id of the parent media item whose list of children
25882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *            will be unsubscribed.
259e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
260e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public void unsubscribe(@NonNull String parentId) {
2617a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        // Check arguments.
2627a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        if (TextUtils.isEmpty(parentId)) {
2637a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            throw new IllegalArgumentException("parentId is empty");
2647a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        }
26582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        mImpl.unsubscribe(parentId, null);
26682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    }
26782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
26882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    /**
26982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * Unsubscribes for changes to the children of the specified media id.
27082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * <p>
27182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * The query callback will no longer be invoked for results associated with
27282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * this id once this method returns.
27382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * </p>
27482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *
27582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @param parentId The id of the parent media item whose list of children
27682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *            will be unsubscribed.
2777a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim     * @param callback A callback sent to the media browse service to subscribe.
27882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     */
2797a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim    public void unsubscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
2807a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        // Check arguments.
2817a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        if (TextUtils.isEmpty(parentId)) {
2827a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            throw new IllegalArgumentException("parentId is empty");
2837a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        }
2847a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        if (callback == null) {
2857a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            throw new IllegalArgumentException("callback is null");
28682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        }
2877a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        mImpl.unsubscribe(parentId, callback);
288e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
289e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
290e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
291e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Retrieves a specific {@link MediaItem} from the connected service. Not
292e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * all services may support this, so falling back to subscribing to the
293e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * parent's id should be used when unavailable.
294e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
295e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param mediaId The id of the item to retrieve.
296e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param cb The callback to receive the result on.
297e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
298e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
299e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        mImpl.getItem(mediaId, cb);
300e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
301e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
30223471681e408dfe4e44975e13e7575ab5a04bc8cJae Seo    /**
30323471681e408dfe4e44975e13e7575ab5a04bc8cJae Seo     * A class with information on a single media item for use in browsing media.
30423471681e408dfe4e44975e13e7575ab5a04bc8cJae Seo     */
305e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public static class MediaItem implements Parcelable {
306e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        private final int mFlags;
307e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        private final MediaDescriptionCompat mDescription;
308e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
309e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /** @hide */
310e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        @Retention(RetentionPolicy.SOURCE)
311e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        @IntDef(flag=true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
312e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public @interface Flags { }
313e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
314e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
315e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Flag: Indicates that the item has children of its own.
316e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
317e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public static final int FLAG_BROWSABLE = 1 << 0;
318e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
319e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
320e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Flag: Indicates that the item is playable.
321e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * <p>
322e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * The id of this item may be passed to
3232490f437a4111d64520f891b2c81685f8fae323cJae Seo         * {@link MediaControllerCompat.TransportControls#playFromMediaId(String, Bundle)}
324e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * to start playing it.
325e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * </p>
326e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
327e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public static final int FLAG_PLAYABLE = 1 << 1;
328e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
329e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
330e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Create a new MediaItem for use in browsing media.
331e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @param description The description of the media, which must include a
332e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         *            media id.
333e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @param flags The flags for this item.
334e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
335e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public MediaItem(@NonNull MediaDescriptionCompat description, @Flags int flags) {
336e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            if (description == null) {
337e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                throw new IllegalArgumentException("description cannot be null");
338e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
339e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            if (TextUtils.isEmpty(description.getMediaId())) {
340e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                throw new IllegalArgumentException("description must have a non-empty media id");
341e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
342e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mFlags = flags;
343e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mDescription = description;
344e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
345e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
346e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
347e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Private constructor.
348e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
349e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        private MediaItem(Parcel in) {
350e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mFlags = in.readInt();
351e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mDescription = MediaDescriptionCompat.CREATOR.createFromParcel(in);
352e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
353e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
354e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        @Override
355e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public int describeContents() {
356e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return 0;
357e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
358e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
359e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        @Override
360e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void writeToParcel(Parcel out, int flags) {
361e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            out.writeInt(mFlags);
362e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mDescription.writeToParcel(out, flags);
363e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
364e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
365e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        @Override
366e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public String toString() {
367e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            final StringBuilder sb = new StringBuilder("MediaItem{");
368e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            sb.append("mFlags=").append(mFlags);
369e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            sb.append(", mDescription=").append(mDescription);
370e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            sb.append('}');
371e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return sb.toString();
372e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
373e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
374e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public static final Parcelable.Creator<MediaItem> CREATOR =
375e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                new Parcelable.Creator<MediaItem>() {
376e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    @Override
377e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    public MediaItem createFromParcel(Parcel in) {
378e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                        return new MediaItem(in);
379e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    }
380e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
381e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    @Override
382e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    public MediaItem[] newArray(int size) {
383e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                        return new MediaItem[size];
384e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    }
385e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                };
386e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
387e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
388e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Gets the flags of the item.
389e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
390e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public @Flags int getFlags() {
391e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return mFlags;
392e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
393e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
394e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
395e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Returns whether this item is browsable.
396e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @see #FLAG_BROWSABLE
397e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
398e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public boolean isBrowsable() {
399e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return (mFlags & FLAG_BROWSABLE) != 0;
400e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
401e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
402e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
403e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Returns whether this item is playable.
404e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @see #FLAG_PLAYABLE
405e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
406e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public boolean isPlayable() {
407e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return (mFlags & FLAG_PLAYABLE) != 0;
408e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
409e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
410e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
411e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Returns the description of the media.
412e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
413e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public @NonNull MediaDescriptionCompat getDescription() {
414e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return mDescription;
415e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
416e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
417e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
418e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Returns the media id for this item.
419e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
420e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public @NonNull String getMediaId() {
421e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return mDescription.getMediaId();
422e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
423e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
424e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
425e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
426e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Callbacks for connection related events.
427e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
428e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public static class ConnectionCallback {
4296b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        final Object mConnectionCallbackObj;
43016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private ConnectionCallbackInternal mConnectionCallbackInternal;
4316b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
4326b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public ConnectionCallback() {
433a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim            if (Build.VERSION.SDK_INT >= 21) {
4346b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                mConnectionCallbackObj =
4356b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                        MediaBrowserCompatApi21.createConnectionCallback(new StubApi21());
4366b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            } else {
4376b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                mConnectionCallbackObj = null;
4386b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
4396b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
4406b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
441e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
442096f2531cb790bc1106377d2da344614a3b88d39Jae Seo         * Invoked after {@link MediaBrowserCompat#connect()} when the request has successfully
443096f2531cb790bc1106377d2da344614a3b88d39Jae Seo         * completed.
444e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
445e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onConnected() {
446e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
447e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
448e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
449e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Invoked when the client is disconnected from the media browser.
450e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
451e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onConnectionSuspended() {
452e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
453e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
454e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
455e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Invoked when the connection to the media browser failed.
456e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
457e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onConnectionFailed() {
458e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
4596b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
46016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void setInternalConnectionCallback(ConnectionCallbackInternal connectionCallbackInternal) {
46116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mConnectionCallbackInternal = connectionCallbackInternal;
46216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
46316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
46416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        interface ConnectionCallbackInternal {
46516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            void onConnected();
46616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            void onConnectionSuspended();
46716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            void onConnectionFailed();
46816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
4696b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
4706b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        private class StubApi21 implements MediaBrowserCompatApi21.ConnectionCallback {
4716b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            @Override
4726b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            public void onConnected() {
47316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (mConnectionCallbackInternal != null) {
47416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mConnectionCallbackInternal.onConnected();
47516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
4766b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                ConnectionCallback.this.onConnected();
4776b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
4786b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
4796b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            @Override
4806b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            public void onConnectionSuspended() {
48116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (mConnectionCallbackInternal != null) {
48216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mConnectionCallbackInternal.onConnectionSuspended();
48316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
4846b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                ConnectionCallback.this.onConnectionSuspended();
4856b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
4866b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
4876b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            @Override
4886b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            public void onConnectionFailed() {
48916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (mConnectionCallbackInternal != null) {
49016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mConnectionCallbackInternal.onConnectionFailed();
49116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
4926b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                ConnectionCallback.this.onConnectionFailed();
4936b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
4946b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
495e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
496e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
497e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
498e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Callbacks for subscription related events.
499e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
500e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public static abstract class SubscriptionCallback {
50116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final Object mSubscriptionCallbackObj;
5027a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        private final IBinder mToken;
503ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim        private WeakReference<Subscription> mSubscriptionRef;
50416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
5057a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        public SubscriptionCallback() {
506ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim            if (Build.VERSION.SDK_INT >= 24 || BuildCompat.isAtLeastN()) {
50701b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                mSubscriptionCallbackObj =
50801b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                        MediaBrowserCompatApi24.createSubscriptionCallback(new StubApi24());
5097a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                mToken = null;
5107a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            } else if (Build.VERSION.SDK_INT >= 21) {
51101b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                mSubscriptionCallbackObj =
51201b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                        MediaBrowserCompatApi21.createSubscriptionCallback(new StubApi21());
5137a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                mToken = new Binder();
5147a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            } else {
5157a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                mSubscriptionCallbackObj = null;
5167a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                mToken = new Binder();
51701b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            }
5186b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
5196b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
520e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
521e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Called when the list of children is loaded or updated.
522e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         *
523e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @param parentId The media id of the parent media item.
524ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim         * @param children The children which were loaded, or null if the id is invalid.
525e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
526ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children) {
527e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
528e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
529e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
53082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * Called when the list of children is loaded or updated.
53182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *
53282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * @param parentId The media id of the parent media item.
53382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * @param children The children which were loaded, or null if the id is invalid.
53482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * @param options A bundle of service-specific arguments to send to the media
53582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *            browse service. The contents of this bundle may affect the
53682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *            information returned when browsing.
53782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         */
53882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children,
53982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                @NonNull Bundle options) {
54082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        }
54182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
54282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        /**
543e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Called when the id doesn't exist or other errors in subscribing.
544e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * <p>
545096f2531cb790bc1106377d2da344614a3b88d39Jae Seo         * If this is called, the subscription remains until {@link MediaBrowserCompat#unsubscribe}
546e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * called, because some errors may heal themselves.
547e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * </p>
548e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         *
54916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * @param parentId The media id of the parent media item whose children could not be loaded.
550e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
551e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onError(@NonNull String parentId) {
552e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
5536b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
55482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        /**
55582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * Called when the id doesn't exist or other errors in subscribing.
55682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * <p>
55782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * If this is called, the subscription remains until {@link MediaBrowserCompat#unsubscribe}
55882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * called, because some errors may heal themselves.
55982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * </p>
56082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *
56182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * @param parentId The media id of the parent media item whose children could
56282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *            not be loaded.
56382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * @param options A bundle of service-specific arguments sent to the media
56482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *            browse service.
56582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         */
56682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        public void onError(@NonNull String parentId, @NonNull Bundle options) {
56782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        }
56882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
569ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim        private void setSubscription(Subscription subscription) {
570ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim            mSubscriptionRef = new WeakReference(subscription);
571ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim        }
572ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim
5736b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        private class StubApi21 implements MediaBrowserCompatApi21.SubscriptionCallback {
5746b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            @Override
57582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            public void onChildrenLoaded(@NonNull String parentId, List<Parcel> children) {
57664f99cb02f21f6a708b1f404b5e0ee6144f3af5bSungsoo Lim                Subscription sub = mSubscriptionRef == null ? null : mSubscriptionRef.get();
577ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                if (sub == null) {
578ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    SubscriptionCallback.this.onChildrenLoaded(
579ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                            parentId, parcelListToItemList(children));
580ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                } else {
581ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    List<MediaBrowserCompat.MediaItem> itemList = parcelListToItemList(children);
582ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    final List<SubscriptionCallback> callbacks = sub.getCallbacks();
583ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    final List<Bundle> optionsList = sub.getOptionsList();
584ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    for (int i = 0; i < callbacks.size(); ++i) {
585ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                        Bundle options = optionsList.get(i);
586ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                        if (options == null) {
587ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                            SubscriptionCallback.this.onChildrenLoaded(parentId, itemList);
588ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                        } else {
589ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                            SubscriptionCallback.this.onChildrenLoaded(
590ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                                    parentId, applyOptions(itemList, options), options);
591ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                        }
592ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    }
593ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                }
5946b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
5956b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
5966b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            @Override
5976b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            public void onError(@NonNull String parentId) {
5987a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                SubscriptionCallback.this.onError(parentId);
5996b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
600a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim
601a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim            List<MediaBrowserCompat.MediaItem> parcelListToItemList(
602a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                    List<Parcel> parcelList) {
603a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                if (parcelList == null) {
604a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                    return null;
605a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                }
606a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                List<MediaBrowserCompat.MediaItem> items = new ArrayList<>();
607a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                for (Parcel parcel : parcelList) {
608a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                    parcel.setDataPosition(0);
609a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                    items.add(MediaBrowserCompat.MediaItem.CREATOR.createFromParcel(parcel));
610a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                    parcel.recycle();
611a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                }
612a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim                return items;
613a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim            }
614ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim
615ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim            List<MediaBrowserCompat.MediaItem> applyOptions(List<MediaBrowserCompat.MediaItem> list,
616ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    final Bundle options) {
617ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                if (list == null) {
618ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    return null;
619ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                }
620ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                int page = options.getInt(MediaBrowserCompat.EXTRA_PAGE, -1);
621ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                int pageSize = options.getInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, -1);
622ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                if (page == -1 && pageSize == -1) {
623ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    return list;
624ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                }
625ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                int fromIndex = pageSize * page;
626ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                int toIndex = fromIndex + pageSize;
627ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                if (page < 0 || pageSize < 1 || fromIndex >= list.size()) {
628ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    return Collections.EMPTY_LIST;
629ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                }
630ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                if (toIndex > list.size()) {
631ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                    toIndex = list.size();
632ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                }
633ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim                return list.subList(fromIndex, toIndex);
634ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim            }
635ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim
6366b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
63701b922eddadab50910ce289921001a63855e1f8eSungsoo Lim
63801b922eddadab50910ce289921001a63855e1f8eSungsoo Lim        private class StubApi24 extends StubApi21
63901b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                implements MediaBrowserCompatApi24.SubscriptionCallback {
64001b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            @Override
6417a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            public void onChildrenLoaded(@NonNull String parentId, List<Parcel> children,
64201b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                    @NonNull Bundle options) {
6437a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                SubscriptionCallback.this.onChildrenLoaded(
6447a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        parentId, parcelListToItemList(children), options);
64501b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            }
64601b922eddadab50910ce289921001a63855e1f8eSungsoo Lim
64701b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            @Override
64801b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            public void onError(@NonNull String parentId, @NonNull Bundle options) {
6497a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                SubscriptionCallback.this.onError(parentId, options);
65001b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            }
65101b922eddadab50910ce289921001a63855e1f8eSungsoo Lim        }
652e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
653e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
654e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
655e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Callback for receiving the result of {@link #getItem}.
656e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
657e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public static abstract class ItemCallback {
65882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        final Object mItemCallbackObj;
65982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
66082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        public ItemCallback() {
661a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim            if (Build.VERSION.SDK_INT >= 23) {
66282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                mItemCallbackObj = MediaBrowserCompatApi23.createItemCallback(new StubApi23());
66382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            } else {
66482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                mItemCallbackObj = null;
66582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
66682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        }
66782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
668e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
669e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Called when the item has been returned by the browser service.
670e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         *
671e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @param item The item that was returned or null if it doesn't exist.
672e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
673e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onItemLoaded(MediaItem item) {
674e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
675e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
676e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
677e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Called when the item doesn't exist or there was an error retrieving it.
678e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         *
679e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @param itemId The media id of the media item which could not be loaded.
680e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
681e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onError(@NonNull String itemId) {
682e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
68382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
68482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        private class StubApi23 implements MediaBrowserCompatApi23.ItemCallback {
68582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            @Override
68682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            public void onItemLoaded(Parcel itemParcel) {
68782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                itemParcel.setDataPosition(0);
68882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                MediaItem item = MediaBrowserCompat.MediaItem.CREATOR.createFromParcel(itemParcel);
68982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                itemParcel.recycle();
69082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                ItemCallback.this.onItemLoaded(item);
69182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
69282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
69382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            @Override
69482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            public void onError(@NonNull String itemId) {
69582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                ItemCallback.this.onError(itemId);
69682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
69782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        }
698e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
699e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
7006b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim    interface MediaBrowserImpl {
7016b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        void connect();
7026b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        void disconnect();
7036b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        boolean isConnected();
7046b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        ComponentName getServiceComponent();
7056b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @NonNull String getRoot();
7066b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Nullable Bundle getExtras();
7076b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @NonNull MediaSessionCompat.Token getSessionToken();
70882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        void subscribe(@NonNull String parentId, Bundle options,
70982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                @NonNull SubscriptionCallback callback);
7107a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        void unsubscribe(@NonNull String parentId, SubscriptionCallback callback);
7116b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb);
7126b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim    }
7136b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
71416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    interface MediaBrowserServiceCallbackImpl {
71516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void onServiceConnected(Messenger callback, String root, MediaSessionCompat.Token session,
71616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                Bundle extra);
71716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void onConnectionFailed(Messenger callback);
71816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void onLoadChildren(Messenger callback, String parentId, List list, Bundle options);
71916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
72016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
72199f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim    static class MediaBrowserImplBase
72216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            implements MediaBrowserImpl, MediaBrowserServiceCallbackImpl {
723e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private static final int CONNECT_STATE_DISCONNECTED = 0;
724e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private static final int CONNECT_STATE_CONNECTING = 1;
725e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private static final int CONNECT_STATE_CONNECTED = 2;
726e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private static final int CONNECT_STATE_SUSPENDED = 3;
727e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
728e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private final Context mContext;
729e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private final ComponentName mServiceComponent;
730e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private final ConnectionCallback mCallback;
731e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private final Bundle mRootHints;
73216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final CallbackHandler mHandler = new CallbackHandler(this);
73382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
734e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
735e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private int mState = CONNECT_STATE_DISCONNECTED;
736e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private MediaServiceConnection mServiceConnection;
7373f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim        private ServiceBinderWrapper mServiceBinderWrapper;
7383f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim        private Messenger mCallbacksMessenger;
739e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private String mRootId;
740e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private MediaSessionCompat.Token mMediaSessionToken;
741e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private Bundle mExtras;
742e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
74399f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim        public MediaBrowserImplBase(Context context, ComponentName serviceComponent,
744e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                ConnectionCallback callback, Bundle rootHints) {
745e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (context == null) {
746e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalArgumentException("context must not be null");
747e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
748e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (serviceComponent == null) {
749e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalArgumentException("service component must not be null");
750e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
751e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (callback == null) {
752e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalArgumentException("connection callback must not be null");
753e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
754e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mContext = context;
755e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mServiceComponent = serviceComponent;
756e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mCallback = callback;
757fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim            mRootHints = rootHints == null ? null : new Bundle(rootHints);
758e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
759e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
7607a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
761e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public void connect() {
762e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (mState != CONNECT_STATE_DISCONNECTED) {
763e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalStateException("connect() called while not disconnected (state="
764e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        + getStateLabel(mState) + ")");
765e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
766e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // TODO: remove this extra check.
7677a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (DEBUG) {
768e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                if (mServiceConnection != null) {
769e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    throw new RuntimeException("mServiceConnection should be null. Instead it is "
770e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                            + mServiceConnection);
771e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
772e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
7733f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mServiceBinderWrapper != null) {
7743f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                throw new RuntimeException("mServiceBinderWrapper should be null. Instead it is "
7753f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                        + mServiceBinderWrapper);
776e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
7773f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mCallbacksMessenger != null) {
7783f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                throw new RuntimeException("mCallbacksMessenger should be null. Instead it is "
7793f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                        + mCallbacksMessenger);
780e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
781e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
782e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mState = CONNECT_STATE_CONNECTING;
783e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
784e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            final Intent intent = new Intent(MediaBrowserServiceCompat.SERVICE_INTERFACE);
785e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            intent.setComponent(mServiceComponent);
786e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
787e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            final ServiceConnection thisConnection = mServiceConnection =
788e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    new MediaServiceConnection();
789e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
790e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            boolean bound = false;
791e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            try {
792e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                bound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
793e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            } catch (Exception ex) {
794e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                Log.e(TAG, "Failed binding to service " + mServiceComponent);
795e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
796e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
797e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (!bound) {
79882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                // Tell them that it didn't work. We are already on the main thread,
79982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                // but we don't want to do callbacks inside of connect(). So post it,
80082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                // and then check that we are on the same ServiceConnection. We know
801e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                // we won't also get an onServiceConnected or onServiceDisconnected,
802e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                // so we won't be doing double callbacks.
803e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                mHandler.post(new Runnable() {
804e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    @Override
805e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    public void run() {
806e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        // Ensure that nobody else came in or tried to connect again.
807e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        if (thisConnection == mServiceConnection) {
808e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                            forceCloseConnection();
809e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                            mCallback.onConnectionFailed();
810e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        }
811e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    }
812e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                });
813e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
814e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
8157a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (DEBUG) {
816e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                Log.d(TAG, "connect...");
817e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                dump();
818e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
819e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
820e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
8217a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
822e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public void disconnect() {
823e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // It's ok to call this any state, because allowing this lets apps not have
82482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            // to check isConnected() unnecessarily. They won't appreciate the extra
82582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            // assertions for this. We do everything we can here to go back to a sane state.
8263f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mCallbacksMessenger != null) {
827e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                try {
82816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mServiceBinderWrapper.disconnect(mCallbacksMessenger);
829e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                } catch (RemoteException ex) {
83082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    // We are disconnecting anyway. Log, just for posterity but it's not
831e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    // a big problem.
832e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
833e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
834e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
835e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            forceCloseConnection();
836e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
8377a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (DEBUG) {
838e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                Log.d(TAG, "disconnect...");
839e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                dump();
840e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
841e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
842e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
843e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        /**
84482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * Null out the variables and unbind from the service. This doesn't include
845e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * calling disconnect on the service, because we only try to do that in the
846e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * clean shutdown cases.
847e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * <p>
848e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * Everywhere that calls this EXCEPT for disconnect() should follow it with
84982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * a call to mCallback.onConnectionFailed(). Disconnect doesn't do that callback
850e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * for a clean shutdown, but everywhere else is a dirty shutdown and should
851e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * notify the app.
852e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         */
853e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private void forceCloseConnection() {
854e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (mServiceConnection != null) {
855e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                mContext.unbindService(mServiceConnection);
856e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
857e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mState = CONNECT_STATE_DISCONNECTED;
858e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mServiceConnection = null;
8593f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mServiceBinderWrapper = null;
8603f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mCallbacksMessenger = null;
86199f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim            mHandler.setCallbacksMessenger(null);
862e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mRootId = null;
863e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mMediaSessionToken = null;
864e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
865e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
8667a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
867e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public boolean isConnected() {
868e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            return mState == CONNECT_STATE_CONNECTED;
869e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
870e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
8717a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
8727a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        public @NonNull ComponentName getServiceComponent() {
873e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (!isConnected()) {
874e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalStateException("getServiceComponent() called while not connected" +
875e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        " (state=" + mState + ")");
876e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
877e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            return mServiceComponent;
878e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
879e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
8807a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
881e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public @NonNull String getRoot() {
882e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (!isConnected()) {
883dfed7fbde83fb36b1993582317a27c5247af958cDongwon Kang                throw new IllegalStateException("getRoot() called while not connected"
884e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        + "(state=" + getStateLabel(mState) + ")");
885e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
886e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            return mRootId;
887e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
888e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
8897a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
8907a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        public @Nullable Bundle getExtras() {
891e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (!isConnected()) {
892e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalStateException("getExtras() called while not connected (state="
893e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        + getStateLabel(mState) + ")");
894e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
895e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            return mExtras;
896e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
897e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
8987a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
899e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public @NonNull MediaSessionCompat.Token getSessionToken() {
900e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (!isConnected()) {
901e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalStateException("getSessionToken() called while not connected"
902e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        + "(state=" + mState + ")");
903e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
904e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            return mMediaSessionToken;
905e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
906e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
9077a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
90882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        public void subscribe(@NonNull String parentId, Bundle options,
90982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                @NonNull SubscriptionCallback callback) {
910e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // Update or create the subscription.
911e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Subscription sub = mSubscriptions.get(parentId);
91282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            if (sub == null) {
91382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                sub = new Subscription();
914e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                mSubscriptions.put(parentId, sub);
915e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
91658302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim            sub.putCallback(options, callback);
917e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
91882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            // If we are connected, tell the service that we are watching. If we aren't
919e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // connected, the service will be told when we connect.
920e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (mState == CONNECT_STATE_CONNECTED) {
921e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                try {
9227a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    mServiceBinderWrapper.addSubscription(parentId, callback.mToken, options,
9237a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            mCallbacksMessenger);
92416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                } catch (RemoteException e) {
92582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    // Process is crashing. We will disconnect, and upon reconnect we will
926e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    // automatically reregister. So nothing to do here.
927e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
928e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
929e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
930e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
931e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
9327a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
9337a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        public void unsubscribe(@NonNull String parentId, SubscriptionCallback callback) {
93482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            Subscription sub = mSubscriptions.get(parentId);
9357a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (sub == null) {
9367a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                return;
9377a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            }
938e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
939e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // Tell the service if necessary.
9407a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            try {
9417a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                if (callback == null) {
9427a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    if (mState == CONNECT_STATE_CONNECTED) {
9437a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        mServiceBinderWrapper.removeSubscription(parentId, null,
9447a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                                mCallbacksMessenger);
9457a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    }
9467a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                } else {
9477a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    final List<SubscriptionCallback> callbacks = sub.getCallbacks();
9487a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    final List<Bundle> optionsList = sub.getOptionsList();
9497a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    for (int i = callbacks.size() - 1; i >= 0; --i) {
9507a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        if (callbacks.get(i) == callback) {
9517a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            if (mState == CONNECT_STATE_CONNECTED) {
9527a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                                mServiceBinderWrapper.removeSubscription(
9537a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                                        parentId, callback.mToken, mCallbacksMessenger);
9547a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            }
9557a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            callbacks.remove(i);
9567a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            optionsList.remove(i);
9577a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        }
9587a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    }
959e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
9607a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            } catch (RemoteException ex) {
9617a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                // Process is crashing. We will disconnect, and upon reconnect we will
9627a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                // automatically reregister. So nothing to do here.
9637a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
964e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
9657a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim
9667a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (sub.isEmpty() || callback == null) {
96782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                mSubscriptions.remove(parentId);
96882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            }
969e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
970e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
9717a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
972d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        public void getItem(@NonNull final String mediaId, @NonNull final ItemCallback cb) {
973e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (TextUtils.isEmpty(mediaId)) {
9747a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                throw new IllegalArgumentException("mediaId is empty");
975e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
976e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (cb == null) {
9777a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                throw new IllegalArgumentException("cb is null");
978e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
979e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (mState != CONNECT_STATE_CONNECTED) {
980e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
981e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                mHandler.post(new Runnable() {
982e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    @Override
983e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    public void run() {
984e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        cb.onError(mediaId);
985e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    }
986e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                });
987e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                return;
988e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
989d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            ResultReceiver receiver = new ItemReceiver(mediaId, cb, mHandler);
990e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            try {
991fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim                mServiceBinderWrapper.getMediaItem(mediaId, receiver, mCallbacksMessenger);
992e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            } catch (RemoteException e) {
993e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                Log.i(TAG, "Remote error getting media item.");
994e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                mHandler.post(new Runnable() {
995e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    @Override
996e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    public void run() {
997e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        cb.onError(mediaId);
998e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    }
999e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                });
1000e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
1001e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
1002e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
10037a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
100416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onServiceConnected(final Messenger callback, final String root,
10053f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                final MediaSessionCompat.Token session, final Bundle extra) {
10063f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Check to make sure there hasn't been a disconnect or a different ServiceConnection.
10073f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (!isCurrent(callback, "onConnect")) {
10083f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                return;
10093f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
10103f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Don't allow them to call us twice.
10113f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mState != CONNECT_STATE_CONNECTING) {
10123f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                Log.w(TAG, "onConnect from service while mState=" + getStateLabel(mState)
10133f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                        + "... ignoring");
10143f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                return;
10153f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
10163f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mRootId = root;
10173f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mMediaSessionToken = session;
10183f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mExtras = extra;
10193f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mState = CONNECT_STATE_CONNECTED;
1020e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
10217a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (DEBUG) {
10223f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                Log.d(TAG, "ServiceCallbacks.onConnect...");
10233f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                dump();
10243f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
10253f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mCallback.onConnected();
10263f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim
10273f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // we may receive some subscriptions before we are connected, so re-subscribe
10283f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // everything now
102982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            try {
103082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                for (Map.Entry<String, Subscription> subscriptionEntry
103182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                        : mSubscriptions.entrySet()) {
103282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    String id = subscriptionEntry.getKey();
103382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    Subscription sub = subscriptionEntry.getValue();
10347a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    List<SubscriptionCallback> callbackList = sub.getCallbacks();
10357a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    List<Bundle> optionsList = sub.getOptionsList();
10367a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    for (int i = 0; i < callbackList.size(); ++i) {
10377a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        mServiceBinderWrapper.addSubscription(id, callbackList.get(i).mToken,
10387a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                                optionsList.get(i), mCallbacksMessenger);
103982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    }
1040e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
104182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            } catch (RemoteException ex) {
104282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                // Process is crashing. We will disconnect, and upon reconnect we will
104382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                // automatically reregister. So nothing to do here.
104482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                Log.d(TAG, "addSubscription failed with RemoteException.");
10453f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
1046e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
1047e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
10487a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
104916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onConnectionFailed(final Messenger callback) {
10503f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            Log.e(TAG, "onConnectFailed for " + mServiceComponent);
1051e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
10523f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Check to make sure there hasn't been a disconnect or a different ServiceConnection.
10533f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (!isCurrent(callback, "onConnectFailed")) {
10543f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                return;
10553f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
10563f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Don't allow them to call us twice.
10573f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mState != CONNECT_STATE_CONNECTING) {
10583f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                Log.w(TAG, "onConnect from service while mState=" + getStateLabel(mState)
10593f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                        + "... ignoring");
10603f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                return;
10613f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
1062e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
10633f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Clean up
10643f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            forceCloseConnection();
1065e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
10663f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Tell the app.
10673f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mCallback.onConnectionFailed();
1068e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
1069e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
10707a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        @Override
107116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onLoadChildren(final Messenger callback, final String parentId,
107282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                final List list, final Bundle options) {
107382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            // Check that there hasn't been a disconnect or a different ServiceConnection.
107482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            if (!isCurrent(callback, "onLoadChildren")) {
107582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                return;
107682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
1077e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
107882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            List<MediaItem> data = list;
10797a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (DEBUG) {
108082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
108182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
1082e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
108382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            // Check that the subscription is still subscribed.
108482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            final Subscription subscription = mSubscriptions.get(parentId);
108582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            if (subscription == null) {
10867a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                if (DEBUG) {
108782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
108882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                }
108982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                return;
109082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
109182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
109282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            // Tell the app.
109382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            SubscriptionCallback subscriptionCallback = subscription.getCallback(options);
109482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            if (subscriptionCallback != null) {
109582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                if (options == null) {
109682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    subscriptionCallback.onChildrenLoaded(parentId, data);
109782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                } else {
109882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    subscriptionCallback.onChildrenLoaded(parentId, data, options);
109982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                }
110082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            }
1101e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
1102e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1103e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        /**
110416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * For debugging.
110516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         */
110616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private static String getStateLabel(int state) {
110716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            switch (state) {
110816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case CONNECT_STATE_DISCONNECTED:
110916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return "CONNECT_STATE_DISCONNECTED";
111016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case CONNECT_STATE_CONNECTING:
111116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return "CONNECT_STATE_CONNECTING";
111216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case CONNECT_STATE_CONNECTED:
111316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return "CONNECT_STATE_CONNECTED";
111416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case CONNECT_STATE_SUSPENDED:
111516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return "CONNECT_STATE_SUSPENDED";
111616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                default:
111716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return "UNKNOWN/" + state;
111816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
111916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
112016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
112116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        /**
112282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * Return true if {@code callback} is the current ServiceCallbacks. Also logs if it's not.
1123e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         */
11243f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim        private boolean isCurrent(Messenger callback, String funcName) {
11253f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mCallbacksMessenger != callback) {
1126e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                if (mState != CONNECT_STATE_DISCONNECTED) {
11273f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                    Log.i(TAG, funcName + " for " + mServiceComponent + " with mCallbacksMessenger="
11283f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                            + mCallbacksMessenger + " this=" + this);
1129e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                }
1130e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                return false;
1131e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
1132e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return true;
1133e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
1134e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
1135e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        /**
1136e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * Log internal state.
1137e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * @hide
1138e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         */
1139e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        void dump() {
1140e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "MediaBrowserCompat...");
1141e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mServiceComponent=" + mServiceComponent);
1142e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mCallback=" + mCallback);
1143e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mRootHints=" + mRootHints);
1144e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mState=" + getStateLabel(mState));
1145e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mServiceConnection=" + mServiceConnection);
11463f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            Log.d(TAG, "  mServiceBinderWrapper=" + mServiceBinderWrapper);
11473f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            Log.d(TAG, "  mCallbacksMessenger=" + mCallbacksMessenger);
1148e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mRootId=" + mRootId);
1149e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mMediaSessionToken=" + mMediaSessionToken);
1150e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
1151e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
1152e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
1153e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * ServiceConnection to the other app.
1154e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
1155e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private class MediaServiceConnection implements ServiceConnection {
1156e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            @Override
1157a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim            public void onServiceConnected(final ComponentName name, final IBinder binder) {
1158a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                postOrRun(new Runnable() {
1159a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    @Override
1160a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    public void run() {
11617a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        if (DEBUG) {
1162a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
1163a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                    + " binder=" + binder);
1164a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            dump();
1165a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        }
11663f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim
1167a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // Make sure we are still the current connection, and that they haven't
1168a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // called disconnect().
1169a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        if (!isCurrent("onServiceConnected")) {
1170a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            return;
1171a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        }
1172e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1173a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // Save their binder
1174fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim                        mServiceBinderWrapper = new ServiceBinderWrapper(binder, mRootHints);
1175a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim
1176a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // We make a new mServiceCallbacks each time we connect so that we can drop
1177a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // responses from previous connections.
1178a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mCallbacksMessenger = new Messenger(mHandler);
117916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        mHandler.setCallbacksMessenger(mCallbacksMessenger);
1180a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim
1181a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mState = CONNECT_STATE_CONNECTING;
1182a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim
1183a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // Call connect, which is async. When we get a response from that we will
1184a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // say that we're connected.
1185a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        try {
11867a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            if (DEBUG) {
1187a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                Log.d(TAG, "ServiceCallbacks.onConnect...");
1188a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                dump();
1189a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            }
1190fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim                            mServiceBinderWrapper.connect(mContext, mCallbacksMessenger);
1191a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        } catch (RemoteException ex) {
1192a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            // Connect failed, which isn't good. But the auto-reconnect on the
119382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                            // service will take over and we will come back. We will also get the
119482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                            // onServiceDisconnected, which has all the cleanup code. So let that
1195a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            // do it.
1196a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
11977a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            if (DEBUG) {
1198a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                Log.d(TAG, "ServiceCallbacks.onConnect...");
1199a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                dump();
1200a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            }
1201a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        }
1202e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    }
1203a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                });
1204e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
1205e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1206e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            @Override
1207a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim            public void onServiceDisconnected(final ComponentName name) {
1208a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                postOrRun(new Runnable() {
1209a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    @Override
1210a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    public void run() {
12117a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        if (DEBUG) {
1212a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
1213a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                    + " this=" + this + " mServiceConnection=" +
1214a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                    mServiceConnection);
1215a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            dump();
1216a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        }
1217e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1218a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // Make sure we are still the current connection, and that they haven't
1219a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // called disconnect().
1220a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        if (!isCurrent("onServiceDisconnected")) {
1221a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            return;
1222a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        }
1223e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1224a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // Clear out what we set in onServiceConnected
1225a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mServiceBinderWrapper = null;
1226a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mCallbacksMessenger = null;
122716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        mHandler.setCallbacksMessenger(null);
1228e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1229a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // And tell the app that it's suspended.
1230a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mState = CONNECT_STATE_SUSPENDED;
1231a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mCallback.onConnectionSuspended();
1232a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    }
1233a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                });
1234a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim            }
1235a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim
1236a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim            private void postOrRun(Runnable r) {
1237a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                if (Thread.currentThread() == mHandler.getLooper().getThread()) {
1238a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    r.run();
1239a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                } else {
1240a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    mHandler.post(r);
1241a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                }
1242e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
1243e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1244e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            /**
124582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim             * Return true if this is the current ServiceConnection. Also logs if it's not.
1246e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake             */
1247e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            private boolean isCurrent(String funcName) {
1248e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                if (mServiceConnection != this) {
1249e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    if (mState != CONNECT_STATE_DISCONNECTED) {
1250e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        // Check mState, because otherwise this log is noisy.
1251e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        Log.i(TAG, funcName + " for " + mServiceComponent +
1252e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                                " with mServiceConnection=" + mServiceConnection + " this=" + this);
1253e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    }
1254e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    return false;
1255e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
1256e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                return true;
1257e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
1258e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
125916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
1260e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
126116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    static class MediaBrowserImplApi21 implements MediaBrowserImpl, MediaBrowserServiceCallbackImpl,
126216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            ConnectionCallback.ConnectionCallbackInternal {
1263fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim        protected final Object mBrowserObj;
1264fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim        protected final Bundle mRootHints;
12652e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim        protected final CallbackHandler mHandler = new CallbackHandler(this);
126616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
12676b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12682e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim        protected ServiceBinderWrapper mServiceBinderWrapper;
12692e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim        protected Messenger mCallbacksMessenger;
12706b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12716b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public MediaBrowserImplApi21(Context context, ComponentName serviceComponent,
12726b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                ConnectionCallback callback, Bundle rootHints) {
12732e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim            // Do not send the client version for API 24 and higher, since we don't need to use
12742e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim            // EXTRA_MESSENGER_BINDER for API 24 and higher.
1275ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim            if (Build.VERSION.SDK_INT < 24 && !BuildCompat.isAtLeastN()) {
12762e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim                if (rootHints == null) {
12772e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim                    rootHints = new Bundle();
12782e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim                }
12792e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim                rootHints.putInt(EXTRA_CLIENT_VERSION, CLIENT_VERSION_CURRENT);
12802e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim                mRootHints = new Bundle(rootHints);
12812e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim            } else {
12822e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim                mRootHints = rootHints == null ? null : new Bundle(rootHints);
12837a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            }
128416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            callback.setInternalConnectionCallback(this);
12856b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            mBrowserObj = MediaBrowserCompatApi21.createBrowser(context, serviceComponent,
1286fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim                    callback.mConnectionCallbackObj, mRootHints);
12876b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
12886b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12896b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
12906b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public void connect() {
12916b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            MediaBrowserCompatApi21.connect(mBrowserObj);
12926b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
12936b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12946b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
12956b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public void disconnect() {
129699f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim            if (mServiceBinderWrapper != null && mCallbacksMessenger != null) {
129799f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim                try {
129899f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim                    mServiceBinderWrapper.unregisterCallbackMessenger(mCallbacksMessenger);
129999f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim                } catch (RemoteException e) {
130099f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim                    Log.i(TAG, "Remote error unregistering client messenger." );
130199f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim                }
130299f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim            }
13036b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            MediaBrowserCompatApi21.disconnect(mBrowserObj);
13046b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
13056b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
13066b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
13076b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public boolean isConnected() {
13086b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            return MediaBrowserCompatApi21.isConnected(mBrowserObj);
13096b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
13106b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
13116b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
13126b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public ComponentName getServiceComponent() {
13136b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            return MediaBrowserCompatApi21.getServiceComponent(mBrowserObj);
13146b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
13156b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
13166b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @NonNull
13176b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
13186b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public String getRoot() {
13196b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            return MediaBrowserCompatApi21.getRoot(mBrowserObj);
13206b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
13216b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
13226b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Nullable
13236b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
13246b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public Bundle getExtras() {
13256b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            return MediaBrowserCompatApi21.getExtras(mBrowserObj);
13266b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
13276b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
13286b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @NonNull
13296b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
13306b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public MediaSessionCompat.Token getSessionToken() {
13316b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            return MediaSessionCompat.Token.fromToken(
13326b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                    MediaBrowserCompatApi21.getSessionToken(mBrowserObj));
13336b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
13346b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
13356b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
133616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void subscribe(@NonNull final String parentId, final Bundle options,
133716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                @NonNull final SubscriptionCallback callback) {
133816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // Update or create the subscription.
133916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Subscription sub = mSubscriptions.get(parentId);
134016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (sub == null) {
134116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                sub = new Subscription();
134216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                mSubscriptions.put(parentId, sub);
134316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
1344ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim            callback.setSubscription(sub);
13457a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            sub.putCallback(options, callback);
13467a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim
13477a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (mServiceBinderWrapper == null) {
13487a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                MediaBrowserCompatApi21.subscribe(
13497a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        mBrowserObj, parentId, callback.mSubscriptionCallbackObj);
13507a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            } else {
13517a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                try {
13527a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    mServiceBinderWrapper.addSubscription(
13537a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            parentId, callback.mToken, options, mCallbacksMessenger);
13547a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                } catch (RemoteException e) {
13557a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    // Process is crashing. We will disconnect, and upon reconnect we will
13567a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    // automatically reregister. So nothing to do here.
13577a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    Log.i(TAG, "Remote error subscribing media item: " + parentId);
135816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
135916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
13606b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
13616b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
13626b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
13637a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        public void unsubscribe(@NonNull String parentId, SubscriptionCallback callback) {
13647a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            Subscription sub = mSubscriptions.get(parentId);
13657a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (sub == null) {
13667a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                return;
136716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
136816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
13697a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (mServiceBinderWrapper == null) {
13707a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                if (callback == null) {
13717a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    MediaBrowserCompatApi21.unsubscribe(mBrowserObj, parentId);
13727a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                } else {
13737a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    final List<SubscriptionCallback> callbacks = sub.getCallbacks();
13747a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    final List<Bundle> optionsList = sub.getOptionsList();
13757a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    for (int i = callbacks.size() - 1; i >= 0; --i) {
13767a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        if (callbacks.get(i) == callback) {
13777a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            callbacks.remove(i);
13787a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            optionsList.remove(i);
13797a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        }
13807a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    }
13817a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    if (callbacks.size() == 0) {
138216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        MediaBrowserCompatApi21.unsubscribe(mBrowserObj, parentId);
138316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    }
13847a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                }
13857a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            } else {
13867a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                // Tell the service if necessary.
13877a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                try {
13887a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    if (callback == null) {
13897a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        mServiceBinderWrapper.removeSubscription(parentId, null,
13907a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                                mCallbacksMessenger);
13917a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    } else {
13927a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        final List<SubscriptionCallback> callbacks = sub.getCallbacks();
13937a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        final List<Bundle> optionsList = sub.getOptionsList();
13947a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        for (int i = callbacks.size() - 1; i >= 0; --i) {
13957a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            if (callbacks.get(i) == callback) {
13967a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                                mServiceBinderWrapper.removeSubscription(
13977a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                                        parentId, callback.mToken, mCallbacksMessenger);
13987a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                                callbacks.remove(i);
13997a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                                optionsList.remove(i);
14007a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            }
14017a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        }
140216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    }
14037a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                } catch (RemoteException ex) {
14047a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    // Process is crashing. We will disconnect, and upon reconnect we will
14057a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    // automatically reregister. So nothing to do here.
14067a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    Log.d(TAG, "removeSubscription failed with RemoteException parentId="
14077a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                            + parentId);
140816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
140916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
14107a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim
14117a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (sub.isEmpty() || callback == null) {
141216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                mSubscriptions.remove(parentId);
141316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
14146b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
14156b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
14166b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
141782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        public void getItem(@NonNull final String mediaId, @NonNull final ItemCallback cb) {
141882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            if (TextUtils.isEmpty(mediaId)) {
14197a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                throw new IllegalArgumentException("mediaId is empty");
142082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
142182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            if (cb == null) {
14227a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                throw new IllegalArgumentException("cb is null");
142382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
142482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            if (!MediaBrowserCompatApi21.isConnected(mBrowserObj)) {
142582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
142682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                mHandler.post(new Runnable() {
142782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    @Override
142882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    public void run() {
142982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                        cb.onError(mediaId);
143082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    }
143182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                });
143282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                return;
143382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
143416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (mServiceBinderWrapper == null) {
143582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                mHandler.post(new Runnable() {
143682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    @Override
143782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    public void run() {
143882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                        // Default framework implementation.
143982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                        cb.onItemLoaded(null);
144082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    }
144182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                });
144282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                return;
144382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
1444d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            ResultReceiver receiver = new ItemReceiver(mediaId, cb, mHandler);
144582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            try {
1446fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim                mServiceBinderWrapper.getMediaItem(mediaId, receiver, mCallbacksMessenger);
144782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            } catch (RemoteException e) {
144816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                Log.i(TAG, "Remote error getting media item: " + mediaId);
144982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                mHandler.post(new Runnable() {
145082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    @Override
145182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    public void run() {
145282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                        cb.onError(mediaId);
145382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    }
145482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                });
145582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
145682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        }
145782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
145816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
145916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onConnected() {
146016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle extras = MediaBrowserCompatApi21.getExtras(mBrowserObj);
146116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (extras == null) {
146216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                return;
146316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
146416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            IBinder serviceBinder = BundleCompat.getBinder(extras, EXTRA_MESSENGER_BINDER);
146516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (serviceBinder != null) {
1466fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim                mServiceBinderWrapper = new ServiceBinderWrapper(serviceBinder, mRootHints);
146716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                mCallbacksMessenger = new Messenger(mHandler);
146816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                mHandler.setCallbacksMessenger(mCallbacksMessenger);
146916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                try {
147016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mServiceBinderWrapper.registerCallbackMessenger(mCallbacksMessenger);
147116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                } catch (RemoteException e) {
147216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    Log.i(TAG, "Remote error registering client messenger." );
147316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
147416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
147516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
147616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
147716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
147816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onConnectionSuspended() {
147916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mServiceBinderWrapper = null;
148016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mCallbacksMessenger = null;
148199f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim            mHandler.setCallbacksMessenger(null);
148216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
148316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
148416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
148516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onConnectionFailed() {
148616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // Do noting
148716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
148816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
148916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
149016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onServiceConnected(final Messenger callback, final String root,
149116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                final MediaSessionCompat.Token session, final Bundle extra) {
14927a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            // This method will not be called.
149316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
149416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
149516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
149616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onConnectionFailed(Messenger callback) {
149716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // This method will not be called.
149816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
149916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
150016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
1501b3f4a7d427953c3e197a2d362a39d918891698ffSungsoo Lim        public void onLoadChildren(Messenger callback, String parentId, List list, Bundle options) {
150216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (mCallbacksMessenger != callback) {
150316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                return;
150416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
150516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
150616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // Check that the subscription is still subscribed.
150716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Subscription subscription = mSubscriptions.get(parentId);
150816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (subscription == null) {
15097a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                if (DEBUG) {
151016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
151116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
151216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                return;
151316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
151416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
151516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // Tell the app.
15167a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            SubscriptionCallback subscriptionCallback = subscription.getCallback(options);
15177a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (subscriptionCallback != null) {
1518b3f4a7d427953c3e197a2d362a39d918891698ffSungsoo Lim                if (options == null) {
1519b3f4a7d427953c3e197a2d362a39d918891698ffSungsoo Lim                    subscriptionCallback.onChildrenLoaded(parentId, list);
1520b3f4a7d427953c3e197a2d362a39d918891698ffSungsoo Lim                } else {
1521b3f4a7d427953c3e197a2d362a39d918891698ffSungsoo Lim                    subscriptionCallback.onChildrenLoaded(parentId, list, options);
1522b3f4a7d427953c3e197a2d362a39d918891698ffSungsoo Lim                }
15237a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            }
152482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        }
152582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim    }
152682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
152782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim    static class MediaBrowserImplApi23 extends MediaBrowserImplApi21 {
152882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        public MediaBrowserImplApi23(Context context, ComponentName serviceComponent,
152982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                ConnectionCallback callback, Bundle rootHints) {
153082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            super(context, serviceComponent, callback, rootHints);
153182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        }
153282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
153382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        @Override
15342e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim        public void getItem(@NonNull final String mediaId, @NonNull final ItemCallback cb) {
15352e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim            if (mServiceBinderWrapper == null) {
15362e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim                MediaBrowserCompatApi23.getItem(mBrowserObj, mediaId, cb.mItemCallbackObj);
15372e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim            } else {
15382e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim                super.getItem(mediaId, cb);
15392e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim            }
15406b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
15416b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim    }
1542d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim
154301b922eddadab50910ce289921001a63855e1f8eSungsoo Lim    static class MediaBrowserImplApi24 extends MediaBrowserImplApi23 {
154401b922eddadab50910ce289921001a63855e1f8eSungsoo Lim        public MediaBrowserImplApi24(Context context, ComponentName serviceComponent,
154501b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                ConnectionCallback callback, Bundle rootHints) {
154601b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            super(context, serviceComponent, callback, rootHints);
154701b922eddadab50910ce289921001a63855e1f8eSungsoo Lim        }
154801b922eddadab50910ce289921001a63855e1f8eSungsoo Lim
154901b922eddadab50910ce289921001a63855e1f8eSungsoo Lim        @Override
155001b922eddadab50910ce289921001a63855e1f8eSungsoo Lim        public void subscribe(@NonNull String parentId, @NonNull Bundle options,
155101b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                @NonNull SubscriptionCallback callback) {
155201b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            if (options == null) {
155301b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                MediaBrowserCompatApi21.subscribe(
15547a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        mBrowserObj, parentId, callback.mSubscriptionCallbackObj);
155501b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            } else {
155601b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                MediaBrowserCompatApi24.subscribe(
15577a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        mBrowserObj, parentId, options, callback.mSubscriptionCallbackObj);
155801b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            }
155901b922eddadab50910ce289921001a63855e1f8eSungsoo Lim        }
156001b922eddadab50910ce289921001a63855e1f8eSungsoo Lim
156101b922eddadab50910ce289921001a63855e1f8eSungsoo Lim        @Override
15627a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        public void unsubscribe(@NonNull String parentId, SubscriptionCallback callback) {
15637a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (callback == null) {
156401b922eddadab50910ce289921001a63855e1f8eSungsoo Lim                MediaBrowserCompatApi21.unsubscribe(mBrowserObj, parentId);
156501b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            } else {
15667a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                MediaBrowserCompatApi24.unsubscribe(mBrowserObj, parentId,
15677a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                        callback.mSubscriptionCallbackObj);
156801b922eddadab50910ce289921001a63855e1f8eSungsoo Lim            }
156901b922eddadab50910ce289921001a63855e1f8eSungsoo Lim        }
15702e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim
15712e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim        @Override
15722e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim        public void getItem(@NonNull final String mediaId, @NonNull final ItemCallback cb) {
15732e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim            MediaBrowserCompatApi23.getItem(mBrowserObj, mediaId, cb.mItemCallbackObj);
15742e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim        }
157501b922eddadab50910ce289921001a63855e1f8eSungsoo Lim    }
157601b922eddadab50910ce289921001a63855e1f8eSungsoo Lim
157716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    private static class Subscription {
157816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final List<SubscriptionCallback> mCallbacks;
157916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final List<Bundle> mOptionsList;
158016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
158116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public Subscription() {
158216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mCallbacks = new ArrayList();
158316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mOptionsList = new ArrayList();
158416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
158516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
158616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public boolean isEmpty() {
158716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            return mCallbacks.isEmpty();
158816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
158916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
159016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public List<Bundle> getOptionsList() {
159116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            return mOptionsList;
159216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
159316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
159416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public List<SubscriptionCallback> getCallbacks() {
159516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            return mCallbacks;
159616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
159716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
159858302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim        public SubscriptionCallback getCallback(Bundle options) {
159958302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim            for (int i = 0; i < mOptionsList.size(); ++i) {
160058302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim                if (MediaBrowserCompatUtils.areSameOptions(mOptionsList.get(i), options)) {
160158302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim                    return mCallbacks.get(i);
160258302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim                }
160358302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim            }
160458302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim            return null;
160558302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim        }
160658302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim
160758302bb8a709941cee04f2aa378b2496e30d0045Sungsoo Lim        public void putCallback(Bundle options, SubscriptionCallback callback) {
160816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            for (int i = 0; i < mOptionsList.size(); ++i) {
160916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (MediaBrowserCompatUtils.areSameOptions(mOptionsList.get(i), options)) {
161016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mCallbacks.set(i, callback);
161116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return;
161216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
161316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
161416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mCallbacks.add(callback);
161516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mOptionsList.add(options);
161616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
161716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
161816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
161916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    private static class CallbackHandler extends Handler {
16207a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        private final WeakReference<MediaBrowserServiceCallbackImpl> mCallbackImplRef;
162116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private WeakReference<Messenger> mCallbacksMessengerRef;
162216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
162316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        CallbackHandler(MediaBrowserServiceCallbackImpl callbackImpl) {
162416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            super();
16257a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            mCallbackImplRef = new WeakReference<>(callbackImpl);
162616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
162716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
162816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
162916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void handleMessage(Message msg) {
16307a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            if (mCallbacksMessengerRef == null || mCallbacksMessengerRef.get() == null ||
16317a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    mCallbackImplRef.get() == null) {
163216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                return;
163316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
163416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle data = msg.getData();
163516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.setClassLoader(MediaSessionCompat.class.getClassLoader());
163616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            switch (msg.what) {
163716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case SERVICE_MSG_ON_CONNECT:
16387a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    mCallbackImplRef.get().onServiceConnected(mCallbacksMessengerRef.get(),
163916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            data.getString(DATA_MEDIA_ITEM_ID),
164016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            (MediaSessionCompat.Token) data.getParcelable(DATA_MEDIA_SESSION_TOKEN),
164116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            data.getBundle(DATA_ROOT_HINTS));
164216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    break;
164316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case SERVICE_MSG_ON_CONNECT_FAILED:
16447a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    mCallbackImplRef.get().onConnectionFailed(mCallbacksMessengerRef.get());
164516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    break;
164616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case SERVICE_MSG_ON_LOAD_CHILDREN:
16477a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                    mCallbackImplRef.get().onLoadChildren(mCallbacksMessengerRef.get(),
164816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            data.getString(DATA_MEDIA_ITEM_ID),
164916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            data.getParcelableArrayList(DATA_MEDIA_ITEM_LIST),
165016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            data.getBundle(DATA_OPTIONS));
165116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    break;
165216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                default:
165316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    Log.w(TAG, "Unhandled message: " + msg
165416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            + "\n  Client version: " + CLIENT_VERSION_CURRENT
165516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            + "\n  Service version: " + msg.arg1);
165616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
165716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
165816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
165916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void setCallbacksMessenger(Messenger callbacksMessenger) {
166016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mCallbacksMessengerRef = new WeakReference<>(callbacksMessenger);
166116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
166216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
166316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
166416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    private static class ServiceBinderWrapper {
166516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private Messenger mMessenger;
1666fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim        private Bundle mRootHints;
166716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
1668fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim        public ServiceBinderWrapper(IBinder target, Bundle rootHints) {
166916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mMessenger = new Messenger(target);
1670fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim            mRootHints = rootHints;
167116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
167216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
1673fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim        void connect(Context context, Messenger callbacksMessenger)
167416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                throws RemoteException {
167516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle data = new Bundle();
167616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putString(DATA_PACKAGE_NAME, context.getPackageName());
1677fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim            data.putBundle(DATA_ROOT_HINTS, mRootHints);
167816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sendRequest(CLIENT_MSG_CONNECT, data, callbacksMessenger);
167916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
168016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
168116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void disconnect(Messenger callbacksMessenger) throws RemoteException {
168216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sendRequest(CLIENT_MSG_DISCONNECT, null, callbacksMessenger);
168316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
168416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
16857a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        void addSubscription(String parentId, IBinder callbackToken, Bundle options,
16867a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                Messenger callbacksMessenger)
168716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                throws RemoteException {
168816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle data = new Bundle();
168916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putString(DATA_MEDIA_ITEM_ID, parentId);
16907a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            BundleCompat.putBinder(data, DATA_CALLBACK_TOKEN, callbackToken);
169116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putBundle(DATA_OPTIONS, options);
169216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sendRequest(CLIENT_MSG_ADD_SUBSCRIPTION, data, callbacksMessenger);
169316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
169416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
16957a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim        void removeSubscription(String parentId, IBinder callbackToken,
16967a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim                Messenger callbacksMessenger)
169716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                throws RemoteException {
169816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle data = new Bundle();
169916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putString(DATA_MEDIA_ITEM_ID, parentId);
17007a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim            BundleCompat.putBinder(data, DATA_CALLBACK_TOKEN, callbackToken);
170116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sendRequest(CLIENT_MSG_REMOVE_SUBSCRIPTION, data, callbacksMessenger);
170216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
170316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
1704fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim        void getMediaItem(String mediaId, ResultReceiver receiver, Messenger callbacksMessenger)
1705fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim                throws RemoteException {
170616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle data = new Bundle();
170716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putString(DATA_MEDIA_ITEM_ID, mediaId);
170816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putParcelable(DATA_RESULT_RECEIVER, receiver);
1709fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim            sendRequest(CLIENT_MSG_GET_MEDIA_ITEM, data, callbacksMessenger);
171016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
171116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
171216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void registerCallbackMessenger(Messenger callbackMessenger) throws RemoteException {
1713fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim            Bundle data = new Bundle();
1714fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim            data.putBundle(DATA_ROOT_HINTS, mRootHints);
1715fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim            sendRequest(CLIENT_MSG_REGISTER_CALLBACK_MESSENGER, data, callbackMessenger);
171616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
171716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
171899f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim        void unregisterCallbackMessenger(Messenger callbackMessenger) throws RemoteException {
171999f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim            sendRequest(CLIENT_MSG_UNREGISTER_CALLBACK_MESSENGER, null, callbackMessenger);
172099f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim        }
172199f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim
172216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private void sendRequest(int what, Bundle data, Messenger cbMessenger)
172316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                throws RemoteException {
172416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Message msg = Message.obtain();
172516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            msg.what = what;
172616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            msg.arg1 = CLIENT_VERSION_CURRENT;
172716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            msg.setData(data);
172816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            msg.replyTo = cbMessenger;
172916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mMessenger.send(msg);
173016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
173116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
173216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
173316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    private  static class ItemReceiver extends ResultReceiver {
1734d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        private final String mMediaId;
1735d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        private final ItemCallback mCallback;
1736d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim
1737d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        ItemReceiver(String mediaId, ItemCallback callback, Handler handler) {
1738d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            super(handler);
1739d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            mMediaId = mediaId;
1740d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            mCallback = callback;
1741d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        }
1742d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim
1743d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        @Override
1744d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        protected void onReceiveResult(int resultCode, Bundle resultData) {
1745d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            resultData.setClassLoader(MediaBrowserCompat.class.getClassLoader());
1746d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            if (resultCode != 0 || resultData == null
1747d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim                    || !resultData.containsKey(MediaBrowserServiceCompat.KEY_MEDIA_ITEM)) {
1748d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim                mCallback.onError(mMediaId);
1749d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim                return;
1750d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            }
1751d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            Parcelable item = resultData.getParcelable(MediaBrowserServiceCompat.KEY_MEDIA_ITEM);
1752d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            if (item instanceof MediaItem) {
1753d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim                mCallback.onItemLoaded((MediaItem) item);
1754d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            } else {
1755d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim                mCallback.onError(mMediaId);
1756d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            }
1757d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        }
1758d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim    }
1759e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo}
1760