MediaBrowserCompat.java revision 26e88318c8f69f62f41591b0df0720cc48b4ce11
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;
22e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Bundle;
23e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Handler;
24e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.IBinder;
253f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Limimport android.os.Message;
263f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Limimport android.os.Messenger;
27e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Parcel;
28e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Parcelable;
29e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.RemoteException;
30e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.IntDef;
31e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.NonNull;
32e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.Nullable;
3382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Limimport android.support.v4.app.BundleCompat;
342490f437a4111d64520f891b2c81685f8fae323cJae Seoimport android.support.v4.media.session.MediaControllerCompat;
35e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.media.session.MediaSessionCompat;
36e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.os.ResultReceiver;
37e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.util.ArrayMap;
38e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.text.TextUtils;
39e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.util.Log;
40e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
41e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.lang.annotation.Retention;
42e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.lang.annotation.RetentionPolicy;
4316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Limimport java.lang.ref.WeakReference;
446b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Limimport java.util.ArrayList;
45e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.util.List;
4682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport java.util.Map;
47e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
4882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Limimport static android.support.v4.media.MediaBrowserProtocol.*;
4982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
50e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo/**
51096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * Browses media content offered by a {@link MediaBrowserServiceCompat}.
52e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p>
53e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * This object is not thread-safe. All calls should happen on the thread on which the browser
54e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * was constructed.
55e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p>
56e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */
57096f2531cb790bc1106377d2da344614a3b88d39Jae Seopublic final class MediaBrowserCompat {
5882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim    private static final String TAG = "MediaBrowserCompat";
593f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim
6082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    /**
6182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * Used as an int extra field to denote the page number to subscribe.
6282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * The value of {@code EXTRA_PAGE} should be greater than or equal to 1.
6382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *
6482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @see android.service.media.MediaBrowserService.BrowserRoot
6582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @see #EXTRA_PAGE_SIZE
6682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * {@hide}
6782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     */
6882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
6982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
7082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    /**
7182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * Used as an int extra field to denote the number of media items in a page.
7282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * The value of {@code EXTRA_PAGE_SIZE} should be greater than or equal to 1.
7382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *
7482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @see android.service.media.MediaBrowserService.BrowserRoot
7582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @see #EXTRA_PAGE
7682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * {@hide}
7782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     */
7882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
7982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
806b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim    private final MediaBrowserImpl mImpl;
81e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
82e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
83e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Creates a media browser for the specified media browse service.
84e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
85e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param context The context.
86e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param serviceComponent The component name of the media browse service.
87e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param callback The connection callback.
88e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param rootHints An optional bundle of service-specific arguments to send
89e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * to the media browse service when connecting and retrieving the root id
9082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * for browsing, or null if none. The contents of this bundle may affect
91e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * the information returned when browsing.
9226e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo     * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_RECENT
9326e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo     * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_OFFLINE
9426e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo     * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_SUGGESTED
95e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
96096f2531cb790bc1106377d2da344614a3b88d39Jae Seo    public MediaBrowserCompat(Context context, ComponentName serviceComponent,
97e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            ConnectionCallback callback, Bundle rootHints) {
9865fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes        if (android.os.Build.VERSION.SDK_INT >= 23) {
9982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            mImpl = new MediaBrowserImplApi23(context, serviceComponent, callback, rootHints);
10065fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes        } else if (android.os.Build.VERSION.SDK_INT >= 21) {
1016b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            mImpl = new MediaBrowserImplApi21(context, serviceComponent, callback, rootHints);
1026b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        } else {
10316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mImpl = new MediaBrowserServiceImplBase(context, serviceComponent, callback, rootHints);
1046b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
105e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
106e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
107e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
108e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Connects to the media browse service.
109e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
110e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * The connection callback specified in the constructor will be invoked
111e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * when the connection completes or fails.
112e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
113e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
114e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public void connect() {
115e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        mImpl.connect();
116e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
117e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
118e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
119e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Disconnects from the media browse service.
120e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * After this, no more callbacks will be received.
121e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
122e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public void disconnect() {
123e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        mImpl.disconnect();
124e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
125e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
126e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
127e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Returns whether the browser is connected to the service.
128e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
129e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public boolean isConnected() {
130e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        return mImpl.isConnected();
131e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
132e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
133e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
134e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Gets the service component that the media browser is connected to.
135e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
136e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public @NonNull
137e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    ComponentName getServiceComponent() {
138e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        return mImpl.getServiceComponent();
139e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
140e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
141e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
142e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Gets the root id.
143e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
144e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Note that the root id may become invalid or change when when the
145e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * browser is disconnected.
146e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
147e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
148e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @throws IllegalStateException if not connected.
149e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
150e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public @NonNull String getRoot() {
151e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        return mImpl.getRoot();
152e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
153e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
154e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
155e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Gets any extras for the media service.
156e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
157e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @throws IllegalStateException if not connected.
158e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
159e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public @Nullable
160e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    Bundle getExtras() {
161e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        return mImpl.getExtras();
162e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
163e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
164e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
165e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Gets the media session token associated with the media browser.
166e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
167e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Note that the session token may become invalid or change when when the
168e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * browser is disconnected.
169e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
170e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
171e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @return The session token for the browser, never null.
172e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
173e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @throws IllegalStateException if not connected.
174e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
175e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     public @NonNull MediaSessionCompat.Token getSessionToken() {
176e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        return mImpl.getSessionToken();
177e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
178e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
179e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
180e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Queries for information about the media items that are contained within
181e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * the specified id and subscribes to receive updates when they change.
182e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
183e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * The list of subscriptions is maintained even when not connected and is
18482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * restored after the reconnection. It is ok to subscribe while not connected
185e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * but the results will not be returned until the connection completes.
186e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
187e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
188e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * If the id is already subscribed with a different callback then the new
189e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * callback will replace the previous one and the child data will be
190e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * reloaded.
191e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
192e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
193e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param parentId The id of the parent media item whose list of children
194e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *            will be subscribed.
195e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param callback The callback to receive the list of children.
196e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
197e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
19882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        mImpl.subscribe(parentId, null, callback);
19982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    }
20082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
20182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    /**
20282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * Queries with service-specific arguments for information about the media items
20382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * that are contained within the specified id and subscribes to receive updates
20482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * when they change.
20582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * <p>
20682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * The list of subscriptions is maintained even when not connected and is
20782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * restored after the reconnection. It is ok to subscribe while not connected
20882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * but the results will not be returned until the connection completes.
20982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * </p>
21082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * <p>
21182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * If the id is already subscribed with a different callback then the new
21282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * callback will replace the previous one and the child data will be
21382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * reloaded.
21482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * </p>
21582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *
21682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @param parentId The id of the parent media item whose list of children
21782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *            will be subscribed.
21882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @param options A bundle of service-specific arguments to send to the media
21982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *            browse service. The contents of this bundle may affect the
22082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *            information returned when browsing.
22182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @param callback The callback to receive the list of children.
22282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * {@hide}
22382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     */
22482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    public void subscribe(@NonNull String parentId, @NonNull Bundle options,
22582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            @NonNull SubscriptionCallback callback) {
22682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        if (options == null) {
22782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            throw new IllegalArgumentException("options are null");
22882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        }
22982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        mImpl.subscribe(parentId, options, callback);
230e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
231e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
232e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
233e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Unsubscribes for changes to the children of the specified media id.
234e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * <p>
235e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * The query callback will no longer be invoked for results associated with
236e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * this id once this method returns.
237e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * </p>
238e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
239e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param parentId The id of the parent media item whose list of children
24082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *            will be unsubscribed.
241e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
242e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public void unsubscribe(@NonNull String parentId) {
24382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        mImpl.unsubscribe(parentId, null);
24482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    }
24582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
24682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    /**
24782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * Unsubscribes for changes to the children of the specified media id.
24882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * <p>
24982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * The query callback will no longer be invoked for results associated with
25082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * this id once this method returns.
25182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * </p>
25282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *
25382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @param parentId The id of the parent media item whose list of children
25482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     *            will be unsubscribed.
25582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * @param options A bundle sent to the media browse service to subscribe.
25682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     * {@hide}
25782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim     */
25882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim    public void unsubscribe(@NonNull String parentId, @NonNull Bundle options) {
25982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        if (options == null) {
26082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            throw new IllegalArgumentException("options are null");
26182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        }
26282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        mImpl.unsubscribe(parentId, options);
263e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
264e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
265e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
266e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Retrieves a specific {@link MediaItem} from the connected service. Not
267e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * all services may support this, so falling back to subscribing to the
268e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * parent's id should be used when unavailable.
269e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     *
270e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param mediaId The id of the item to retrieve.
271e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * @param cb The callback to receive the result on.
272e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
273e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
274e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        mImpl.getItem(mediaId, cb);
275e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
276e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
27723471681e408dfe4e44975e13e7575ab5a04bc8cJae Seo    /**
27823471681e408dfe4e44975e13e7575ab5a04bc8cJae Seo     * A class with information on a single media item for use in browsing media.
27923471681e408dfe4e44975e13e7575ab5a04bc8cJae Seo     */
280e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public static class MediaItem implements Parcelable {
281e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        private final int mFlags;
282e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        private final MediaDescriptionCompat mDescription;
283e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
284e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /** @hide */
285e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        @Retention(RetentionPolicy.SOURCE)
286e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        @IntDef(flag=true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
287e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public @interface Flags { }
288e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
289e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
290e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Flag: Indicates that the item has children of its own.
291e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
292e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public static final int FLAG_BROWSABLE = 1 << 0;
293e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
294e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
295e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Flag: Indicates that the item is playable.
296e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * <p>
297e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * The id of this item may be passed to
2982490f437a4111d64520f891b2c81685f8fae323cJae Seo         * {@link MediaControllerCompat.TransportControls#playFromMediaId(String, Bundle)}
299e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * to start playing it.
300e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * </p>
301e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
302e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public static final int FLAG_PLAYABLE = 1 << 1;
303e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
304e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
305e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Create a new MediaItem for use in browsing media.
306e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @param description The description of the media, which must include a
307e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         *            media id.
308e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @param flags The flags for this item.
309e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
310e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public MediaItem(@NonNull MediaDescriptionCompat description, @Flags int flags) {
311e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            if (description == null) {
312e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                throw new IllegalArgumentException("description cannot be null");
313e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
314e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            if (TextUtils.isEmpty(description.getMediaId())) {
315e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                throw new IllegalArgumentException("description must have a non-empty media id");
316e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
317e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mFlags = flags;
318e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mDescription = description;
319e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
320e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
321e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
322e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Private constructor.
323e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
324e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        private MediaItem(Parcel in) {
325e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mFlags = in.readInt();
326e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mDescription = MediaDescriptionCompat.CREATOR.createFromParcel(in);
327e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
328e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
329e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        @Override
330e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public int describeContents() {
331e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return 0;
332e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
333e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
334e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        @Override
335e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void writeToParcel(Parcel out, int flags) {
336e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            out.writeInt(mFlags);
337e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mDescription.writeToParcel(out, flags);
338e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
339e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
340e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        @Override
341e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public String toString() {
342e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            final StringBuilder sb = new StringBuilder("MediaItem{");
343e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            sb.append("mFlags=").append(mFlags);
344e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            sb.append(", mDescription=").append(mDescription);
345e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            sb.append('}');
346e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return sb.toString();
347e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
348e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
349e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public static final Parcelable.Creator<MediaItem> CREATOR =
350e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                new Parcelable.Creator<MediaItem>() {
351e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    @Override
352e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    public MediaItem createFromParcel(Parcel in) {
353e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                        return new MediaItem(in);
354e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    }
355e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
356e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    @Override
357e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    public MediaItem[] newArray(int size) {
358e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                        return new MediaItem[size];
359e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                    }
360e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                };
361e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
362e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
363e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Gets the flags of the item.
364e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
365e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public @Flags int getFlags() {
366e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return mFlags;
367e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
368e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
369e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
370e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Returns whether this item is browsable.
371e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @see #FLAG_BROWSABLE
372e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
373e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public boolean isBrowsable() {
374e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return (mFlags & FLAG_BROWSABLE) != 0;
375e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
376e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
377e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
378e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Returns whether this item is playable.
379e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @see #FLAG_PLAYABLE
380e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
381e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public boolean isPlayable() {
382e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return (mFlags & FLAG_PLAYABLE) != 0;
383e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
384e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
385e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
386e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Returns the description of the media.
387e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
388e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public @NonNull MediaDescriptionCompat getDescription() {
389e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return mDescription;
390e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
391e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
392e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
393e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Returns the media id for this item.
394e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
395e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public @NonNull String getMediaId() {
396e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return mDescription.getMediaId();
397e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
398e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
399e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
400e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
401e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Callbacks for connection related events.
402e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
403e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public static class ConnectionCallback {
4046b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        final Object mConnectionCallbackObj;
40516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private ConnectionCallbackInternal mConnectionCallbackInternal;
4066b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
4076b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public ConnectionCallback() {
40865fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes            if (android.os.Build.VERSION.SDK_INT >= 21) {
4096b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                mConnectionCallbackObj =
4106b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                        MediaBrowserCompatApi21.createConnectionCallback(new StubApi21());
4116b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            } else {
4126b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                mConnectionCallbackObj = null;
4136b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
4146b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
4156b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
416e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
417096f2531cb790bc1106377d2da344614a3b88d39Jae Seo         * Invoked after {@link MediaBrowserCompat#connect()} when the request has successfully
418096f2531cb790bc1106377d2da344614a3b88d39Jae Seo         * completed.
419e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
420e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onConnected() {
421e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
422e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
423e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
424e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Invoked when the client is disconnected from the media browser.
425e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
426e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onConnectionSuspended() {
427e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
428e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
429e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
430e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Invoked when the connection to the media browser failed.
431e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
432e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onConnectionFailed() {
433e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
4346b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
43516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void setInternalConnectionCallback(ConnectionCallbackInternal connectionCallbackInternal) {
43616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mConnectionCallbackInternal = connectionCallbackInternal;
43716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
43816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
43916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        interface ConnectionCallbackInternal {
44016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            void onConnected();
44116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            void onConnectionSuspended();
44216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            void onConnectionFailed();
44316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
4446b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
4456b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        private class StubApi21 implements MediaBrowserCompatApi21.ConnectionCallback {
4466b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            @Override
4476b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            public void onConnected() {
44816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (mConnectionCallbackInternal != null) {
44916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mConnectionCallbackInternal.onConnected();
45016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
4516b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                ConnectionCallback.this.onConnected();
4526b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
4536b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
4546b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            @Override
4556b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            public void onConnectionSuspended() {
45616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (mConnectionCallbackInternal != null) {
45716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mConnectionCallbackInternal.onConnectionSuspended();
45816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
4596b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                ConnectionCallback.this.onConnectionSuspended();
4606b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
4616b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
4626b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            @Override
4636b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            public void onConnectionFailed() {
46416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (mConnectionCallbackInternal != null) {
46516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mConnectionCallbackInternal.onConnectionFailed();
46616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
4676b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                ConnectionCallback.this.onConnectionFailed();
4686b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
4696b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
470e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
471e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
472e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
473e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Callbacks for subscription related events.
474e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
475e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public static abstract class SubscriptionCallback {
47616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        /**
47716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * Called when the list of children is loaded or updated.
47816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         *
47916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * @param parentId The media id of the parent media item.
48016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * @param children The children which were loaded, or null if the id is invalid.
48116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         */
48216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children) {
48316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
4846b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
48516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        /**
48616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * Called when the list of children is loaded or updated.
48716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         *
48816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * @param parentId The media id of the parent media item.
48916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * @param children The children which were loaded, or null if the id is invalid.
49016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * @param options A bundle of service-specific arguments to send to the media
49116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         *            browse service. The contents of this bundle may affect the
49216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         *            information returned when browsing.
49316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * {@hide}
49416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         */
49516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children,
49616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                @NonNull Bundle options) {
49716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
49816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
49916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        /**
50016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * Called when the id doesn't exist or other errors in subscribing.
50116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * <p>
50216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * If this is called, the subscription remains until {@link MediaBrowserCompat#unsubscribe}
50316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * called, because some errors may heal themselves.
50416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * </p>
50516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         *
50616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * @param parentId The media id of the parent media item whose children could not be loaded.
50716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         */
50816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onError(@NonNull String parentId) {
50916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
51016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
51116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        /**
51216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * Called when the id doesn't exist or other errors in subscribing.
51316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * <p>
51416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * If this is called, the subscription remains until {@link MediaBrowserCompat#unsubscribe}
51516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * called, because some errors may heal themselves.
51616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * </p>
51716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         *
51816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * @param parentId The media id of the parent media item whose children could
51916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         *            not be loaded.
52016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * @param options A bundle of service-specific arguments sent to the media
52116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         *            browse service.
52216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * {@hide}
52316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         */
52416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onError(@NonNull String parentId, @NonNull Bundle options) {
52516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
52616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
52716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
52816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    /**
52916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim     * Callbacks for subscription related events.
53016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim     */
531c0a233f1980faedbb9ff82334814a0d8cbe6148bChris Banes    static class SubscriptionCallbackApi21 extends SubscriptionCallback {
53216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        SubscriptionCallback mSubscriptionCallback;
53316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final Object mSubscriptionCallbackObj;
53416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private Bundle mOptions;
53516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
53616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public SubscriptionCallbackApi21(SubscriptionCallback callback, Bundle options) {
53716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mSubscriptionCallback = callback;
53816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mOptions = options;
53965fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes            mSubscriptionCallbackObj =
54065fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                    MediaBrowserCompatApi21.createSubscriptionCallback(new StubApi21());
5416b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
5426b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
543e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
544e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Called when the list of children is loaded or updated.
545e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         *
546e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @param parentId The media id of the parent media item.
547ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim         * @param children The children which were loaded, or null if the id is invalid.
548e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
549ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children) {
55016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mSubscriptionCallback.onChildrenLoaded(parentId, children);
551e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
552e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
553e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
55482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * Called when the list of children is loaded or updated.
55582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *
55682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * @param parentId The media id of the parent media item.
55782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * @param children The children which were loaded, or null if the id is invalid.
55882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * @param options A bundle of service-specific arguments to send to the media
55982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *            browse service. The contents of this bundle may affect the
56082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *            information returned when browsing.
56182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * {@hide}
56282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         */
56382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children,
56482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                @NonNull Bundle options) {
56516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mSubscriptionCallback.onChildrenLoaded(parentId, children, options);
56682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        }
56782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
56882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        /**
569e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Called when the id doesn't exist or other errors in subscribing.
570e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * <p>
571096f2531cb790bc1106377d2da344614a3b88d39Jae Seo         * If this is called, the subscription remains until {@link MediaBrowserCompat#unsubscribe}
572e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * called, because some errors may heal themselves.
573e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * </p>
574e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         *
57516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * @param parentId The media id of the parent media item whose children could not be loaded.
576e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
577e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onError(@NonNull String parentId) {
57816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mSubscriptionCallback.onError(parentId);
579e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
5806b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
58182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        /**
58282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * Called when the id doesn't exist or other errors in subscribing.
58382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * <p>
58482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * If this is called, the subscription remains until {@link MediaBrowserCompat#unsubscribe}
58582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * called, because some errors may heal themselves.
58682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * </p>
58782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *
58882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * @param parentId The media id of the parent media item whose children could
58982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *            not be loaded.
59082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * @param options A bundle of service-specific arguments sent to the media
59182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         *            browse service.
59282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * {@hide}
59382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         */
59482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        public void onError(@NonNull String parentId, @NonNull Bundle options) {
59516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mSubscriptionCallback.onError(parentId, options);
59682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        }
59782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
5986b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        private class StubApi21 implements MediaBrowserCompatApi21.SubscriptionCallback {
5996b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            @Override
60082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            public void onChildrenLoaded(@NonNull String parentId, List<Parcel> children) {
60165fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                List<MediaBrowserCompat.MediaItem> mediaItems = null;
60265fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                if (children != null) {
60365fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                    mediaItems = new ArrayList<>();
60465fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                    for (Parcel parcel : children) {
60565fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                        parcel.setDataPosition(0);
60665fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                        mediaItems.add(
60765fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                                MediaBrowserCompat.MediaItem.CREATOR.createFromParcel(parcel));
60865fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                        parcel.recycle();
60965fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                    }
61065fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes                }
61116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (mOptions != null) {
61216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    SubscriptionCallbackApi21.this.onChildrenLoaded(parentId,
61316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            MediaBrowserCompatUtils.applyOptions(mediaItems, mOptions),
61416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            mOptions);
61516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                } else {
61616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    SubscriptionCallbackApi21.this.onChildrenLoaded(parentId, mediaItems);
61716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
6186b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
6196b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
6206b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            @Override
6216b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            public void onError(@NonNull String parentId) {
62216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (mOptions != null) {
62316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    SubscriptionCallbackApi21.this.onError(parentId, mOptions);
62416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                } else {
62516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    SubscriptionCallbackApi21.this.onError(parentId);
62616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
6276b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            }
6286b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
629e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
630e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
631e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    /**
632e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     * Callback for receiving the result of {@link #getItem}.
633e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo     */
634e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    public static abstract class ItemCallback {
63582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        final Object mItemCallbackObj;
63682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
63782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        public ItemCallback() {
63865fa61412f46d6cddca410aeb07a79fd081536c0Chris Banes            if (android.os.Build.VERSION.SDK_INT >= 23) {
63982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                mItemCallbackObj = MediaBrowserCompatApi23.createItemCallback(new StubApi23());
64082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            } else {
64182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                mItemCallbackObj = null;
64282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
64382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        }
64482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
645e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
646e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Called when the item has been returned by the browser service.
647e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         *
648e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @param item The item that was returned or null if it doesn't exist.
649e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
650e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onItemLoaded(MediaItem item) {
651e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
652e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
653e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
654e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * Called when the item doesn't exist or there was an error retrieving it.
655e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         *
656e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         * @param itemId The media id of the media item which could not be loaded.
657e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
658e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        public void onError(@NonNull String itemId) {
659e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
66082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
66182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        private class StubApi23 implements MediaBrowserCompatApi23.ItemCallback {
66282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            @Override
66382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            public void onItemLoaded(Parcel itemParcel) {
66482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                itemParcel.setDataPosition(0);
66582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                MediaItem item = MediaBrowserCompat.MediaItem.CREATOR.createFromParcel(itemParcel);
66682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                itemParcel.recycle();
66782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                ItemCallback.this.onItemLoaded(item);
66882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
66982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
67082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            @Override
67182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            public void onError(@NonNull String itemId) {
67282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                ItemCallback.this.onError(itemId);
67382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
67482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        }
675e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo    }
676e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
6776b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim    interface MediaBrowserImpl {
6786b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        void connect();
6796b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        void disconnect();
6806b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        boolean isConnected();
6816b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        ComponentName getServiceComponent();
6826b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @NonNull String getRoot();
6836b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Nullable Bundle getExtras();
6846b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @NonNull MediaSessionCompat.Token getSessionToken();
68582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        void subscribe(@NonNull String parentId, Bundle options,
68682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                @NonNull SubscriptionCallback callback);
68782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        void unsubscribe(@NonNull String parentId, Bundle options);
6886b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb);
6896b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim    }
6906b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
69116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    interface MediaBrowserServiceCallbackImpl {
69216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void onServiceConnected(Messenger callback, String root, MediaSessionCompat.Token session,
69316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                Bundle extra);
69416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void onConnectionFailed(Messenger callback);
69516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void onLoadChildren(Messenger callback, String parentId, List list, Bundle options);
69616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
69716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
69816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    static class MediaBrowserServiceImplBase
69916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            implements MediaBrowserImpl, MediaBrowserServiceCallbackImpl {
700e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private static final boolean DBG = false;
701e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
702e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private static final int CONNECT_STATE_DISCONNECTED = 0;
703e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private static final int CONNECT_STATE_CONNECTING = 1;
704e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private static final int CONNECT_STATE_CONNECTED = 2;
705e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private static final int CONNECT_STATE_SUSPENDED = 3;
706e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
707e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private final Context mContext;
708e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private final ComponentName mServiceComponent;
709e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private final ConnectionCallback mCallback;
710e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private final Bundle mRootHints;
71116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final CallbackHandler mHandler = new CallbackHandler(this);
71282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
713e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
714e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private int mState = CONNECT_STATE_DISCONNECTED;
715e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private MediaServiceConnection mServiceConnection;
7163f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim        private ServiceBinderWrapper mServiceBinderWrapper;
7173f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim        private Messenger mCallbacksMessenger;
718e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private String mRootId;
719e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private MediaSessionCompat.Token mMediaSessionToken;
720e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private Bundle mExtras;
721e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
72216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public MediaBrowserServiceImplBase(Context context, ComponentName serviceComponent,
723e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                ConnectionCallback callback, Bundle rootHints) {
724e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (context == null) {
725e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalArgumentException("context must not be null");
726e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
727e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (serviceComponent == null) {
728e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalArgumentException("service component must not be null");
729e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
730e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (callback == null) {
731e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalArgumentException("connection callback must not be null");
732e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
733e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mContext = context;
734e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mServiceComponent = serviceComponent;
735e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mCallback = callback;
736e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mRootHints = rootHints;
737e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
738e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
739e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public void connect() {
740e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (mState != CONNECT_STATE_DISCONNECTED) {
741e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalStateException("connect() called while not disconnected (state="
742e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        + getStateLabel(mState) + ")");
743e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
744e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // TODO: remove this extra check.
745e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (DBG) {
746e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                if (mServiceConnection != null) {
747e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    throw new RuntimeException("mServiceConnection should be null. Instead it is "
748e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                            + mServiceConnection);
749e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
750e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
7513f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mServiceBinderWrapper != null) {
7523f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                throw new RuntimeException("mServiceBinderWrapper should be null. Instead it is "
7533f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                        + mServiceBinderWrapper);
754e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
7553f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mCallbacksMessenger != null) {
7563f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                throw new RuntimeException("mCallbacksMessenger should be null. Instead it is "
7573f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                        + mCallbacksMessenger);
758e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
759e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
760e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            mState = CONNECT_STATE_CONNECTING;
761e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
762e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            final Intent intent = new Intent(MediaBrowserServiceCompat.SERVICE_INTERFACE);
763e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            intent.setComponent(mServiceComponent);
764e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
765e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            final ServiceConnection thisConnection = mServiceConnection =
766e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    new MediaServiceConnection();
767e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
768e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            boolean bound = false;
769e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            try {
770e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                bound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
771e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            } catch (Exception ex) {
772e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                Log.e(TAG, "Failed binding to service " + mServiceComponent);
773e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
774e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
775e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (!bound) {
77682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                // Tell them that it didn't work. We are already on the main thread,
77782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                // but we don't want to do callbacks inside of connect(). So post it,
77882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                // and then check that we are on the same ServiceConnection. We know
779e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                // we won't also get an onServiceConnected or onServiceDisconnected,
780e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                // so we won't be doing double callbacks.
781e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                mHandler.post(new Runnable() {
782e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    @Override
783e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    public void run() {
784e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        // Ensure that nobody else came in or tried to connect again.
785e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        if (thisConnection == mServiceConnection) {
786e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                            forceCloseConnection();
787e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                            mCallback.onConnectionFailed();
788e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        }
789e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    }
790e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                });
791e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
792e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
793e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            if (DBG) {
794e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                Log.d(TAG, "connect...");
795e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                dump();
796e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
797e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
798e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
799e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public void disconnect() {
800e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // It's ok to call this any state, because allowing this lets apps not have
80182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            // to check isConnected() unnecessarily. They won't appreciate the extra
80282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            // assertions for this. We do everything we can here to go back to a sane state.
8033f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mCallbacksMessenger != null) {
804e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                try {
80516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mServiceBinderWrapper.disconnect(mCallbacksMessenger);
806e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                } catch (RemoteException ex) {
80782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    // We are disconnecting anyway. Log, just for posterity but it's not
808e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    // a big problem.
809e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
810e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
811e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
812e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            forceCloseConnection();
813e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
814e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (DBG) {
815e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                Log.d(TAG, "disconnect...");
816e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                dump();
817e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
818e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
819e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
820e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        /**
82182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * Null out the variables and unbind from the service. This doesn't include
822e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * calling disconnect on the service, because we only try to do that in the
823e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * clean shutdown cases.
824e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * <p>
825e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * Everywhere that calls this EXCEPT for disconnect() should follow it with
82682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * a call to mCallback.onConnectionFailed(). Disconnect doesn't do that callback
827e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * for a clean shutdown, but everywhere else is a dirty shutdown and should
828e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * notify the app.
829e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         */
830e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private void forceCloseConnection() {
831e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (mServiceConnection != null) {
832e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                mContext.unbindService(mServiceConnection);
833e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
834e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mState = CONNECT_STATE_DISCONNECTED;
835e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mServiceConnection = null;
8363f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mServiceBinderWrapper = null;
8373f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mCallbacksMessenger = null;
838e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mRootId = null;
839e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            mMediaSessionToken = null;
840e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
841e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
842e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public boolean isConnected() {
843e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            return mState == CONNECT_STATE_CONNECTED;
844e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
845e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
846e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public @NonNull
847e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        ComponentName getServiceComponent() {
848e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (!isConnected()) {
849e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalStateException("getServiceComponent() called while not connected" +
850e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        " (state=" + mState + ")");
851e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
852e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            return mServiceComponent;
853e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
854e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
855e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public @NonNull String getRoot() {
856e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (!isConnected()) {
857dfed7fbde83fb36b1993582317a27c5247af958cDongwon Kang                throw new IllegalStateException("getRoot() called while not connected"
858e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        + "(state=" + getStateLabel(mState) + ")");
859e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
860e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            return mRootId;
861e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
862e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
863e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public @Nullable
864e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        Bundle getExtras() {
865e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (!isConnected()) {
866e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalStateException("getExtras() called while not connected (state="
867e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        + getStateLabel(mState) + ")");
868e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
869e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            return mExtras;
870e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
871e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
872e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        public @NonNull MediaSessionCompat.Token getSessionToken() {
873e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (!isConnected()) {
874e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalStateException("getSessionToken() called while not connected"
875e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        + "(state=" + mState + ")");
876e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
877e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            return mMediaSessionToken;
878e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
879e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
88082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        public void subscribe(@NonNull String parentId, Bundle options,
88182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                @NonNull SubscriptionCallback callback) {
882e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // Check arguments.
88382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            if (TextUtils.isEmpty(parentId)) {
88482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                throw new IllegalArgumentException("parentId is empty.");
885e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
886e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (callback == null) {
887e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalArgumentException("callback is null");
888e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
889e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // Update or create the subscription.
890e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Subscription sub = mSubscriptions.get(parentId);
89182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            if (sub == null) {
89282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                sub = new Subscription();
893e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                mSubscriptions.put(parentId, sub);
894e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
89516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sub.setCallbackForOptions(callback, options);
896e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
89782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            // If we are connected, tell the service that we are watching. If we aren't
898e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // connected, the service will be told when we connect.
899e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (mState == CONNECT_STATE_CONNECTED) {
900e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                try {
90116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mServiceBinderWrapper.addSubscription(parentId, options, mCallbacksMessenger);
90216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                } catch (RemoteException e) {
90382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    // Process is crashing. We will disconnect, and upon reconnect we will
904e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    // automatically reregister. So nothing to do here.
905e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
906e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
907e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
908e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
909e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
91082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        public void unsubscribe(@NonNull String parentId, Bundle options) {
911e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // Check arguments.
912e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (TextUtils.isEmpty(parentId)) {
913e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalArgumentException("parentId is empty.");
914e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
915e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
916e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // Remove from our list.
91782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            Subscription sub = mSubscriptions.get(parentId);
918e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
919e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            // Tell the service if necessary.
92082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            if (sub != null && sub.remove(options) && mState == CONNECT_STATE_CONNECTED) {
921e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                try {
92216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mServiceBinderWrapper.removeSubscription(
92316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            parentId, options, 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, "removeSubscription failed with RemoteException parentId="
928e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                            + parentId);
929e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
930e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
93182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            if (sub != null && sub.isEmpty()) {
93282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                mSubscriptions.remove(parentId);
93382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            }
934e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
935e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
936d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        public void getItem(@NonNull final String mediaId, @NonNull final ItemCallback cb) {
937e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (TextUtils.isEmpty(mediaId)) {
938e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalArgumentException("mediaId is empty.");
939e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
940e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (cb == null) {
941e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                throw new IllegalArgumentException("cb is null.");
942e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
943e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            if (mState != CONNECT_STATE_CONNECTED) {
944e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
945e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                mHandler.post(new Runnable() {
946e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    @Override
947e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    public void run() {
948e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        cb.onError(mediaId);
949e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    }
950e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                });
951e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                return;
952e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
953d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            ResultReceiver receiver = new ItemReceiver(mediaId, cb, mHandler);
954e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            try {
9553f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                mServiceBinderWrapper.getMediaItem(mediaId, receiver);
956e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            } catch (RemoteException e) {
957e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                Log.i(TAG, "Remote error getting media item.");
958e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                mHandler.post(new Runnable() {
959e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    @Override
960e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    public void run() {
961e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        cb.onError(mediaId);
962e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    }
963e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                });
964e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
965e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
966e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
96716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onServiceConnected(final Messenger callback, final String root,
9683f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                final MediaSessionCompat.Token session, final Bundle extra) {
9693f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Check to make sure there hasn't been a disconnect or a different ServiceConnection.
9703f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (!isCurrent(callback, "onConnect")) {
9713f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                return;
9723f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
9733f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Don't allow them to call us twice.
9743f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mState != CONNECT_STATE_CONNECTING) {
9753f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                Log.w(TAG, "onConnect from service while mState=" + getStateLabel(mState)
9763f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                        + "... ignoring");
9773f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                return;
9783f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
9793f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mRootId = root;
9803f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mMediaSessionToken = session;
9813f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mExtras = extra;
9823f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mState = CONNECT_STATE_CONNECTED;
983e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
9843f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (DBG) {
9853f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                Log.d(TAG, "ServiceCallbacks.onConnect...");
9863f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                dump();
9873f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
9883f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mCallback.onConnected();
9893f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim
9903f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // we may receive some subscriptions before we are connected, so re-subscribe
9913f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // everything now
99282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            try {
99382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                for (Map.Entry<String, Subscription> subscriptionEntry
99482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                        : mSubscriptions.entrySet()) {
99582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    String id = subscriptionEntry.getKey();
99682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    Subscription sub = subscriptionEntry.getValue();
99782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    for (Bundle options : sub.getOptionsList()) {
99816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        mServiceBinderWrapper.addSubscription(id, options, mCallbacksMessenger);
99982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    }
1000e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
100182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            } catch (RemoteException ex) {
100282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                // Process is crashing. We will disconnect, and upon reconnect we will
100382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                // automatically reregister. So nothing to do here.
100482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                Log.d(TAG, "addSubscription failed with RemoteException.");
10053f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
1006e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
1007e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
100816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onConnectionFailed(final Messenger callback) {
10093f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            Log.e(TAG, "onConnectFailed for " + mServiceComponent);
1010e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
10113f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Check to make sure there hasn't been a disconnect or a different ServiceConnection.
10123f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (!isCurrent(callback, "onConnectFailed")) {
10133f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                return;
10143f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
10153f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Don't allow them to call us twice.
10163f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mState != CONNECT_STATE_CONNECTING) {
10173f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                Log.w(TAG, "onConnect from service while mState=" + getStateLabel(mState)
10183f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                        + "... ignoring");
10193f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                return;
10203f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            }
1021e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
10223f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Clean up
10233f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            forceCloseConnection();
1024e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
10253f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            // Tell the app.
10263f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            mCallback.onConnectionFailed();
1027e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
1028e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
102916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onLoadChildren(final Messenger callback, final String parentId,
103082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                final List list, final Bundle options) {
103182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            // Check that there hasn't been a disconnect or a different ServiceConnection.
103282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            if (!isCurrent(callback, "onLoadChildren")) {
103382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                return;
103482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
1035e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
103682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            List<MediaItem> data = list;
10373f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (DBG) {
103882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
103982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
1040e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
104182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            // Check that the subscription is still subscribed.
104282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            final Subscription subscription = mSubscriptions.get(parentId);
104382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            if (subscription == null) {
104482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                if (DBG) {
104582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
104682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                }
104782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                return;
104882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
104982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
105082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            // Tell the app.
105182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            SubscriptionCallback subscriptionCallback = subscription.getCallback(options);
105282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            if (subscriptionCallback != null) {
105382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                if (options == null) {
105482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    subscriptionCallback.onChildrenLoaded(parentId, data);
105582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                } else {
105682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                    subscriptionCallback.onChildrenLoaded(parentId, data, options);
105782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                }
105882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim            }
1059e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        }
1060e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1061e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        /**
106216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         * For debugging.
106316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim         */
106416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private static String getStateLabel(int state) {
106516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            switch (state) {
106616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case CONNECT_STATE_DISCONNECTED:
106716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return "CONNECT_STATE_DISCONNECTED";
106816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case CONNECT_STATE_CONNECTING:
106916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return "CONNECT_STATE_CONNECTING";
107016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case CONNECT_STATE_CONNECTED:
107116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return "CONNECT_STATE_CONNECTED";
107216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case CONNECT_STATE_SUSPENDED:
107316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return "CONNECT_STATE_SUSPENDED";
107416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                default:
107516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return "UNKNOWN/" + state;
107616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
107716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
107816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
107916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        /**
108082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim         * Return true if {@code callback} is the current ServiceCallbacks. Also logs if it's not.
1081e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         */
10823f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim        private boolean isCurrent(Messenger callback, String funcName) {
10833f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            if (mCallbacksMessenger != callback) {
1084e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                if (mState != CONNECT_STATE_DISCONNECTED) {
10853f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                    Log.i(TAG, funcName + " for " + mServiceComponent + " with mCallbacksMessenger="
10863f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim                            + mCallbacksMessenger + " this=" + this);
1087e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                }
1088e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo                return false;
1089e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
1090e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            return true;
1091e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
1092e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
1093e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        /**
1094e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * Log internal state.
1095e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * @hide
1096e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         */
1097e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        void dump() {
1098e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "MediaBrowserCompat...");
1099e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mServiceComponent=" + mServiceComponent);
1100e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mCallback=" + mCallback);
1101e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mRootHints=" + mRootHints);
1102e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mState=" + getStateLabel(mState));
1103e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mServiceConnection=" + mServiceConnection);
11043f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            Log.d(TAG, "  mServiceBinderWrapper=" + mServiceBinderWrapper);
11053f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim            Log.d(TAG, "  mCallbacksMessenger=" + mCallbacksMessenger);
1106e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mRootId=" + mRootId);
1107e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            Log.d(TAG, "  mMediaSessionToken=" + mMediaSessionToken);
1108e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
1109e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
1110e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        /**
1111e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake         * ServiceConnection to the other app.
1112e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo         */
1113e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake        private class MediaServiceConnection implements ServiceConnection {
1114e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            @Override
1115a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim            public void onServiceConnected(final ComponentName name, final IBinder binder) {
1116a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                postOrRun(new Runnable() {
1117a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    @Override
1118a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    public void run() {
1119a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        if (DBG) {
1120a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
1121a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                    + " binder=" + binder);
1122a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            dump();
1123a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        }
11243f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim
1125a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // Make sure we are still the current connection, and that they haven't
1126a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // called disconnect().
1127a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        if (!isCurrent("onServiceConnected")) {
1128a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            return;
1129a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        }
1130e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1131a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // Save their binder
1132a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mServiceBinderWrapper = new ServiceBinderWrapper(binder);
1133a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim
1134a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // We make a new mServiceCallbacks each time we connect so that we can drop
1135a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // responses from previous connections.
1136a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mCallbacksMessenger = new Messenger(mHandler);
113716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        mHandler.setCallbacksMessenger(mCallbacksMessenger);
1138a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim
1139a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mState = CONNECT_STATE_CONNECTING;
1140a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim
1141a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // Call connect, which is async. When we get a response from that we will
1142a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // say that we're connected.
1143a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        try {
1144a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            if (DBG) {
1145a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                Log.d(TAG, "ServiceCallbacks.onConnect...");
1146a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                dump();
1147a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            }
114816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            mServiceBinderWrapper.connect(
114916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                                    mContext, mRootHints, mCallbacksMessenger);
1150a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        } catch (RemoteException ex) {
1151a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            // Connect failed, which isn't good. But the auto-reconnect on the
115282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                            // service will take over and we will come back. We will also get the
115382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim                            // onServiceDisconnected, which has all the cleanup code. So let that
1154a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            // do it.
1155a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
1156a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            if (DBG) {
1157a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                Log.d(TAG, "ServiceCallbacks.onConnect...");
1158a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                dump();
1159a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            }
1160a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        }
1161e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    }
1162a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                });
1163e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
1164e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1165e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            @Override
1166a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim            public void onServiceDisconnected(final ComponentName name) {
1167a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                postOrRun(new Runnable() {
1168a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    @Override
1169a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    public void run() {
1170a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        if (DBG) {
1171a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
1172a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                    + " this=" + this + " mServiceConnection=" +
1173a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                                    mServiceConnection);
1174a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            dump();
1175a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        }
1176e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1177a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // Make sure we are still the current connection, and that they haven't
1178a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // called disconnect().
1179a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        if (!isCurrent("onServiceDisconnected")) {
1180a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                            return;
1181a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        }
1182e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1183a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // Clear out what we set in onServiceConnected
1184a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mServiceBinderWrapper = null;
1185a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mCallbacksMessenger = null;
118616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        mHandler.setCallbacksMessenger(null);
1187e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1188a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        // And tell the app that it's suspended.
1189a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mState = CONNECT_STATE_SUSPENDED;
1190a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                        mCallback.onConnectionSuspended();
1191a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    }
1192a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                });
1193a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim            }
1194a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim
1195a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim            private void postOrRun(Runnable r) {
1196a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                if (Thread.currentThread() == mHandler.getLooper().getThread()) {
1197a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    r.run();
1198a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                } else {
1199a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                    mHandler.post(r);
1200a4b87b4df1dda9f012dad8b50d462d7396a80faaSungsoo Lim                }
1201e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            }
1202e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake
1203e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            /**
120482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim             * Return true if this is the current ServiceConnection. Also logs if it's not.
1205e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake             */
1206e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake            private boolean isCurrent(String funcName) {
1207e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                if (mServiceConnection != this) {
1208e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    if (mState != CONNECT_STATE_DISCONNECTED) {
1209e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        // Check mState, because otherwise this log is noisy.
1210e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                        Log.i(TAG, funcName + " for " + mServiceComponent +
1211e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                                " with mServiceConnection=" + mServiceConnection + " this=" + this);
1212e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    }
1213e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                    return false;
1214e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                }
1215e2447bb2dce5401b3cd473c1d276bc7d58592540Ian Lake                return true;
1216e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo            }
1217e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo        }
121816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
1219e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo
122016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    static class MediaBrowserImplApi21 implements MediaBrowserImpl, MediaBrowserServiceCallbackImpl,
122116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            ConnectionCallback.ConnectionCallbackInternal {
122216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private static final boolean DBG = false;
122382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
122416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        protected Object mBrowserObj;
122582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim
122616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final ComponentName mServiceComponent;
122716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final CallbackHandler mHandler = new CallbackHandler(this);
122816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
12296b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
123016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private ServiceBinderWrapper mServiceBinderWrapper;
123116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private Messenger mCallbacksMessenger;
12326b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12336b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public MediaBrowserImplApi21(Context context, ComponentName serviceComponent,
12346b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                ConnectionCallback callback, Bundle rootHints) {
123516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mServiceComponent = serviceComponent;
123616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            callback.setInternalConnectionCallback(this);
12376b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            mBrowserObj = MediaBrowserCompatApi21.createBrowser(context, serviceComponent,
12386b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                    callback.mConnectionCallbackObj, rootHints);
12396b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
12406b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12416b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
12426b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public void connect() {
12436b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            MediaBrowserCompatApi21.connect(mBrowserObj);
12446b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
12456b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12466b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
12476b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public void disconnect() {
12486b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            MediaBrowserCompatApi21.disconnect(mBrowserObj);
12496b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
12506b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12516b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
12526b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public boolean isConnected() {
12536b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            return MediaBrowserCompatApi21.isConnected(mBrowserObj);
12546b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
12556b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12566b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
12576b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public ComponentName getServiceComponent() {
12586b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            return MediaBrowserCompatApi21.getServiceComponent(mBrowserObj);
12596b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
12606b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12616b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @NonNull
12626b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
12636b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public String getRoot() {
12646b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            return MediaBrowserCompatApi21.getRoot(mBrowserObj);
12656b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
12666b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12676b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Nullable
12686b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
12696b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public Bundle getExtras() {
12706b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            return MediaBrowserCompatApi21.getExtras(mBrowserObj);
12716b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
12726b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12736b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @NonNull
12746b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
12756b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public MediaSessionCompat.Token getSessionToken() {
12766b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim            return MediaSessionCompat.Token.fromToken(
12776b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim                    MediaBrowserCompatApi21.getSessionToken(mBrowserObj));
12786b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
12796b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
12806b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
128116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void subscribe(@NonNull final String parentId, final Bundle options,
128216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                @NonNull final SubscriptionCallback callback) {
128316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // Update or create the subscription.
128416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            SubscriptionCallbackApi21 cb21 = new SubscriptionCallbackApi21(callback, options);
128516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Subscription sub = mSubscriptions.get(parentId);
128616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (sub == null) {
128716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                sub = new Subscription();
128816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                mSubscriptions.put(parentId, sub);
128916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
129016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sub.setCallbackForOptions(cb21, options);
129116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (MediaBrowserCompatApi21.isConnected(mBrowserObj)) {
129216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (options == null || mServiceBinderWrapper == null) {
129316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    MediaBrowserCompatApi21.subscribe(
129416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            mBrowserObj, parentId, cb21.mSubscriptionCallbackObj);
129516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                } else {
129616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    try {
129716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        mServiceBinderWrapper.addSubscription(
129816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                                parentId, options, mCallbacksMessenger);
129916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    } catch (RemoteException e) {
130016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        // Process is crashing. We will disconnect, and upon reconnect we will
130116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        // automatically reregister. So nothing to do here.
130216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        Log.i(TAG, "Remote error subscribing media item: " + parentId);
130316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    }
130416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
130516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
13066b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
13076b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
13086b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
130982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim        public void unsubscribe(@NonNull String parentId, Bundle options) {
131016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // Check arguments.
131116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (TextUtils.isEmpty(parentId)) {
131216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                throw new IllegalArgumentException("parentId is empty.");
131316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
131416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
131516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // Remove from our list.
131616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Subscription sub = mSubscriptions.get(parentId);
131716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (sub != null && sub.remove(options)) {
131816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                // Tell the service if necessary.
131916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (options == null || mServiceBinderWrapper == null) {
132016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    if (mServiceBinderWrapper != null || sub.isEmpty()) {
132116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        MediaBrowserCompatApi21.unsubscribe(mBrowserObj, parentId);
132216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    }
132316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                } else if (mServiceBinderWrapper == null) {
132416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    try {
132516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        mServiceBinderWrapper.removeSubscription(
132616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                                parentId, options, mCallbacksMessenger);
132716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    } catch (RemoteException e) {
132816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        // Process is crashing. We will disconnect, and upon reconnect we will
132916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        // automatically reregister. So nothing to do here.
133016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        Log.d(TAG, "removeSubscription failed with RemoteException parentId="
133116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                                + parentId);
133216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    }
133316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
133416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
133516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (sub != null && sub.isEmpty()) {
133616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                mSubscriptions.remove(parentId);
133716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
13386b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
13396b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim
13406b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        @Override
134182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        public void getItem(@NonNull final String mediaId, @NonNull final ItemCallback cb) {
134282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            if (TextUtils.isEmpty(mediaId)) {
134382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                throw new IllegalArgumentException("mediaId is empty.");
134482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
134582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            if (cb == null) {
134682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                throw new IllegalArgumentException("cb is null.");
134782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
134882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            if (!MediaBrowserCompatApi21.isConnected(mBrowserObj)) {
134982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
135082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                mHandler.post(new Runnable() {
135182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    @Override
135282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    public void run() {
135382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                        cb.onError(mediaId);
135482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    }
135582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                });
135682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                return;
135782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
135816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (mServiceBinderWrapper == null) {
135982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                mHandler.post(new Runnable() {
136082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    @Override
136182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    public void run() {
136282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                        // Default framework implementation.
136382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                        cb.onItemLoaded(null);
136482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    }
136582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                });
136682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                return;
136782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
1368d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            ResultReceiver receiver = new ItemReceiver(mediaId, cb, mHandler);
136982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            try {
137016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                mServiceBinderWrapper.getMediaItem(mediaId, receiver);
137182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            } catch (RemoteException e) {
137216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                Log.i(TAG, "Remote error getting media item: " + mediaId);
137382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                mHandler.post(new Runnable() {
137482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    @Override
137582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    public void run() {
137682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                        cb.onError(mediaId);
137782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                    }
137882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                });
137982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            }
138082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        }
138182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
138216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
138316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onConnected() {
138416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle extras = MediaBrowserCompatApi21.getExtras(mBrowserObj);
138516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (extras == null) {
138616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                return;
138716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
138816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            IBinder serviceBinder = BundleCompat.getBinder(extras, EXTRA_MESSENGER_BINDER);
138916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (serviceBinder != null) {
139016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                mServiceBinderWrapper = new ServiceBinderWrapper(serviceBinder);
139116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                mCallbacksMessenger = new Messenger(mHandler);
139216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                mHandler.setCallbacksMessenger(mCallbacksMessenger);
139316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                try {
139416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mServiceBinderWrapper.registerCallbackMessenger(mCallbacksMessenger);
139516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                } catch (RemoteException e) {
139616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    Log.i(TAG, "Remote error registering client messenger." );
139716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
139816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                onServiceConnected(mCallbacksMessenger, null, null, null);
139916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
140016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
140116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
140216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
140316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onConnectionSuspended() {
140416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mServiceBinderWrapper = null;
140516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mCallbacksMessenger = null;
140616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
140716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
140816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
140916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onConnectionFailed() {
141016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // Do noting
141116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
141216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
141316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        // FYI, this method is not called by CallbackHandler.
141416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
141516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onServiceConnected(final Messenger callback, final String root,
141616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                final MediaSessionCompat.Token session, final Bundle extra) {
141716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // we may receive some subscriptions before we are connected, so re-subscribe
141816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // everything now
141916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            for (Map.Entry<String, Subscription> subscriptionEntry : mSubscriptions.entrySet()) {
142016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                String id = subscriptionEntry.getKey();
142116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                Subscription sub = subscriptionEntry.getValue();
142216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                List<Bundle> optionsList = sub.getOptionsList();
142316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                List<SubscriptionCallback> callbackList = sub.getCallbacks();
142416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                for (int i = 0; i < optionsList.size(); ++i) {
142516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    if (optionsList.get(i) == null) {
142616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        MediaBrowserCompatApi21.subscribe(mBrowserObj, id,
142716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                                ((SubscriptionCallbackApi21)callbackList.get(i))
142816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                                        .mSubscriptionCallbackObj);
142916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    } else {
143016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        try {
143116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            mServiceBinderWrapper.addSubscription(
143216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                                    id, optionsList.get(i), mCallbacksMessenger);
143316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        } catch (RemoteException e) {
143416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            // Process is crashing. We will disconnect, and upon reconnect we will
143516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            // automatically reregister. So nothing to do here.
143616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            Log.d(TAG, "addSubscription failed with RemoteException parentId=" + id);
143716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                        }
143816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    }
143916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
144016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
144116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
144216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
144316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
144416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onConnectionFailed(Messenger callback) {
144516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // This method will not be called.
144616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
144716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
144816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
144916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void onLoadChildren(Messenger callback, String parentId, List list,
145016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                @NonNull Bundle options) {
145116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (mCallbacksMessenger != callback) {
145216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                return;
145316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
145416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
145516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            List<MediaItem> data = list;
145616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (DBG) {
145716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
145816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
145916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
146016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // Check that the subscription is still subscribed.
146116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Subscription subscription = mSubscriptions.get(parentId);
146216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (subscription == null) {
146316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (DBG) {
146416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
146516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
146616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                return;
146716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
146816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
146916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            // Tell the app.
147016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            subscription.getCallback(options).onChildrenLoaded(parentId, data, options);
147182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        }
147282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim    }
147382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
147482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim    static class MediaBrowserImplApi23 extends MediaBrowserImplApi21 {
147582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        public MediaBrowserImplApi23(Context context, ComponentName serviceComponent,
147682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim                ConnectionCallback callback, Bundle rootHints) {
147782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            super(context, serviceComponent, callback, rootHints);
147882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        }
147982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim
148082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim        @Override
14816b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        public void getItem(@NonNull String mediaId, @NonNull ItemCallback cb) {
148282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim            MediaBrowserCompatApi23.getItem(mBrowserObj, mediaId, cb.mItemCallbackObj);
14836b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim        }
14846b565ded51fc2e48e9d5ac652e1fbf3d9255dd3eSungsoo Lim    }
1485d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim
148616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    private static class Subscription {
148716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final List<SubscriptionCallback> mCallbacks;
148816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final List<Bundle> mOptionsList;
148916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
149016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public Subscription() {
149116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mCallbacks = new ArrayList();
149216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mOptionsList = new ArrayList();
149316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
149416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
149516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public boolean isEmpty() {
149616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            return mCallbacks.isEmpty();
149716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
149816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
149916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public List<Bundle> getOptionsList() {
150016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            return mOptionsList;
150116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
150216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
150316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public List<SubscriptionCallback> getCallbacks() {
150416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            return mCallbacks;
150516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
150616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
150716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void setCallbackForOptions(SubscriptionCallback callback, Bundle options) {
150816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            for (int i = 0; i < mOptionsList.size(); ++i) {
150916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (MediaBrowserCompatUtils.areSameOptions(mOptionsList.get(i), options)) {
151016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mCallbacks.set(i, callback);
151116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return;
151216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
151316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
151416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mCallbacks.add(callback);
151516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mOptionsList.add(options);
151616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
151716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
151816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public boolean remove(Bundle options) {
151916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            for (int i = 0; i < mOptionsList.size(); ++i) {
152016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (MediaBrowserCompatUtils.areSameOptions(mOptionsList.get(i), options)) {
152116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mCallbacks.remove(i);
152216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mOptionsList.remove(i);
152316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return true;
152416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
152516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
152616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            return false;
152716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
152816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
152916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public SubscriptionCallback getCallback(Bundle options) {
153016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            for (int i = 0; i < mOptionsList.size(); ++i) {
153116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                if (MediaBrowserCompatUtils.areSameOptions(mOptionsList.get(i), options)) {
153216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    return mCallbacks.get(i);
153316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                }
153416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
153516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            return null;
153616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
153716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
153816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
153916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    private static class CallbackHandler extends Handler {
154016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private final MediaBrowserServiceCallbackImpl mCallbackImpl;
154116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private WeakReference<Messenger> mCallbacksMessengerRef;
154216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
154316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        CallbackHandler(MediaBrowserServiceCallbackImpl callbackImpl) {
154416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            super();
154516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mCallbackImpl = callbackImpl;
154616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
154716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
154816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        @Override
154916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public void handleMessage(Message msg) {
155016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            if (mCallbacksMessengerRef == null) {
155116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                return;
155216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
155316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle data = msg.getData();
155416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.setClassLoader(MediaSessionCompat.class.getClassLoader());
155516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            switch (msg.what) {
155616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case SERVICE_MSG_ON_CONNECT:
155716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mCallbackImpl.onServiceConnected(mCallbacksMessengerRef.get(),
155816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            data.getString(DATA_MEDIA_ITEM_ID),
155916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            (MediaSessionCompat.Token) data.getParcelable(DATA_MEDIA_SESSION_TOKEN),
156016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            data.getBundle(DATA_ROOT_HINTS));
156116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    break;
156216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case SERVICE_MSG_ON_CONNECT_FAILED:
156316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mCallbackImpl.onConnectionFailed(mCallbacksMessengerRef.get());
156416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    break;
156516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                case SERVICE_MSG_ON_LOAD_CHILDREN:
156616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    mCallbackImpl.onLoadChildren(mCallbacksMessengerRef.get(),
156716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            data.getString(DATA_MEDIA_ITEM_ID),
156816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            data.getParcelableArrayList(DATA_MEDIA_ITEM_LIST),
156916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            data.getBundle(DATA_OPTIONS));
157016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    break;
157116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                default:
157216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                    Log.w(TAG, "Unhandled message: " + msg
157316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            + "\n  Client version: " + CLIENT_VERSION_CURRENT
157416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                            + "\n  Service version: " + msg.arg1);
157516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            }
157616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
157716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
157816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void setCallbacksMessenger(Messenger callbacksMessenger) {
157916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mCallbacksMessengerRef = new WeakReference<>(callbacksMessenger);
158016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
158116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
158216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
158316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    private static class ServiceBinderWrapper {
158416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private Messenger mMessenger;
158516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
158616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        public ServiceBinderWrapper(IBinder target) {
158716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mMessenger = new Messenger(target);
158816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
158916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
159016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void connect(Context context, Bundle rootHint, Messenger callbacksMessenger)
159116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                throws RemoteException {
159216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle data = new Bundle();
159316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putString(DATA_PACKAGE_NAME, context.getPackageName());
159416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putBundle(DATA_ROOT_HINTS, rootHint);
159516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sendRequest(CLIENT_MSG_CONNECT, data, callbacksMessenger);
159616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
159716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
159816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void disconnect(Messenger callbacksMessenger) throws RemoteException {
159916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sendRequest(CLIENT_MSG_DISCONNECT, null, callbacksMessenger);
160016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
160116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
160216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void addSubscription(String parentId, Bundle options, Messenger callbacksMessenger)
160316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                throws RemoteException {
160416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle data = new Bundle();
160516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putString(DATA_MEDIA_ITEM_ID, parentId);
160616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putBundle(DATA_OPTIONS, options);
160716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sendRequest(CLIENT_MSG_ADD_SUBSCRIPTION, data, callbacksMessenger);
160816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
160916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
161016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void removeSubscription(String parentId, Bundle options, Messenger callbacksMessenger)
161116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                throws RemoteException {
161216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle data = new Bundle();
161316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putString(DATA_MEDIA_ITEM_ID, parentId);
161416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putBundle(DATA_OPTIONS, options);
161516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sendRequest(CLIENT_MSG_REMOVE_SUBSCRIPTION, data, callbacksMessenger);
161616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
161716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
161816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void getMediaItem(String mediaId, ResultReceiver receiver) throws RemoteException {
161916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Bundle data = new Bundle();
162016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putString(DATA_MEDIA_ITEM_ID, mediaId);
162116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            data.putParcelable(DATA_RESULT_RECEIVER, receiver);
162216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sendRequest(CLIENT_MSG_GET_MEDIA_ITEM, data, null);
162316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
162416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
162516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        void registerCallbackMessenger(Messenger callbackMessenger) throws RemoteException {
162616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            sendRequest(CLIENT_MSG_REGISTER_CALLBACK_MESSENGER, null, callbackMessenger);
162716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
162816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
162916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        private void sendRequest(int what, Bundle data, Messenger cbMessenger)
163016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim                throws RemoteException {
163116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            Message msg = Message.obtain();
163216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            msg.what = what;
163316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            msg.arg1 = CLIENT_VERSION_CURRENT;
163416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            msg.setData(data);
163516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            msg.replyTo = cbMessenger;
163616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim            mMessenger.send(msg);
163716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim        }
163816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    }
163916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim
164016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim    private  static class ItemReceiver extends ResultReceiver {
1641d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        private final String mMediaId;
1642d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        private final ItemCallback mCallback;
1643d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim
1644d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        ItemReceiver(String mediaId, ItemCallback callback, Handler handler) {
1645d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            super(handler);
1646d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            mMediaId = mediaId;
1647d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            mCallback = callback;
1648d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        }
1649d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim
1650d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        @Override
1651d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        protected void onReceiveResult(int resultCode, Bundle resultData) {
1652d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            resultData.setClassLoader(MediaBrowserCompat.class.getClassLoader());
1653d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            if (resultCode != 0 || resultData == null
1654d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim                    || !resultData.containsKey(MediaBrowserServiceCompat.KEY_MEDIA_ITEM)) {
1655d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim                mCallback.onError(mMediaId);
1656d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim                return;
1657d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            }
1658d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            Parcelable item = resultData.getParcelable(MediaBrowserServiceCompat.KEY_MEDIA_ITEM);
1659d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            if (item instanceof MediaItem) {
1660d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim                mCallback.onItemLoaded((MediaItem) item);
1661d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            } else {
1662d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim                mCallback.onError(mMediaId);
1663d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim            }
1664d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim        }
1665d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim    }
1666e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo}
1667