MediaBrowserServiceCompat.java revision 6a4150834d679d66abef50aff74d30ae2e846a32
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 Seo 17e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seopackage android.support.v4.media; 18e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 19e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.app.Service; 20e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.content.Intent; 21e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.content.pm.PackageManager; 22e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Binder; 236a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Limimport android.os.Build; 24e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Bundle; 25e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Handler; 26e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.IBinder; 276a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Limimport android.os.Parcel; 28e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.RemoteException; 29e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.NonNull; 30e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.Nullable; 31e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.media.session.MediaSessionCompat; 32e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.os.ResultReceiver; 33e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.util.ArrayMap; 34e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.text.TextUtils; 35e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.util.Log; 36e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 37e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.io.FileDescriptor; 38e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.io.PrintWriter; 396a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Limimport java.util.ArrayList; 40e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.util.HashSet; 41e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.util.List; 42e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 43e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo/** 44e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Base class for media browse services. 45e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 46e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Media browse services enable applications to browse media content provided by an application 47e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * and ask the application to start playing it. They may also be used to control content that 48096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * is already playing by way of a {@link MediaSessionCompat}. 49e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p> 50e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 51e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * To extend this class, you must declare the service in your manifest file with 52e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * an intent filter with the {@link #SERVICE_INTERFACE} action. 53e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 54e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * For example: 55e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p><pre> 56096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * <service android:name=".MyMediaBrowserServiceCompat" 57e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * android:label="@string/service_name" > 58e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <intent-filter> 596a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim * <action android:name="android.media.browse.MediaBrowserService" /> 60e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </intent-filter> 61e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </service> 62e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </pre> 63e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @hide 64e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 65096f2531cb790bc1106377d2da344614a3b88d39Jae Seopublic abstract class MediaBrowserServiceCompat extends Service { 66096f2531cb790bc1106377d2da344614a3b88d39Jae Seo private static final String TAG = "MediaBrowserServiceCompat"; 67e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private static final boolean DBG = false; 68e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 696a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim private MediaBrowserServiceImpl mImpl; 706a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 71e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 72e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The {@link Intent} that must be declared as handled by the service. 73e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 746a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"; 75e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 76e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 77e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * A key for passing the MediaItem to the ResultReceiver in getItem. 78e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 79e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @hide 80e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 81e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public static final String KEY_MEDIA_ITEM = "media_item"; 82e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 83e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap(); 84e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private final Handler mHandler = new Handler(); 85e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo MediaSessionCompat.Token mSession; 86e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 876a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim interface MediaBrowserServiceImpl { 886a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void onCreate(); 896a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim IBinder onBind(Intent intent); 906a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 916a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 926a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim class MediaBrowserServiceImplBase implements MediaBrowserServiceImpl { 936a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim private ServiceBinderCompat mBinder; 946a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 956a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 966a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void onCreate() { 976a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mBinder = new ServiceBinderCompat(new ServiceStub()); 986a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 996a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 1006a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 1016a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public IBinder onBind(Intent intent) { 1026a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim // STOPSHIP: Use messenger or version management for further extension 1036a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim if (SERVICE_INTERFACE.equals(intent.getAction())) { 1046a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim return mBinder; 1056a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 1066a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim return null; 1076a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 1086a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 1096a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 1106a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim class MediaBrowserServiceImplApi21 implements MediaBrowserServiceImpl { 1116a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim private Object mServiceObj; 1126a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 1136a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 1146a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void onCreate() { 1156a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mServiceObj = MediaBrowserServiceCompatApi21.createService(); 1166a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim MediaBrowserServiceCompatApi21.onCreate(mServiceObj, 1176a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim new ServiceStubApi21(new ServiceStub())); 1186a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 1196a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 1206a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 1216a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public IBinder onBind(Intent intent) { 1226a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim return MediaBrowserServiceCompatApi21.onBind(mServiceObj, intent); 1236a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 1246a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 1256a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 126e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 127e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * All the info about a connection. 128e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 129e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private class ConnectionRecord { 130e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo String pkg; 131e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Bundle rootHints; 1326a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim ServiceCallbacks callbacks; 133e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo BrowserRoot root; 134e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo HashSet<String> subscriptions = new HashSet(); 135e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 136e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 137e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 138096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * Completion handler for asynchronous callback methods in {@link MediaBrowserServiceCompat}. 139e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 140e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Each of the methods that takes one of these to send the result must call 141e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * {@link #sendResult} to respond to the caller with the given results. If those 142e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * functions return without calling {@link #sendResult}, they must instead call 143e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * {@link #detach} before returning, and then may call {@link #sendResult} when 144e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * they are done. If more than one of those methods is called, an exception will 145e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * be thrown. 146e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 147096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @see MediaBrowserServiceCompat#onLoadChildren 148096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @see MediaBrowserServiceCompat#onLoadItem 149e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1506a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public static class Result<T> { 151e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private Object mDebug; 152e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean mDetachCalled; 153e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean mSendResultCalled; 154e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 155e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Result(Object debug) { 156e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mDebug = debug; 157e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 158e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 159e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 160e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Send the result back to the caller. 161e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 162e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void sendResult(T result) { 163e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSendResultCalled) { 164e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("sendResult() called twice for: " + mDebug); 165e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 166e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mSendResultCalled = true; 167e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo onResultSent(result); 168e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 169e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 170e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 171e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Detach this message from the current thread and allow the {@link #sendResult} 172e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * call to happen later. 173e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 174e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void detach() { 175e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mDetachCalled) { 176e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("detach() called when detach() had already" 177e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been called for: " + mDebug); 178e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 179e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSendResultCalled) { 180e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("detach() called when sendResult() had already" 181e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been called for: " + mDebug); 182e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 183e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mDetachCalled = true; 184e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 185e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 186e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo boolean isDone() { 187e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mDetachCalled || mSendResultCalled; 188e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 189e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 190e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 191e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called when the result is sent, after assertions about not being called twice 192e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * have happened. 193e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 194e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo void onResultSent(T result) { 195e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 196e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 197e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1986a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim private class ServiceStub { 199e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void connect(final String pkg, final Bundle rootHints, 2006a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final ServiceCallbacks callbacks) { 201e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 202e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final int uid = Binder.getCallingUid(); 203e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!isValidPackage(pkg, uid)) { 204e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid 205e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " package=" + pkg); 206e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 207e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 208e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mHandler.post(new Runnable() { 2096a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 2106a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void run() { 2116a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final IBinder b = callbacks.asBinder(); 2126a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 2136a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim // Clear out the old subscriptions. We are getting new ones. 2146a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mConnections.remove(b); 2156a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 2166a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final ConnectionRecord connection = new ConnectionRecord(); 2176a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim connection.pkg = pkg; 2186a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim connection.rootHints = rootHints; 2196a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim connection.callbacks = callbacks; 2206a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 2216a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim connection.root = 2226a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim MediaBrowserServiceCompat.this.onGetRoot(pkg, uid, rootHints); 2236a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 2246a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim // If they didn't return something, don't allow this client. 2256a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim if (connection.root == null) { 2266a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim Log.i(TAG, "No root for client " + pkg + " from service " 2276a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim + getClass().getName()); 2286a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim try { 2296a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim callbacks.onConnectFailed(); 2306a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } catch (RemoteException ex) { 2316a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. " 2326a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim + "pkg=" + pkg); 2336a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 2346a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } else { 2356a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim try { 2366a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mConnections.put(b, connection); 2376a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim if (mSession != null) { 2386a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim callbacks.onConnect(connection.root.getRootId(), 2396a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mSession, connection.root.getExtras()); 240e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 2416a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } catch (RemoteException ex) { 2426a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim Log.w(TAG, "Calling onConnect() failed. Dropping client. " 2436a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim + "pkg=" + pkg); 2446a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mConnections.remove(b); 245e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 246e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 2476a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 2486a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim }); 249e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 250e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 2516a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void disconnect(final ServiceCallbacks callbacks) { 252e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mHandler.post(new Runnable() { 2536a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 2546a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void run() { 2556a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final IBinder b = callbacks.asBinder(); 2566a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 2576a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim // Clear out the old subscriptions. We are getting new ones. 2586a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final ConnectionRecord old = mConnections.remove(b); 2596a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim if (old != null) { 2606a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim // TODO 261e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 2626a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 2636a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim }); 264e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 265e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 266e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 2676a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void addSubscription(final String id, final ServiceCallbacks callbacks) { 268e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mHandler.post(new Runnable() { 2696a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 2706a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void run() { 2716a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final IBinder b = callbacks.asBinder(); 272e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 2736a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim // Get the record for the connection 2746a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final ConnectionRecord connection = mConnections.get(b); 2756a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim if (connection == null) { 2766a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim Log.w(TAG, "addSubscription for callback that isn't registered id=" 2776a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim + id); 2786a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim return; 279e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 2806a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 2816a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim MediaBrowserServiceCompat.this.addSubscription(id, connection); 2826a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 2836a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim }); 284e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 285e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 2866a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void removeSubscription(final String id, final ServiceCallbacks callbacks) { 287e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mHandler.post(new Runnable() { 288e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 289e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 290e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final IBinder b = callbacks.asBinder(); 291e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 292e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo ConnectionRecord connection = mConnections.get(b); 293e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (connection == null) { 294e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "removeSubscription for callback that isn't registered id=" 295e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + id); 296e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 297e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 298e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!connection.subscriptions.remove(id)) { 299e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "removeSubscription called for " + id 300e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " which is not subscribed"); 301e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 302e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 303e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 304e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 305e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 306e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void getMediaItem(final String mediaId, final ResultReceiver receiver) { 307e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (TextUtils.isEmpty(mediaId) || receiver == null) { 308e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 309e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 310e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 311e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mHandler.post(new Runnable() { 312e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 313e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 314e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo performLoadItem(mediaId, receiver); 315e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 316e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 317e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 318e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 319e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 3206a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim private class ServiceBinderCompat extends IMediaBrowserServiceCompat.Stub { 3216a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final ServiceStub mServiceStub; 3226a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3236a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim ServiceBinderCompat(ServiceStub binder) { 3246a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mServiceStub = binder; 3256a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3266a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3276a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3286a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void connect(final String pkg, final Bundle rootHints, 3296a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final IMediaBrowserServiceCompatCallbacks callbacks) { 3306a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mServiceStub.connect(pkg, rootHints, new ServiceCallbacksCompat(callbacks)); 3316a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3326a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3336a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3346a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void disconnect(final IMediaBrowserServiceCompatCallbacks callbacks) { 3356a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mConnections.get(callbacks.asBinder()); 3366a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mServiceStub.disconnect(new ServiceCallbacksCompat(callbacks)); 3376a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3386a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3396a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3406a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3416a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void addSubscription( 3426a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final String id, final IMediaBrowserServiceCompatCallbacks callbacks) { 3436a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mServiceStub.addSubscription(id, new ServiceCallbacksCompat(callbacks)); 3446a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3456a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3466a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3476a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void removeSubscription(final String id, 3486a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final IMediaBrowserServiceCompatCallbacks callbacks) { 3496a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mServiceStub.removeSubscription(id, new ServiceCallbacksCompat(callbacks)); 3506a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3516a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3526a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3536a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void getMediaItem(final String mediaId, final ResultReceiver receiver) { 3546a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mServiceStub.getMediaItem(mediaId, receiver); 3556a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3566a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3576a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3586a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim private class ServiceStubApi21 implements MediaBrowserServiceCompatApi21.ServiceStub { 3596a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final ServiceStub mBinder; 3606a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3616a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim ServiceStubApi21(ServiceStub binder) { 3626a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mBinder = binder; 3636a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3646a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3656a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3666a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void connect(final String pkg, final Bundle rootHints, 3676a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { 3686a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mBinder.connect(pkg, rootHints, new ServiceCallbacksApi21(callbacks)); 3696a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3706a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3716a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3726a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void disconnect(final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { 3736a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mBinder.disconnect(new ServiceCallbacksApi21(callbacks)); 3746a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3756a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3766a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3776a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3786a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void addSubscription( 3796a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final String id, final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { 3806a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mBinder.addSubscription(id, new ServiceCallbacksApi21(callbacks)); 3816a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3826a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3836a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3846a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void removeSubscription(final String id, 3856a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { 3866a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mBinder.removeSubscription(id, new ServiceCallbacksApi21(callbacks)); 3876a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3886a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3896a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3906a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void getMediaItem(final String mediaId, final android.os.ResultReceiver receiver) { 3916a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim ResultReceiver receiverCompat = new ResultReceiver(mHandler) { 3926a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim @Override 3936a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim protected void onReceiveResult(int resultCode, Bundle resultData) { 3946a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim receiver.send(resultCode, resultData); 3956a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3966a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim }; 3976a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mBinder.getMediaItem(mediaId, receiverCompat); 3986a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 3996a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4006a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4016a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim private interface ServiceCallbacks { 4026a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim IBinder asBinder(); 4036a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) 4046a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim throws RemoteException; 4056a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim void onConnectFailed() throws RemoteException; 4066a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list) 4076a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim throws RemoteException; 4086a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4096a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4106a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim private class ServiceCallbacksCompat implements ServiceCallbacks { 4116a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final IMediaBrowserServiceCompatCallbacks mCallbacks; 4126a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4136a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim ServiceCallbacksCompat(IMediaBrowserServiceCompatCallbacks callbacks) { 4146a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mCallbacks = callbacks; 4156a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4166a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4176a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public IBinder asBinder() { 4186a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim return mCallbacks.asBinder(); 4196a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4206a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4216a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) 4226a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim throws RemoteException { 4236a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mCallbacks.onConnect(root, session, extras); 4246a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4256a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4266a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void onConnectFailed() throws RemoteException { 4276a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mCallbacks.onConnectFailed(); 4286a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4296a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4306a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list) 4316a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim throws RemoteException { 4326a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mCallbacks.onLoadChildren(mediaId, list); 4336a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4346a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4356a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4366a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim private class ServiceCallbacksApi21 implements ServiceCallbacks { 4376a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim final MediaBrowserServiceCompatApi21.ServiceCallbacks mCallbacks; 4386a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4396a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim ServiceCallbacksApi21(MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { 4406a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mCallbacks = callbacks; 4416a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4426a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4436a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public IBinder asBinder() { 4446a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim return mCallbacks.asBinder(); 4456a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4466a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4476a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) 4486a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim throws RemoteException { 4496a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mCallbacks.onConnect(root, session.getToken(), extras); 4506a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4516a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4526a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void onConnectFailed() throws RemoteException { 4536a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mCallbacks.onConnectFailed(); 4546a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4556a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 4566a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list) 4576a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim throws RemoteException { 4586a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim List<Parcel> parcelList = null; 4596a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim if (list != null) { 4606a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim parcelList = new ArrayList<>(); 4616a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim for (MediaBrowserCompat.MediaItem item : list) { 4626a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim Parcel parcel = Parcel.obtain(); 4636a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim item.writeToParcel(parcel, 0); 4646a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim parcelList.add(parcel); 4656a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4666a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4676a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mCallbacks.onLoadChildren(mediaId, parcelList); 4686a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4696a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4706a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 471e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 472e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void onCreate() { 473e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo super.onCreate(); 4746a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim if (Build.VERSION.SDK_INT >= 21) { 4756a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mImpl = new MediaBrowserServiceImplApi21(); 4766a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } else { 4776a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mImpl = new MediaBrowserServiceImplBase(); 4786a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim } 4796a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim mImpl.onCreate(); 480e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 481e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 482e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 483e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public IBinder onBind(Intent intent) { 4846a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim return mImpl.onBind(intent); 485e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 486e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 487e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 488e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 489e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 490e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 491e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 492e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get the root information for browsing by a particular client. 493e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 494e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The implementation should verify that the client package has permission 495e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * to access browse media information before returning the root id; it 496e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * should return null if the client is not allowed to access this 497e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * information. 498e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p> 499e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 500e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param clientPackageName The package name of the application which is 501e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * requesting access to browse media. 502e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param clientUid The uid of the application which is requesting access to 503e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * browse media. 504e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param rootHints An optional bundle of service-specific arguments to send 505e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * to the media browse service when connecting and retrieving the 506e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * root id for browsing, or null if none. The contents of this 507e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * bundle may affect the information returned when browsing. 508e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @return The {@link BrowserRoot} for accessing this app's content or null. 509e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 510e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName, 511e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo int clientUid, @Nullable Bundle rootHints); 512e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 513e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 514e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get information about the children of a media item. 515e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 516e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Implementations must call {@link Result#sendResult result.sendResult} 517e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * with the list of children. If loading the children will be an expensive 518e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * operation that should be performed on another thread, 519e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * {@link Result#detach result.detach} may be called before returning from 520e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * this function, and then {@link Result#sendResult result.sendResult} 521e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * called when the loading is complete. 522e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 523e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param parentId The id of the parent media item whose children are to be 524e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * queried. 525e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param result The Result to send the list of children to, or null if the 526e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * id is invalid. 527e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 528e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public abstract void onLoadChildren(@NonNull String parentId, 529096f2531cb790bc1106377d2da344614a3b88d39Jae Seo @NonNull Result<List<MediaBrowserCompat.MediaItem>> result); 530e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 531e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 532e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get information about a specific media item. 533e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 534e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Implementations must call {@link Result#sendResult result.sendResult}. If 535e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * loading the item will be an expensive operation {@link Result#detach 536e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * result.detach} may be called before returning from this function, and 537e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * then {@link Result#sendResult result.sendResult} called when the item has 538e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * been loaded. 539e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 540e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The default implementation sends a null result. 541e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 542e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param itemId The id for the specific 543096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * {@link MediaBrowserCompat.MediaItem}. 544e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param result The Result to send the item to, or null if the id is 545e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * invalid. 546e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 547096f2531cb790bc1106377d2da344614a3b88d39Jae Seo public void onLoadItem(String itemId, Result<MediaBrowserCompat.MediaItem> result) { 548e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo result.sendResult(null); 549e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 550e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 551e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 552e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Call to set the media session. 553e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 554e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * This should be called as soon as possible during the service's startup. 555e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * It may only be called once. 556e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 557096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @param token The token for the service's {@link MediaSessionCompat}. 558e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 559e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void setSessionToken(final MediaSessionCompat.Token token) { 560e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (token == null) { 561e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("Session token may not be null."); 562e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 563e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSession != null) { 564e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("The session token has already been set."); 565e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 566e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mSession = token; 567e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mHandler.post(new Runnable() { 568e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 569e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 570e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo for (IBinder key : mConnections.keySet()) { 571e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo ConnectionRecord connection = mConnections.get(key); 572e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo try { 573e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo connection.callbacks.onConnect(connection.root.getRootId(), token, 574e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo connection.root.getExtras()); 575e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } catch (RemoteException e) { 576e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid."); 577e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mConnections.remove(key); 578e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 579e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 580e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 581e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 582e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 583e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 584e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 585e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Gets the session token, or null if it has not yet been created 586e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * or if it has been destroyed. 587e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 588e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public @Nullable MediaSessionCompat.Token getSessionToken() { 589e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mSession; 590e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 591e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 592e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 593e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Notifies all connected media browsers that the children of 594e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * the specified parent id have changed in some way. 595e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * This will cause browsers to fetch subscribed content again. 596e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 597e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param parentId The id of the parent media item whose 598e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * children changed. 599e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 600e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void notifyChildrenChanged(@NonNull final String parentId) { 601e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (parentId == null) { 602e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged"); 603e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 604e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mHandler.post(new Runnable() { 605e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 606e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 607e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo for (IBinder binder : mConnections.keySet()) { 608e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo ConnectionRecord connection = mConnections.get(binder); 609e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (connection.subscriptions.contains(parentId)) { 610e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo performLoadChildren(parentId, connection); 611e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 612e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 613e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 614e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 615e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 616e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 617e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 618e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Return whether the given package is one of the ones that is owned by the uid. 619e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 620e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean isValidPackage(String pkg, int uid) { 621e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (pkg == null) { 622e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return false; 623e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 624e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final PackageManager pm = getPackageManager(); 625e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final String[] packages = pm.getPackagesForUid(uid); 626e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final int N = packages.length; 627e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo for (int i=0; i<N; i++) { 628e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (packages[i].equals(pkg)) { 629e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return true; 630e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 631e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 632e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return false; 633e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 634e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 635e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 636e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Save the subscription and if it is a new subscription send the results. 637e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 638e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private void addSubscription(String id, ConnectionRecord connection) { 639e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // Save the subscription 640e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo connection.subscriptions.add(id); 641e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 642e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // send the results 643e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo performLoadChildren(id, connection); 644e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 645e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 646e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 647e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Call onLoadChildren and then send the results back to the connection. 648e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 649e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Callers must make sure that this connection is still connected. 650e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 651e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private void performLoadChildren(final String parentId, final ConnectionRecord connection) { 652096f2531cb790bc1106377d2da344614a3b88d39Jae Seo final Result<List<MediaBrowserCompat.MediaItem>> result 653096f2531cb790bc1106377d2da344614a3b88d39Jae Seo = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) { 654e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 655096f2531cb790bc1106377d2da344614a3b88d39Jae Seo void onResultSent(List<MediaBrowserCompat.MediaItem> list) { 656e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (list == null) { 657e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("onLoadChildren sent null list for id " 658e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + parentId); 659e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 660e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mConnections.get(connection.callbacks.asBinder()) != connection) { 661e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (DBG) { 662e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.d(TAG, "Not sending onLoadChildren result for connection that has" 663e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been disconnected. pkg=" + connection.pkg + " id=" + parentId); 664e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 665e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 666e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 667e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 668e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo try { 669e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo connection.callbacks.onLoadChildren(parentId, list); 670e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } catch (RemoteException ex) { 671e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // The other side is in the process of crashing. 672e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId 673e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " package=" + connection.pkg); 674e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 675e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 676e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }; 677e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 678e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo onLoadChildren(parentId, result); 679e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 680e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!result.isDone()) { 681e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("onLoadChildren must call detach() or sendResult()" 682e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " before returning for package=" + connection.pkg + " id=" + parentId); 683e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 684e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 685e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 686e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private void performLoadItem(String itemId, final ResultReceiver receiver) { 687096f2531cb790bc1106377d2da344614a3b88d39Jae Seo final Result<MediaBrowserCompat.MediaItem> result = 688096f2531cb790bc1106377d2da344614a3b88d39Jae Seo new Result<MediaBrowserCompat.MediaItem>(itemId) { 689e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 690096f2531cb790bc1106377d2da344614a3b88d39Jae Seo void onResultSent(MediaBrowserCompat.MediaItem item) { 691e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Bundle bundle = new Bundle(); 692e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo bundle.putParcelable(KEY_MEDIA_ITEM, item); 693e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo receiver.send(0, bundle); 694e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 695e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }; 696e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 697096f2531cb790bc1106377d2da344614a3b88d39Jae Seo MediaBrowserServiceCompat.this.onLoadItem(itemId, result); 698e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 699e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!result.isDone()) { 700e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("onLoadItem must call detach() or sendResult()" 701e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " before returning for id=" + itemId); 702e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 703e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 704e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 705e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 706e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Contains information that the browser service needs to send to the client 707e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * when first connected. 708e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 709e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public static final class BrowserRoot { 710e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final private String mRootId; 711e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final private Bundle mExtras; 712e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 713e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 714e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Constructs a browser root. 715e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param rootId The root id for browsing. 716e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param extras Any extras about the browser service. 717e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 718e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) { 719e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (rootId == null) { 720e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " + 721e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo "Use null for BrowserRoot instead."); 722e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 723e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mRootId = rootId; 724e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mExtras = extras; 725e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 726e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 727e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 728e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Gets the root id for browsing. 729e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 730e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public String getRootId() { 731e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mRootId; 732e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 733e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 734e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 735e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Gets any extras about the brwoser service. 736e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 737e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public Bundle getExtras() { 738e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mExtras; 739e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 740e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 741e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo} 742