MediaBrowserServiceCompat.java revision fda621da7916073852394d14fcd2cb37f202287d
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; 239703a1e215168b6b580430ec490ca616b6490c80Sungsoo Limimport android.os.Build; 24e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Bundle; 25e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Handler; 26e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.IBinder; 273f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Limimport android.os.Message; 283f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Limimport android.os.Messenger; 299703a1e215168b6b580430ec490ca616b6490c80Sungsoo Limimport android.os.Parcel; 30e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.RemoteException; 3182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport android.support.annotation.IntDef; 32e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.NonNull; 33e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.Nullable; 3482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Limimport android.support.v4.app.BundleCompat; 35e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.media.session.MediaSessionCompat; 36e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.os.ResultReceiver; 37e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.util.ArrayMap; 387a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Limimport android.support.v4.util.Pair; 39e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.text.TextUtils; 40e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.util.Log; 41e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 42e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.io.FileDescriptor; 43e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.io.PrintWriter; 4482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport java.lang.annotation.Retention; 4582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport java.lang.annotation.RetentionPolicy; 469703a1e215168b6b580430ec490ca616b6490c80Sungsoo Limimport java.util.ArrayList; 4782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport java.util.Collections; 4882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport java.util.HashMap; 49e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.util.List; 50e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 5182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Limimport static android.support.v4.media.MediaBrowserProtocol.*; 5282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim 53e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo/** 54e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Base class for media browse services. 55e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 56e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Media browse services enable applications to browse media content provided by an application 5782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * and ask the application to start playing it. They may also be used to control content that 58096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * is already playing by way of a {@link MediaSessionCompat}. 59e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p> 60e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 61e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * To extend this class, you must declare the service in your manifest file with 62e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * an intent filter with the {@link #SERVICE_INTERFACE} action. 63e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 64e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * For example: 65e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p><pre> 66096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * <service android:name=".MyMediaBrowserServiceCompat" 67e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * android:label="@string/service_name" > 68e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <intent-filter> 699703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim * <action android:name="android.media.browse.MediaBrowserService" /> 70e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </intent-filter> 71e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </service> 72e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </pre> 73e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 74096f2531cb790bc1106377d2da344614a3b88d39Jae Seopublic abstract class MediaBrowserServiceCompat extends Service { 757a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim private static final String TAG = "MBServiceCompat"; 767a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 77e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 789703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private MediaBrowserServiceImpl mImpl; 799703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 80e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 81e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The {@link Intent} that must be declared as handled by the service. 82e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 839703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"; 84e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 85e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 86e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * A key for passing the MediaItem to the ResultReceiver in getItem. 87e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 88e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @hide 89e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 90e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public static final String KEY_MEDIA_ITEM = "media_item"; 91e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 9282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 0x00000001; 9382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 9482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim /** @hide */ 9582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim @Retention(RetentionPolicy.SOURCE) 9682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED }) 9782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim private @interface ResultFlags { } 9882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 9982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>(); 100fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim private ConnectionRecord mCurConnection; 1013f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim private final ServiceHandler mHandler = new ServiceHandler(); 102e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo MediaSessionCompat.Token mSession; 103e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1049703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim interface MediaBrowserServiceImpl { 1053f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim void onCreate(); 1069703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim IBinder onBind(Intent intent); 1077a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim void setSessionToken(MediaSessionCompat.Token token); 108900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim void notifyChildrenChanged(final String parentId, final Bundle options); 109fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim Bundle getBrowserRootHints(); 1109703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1119703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1129703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim class MediaBrowserServiceImplBase implements MediaBrowserServiceImpl { 1133f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim private Messenger mMessenger; 1149703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1159703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 1169703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onCreate() { 1173f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mMessenger = new Messenger(mHandler); 1189703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1199703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1209703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 1219703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public IBinder onBind(Intent intent) { 1229703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (SERVICE_INTERFACE.equals(intent.getAction())) { 1233f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim return mMessenger.getBinder(); 1249703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1259703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return null; 1269703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1277a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim 1287a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim @Override 1297a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void setSessionToken(final MediaSessionCompat.Token token) { 1307a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mHandler.post(new Runnable() { 1317a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim @Override 1327a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void run() { 1337a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim for (IBinder key : mConnections.keySet()) { 1347a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim ConnectionRecord connection = mConnections.get(key); 1357a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim try { 1367a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim connection.callbacks.onConnect(connection.root.getRootId(), token, 1377a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim connection.root.getExtras()); 1387a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } catch (RemoteException e) { 1397a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid."); 1407a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mConnections.remove(key); 1417a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 1427a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 1437a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 1447a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim }); 1457a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 146900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 147900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 148900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void notifyChildrenChanged(@NonNull final String parentId, final Bundle options) { 149900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mHandler.post(new Runnable() { 150900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 151900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void run() { 152900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim for (IBinder binder : mConnections.keySet()) { 153900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim ConnectionRecord connection = mConnections.get(binder); 154900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim List<Pair<IBinder, Bundle>> callbackList = 155900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim connection.subscriptions.get(parentId); 156900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (callbackList != null) { 157900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim for (Pair<IBinder, Bundle> callback : callbackList) { 158900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (MediaBrowserCompatUtils.hasDuplicatedItems( 159900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim options, callback.second)) { 160900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim performLoadChildren(parentId, connection, callback.second); 161900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 162900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 163900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 164900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 165900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 166900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim }); 167900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 168fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim 169fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim @Override 170fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public Bundle getBrowserRootHints() { 171fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim if (mCurConnection == null) { 172fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim throw new IllegalStateException("This should be called inside of onLoadChildren or" 173fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim + " onLoadItem methods"); 174fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 175fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints); 176fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 1779703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1789703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1797a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim class MediaBrowserServiceImplApi21 implements MediaBrowserServiceImpl, 1807a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompatApi21.ServiceCompatProxy { 181900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim Object mServiceObj; 182900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim Messenger mMessenger; 1839703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1849703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 1859703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onCreate() { 1867a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceObj = MediaBrowserServiceCompatApi21.createService( 1877a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompat.this, this); 1887a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompatApi21.onCreate(mServiceObj); 1899703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1909703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1919703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 1929703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public IBinder onBind(Intent intent) { 1939703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return MediaBrowserServiceCompatApi21.onBind(mServiceObj, intent); 1949703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 19582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim 19682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim @Override 1977a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void setSessionToken(MediaSessionCompat.Token token) { 1987a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompatApi21.setSessionToken(mServiceObj, token.getToken()); 19982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 20082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim 20182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim @Override 202900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void notifyChildrenChanged(final String parentId, final Bundle options) { 203900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (mMessenger == null) { 204900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim // TODO: Support notifyChildrenChanged with options. 205900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompatApi21.notifyChildrenChanged(mServiceObj, parentId); 206900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } else { 207900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mHandler.post(new Runnable() { 208900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 209900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void run() { 210900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim for (IBinder binder : mConnections.keySet()) { 211900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim ConnectionRecord connection = mConnections.get(binder); 212900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim List<Pair<IBinder, Bundle>> callbackList = 213900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim connection.subscriptions.get(parentId); 214900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (callbackList != null) { 215900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim for (Pair<IBinder, Bundle> callback : callbackList) { 216900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (MediaBrowserCompatUtils.hasDuplicatedItems( 217900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim options, callback.second)) { 218900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim performLoadChildren(parentId, connection, callback.second); 219900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 220900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 221900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 222900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 223900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 224900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim }); 225900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 226900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 227900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 228900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 229fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public Bundle getBrowserRootHints() { 230fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim if (mMessenger == null) { 231fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim // TODO: Handle getBrowserRootHints when connected with framework MediaBrowser. 232fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return null; 233fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 234fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim if (mCurConnection == null) { 235fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim throw new IllegalStateException("This should be called inside of onLoadChildren or" 236fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim + " onLoadItem methods"); 237fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 238fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints); 239fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 240fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim 241fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim @Override 2427a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public MediaBrowserServiceCompatApi21.BrowserRoot onGetRoot( 2437a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim String clientPackageName, int clientUid, Bundle rootHints) { 2447a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim Bundle rootExtras = null; 2457a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (rootHints != null && rootHints.getInt(EXTRA_CLIENT_VERSION, 0) != 0) { 2467a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim rootHints.remove(EXTRA_CLIENT_VERSION); 2477a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mMessenger = new Messenger(mHandler); 2487a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim rootExtras = new Bundle(); 2497a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim rootExtras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT); 2507a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim BundleCompat.putBinder(rootExtras, EXTRA_MESSENGER_BINDER, mMessenger.getBinder()); 2517a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 2527a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim BrowserRoot root = MediaBrowserServiceCompat.this.onGetRoot( 2537a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim clientPackageName, clientUid, rootHints); 2547a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (root == null) { 2557a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return null; 2567a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 2577a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (rootExtras == null) { 2587a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim rootExtras = root.getExtras(); 2597a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } else if (root.getExtras() != null) { 2607a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim rootExtras.putAll(root.getExtras()); 2617a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 2627a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return new MediaBrowserServiceCompatApi21.BrowserRoot( 2637a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim root.getRootId(), rootExtras); 26482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 26501b922eddadab50910ce289921001a63855e1f8eSungsoo Lim 26601b922eddadab50910ce289921001a63855e1f8eSungsoo Lim @Override 2677a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void onLoadChildren(String parentId, 2687a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim final MediaBrowserServiceCompatApi21.ResultWrapper resultWrapper) { 2697a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim final Result<List<MediaBrowserCompat.MediaItem>> result 2707a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) { 2717a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim @Override 272900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim void onResultSent(List<MediaBrowserCompat.MediaItem> list, @ResultFlags int flags) { 2737a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim List<Parcel> parcelList = null; 2747a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (list != null) { 2757a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim parcelList = new ArrayList<>(); 2767a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim for (MediaBrowserCompat.MediaItem item : list) { 2777a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim Parcel parcel = Parcel.obtain(); 2787a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim item.writeToParcel(parcel, 0); 2797a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim parcelList.add(parcel); 2807a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 2817a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 2827a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim resultWrapper.sendResult(parcelList); 2837a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 2847a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim 2857a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim @Override 2867a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void detach() { 2877a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim resultWrapper.detach(); 2887a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 2897a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim }; 2907a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompat.this.onLoadChildren(parentId, result); 29101b922eddadab50910ce289921001a63855e1f8eSungsoo Lim } 29201b922eddadab50910ce289921001a63855e1f8eSungsoo Lim } 29301b922eddadab50910ce289921001a63855e1f8eSungsoo Lim 294900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim class MediaBrowserServiceImplApi24 extends MediaBrowserServiceImplApi21 implements 295900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompatApi24.ServiceCompatProxy { 296900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 297900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void onCreate() { 298900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mServiceObj = MediaBrowserServiceCompatApi24.createService( 299900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompat.this, this); 300900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompatApi21.onCreate(mServiceObj); 301900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 302900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 303900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 304900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void notifyChildrenChanged(final String parentId, final Bundle options) { 305900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (options == null) { 306900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompatApi21.notifyChildrenChanged(mServiceObj, parentId); 307900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } else { 308900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompatApi24.notifyChildrenChanged(mServiceObj, parentId, 309900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim options); 310900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 311900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 312900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 313900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 314900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void onLoadChildren(String parentId, 315900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim final MediaBrowserServiceCompatApi24.ResultWrapper resultWrapper, Bundle options) { 316900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim final Result<List<MediaBrowserCompat.MediaItem>> result 317900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) { 318900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 319900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim void onResultSent(List<MediaBrowserCompat.MediaItem> list, @ResultFlags int flags) { 320900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim List<Parcel> parcelList = null; 321900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (list != null) { 322900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim parcelList = new ArrayList<>(); 323900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim for (MediaBrowserCompat.MediaItem item : list) { 324900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim Parcel parcel = Parcel.obtain(); 325900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim item.writeToParcel(parcel, 0); 326900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim parcelList.add(parcel); 327900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 328900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 329900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim resultWrapper.sendResult(parcelList, flags); 330900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 331900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 332900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 333900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void detach() { 334900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim resultWrapper.detach(); 335900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 336900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim }; 337900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompat.this.onLoadChildren(parentId, result, options); 338900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 339fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim 340fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim @Override 341fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public Bundle getBrowserRootHints() { 342fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return MediaBrowserServiceCompatApi24.getBrowserRootHints(mServiceObj); 343fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 344900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 345900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 3463f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim private final class ServiceHandler extends Handler { 3477a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim private final ServiceBinderImpl mServiceBinderImpl = new ServiceBinderImpl(); 3483f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 3493f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim @Override 3503f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim public void handleMessage(Message msg) { 351094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim Bundle data = msg.getData(); 3523f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim switch (msg.what) { 35382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_CONNECT: 3547a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.connect(data.getString(DATA_PACKAGE_NAME), 355094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.getInt(DATA_CALLING_UID), data.getBundle(DATA_ROOT_HINTS), 3563f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 3573f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 35882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_DISCONNECT: 3597a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.disconnect(new ServiceCallbacksCompat(msg.replyTo)); 3603f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 36182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_ADD_SUBSCRIPTION: 3627a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.addSubscription(data.getString(DATA_MEDIA_ITEM_ID), 3637a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim BundleCompat.getBinder(data, DATA_CALLBACK_TOKEN), 3647a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim data.getBundle(DATA_OPTIONS), 3657a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 3663f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 36782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_REMOVE_SUBSCRIPTION: 3687a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.removeSubscription(data.getString(DATA_MEDIA_ITEM_ID), 3697a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim BundleCompat.getBinder(data, DATA_CALLBACK_TOKEN), 3707a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 3713f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 37282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_GET_MEDIA_ITEM: 3737a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.getMediaItem(data.getString(DATA_MEDIA_ITEM_ID), 374fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim (ResultReceiver) data.getParcelable(DATA_RESULT_RECEIVER), 375fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 3763f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 37716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim case CLIENT_MSG_REGISTER_CALLBACK_MESSENGER: 378fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim mServiceBinderImpl.registerCallbacks(new ServiceCallbacksCompat(msg.replyTo), 379fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim data.getBundle(DATA_ROOT_HINTS)); 38016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim break; 38199f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim case CLIENT_MSG_UNREGISTER_CALLBACK_MESSENGER: 3827a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.unregisterCallbacks(new ServiceCallbacksCompat(msg.replyTo)); 38399f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim break; 3843f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim default: 38582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim Log.w(TAG, "Unhandled message: " + msg 38682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim + "\n Service version: " + SERVICE_VERSION_CURRENT 38782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim + "\n Client version: " + msg.arg1); 3883f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 3893f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 3903f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 391094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim @Override 392094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 393094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim // Binder.getCallingUid() in handleMessage will return the uid of this process. 394094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim // In order to get the right calling uid, Binder.getCallingUid() should be called here. 395094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim Bundle data = msg.getData(); 396d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim data.setClassLoader(MediaBrowserCompat.class.getClassLoader()); 397094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putInt(DATA_CALLING_UID, Binder.getCallingUid()); 398094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim return super.sendMessageAtTime(msg, uptimeMillis); 399094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim } 400094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim 4013f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim public void postOrRun(Runnable r) { 4023f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim if (Thread.currentThread() == getLooper().getThread()) { 4033f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim r.run(); 4043f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } else { 4053f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim post(r); 4063f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 4073f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 4083f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 4097a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public ServiceBinderImpl getServiceBinderImpl() { 4107a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return mServiceBinderImpl; 4113f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 4123f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 4133f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 414e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 415e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * All the info about a connection. 416e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 417e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private class ConnectionRecord { 418e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo String pkg; 419e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Bundle rootHints; 4209703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim ServiceCallbacks callbacks; 421e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo BrowserRoot root; 4227a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap(); 423e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 424e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 425e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 426096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * Completion handler for asynchronous callback methods in {@link MediaBrowserServiceCompat}. 427e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 428e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Each of the methods that takes one of these to send the result must call 42982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * {@link #sendResult} to respond to the caller with the given results. If those 430e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * functions return without calling {@link #sendResult}, they must instead call 431e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * {@link #detach} before returning, and then may call {@link #sendResult} when 43282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * they are done. If more than one of those methods is called, an exception will 433e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * be thrown. 434e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 435096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @see MediaBrowserServiceCompat#onLoadChildren 436096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @see MediaBrowserServiceCompat#onLoadItem 437e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 4389703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public static class Result<T> { 439e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private Object mDebug; 440e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean mDetachCalled; 441e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean mSendResultCalled; 44282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim private int mFlags; 443e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 444e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Result(Object debug) { 445e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mDebug = debug; 446e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 447e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 448e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 449e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Send the result back to the caller. 450e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 451e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void sendResult(T result) { 452e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSendResultCalled) { 453e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("sendResult() called twice for: " + mDebug); 454e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 455e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mSendResultCalled = true; 45682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim onResultSent(result, mFlags); 457e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 458e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 459e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 460e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Detach this message from the current thread and allow the {@link #sendResult} 461e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * call to happen later. 462e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 463e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void detach() { 464e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mDetachCalled) { 465e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("detach() called when detach() had already" 466e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been called for: " + mDebug); 467e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 468e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSendResultCalled) { 469e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("detach() called when sendResult() had already" 470e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been called for: " + mDebug); 471e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 472e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mDetachCalled = true; 473e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 474e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 475e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo boolean isDone() { 476e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mDetachCalled || mSendResultCalled; 477e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 478e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 47982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim void setFlags(@ResultFlags int flags) { 48082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim mFlags = flags; 48182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 48282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 483e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 484e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called when the result is sent, after assertions about not being called twice 485e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * have happened. 486e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 48782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim void onResultSent(T result, @ResultFlags int flags) { 488e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 489e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 490e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 4917a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim private class ServiceBinderImpl { 492094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim public void connect(final String pkg, final int uid, final Bundle rootHints, 4939703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ServiceCallbacks callbacks) { 494e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 495e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!isValidPackage(pkg, uid)) { 496e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid 497e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " package=" + pkg); 498e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 499e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 5003f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 5019703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 5029703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void run() { 5039703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final IBinder b = callbacks.asBinder(); 5049703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 50582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim // Clear out the old subscriptions. We are getting new ones. 5069703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mConnections.remove(b); 5079703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5089703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ConnectionRecord connection = new ConnectionRecord(); 5099703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.pkg = pkg; 5109703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.rootHints = rootHints; 5119703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.callbacks = callbacks; 5129703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5139703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.root = 5149703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim MediaBrowserServiceCompat.this.onGetRoot(pkg, uid, rootHints); 5159703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5169703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // If they didn't return something, don't allow this client. 5179703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (connection.root == null) { 5189703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.i(TAG, "No root for client " + pkg + " from service " 5199703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + getClass().getName()); 5209703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim try { 5219703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim callbacks.onConnectFailed(); 5229703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } catch (RemoteException ex) { 5239703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. " 5249703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + "pkg=" + pkg); 5259703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5269703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } else { 5279703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim try { 5289703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mConnections.put(b, connection); 5299703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (mSession != null) { 5309703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim callbacks.onConnect(connection.root.getRootId(), 5319703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mSession, connection.root.getExtras()); 532e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 5339703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } catch (RemoteException ex) { 5349703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.w(TAG, "Calling onConnect() failed. Dropping client. " 5359703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + "pkg=" + pkg); 5369703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mConnections.remove(b); 537e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 538e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 5399703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5409703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim }); 541e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 542e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 5439703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void disconnect(final ServiceCallbacks callbacks) { 5443f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 5459703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 5469703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void run() { 5479703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final IBinder b = callbacks.asBinder(); 5489703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 54982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim // Clear out the old subscriptions. We are getting new ones. 5509703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ConnectionRecord old = mConnections.remove(b); 5519703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (old != null) { 5529703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // TODO 553e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 5549703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5559703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim }); 556e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 557e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 5587a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void addSubscription(final String id, final IBinder token, final Bundle options, 55982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim final ServiceCallbacks callbacks) { 5603f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 5619703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 5629703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void run() { 5639703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final IBinder b = callbacks.asBinder(); 5646a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 5659703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // Get the record for the connection 5669703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ConnectionRecord connection = mConnections.get(b); 5679703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (connection == null) { 5689703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.w(TAG, "addSubscription for callback that isn't registered id=" 5699703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + id); 5709703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return; 571493571364635be0190cea8ee230a601070391e6fIan Pedowitz } 5729703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5737a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompat.this.addSubscription(id, connection, token, options); 5749703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5759703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim }); 576e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 577e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 5787a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void removeSubscription(final String id, final IBinder token, 57982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim final ServiceCallbacks callbacks) { 5803f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 581e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 582e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 583e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final IBinder b = callbacks.asBinder(); 584e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 585e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo ConnectionRecord connection = mConnections.get(b); 586e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (connection == null) { 587e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "removeSubscription for callback that isn't registered id=" 588e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + id); 589e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 590e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 59182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim if (!MediaBrowserServiceCompat.this.removeSubscription( 5927a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim id, connection, token)) { 593e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "removeSubscription called for " + id 594e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " which is not subscribed"); 595e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 596e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 597e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 598e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 599e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 600fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public void getMediaItem(final String mediaId, final ResultReceiver receiver, 601fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim final ServiceCallbacks callbacks) { 602e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (TextUtils.isEmpty(mediaId) || receiver == null) { 603e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 604e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 605e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 6063f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 607e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 608e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 609fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim final IBinder b = callbacks.asBinder(); 610fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim 611fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim ConnectionRecord connection = mConnections.get(b); 612fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim if (connection == null) { 613fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim Log.w(TAG, "getMediaItem for callback that isn't registered id=" + mediaId); 614fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return; 615fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 616fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim performLoadItem(mediaId, connection, receiver); 617e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 618e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 619e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 62016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim 62116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim // Used when {@link MediaBrowserProtocol#EXTRA_MESSENGER_BINDER} is used. 622fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public void registerCallbacks(final ServiceCallbacks callbacks, final Bundle rootHints) { 62316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim mHandler.postOrRun(new Runnable() { 62416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim @Override 62516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim public void run() { 62616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim final IBinder b = callbacks.asBinder(); 62716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim // Clear out the old subscriptions. We are getting new ones. 62816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim mConnections.remove(b); 62916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim 63016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim final ConnectionRecord connection = new ConnectionRecord(); 63116d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim connection.callbacks = callbacks; 632fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim connection.rootHints = rootHints; 63316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim mConnections.put(b, connection); 63416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim } 63516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim }); 63616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim } 63799f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim 63899f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim // Used when {@link MediaBrowserProtocol#EXTRA_MESSENGER_BINDER} is used. 63999f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim public void unregisterCallbacks(final ServiceCallbacks callbacks) { 64099f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim mHandler.postOrRun(new Runnable() { 64199f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim @Override 64299f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim public void run() { 64399f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim final IBinder b = callbacks.asBinder(); 64499f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim mConnections.remove(b); 64599f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim } 64699f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim }); 64799f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim } 648e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 649e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 6509703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private interface ServiceCallbacks { 6519703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim IBinder asBinder(); 6529703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) 6539703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException; 6549703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim void onConnectFailed() throws RemoteException; 65582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list, Bundle options) 6569703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException; 6579703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 6589703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 6599703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private class ServiceCallbacksCompat implements ServiceCallbacks { 6603f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim final Messenger mCallbacks; 6619703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 6623f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim ServiceCallbacksCompat(Messenger callbacks) { 6639703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mCallbacks = callbacks; 6649703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 6659703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 6669703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public IBinder asBinder() { 6673f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim return mCallbacks.getBinder(); 6689703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 6699703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 6709703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) 6719703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException { 67282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim if (extras == null) { 67382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim extras = new Bundle(); 67482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 67582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim extras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT); 6763f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim Bundle data = new Bundle(); 677094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putString(DATA_MEDIA_ITEM_ID, root); 678094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putParcelable(DATA_MEDIA_SESSION_TOKEN, session); 679094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putBundle(DATA_ROOT_HINTS, extras); 680094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim sendRequest(SERVICE_MSG_ON_CONNECT, data); 6819703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 6829703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 6839703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onConnectFailed() throws RemoteException { 684094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim sendRequest(SERVICE_MSG_ON_CONNECT_FAILED, null); 6859703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 6869703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 68782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list, 68882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim Bundle options) throws RemoteException { 689094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim Bundle data = new Bundle(); 690094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putString(DATA_MEDIA_ITEM_ID, mediaId); 69182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim data.putBundle(DATA_OPTIONS, options); 692ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim if (list != null) { 693094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putParcelableArrayList(DATA_MEDIA_ITEM_LIST, 694ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim list instanceof ArrayList ? (ArrayList) list : new ArrayList<>(list)); 695ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim } 696094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim sendRequest(SERVICE_MSG_ON_LOAD_CHILDREN, data); 6973f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 6983f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 699094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim private void sendRequest(int what, Bundle data) throws RemoteException { 7003f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim Message msg = Message.obtain(); 7013f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim msg.what = what; 70282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim msg.arg1 = SERVICE_VERSION_CURRENT; 7033f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim msg.setData(data); 7043f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mCallbacks.send(msg); 7059703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7069703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7079703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 708e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 709e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void onCreate() { 710e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo super.onCreate(); 711900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (Build.VERSION.SDK_INT >= 24) { 712900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mImpl = new MediaBrowserServiceImplApi24(); 713900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } else if (Build.VERSION.SDK_INT >= 21) { 7149703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mImpl = new MediaBrowserServiceImplApi21(); 7159703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } else { 7169703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mImpl = new MediaBrowserServiceImplBase(); 7179703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7189703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mImpl.onCreate(); 719e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 720e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 721e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 722e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public IBinder onBind(Intent intent) { 7239703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return mImpl.onBind(intent); 724e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 725e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 726e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 727e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 728e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 729e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 730e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 731e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get the root information for browsing by a particular client. 732e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 733e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The implementation should verify that the client package has permission 734e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * to access browse media information before returning the root id; it 735e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * should return null if the client is not allowed to access this 736e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * information. 737e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p> 738e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 739e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param clientPackageName The package name of the application which is 740e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * requesting access to browse media. 741e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param clientUid The uid of the application which is requesting access to 742e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * browse media. 743e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param rootHints An optional bundle of service-specific arguments to send 744e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * to the media browse service when connecting and retrieving the 745e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * root id for browsing, or null if none. The contents of this 746e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * bundle may affect the information returned when browsing. 747e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @return The {@link BrowserRoot} for accessing this app's content or null. 74826e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo * @see BrowserRoot#EXTRA_RECENT 74926e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo * @see BrowserRoot#EXTRA_OFFLINE 75026e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo * @see BrowserRoot#EXTRA_SUGGESTED 751e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 752e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName, 753e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo int clientUid, @Nullable Bundle rootHints); 754e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 755e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 756e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get information about the children of a media item. 757e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 758e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Implementations must call {@link Result#sendResult result.sendResult} 759e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * with the list of children. If loading the children will be an expensive 760e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * operation that should be performed on another thread, 761e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * {@link Result#detach result.detach} may be called before returning from 762e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * this function, and then {@link Result#sendResult result.sendResult} 763e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * called when the loading is complete. 764e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 765e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param parentId The id of the parent media item whose children are to be 766e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * queried. 767e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param result The Result to send the list of children to, or null if the 768e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * id is invalid. 769e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 770e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public abstract void onLoadChildren(@NonNull String parentId, 771096f2531cb790bc1106377d2da344614a3b88d39Jae Seo @NonNull Result<List<MediaBrowserCompat.MediaItem>> result); 772e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 773e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 77482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * Called to get information about the children of a media item. 77582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * <p> 77682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * Implementations must call {@link Result#sendResult result.sendResult} 77782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * with the list of children. If loading the children will be an expensive 77882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * operation that should be performed on another thread, 77982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * {@link Result#detach result.detach} may be called before returning from 78082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * this function, and then {@link Result#sendResult result.sendResult} 78182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * called when the loading is complete. 78282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * 78382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * @param parentId The id of the parent media item whose children are to be 78482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * queried. 78582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * @param result The Result to send the list of children to, or null if the 78682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * id is invalid. 78782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * @param options A bundle of service-specific arguments sent from the media 78882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * browse. The information returned through the result should be 78982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * affected by the contents of this bundle. 79082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim */ 79182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim public void onLoadChildren(@NonNull String parentId, 79282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim @NonNull Result<List<MediaBrowserCompat.MediaItem>> result, @NonNull Bundle options) { 79382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim // To support backward compatibility, when the implementation of MediaBrowserService doesn't 79482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim // override onLoadChildren() with options, onLoadChildren() without options will be used 79582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim // instead, and the options will be applied in the implementation of result.onResultSent(). 79682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim result.setFlags(RESULT_FLAG_OPTION_NOT_HANDLED); 79782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim onLoadChildren(parentId, result); 79882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 79982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 80082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim /** 801e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get information about a specific media item. 802e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 803e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Implementations must call {@link Result#sendResult result.sendResult}. If 804e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * loading the item will be an expensive operation {@link Result#detach 805e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * result.detach} may be called before returning from this function, and 806e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * then {@link Result#sendResult result.sendResult} called when the item has 807e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * been loaded. 808e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 809e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The default implementation sends a null result. 810e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 811fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * @param itemId The id for the specific {@link MediaBrowserCompat.MediaItem}. 812e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param result The Result to send the item to, or null if the id is 813e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * invalid. 814e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 815096f2531cb790bc1106377d2da344614a3b88d39Jae Seo public void onLoadItem(String itemId, Result<MediaBrowserCompat.MediaItem> result) { 816e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo result.sendResult(null); 817e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 818e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 819e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 820e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Call to set the media session. 821e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 822e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * This should be called as soon as possible during the service's startup. 823e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * It may only be called once. 824e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 825096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @param token The token for the service's {@link MediaSessionCompat}. 826e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 8277a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void setSessionToken(MediaSessionCompat.Token token) { 828e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (token == null) { 829e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("Session token may not be null."); 830e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 831e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSession != null) { 832e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("The session token has already been set."); 833e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 834e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mSession = token; 8357a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mImpl.setSessionToken(token); 836e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 837e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 838e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 839e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Gets the session token, or null if it has not yet been created 840e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * or if it has been destroyed. 841e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 842e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public @Nullable MediaSessionCompat.Token getSessionToken() { 843e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mSession; 844e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 845e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 846e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 847fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * Gets the root hints sent from the currently connected {@link MediaBrowserCompat}. 848fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * Note that this will return null when connected to {@link android.media.browse.MediaBrowser} 849fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * and running on API 23 or lower. 850fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * 851fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * @throws IllegalStateException If this method is called outside of {@link #onLoadChildren} 852fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * or {@link #onLoadItem} 853fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim */ 854fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public final Bundle getBrowserRootHints() { 855fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return mImpl.getBrowserRootHints(); 856fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 857fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim 858fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim /** 859e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Notifies all connected media browsers that the children of 860e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * the specified parent id have changed in some way. 861e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * This will cause browsers to fetch subscribed content again. 862e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 863e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param parentId The id of the parent media item whose 864e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * children changed. 865e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 86682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim public void notifyChildrenChanged(@NonNull String parentId) { 867900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (parentId == null) { 868900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged"); 869900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 870900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mImpl.notifyChildrenChanged(parentId, null); 87182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 87282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 87382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim /** 87482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * Notifies all connected media browsers that the children of 87582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * the specified parent id have changed in some way. 87682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * This will cause browsers to fetch subscribed content again. 87782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * 87882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * @param parentId The id of the parent media item whose 87982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * children changed. 88082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * @param options A bundle of service-specific arguments to send 88182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * to the media browse. The contents of this bundle may 88282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * contain the information about the change. 88382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim */ 88482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim public void notifyChildrenChanged(@NonNull String parentId, @NonNull Bundle options) { 885e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (parentId == null) { 886e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged"); 887e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 888900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (options == null) { 889900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim throw new IllegalArgumentException("options cannot be null in notifyChildrenChanged"); 890900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 891900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mImpl.notifyChildrenChanged(parentId, options); 892e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 893e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 894e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 895e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Return whether the given package is one of the ones that is owned by the uid. 896e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 897e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean isValidPackage(String pkg, int uid) { 898e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (pkg == null) { 899e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return false; 900e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 901e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final PackageManager pm = getPackageManager(); 902e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final String[] packages = pm.getPackagesForUid(uid); 903e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final int N = packages.length; 904e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo for (int i=0; i<N; i++) { 905e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (packages[i].equals(pkg)) { 906e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return true; 907e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 908e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 909e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return false; 910e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 911e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 912e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 913e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Save the subscription and if it is a new subscription send the results. 914e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 9157a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim private void addSubscription(String id, ConnectionRecord connection, IBinder token, 9167a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim Bundle options) { 917e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // Save the subscription 9187a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id); 9197a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (callbackList == null) { 9207a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim callbackList = new ArrayList<>(); 92182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 9227a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim for (Pair<IBinder, Bundle> callback : callbackList) { 9237a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (token == callback.first 9247a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim && MediaBrowserCompatUtils.areSameOptions(options, callback.second)) { 92582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim return; 92682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 92782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 9287a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim callbackList.add(new Pair<>(token, options)); 9297a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim connection.subscriptions.put(id, callbackList); 930e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // send the results 93182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim performLoadChildren(id, connection, options); 93282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 93382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 93482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim /** 93582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * Remove the subscription. 93682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim */ 9377a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim private boolean removeSubscription(String id, ConnectionRecord connection, IBinder token) { 9387a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (token == null) { 9397a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return connection.subscriptions.remove(id) != null; 9407a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 94182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim boolean removed = false; 9427a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id); 9437a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (callbackList != null) { 9447a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim for (Pair<IBinder, Bundle> callback : callbackList) { 9457a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (token == callback.first) { 94682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim removed = true; 9477a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim callbackList.remove(callback); 94882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 94982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 9507a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (callbackList.size() == 0) { 95182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim connection.subscriptions.remove(id); 95282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 95382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 95482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim return removed; 955e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 956e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 957e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 958e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Call onLoadChildren and then send the results back to the connection. 959e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 960e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Callers must make sure that this connection is still connected. 961e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 96282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim private void performLoadChildren(final String parentId, final ConnectionRecord connection, 96382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim final Bundle options) { 964096f2531cb790bc1106377d2da344614a3b88d39Jae Seo final Result<List<MediaBrowserCompat.MediaItem>> result 965096f2531cb790bc1106377d2da344614a3b88d39Jae Seo = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) { 966e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 967900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim void onResultSent(List<MediaBrowserCompat.MediaItem> list, @ResultFlags int flags) { 968e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mConnections.get(connection.callbacks.asBinder()) != connection) { 9697a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (DEBUG) { 970e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.d(TAG, "Not sending onLoadChildren result for connection that has" 971e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been disconnected. pkg=" + connection.pkg + " id=" + parentId); 972e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 973e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 974e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 975e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 97682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim List<MediaBrowserCompat.MediaItem> filteredList = 977900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim (flags & RESULT_FLAG_OPTION_NOT_HANDLED) != 0 9787a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim ? applyOptions(list, options) : list; 979e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo try { 98082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim connection.callbacks.onLoadChildren(parentId, filteredList, options); 981e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } catch (RemoteException ex) { 982e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // The other side is in the process of crashing. 983e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId 984e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " package=" + connection.pkg); 985e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 986e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 987e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }; 988e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 989fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim mCurConnection = connection; 99082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim if (options == null) { 99182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim onLoadChildren(parentId, result); 99282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } else { 99382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim onLoadChildren(parentId, result, options); 99482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 995fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim mCurConnection = null; 996e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 997e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!result.isDone()) { 998e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("onLoadChildren must call detach() or sendResult()" 999e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " before returning for package=" + connection.pkg + " id=" + parentId); 1000e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1001e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1002e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 100382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim private List<MediaBrowserCompat.MediaItem> applyOptions(List<MediaBrowserCompat.MediaItem> list, 100482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim final Bundle options) { 10057a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (list == null) { 10067a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return null; 10077a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 100882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim int page = options.getInt(MediaBrowserCompat.EXTRA_PAGE, -1); 100982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim int pageSize = options.getInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, -1); 101082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim if (page == -1 && pageSize == -1) { 101182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim return list; 101282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 10137a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim int fromIndex = pageSize * page; 101482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim int toIndex = fromIndex + pageSize; 10157a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (page < 0 || pageSize < 1 || fromIndex >= list.size()) { 10167a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return Collections.EMPTY_LIST; 101782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 101882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim if (toIndex > list.size()) { 101982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim toIndex = list.size(); 102082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 102182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim return list.subList(fromIndex, toIndex); 102282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 102382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 1024fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim private void performLoadItem(String itemId, ConnectionRecord connection, 1025fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim final ResultReceiver receiver) { 1026096f2531cb790bc1106377d2da344614a3b88d39Jae Seo final Result<MediaBrowserCompat.MediaItem> result = 1027096f2531cb790bc1106377d2da344614a3b88d39Jae Seo new Result<MediaBrowserCompat.MediaItem>(itemId) { 1028a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim @Override 1029900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim void onResultSent(MediaBrowserCompat.MediaItem item, @ResultFlags int flags) { 1030a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim Bundle bundle = new Bundle(); 1031a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim bundle.putParcelable(KEY_MEDIA_ITEM, item); 1032a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim receiver.send(0, bundle); 1033a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim } 1034a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim }; 1035e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1036fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim mCurConnection = connection; 1037fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim onLoadItem(itemId, result); 1038fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim mCurConnection = null; 1039e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1040e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!result.isDone()) { 1041e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("onLoadItem must call detach() or sendResult()" 1042e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " before returning for id=" + itemId); 1043e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1044e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1045e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1046e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 1047e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Contains information that the browser service needs to send to the client 1048e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * when first connected. 1049e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1050e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public static final class BrowserRoot { 10518e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo /** 10528e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * The lookup key for a boolean that indicates whether the browser service should return a 10538e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * browser root for recently played media items. 10548e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 10558e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>When creating a media browser for a given media browser service, this key can be 10568e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * supplied as a root hint for retrieving media items that are recently played. 10578e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * If the media browser service can provide such media items, the implementation must return 10588e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back. 10598e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 10608e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>The root hint may contain multiple keys. 10618e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 10628e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_OFFLINE 10638e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_SUGGESTED 10648e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo */ 10658e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo public static final String EXTRA_RECENT = "android.service.media.extra.RECENT"; 10668e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo 10678e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo /** 10688e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * The lookup key for a boolean that indicates whether the browser service should return a 10698e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * browser root for offline media items. 10708e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 10718e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>When creating a media browser for a given media browser service, this key can be 10728e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * supplied as a root hint for retrieving media items that are can be played without an 10738e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * internet connection. 10748e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * If the media browser service can provide such media items, the implementation must return 10758e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back. 10768e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 10778e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>The root hint may contain multiple keys. 10788e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 10798e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_RECENT 10808e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_SUGGESTED 10818e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo */ 10828e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE"; 10838e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo 10848e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo /** 10858e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * The lookup key for a boolean that indicates whether the browser service should return a 10868e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * browser root for suggested media items. 10878e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 10888e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>When creating a media browser for a given media browser service, this key can be 10898e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * supplied as a root hint for retrieving the media items suggested by the media browser 10909763c3d83aeb160ad7c52f6e48aa4806477f1de0Jae Seo * service. The list of media items passed in {@link android.support.v4.media.MediaBrowserCompat.SubscriptionCallback#onChildrenLoaded(String, List)} 10919763c3d83aeb160ad7c52f6e48aa4806477f1de0Jae Seo * is considered ordered by relevance, first being the top suggestion. 10928e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * If the media browser service can provide such media items, the implementation must return 10938e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back. 10948e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 10958e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>The root hint may contain multiple keys. 10968e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 10978e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_RECENT 10988e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_OFFLINE 10998e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo */ 11008e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED"; 11018e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo 1102e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final private String mRootId; 1103e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final private Bundle mExtras; 1104e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1105e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 1106e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Constructs a browser root. 1107e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param rootId The root id for browsing. 1108e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param extras Any extras about the browser service. 1109e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1110e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) { 1111e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (rootId == null) { 1112e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " + 1113e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo "Use null for BrowserRoot instead."); 1114e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1115e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mRootId = rootId; 1116e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mExtras = extras; 1117e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1118e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1119e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 1120e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Gets the root id for browsing. 1121e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1122e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public String getRootId() { 1123e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mRootId; 1124e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1125e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1126e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 112723471681e408dfe4e44975e13e7575ab5a04bc8cJae Seo * Gets any extras about the browser service. 1128e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1129e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public Bundle getExtras() { 1130e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mExtras; 1131e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1132e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1133e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo} 1134