MediaBrowserServiceCompat.java revision c39d9c75590eca86a5e7e32a8824ba04a0d42e9b
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 19c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport static android.support.annotation.RestrictTo.Scope.GROUP_ID; 207584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.CLIENT_MSG_ADD_SUBSCRIPTION; 217584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.CLIENT_MSG_CONNECT; 227584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.CLIENT_MSG_DISCONNECT; 237584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.CLIENT_MSG_GET_MEDIA_ITEM; 247584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.CLIENT_MSG_REGISTER_CALLBACK_MESSENGER; 257584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.CLIENT_MSG_REMOVE_SUBSCRIPTION; 267584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.CLIENT_MSG_UNREGISTER_CALLBACK_MESSENGER; 277584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.DATA_CALLBACK_TOKEN; 287584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.DATA_CALLING_UID; 297584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.DATA_MEDIA_ITEM_ID; 307584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.DATA_MEDIA_ITEM_LIST; 317584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.DATA_MEDIA_SESSION_TOKEN; 327584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.DATA_OPTIONS; 337584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.DATA_PACKAGE_NAME; 347584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.DATA_RESULT_RECEIVER; 357584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.DATA_ROOT_HINTS; 367584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.EXTRA_CLIENT_VERSION; 377584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.EXTRA_MESSENGER_BINDER; 387584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.EXTRA_SERVICE_VERSION; 397584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_CONNECT; 407584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_CONNECT_FAILED; 417584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.SERVICE_MSG_ON_LOAD_CHILDREN; 427584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seoimport static android.support.v4.media.MediaBrowserProtocol.SERVICE_VERSION_CURRENT; 437584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seo 44e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.app.Service; 45e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.content.Intent; 46e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.content.pm.PackageManager; 47e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Binder; 489703a1e215168b6b580430ec490ca616b6490c80Sungsoo Limimport android.os.Build; 49e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Bundle; 50e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Handler; 51e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.IBinder; 523f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Limimport android.os.Message; 533f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Limimport android.os.Messenger; 549703a1e215168b6b580430ec490ca616b6490c80Sungsoo Limimport android.os.Parcel; 55e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.RemoteException; 5682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport android.support.annotation.IntDef; 57e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.NonNull; 58e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.Nullable; 59c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo; 6082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Limimport android.support.v4.app.BundleCompat; 61e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.media.session.MediaSessionCompat; 62ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Limimport android.support.v4.os.BuildCompat; 63e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.os.ResultReceiver; 64e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.util.ArrayMap; 657a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Limimport android.support.v4.util.Pair; 66e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.text.TextUtils; 67e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.util.Log; 68e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 69e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.io.FileDescriptor; 70e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.io.PrintWriter; 7182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport java.lang.annotation.Retention; 7282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport java.lang.annotation.RetentionPolicy; 739703a1e215168b6b580430ec490ca616b6490c80Sungsoo Limimport java.util.ArrayList; 7482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport java.util.Collections; 7582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Limimport java.util.HashMap; 767528c2286abed5012e9759e3b122cfcf5e5b54bfSungsoo Limimport java.util.Iterator; 77e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.util.List; 78e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 79e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo/** 80e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Base class for media browse services. 81e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 82e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Media browse services enable applications to browse media content provided by an application 8382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * and ask the application to start playing it. They may also be used to control content that 84096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * is already playing by way of a {@link MediaSessionCompat}. 85e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p> 86e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 87e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * To extend this class, you must declare the service in your manifest file with 88e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * an intent filter with the {@link #SERVICE_INTERFACE} action. 89e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 90e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * For example: 91e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p><pre> 92096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * <service android:name=".MyMediaBrowserServiceCompat" 93e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * android:label="@string/service_name" > 94e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <intent-filter> 959703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim * <action android:name="android.media.browse.MediaBrowserService" /> 96e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </intent-filter> 97e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </service> 98e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </pre> 99e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 100096f2531cb790bc1106377d2da344614a3b88d39Jae Seopublic abstract class MediaBrowserServiceCompat extends Service { 101b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas static final String TAG = "MBServiceCompat"; 102b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 103e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1049703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private MediaBrowserServiceImpl mImpl; 1059703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 106e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 107e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The {@link Intent} that must be declared as handled by the service. 108e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1099703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"; 110e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 111e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 112e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * A key for passing the MediaItem to the ResultReceiver in getItem. 113e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 114e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @hide 115e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 116c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette @RestrictTo(GROUP_ID) 117e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public static final String KEY_MEDIA_ITEM = "media_item"; 118e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 119b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas static final int RESULT_FLAG_OPTION_NOT_HANDLED = 0x00000001; 1207ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo static final int RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED = 0x00000002; 12182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 12282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim /** @hide */ 123c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viverette @RestrictTo(GROUP_ID) 12482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim @Retention(RetentionPolicy.SOURCE) 1257ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED, 1267ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED }) 12782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim private @interface ResultFlags { } 12882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 129b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>(); 130b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas ConnectionRecord mCurConnection; 131b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas final ServiceHandler mHandler = new ServiceHandler(); 132e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo MediaSessionCompat.Token mSession; 133e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1349703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim interface MediaBrowserServiceImpl { 1353f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim void onCreate(); 1369703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim IBinder onBind(Intent intent); 1377a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim void setSessionToken(MediaSessionCompat.Token token); 138900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim void notifyChildrenChanged(final String parentId, final Bundle options); 139fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim Bundle getBrowserRootHints(); 1409703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1419703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1429703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim class MediaBrowserServiceImplBase implements MediaBrowserServiceImpl { 1433f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim private Messenger mMessenger; 1449703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1459703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 1469703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onCreate() { 1473f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mMessenger = new Messenger(mHandler); 1489703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1499703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1509703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 1519703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public IBinder onBind(Intent intent) { 1529703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (SERVICE_INTERFACE.equals(intent.getAction())) { 1533f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim return mMessenger.getBinder(); 1549703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1559703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return null; 1569703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1577a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim 1587a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim @Override 1597a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void setSessionToken(final MediaSessionCompat.Token token) { 1607a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mHandler.post(new Runnable() { 1617a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim @Override 1627a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void run() { 1637528c2286abed5012e9759e3b122cfcf5e5b54bfSungsoo Lim Iterator<ConnectionRecord> iter = mConnections.values().iterator(); 1647528c2286abed5012e9759e3b122cfcf5e5b54bfSungsoo Lim while (iter.hasNext()){ 1657528c2286abed5012e9759e3b122cfcf5e5b54bfSungsoo Lim ConnectionRecord connection = iter.next(); 1667a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim try { 1677a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim connection.callbacks.onConnect(connection.root.getRootId(), token, 1687a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim connection.root.getExtras()); 1697a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } catch (RemoteException e) { 1707a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid."); 1717528c2286abed5012e9759e3b122cfcf5e5b54bfSungsoo Lim iter.remove(); 1727a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 1737a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 1747a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 1757a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim }); 1767a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 177900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 178900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 179900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void notifyChildrenChanged(@NonNull final String parentId, final Bundle options) { 180900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mHandler.post(new Runnable() { 181900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 182900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void run() { 183900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim for (IBinder binder : mConnections.keySet()) { 184900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim ConnectionRecord connection = mConnections.get(binder); 185900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim List<Pair<IBinder, Bundle>> callbackList = 186900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim connection.subscriptions.get(parentId); 187900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (callbackList != null) { 188900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim for (Pair<IBinder, Bundle> callback : callbackList) { 189900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (MediaBrowserCompatUtils.hasDuplicatedItems( 190900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim options, callback.second)) { 191900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim performLoadChildren(parentId, connection, callback.second); 192900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 193900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 194900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 195900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 196900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 197900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim }); 198900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 199fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim 200fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim @Override 201fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public Bundle getBrowserRootHints() { 202fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim if (mCurConnection == null) { 203fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim throw new IllegalStateException("This should be called inside of onLoadChildren or" 204fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim + " onLoadItem methods"); 205fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 206fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints); 207fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 2089703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 2099703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 2107a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim class MediaBrowserServiceImplApi21 implements MediaBrowserServiceImpl, 2117a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompatApi21.ServiceCompatProxy { 212900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim Object mServiceObj; 213900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim Messenger mMessenger; 2149703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 2159703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 2169703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onCreate() { 2177a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceObj = MediaBrowserServiceCompatApi21.createService( 2187a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompat.this, this); 2197a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompatApi21.onCreate(mServiceObj); 2209703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 2219703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 2229703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 2239703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public IBinder onBind(Intent intent) { 2249703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return MediaBrowserServiceCompatApi21.onBind(mServiceObj, intent); 2259703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 22682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim 22782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim @Override 2287a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void setSessionToken(MediaSessionCompat.Token token) { 2297a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompatApi21.setSessionToken(mServiceObj, token.getToken()); 23082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 23182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim 23282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim @Override 233900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void notifyChildrenChanged(final String parentId, final Bundle options) { 234900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (mMessenger == null) { 235900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompatApi21.notifyChildrenChanged(mServiceObj, parentId); 236900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } else { 237900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mHandler.post(new Runnable() { 238900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 239900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void run() { 240900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim for (IBinder binder : mConnections.keySet()) { 241900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim ConnectionRecord connection = mConnections.get(binder); 242900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim List<Pair<IBinder, Bundle>> callbackList = 243900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim connection.subscriptions.get(parentId); 244900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (callbackList != null) { 245900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim for (Pair<IBinder, Bundle> callback : callbackList) { 246900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (MediaBrowserCompatUtils.hasDuplicatedItems( 247900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim options, callback.second)) { 248900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim performLoadChildren(parentId, connection, callback.second); 249900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 250900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 251900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 252900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 253900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 254900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim }); 255900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 256900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 257900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 258900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 259fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public Bundle getBrowserRootHints() { 260fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim if (mMessenger == null) { 261fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim // TODO: Handle getBrowserRootHints when connected with framework MediaBrowser. 262fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return null; 263fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 264fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim if (mCurConnection == null) { 265fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim throw new IllegalStateException("This should be called inside of onLoadChildren or" 266fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim + " onLoadItem methods"); 267fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 268fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints); 269fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 270fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim 271fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim @Override 2727a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public MediaBrowserServiceCompatApi21.BrowserRoot onGetRoot( 2737a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim String clientPackageName, int clientUid, Bundle rootHints) { 2747a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim Bundle rootExtras = null; 2757a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (rootHints != null && rootHints.getInt(EXTRA_CLIENT_VERSION, 0) != 0) { 2767a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim rootHints.remove(EXTRA_CLIENT_VERSION); 2777a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mMessenger = new Messenger(mHandler); 2787a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim rootExtras = new Bundle(); 2797a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim rootExtras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT); 2807a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim BundleCompat.putBinder(rootExtras, EXTRA_MESSENGER_BINDER, mMessenger.getBinder()); 2817a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 2827a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim BrowserRoot root = MediaBrowserServiceCompat.this.onGetRoot( 2837a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim clientPackageName, clientUid, rootHints); 2847a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (root == null) { 2857a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return null; 2867a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 2877a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (rootExtras == null) { 2887a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim rootExtras = root.getExtras(); 2897a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } else if (root.getExtras() != null) { 2907a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim rootExtras.putAll(root.getExtras()); 2917a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 2927a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return new MediaBrowserServiceCompatApi21.BrowserRoot( 2937a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim root.getRootId(), rootExtras); 29482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 29501b922eddadab50910ce289921001a63855e1f8eSungsoo Lim 29601b922eddadab50910ce289921001a63855e1f8eSungsoo Lim @Override 2977a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void onLoadChildren(String parentId, 2982e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim final MediaBrowserServiceCompatApi21.ResultWrapper<List<Parcel>> resultWrapper) { 2997a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim final Result<List<MediaBrowserCompat.MediaItem>> result 3007a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) { 3017a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim @Override 302900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim void onResultSent(List<MediaBrowserCompat.MediaItem> list, @ResultFlags int flags) { 3037a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim List<Parcel> parcelList = null; 3047a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (list != null) { 3057a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim parcelList = new ArrayList<>(); 3067a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim for (MediaBrowserCompat.MediaItem item : list) { 3077a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim Parcel parcel = Parcel.obtain(); 3087a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim item.writeToParcel(parcel, 0); 3097a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim parcelList.add(parcel); 3107a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 3117a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 3127a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim resultWrapper.sendResult(parcelList); 3137a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 3147a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim 3157a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim @Override 3167a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void detach() { 3177a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim resultWrapper.detach(); 3187a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 3197a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim }; 3207a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompat.this.onLoadChildren(parentId, result); 32101b922eddadab50910ce289921001a63855e1f8eSungsoo Lim } 32201b922eddadab50910ce289921001a63855e1f8eSungsoo Lim } 32301b922eddadab50910ce289921001a63855e1f8eSungsoo Lim 3242e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim class MediaBrowserServiceImplApi23 extends MediaBrowserServiceImplApi21 implements 3252e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim MediaBrowserServiceCompatApi23.ServiceCompatProxy { 3262e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim @Override 3272e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim public void onCreate() { 3282e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim mServiceObj = MediaBrowserServiceCompatApi23.createService( 3292e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim MediaBrowserServiceCompat.this, this); 3302e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim MediaBrowserServiceCompatApi21.onCreate(mServiceObj); 3312e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim } 3322e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim 3332e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim @Override 3342e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim public void onLoadItem(String itemId, 3352e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim final MediaBrowserServiceCompatApi21.ResultWrapper<Parcel> resultWrapper) { 3362e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim final Result<MediaBrowserCompat.MediaItem> result 3372e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim = new Result<MediaBrowserCompat.MediaItem>(itemId) { 3382e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim @Override 3392e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim void onResultSent(MediaBrowserCompat.MediaItem item, @ResultFlags int flags) { 340777d23227fb217431dc1c50b25be6ffd60999bdeSungsoo if (item == null) { 341777d23227fb217431dc1c50b25be6ffd60999bdeSungsoo resultWrapper.sendResult(null); 342777d23227fb217431dc1c50b25be6ffd60999bdeSungsoo } else { 343777d23227fb217431dc1c50b25be6ffd60999bdeSungsoo Parcel parcelItem = Parcel.obtain(); 344777d23227fb217431dc1c50b25be6ffd60999bdeSungsoo item.writeToParcel(parcelItem, 0); 345777d23227fb217431dc1c50b25be6ffd60999bdeSungsoo resultWrapper.sendResult(parcelItem); 346777d23227fb217431dc1c50b25be6ffd60999bdeSungsoo } 3472e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim } 3482e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim 3492e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim @Override 3502e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim public void detach() { 3512e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim resultWrapper.detach(); 3522e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim } 3532e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim }; 3542e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim MediaBrowserServiceCompat.this.onLoadItem(itemId, result); 3552e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim } 3562e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim } 3572e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim 3582e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim class MediaBrowserServiceImplApi24 extends MediaBrowserServiceImplApi23 implements 359900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompatApi24.ServiceCompatProxy { 360900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 361900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void onCreate() { 362900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mServiceObj = MediaBrowserServiceCompatApi24.createService( 363900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompat.this, this); 364900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompatApi21.onCreate(mServiceObj); 365900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 366900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 367900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 368900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void notifyChildrenChanged(final String parentId, final Bundle options) { 369900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (options == null) { 370900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompatApi21.notifyChildrenChanged(mServiceObj, parentId); 371900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } else { 372900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompatApi24.notifyChildrenChanged(mServiceObj, parentId, 373900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim options); 374900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 375900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 376900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 377900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 378900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void onLoadChildren(String parentId, 379900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim final MediaBrowserServiceCompatApi24.ResultWrapper resultWrapper, Bundle options) { 380900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim final Result<List<MediaBrowserCompat.MediaItem>> result 381900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) { 382900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 383900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim void onResultSent(List<MediaBrowserCompat.MediaItem> list, @ResultFlags int flags) { 384900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim List<Parcel> parcelList = null; 385900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (list != null) { 386900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim parcelList = new ArrayList<>(); 387900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim for (MediaBrowserCompat.MediaItem item : list) { 388900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim Parcel parcel = Parcel.obtain(); 389900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim item.writeToParcel(parcel, 0); 390900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim parcelList.add(parcel); 391900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 392900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 393900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim resultWrapper.sendResult(parcelList, flags); 394900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 395900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 396900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim @Override 397900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim public void detach() { 398900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim resultWrapper.detach(); 399900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 400900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim }; 401900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim MediaBrowserServiceCompat.this.onLoadChildren(parentId, result, options); 402900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 403fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim 404fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim @Override 405fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public Bundle getBrowserRootHints() { 406fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return MediaBrowserServiceCompatApi24.getBrowserRootHints(mServiceObj); 407fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 408900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 409900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim 4103f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim private final class ServiceHandler extends Handler { 4117a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim private final ServiceBinderImpl mServiceBinderImpl = new ServiceBinderImpl(); 4123f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 413b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas ServiceHandler() { 414b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas } 415b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas 4163f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim @Override 4173f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim public void handleMessage(Message msg) { 418094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim Bundle data = msg.getData(); 4193f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim switch (msg.what) { 42082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_CONNECT: 4217a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.connect(data.getString(DATA_PACKAGE_NAME), 422094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.getInt(DATA_CALLING_UID), data.getBundle(DATA_ROOT_HINTS), 4233f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 4243f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 42582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_DISCONNECT: 4267a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.disconnect(new ServiceCallbacksCompat(msg.replyTo)); 4273f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 42882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_ADD_SUBSCRIPTION: 4297a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.addSubscription(data.getString(DATA_MEDIA_ITEM_ID), 4307a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim BundleCompat.getBinder(data, DATA_CALLBACK_TOKEN), 4317a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim data.getBundle(DATA_OPTIONS), 4327a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 4333f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 43482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_REMOVE_SUBSCRIPTION: 4357a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.removeSubscription(data.getString(DATA_MEDIA_ITEM_ID), 4367a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim BundleCompat.getBinder(data, DATA_CALLBACK_TOKEN), 4377a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 4383f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 43982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_GET_MEDIA_ITEM: 4407a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.getMediaItem(data.getString(DATA_MEDIA_ITEM_ID), 441fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim (ResultReceiver) data.getParcelable(DATA_RESULT_RECEIVER), 442fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 4433f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 44416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim case CLIENT_MSG_REGISTER_CALLBACK_MESSENGER: 445fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim mServiceBinderImpl.registerCallbacks(new ServiceCallbacksCompat(msg.replyTo), 446fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim data.getBundle(DATA_ROOT_HINTS)); 44716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim break; 44899f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim case CLIENT_MSG_UNREGISTER_CALLBACK_MESSENGER: 4497a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mServiceBinderImpl.unregisterCallbacks(new ServiceCallbacksCompat(msg.replyTo)); 45099f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim break; 4513f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim default: 45282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim Log.w(TAG, "Unhandled message: " + msg 45382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim + "\n Service version: " + SERVICE_VERSION_CURRENT 45482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim + "\n Client version: " + msg.arg1); 4553f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 4563f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 4573f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 458094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim @Override 459094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 460094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim // Binder.getCallingUid() in handleMessage will return the uid of this process. 461094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim // In order to get the right calling uid, Binder.getCallingUid() should be called here. 462094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim Bundle data = msg.getData(); 463d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim data.setClassLoader(MediaBrowserCompat.class.getClassLoader()); 464094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putInt(DATA_CALLING_UID, Binder.getCallingUid()); 465094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim return super.sendMessageAtTime(msg, uptimeMillis); 466094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim } 467094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim 4683f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim public void postOrRun(Runnable r) { 4693f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim if (Thread.currentThread() == getLooper().getThread()) { 4703f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim r.run(); 4713f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } else { 4723f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim post(r); 4733f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 4743f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 4753f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 4763f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 477e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 478e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * All the info about a connection. 479e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 480e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private class ConnectionRecord { 481e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo String pkg; 482e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Bundle rootHints; 4839703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim ServiceCallbacks callbacks; 484e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo BrowserRoot root; 4857a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap(); 486b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas 487b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas ConnectionRecord() { 488b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas } 489e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 490e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 491e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 492096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * Completion handler for asynchronous callback methods in {@link MediaBrowserServiceCompat}. 493e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 494e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Each of the methods that takes one of these to send the result must call 49582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * {@link #sendResult} to respond to the caller with the given results. If those 496e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * functions return without calling {@link #sendResult}, they must instead call 497e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * {@link #detach} before returning, and then may call {@link #sendResult} when 49882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * they are done. If more than one of those methods is called, an exception will 499e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * be thrown. 500e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 501096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @see MediaBrowserServiceCompat#onLoadChildren 502096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @see MediaBrowserServiceCompat#onLoadItem 503e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 5049703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public static class Result<T> { 505e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private Object mDebug; 506e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean mDetachCalled; 507e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean mSendResultCalled; 50882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim private int mFlags; 509e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 510e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Result(Object debug) { 511e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mDebug = debug; 512e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 513e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 514e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 515e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Send the result back to the caller. 516e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 517e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void sendResult(T result) { 518e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSendResultCalled) { 519e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("sendResult() called twice for: " + mDebug); 520e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 521e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mSendResultCalled = true; 52282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim onResultSent(result, mFlags); 523e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 524e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 525e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 526e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Detach this message from the current thread and allow the {@link #sendResult} 527e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * call to happen later. 528e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 529e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void detach() { 530e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mDetachCalled) { 531e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("detach() called when detach() had already" 532e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been called for: " + mDebug); 533e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 534e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSendResultCalled) { 535e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("detach() called when sendResult() had already" 536e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been called for: " + mDebug); 537e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 538e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mDetachCalled = true; 539e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 540e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 541e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo boolean isDone() { 542e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mDetachCalled || mSendResultCalled; 543e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 544e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 54582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim void setFlags(@ResultFlags int flags) { 54682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim mFlags = flags; 54782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 54882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 549e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 550e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called when the result is sent, after assertions about not being called twice 551e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * have happened. 552e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 55382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim void onResultSent(T result, @ResultFlags int flags) { 554e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 555e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 556e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 5577a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim private class ServiceBinderImpl { 558b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas ServiceBinderImpl() { 559b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas } 560b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas 561094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim public void connect(final String pkg, final int uid, final Bundle rootHints, 5629703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ServiceCallbacks callbacks) { 563e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 564e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!isValidPackage(pkg, uid)) { 565e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid 566e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " package=" + pkg); 567e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 568e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 5693f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 5709703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 5719703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void run() { 5729703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final IBinder b = callbacks.asBinder(); 5739703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 57482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim // Clear out the old subscriptions. We are getting new ones. 5759703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mConnections.remove(b); 5769703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5779703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ConnectionRecord connection = new ConnectionRecord(); 5789703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.pkg = pkg; 5799703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.rootHints = rootHints; 5809703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.callbacks = callbacks; 5819703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5829703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.root = 5839703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim MediaBrowserServiceCompat.this.onGetRoot(pkg, uid, rootHints); 5849703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5859703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // If they didn't return something, don't allow this client. 5869703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (connection.root == null) { 5879703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.i(TAG, "No root for client " + pkg + " from service " 5889703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + getClass().getName()); 5899703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim try { 5909703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim callbacks.onConnectFailed(); 5919703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } catch (RemoteException ex) { 5929703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. " 5939703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + "pkg=" + pkg); 5949703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5959703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } else { 5969703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim try { 5979703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mConnections.put(b, connection); 5989703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (mSession != null) { 5999703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim callbacks.onConnect(connection.root.getRootId(), 6009703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mSession, connection.root.getExtras()); 601e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 6029703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } catch (RemoteException ex) { 6039703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.w(TAG, "Calling onConnect() failed. Dropping client. " 6049703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + "pkg=" + pkg); 6059703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mConnections.remove(b); 606e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 607e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 6089703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 6099703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim }); 610e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 611e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 6129703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void disconnect(final ServiceCallbacks callbacks) { 6133f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 6149703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 6159703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void run() { 6169703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final IBinder b = callbacks.asBinder(); 6179703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 61882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim // Clear out the old subscriptions. We are getting new ones. 6199703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ConnectionRecord old = mConnections.remove(b); 6209703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (old != null) { 6219703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // TODO 622e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 6239703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 6249703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim }); 625e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 626e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 6277a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void addSubscription(final String id, final IBinder token, final Bundle options, 62882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim final ServiceCallbacks callbacks) { 6293f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 6309703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 6319703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void run() { 6329703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final IBinder b = callbacks.asBinder(); 6336a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 6349703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // Get the record for the connection 6359703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ConnectionRecord connection = mConnections.get(b); 6369703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (connection == null) { 6379703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.w(TAG, "addSubscription for callback that isn't registered id=" 6389703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + id); 6399703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return; 640493571364635be0190cea8ee230a601070391e6fIan Pedowitz } 6419703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 6427a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim MediaBrowserServiceCompat.this.addSubscription(id, connection, token, options); 6439703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 6449703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim }); 645e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 646e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 6477a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void removeSubscription(final String id, final IBinder token, 64882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim final ServiceCallbacks callbacks) { 6493f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 650e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 651e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 652e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final IBinder b = callbacks.asBinder(); 653e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 654e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo ConnectionRecord connection = mConnections.get(b); 655e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (connection == null) { 656e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "removeSubscription for callback that isn't registered id=" 657e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + id); 658e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 659e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 66082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim if (!MediaBrowserServiceCompat.this.removeSubscription( 6617a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim id, connection, token)) { 662e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "removeSubscription called for " + id 663e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " which is not subscribed"); 664e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 665e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 666e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 667e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 668e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 669fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public void getMediaItem(final String mediaId, final ResultReceiver receiver, 670fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim final ServiceCallbacks callbacks) { 671e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (TextUtils.isEmpty(mediaId) || receiver == null) { 672e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 673e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 674e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 6753f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 676e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 677e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 678fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim final IBinder b = callbacks.asBinder(); 679fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim 680fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim ConnectionRecord connection = mConnections.get(b); 681fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim if (connection == null) { 682fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim Log.w(TAG, "getMediaItem for callback that isn't registered id=" + mediaId); 683fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return; 684fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 685fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim performLoadItem(mediaId, connection, receiver); 686e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 687e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 688e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 68916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim 69016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim // Used when {@link MediaBrowserProtocol#EXTRA_MESSENGER_BINDER} is used. 691fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public void registerCallbacks(final ServiceCallbacks callbacks, final Bundle rootHints) { 69216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim mHandler.postOrRun(new Runnable() { 69316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim @Override 69416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim public void run() { 69516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim final IBinder b = callbacks.asBinder(); 69616d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim // Clear out the old subscriptions. We are getting new ones. 69716d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim mConnections.remove(b); 69816d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim 69916d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim final ConnectionRecord connection = new ConnectionRecord(); 70016d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim connection.callbacks = callbacks; 701fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim connection.rootHints = rootHints; 70216d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim mConnections.put(b, connection); 70316d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim } 70416d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim }); 70516d709bad185d0d5e9bf2ba88132fb592e63041dSungsoo Lim } 70699f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim 70799f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim // Used when {@link MediaBrowserProtocol#EXTRA_MESSENGER_BINDER} is used. 70899f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim public void unregisterCallbacks(final ServiceCallbacks callbacks) { 70999f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim mHandler.postOrRun(new Runnable() { 71099f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim @Override 71199f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim public void run() { 71299f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim final IBinder b = callbacks.asBinder(); 71399f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim mConnections.remove(b); 71499f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim } 71599f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim }); 71699f783676dda9a66b2f1a576c12ee2402d8bbcd0Sungsoo Lim } 717e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 718e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 7199703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private interface ServiceCallbacks { 7209703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim IBinder asBinder(); 7219703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) 7229703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException; 7239703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim void onConnectFailed() throws RemoteException; 72482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list, Bundle options) 7259703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException; 7269703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7279703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 7289703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private class ServiceCallbacksCompat implements ServiceCallbacks { 7293f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim final Messenger mCallbacks; 7309703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 7313f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim ServiceCallbacksCompat(Messenger callbacks) { 7329703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mCallbacks = callbacks; 7339703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7349703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 73515375aa6fd54b036f97f99229aefab2822c8a1c9Aurimas Liutikas @Override 7369703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public IBinder asBinder() { 7373f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim return mCallbacks.getBinder(); 7389703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7399703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 74015375aa6fd54b036f97f99229aefab2822c8a1c9Aurimas Liutikas @Override 7419703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) 7429703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException { 74382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim if (extras == null) { 74482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim extras = new Bundle(); 74582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 74682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim extras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT); 7473f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim Bundle data = new Bundle(); 748094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putString(DATA_MEDIA_ITEM_ID, root); 749094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putParcelable(DATA_MEDIA_SESSION_TOKEN, session); 750094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putBundle(DATA_ROOT_HINTS, extras); 751094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim sendRequest(SERVICE_MSG_ON_CONNECT, data); 7529703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7539703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 75415375aa6fd54b036f97f99229aefab2822c8a1c9Aurimas Liutikas @Override 7559703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onConnectFailed() throws RemoteException { 756094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim sendRequest(SERVICE_MSG_ON_CONNECT_FAILED, null); 7579703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7589703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 75915375aa6fd54b036f97f99229aefab2822c8a1c9Aurimas Liutikas @Override 76082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list, 76182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim Bundle options) throws RemoteException { 762094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim Bundle data = new Bundle(); 763094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putString(DATA_MEDIA_ITEM_ID, mediaId); 76482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim data.putBundle(DATA_OPTIONS, options); 765ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim if (list != null) { 766094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putParcelableArrayList(DATA_MEDIA_ITEM_LIST, 767ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim list instanceof ArrayList ? (ArrayList) list : new ArrayList<>(list)); 768ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim } 769094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim sendRequest(SERVICE_MSG_ON_LOAD_CHILDREN, data); 7703f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 7713f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 772094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim private void sendRequest(int what, Bundle data) throws RemoteException { 7733f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim Message msg = Message.obtain(); 7743f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim msg.what = what; 77582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim msg.arg1 = SERVICE_VERSION_CURRENT; 7763f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim msg.setData(data); 7773f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mCallbacks.send(msg); 7789703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7799703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7809703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 781e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 782e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void onCreate() { 783e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo super.onCreate(); 784ac127f074a064c2b5e87102bd7f6c3e4a5d5cdfdSungsoo Lim if (Build.VERSION.SDK_INT >= 24 || BuildCompat.isAtLeastN()) { 785900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mImpl = new MediaBrowserServiceImplApi24(); 7862e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim } else if (Build.VERSION.SDK_INT >= 23) { 7872e7d3a28e00195c160cc4f5668e2d7f64eb590daSungsoo Lim mImpl = new MediaBrowserServiceImplApi23(); 788900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } else if (Build.VERSION.SDK_INT >= 21) { 7899703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mImpl = new MediaBrowserServiceImplApi21(); 7909703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } else { 7919703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mImpl = new MediaBrowserServiceImplBase(); 7929703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 7939703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mImpl.onCreate(); 794e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 795e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 796e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 797e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public IBinder onBind(Intent intent) { 7989703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return mImpl.onBind(intent); 799e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 800e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 801e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 802e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 803e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 804e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 805e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 806e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get the root information for browsing by a particular client. 807e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 808e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The implementation should verify that the client package has permission 809e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * to access browse media information before returning the root id; it 810e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * should return null if the client is not allowed to access this 811e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * information. 812e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p> 813e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 814e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param clientPackageName The package name of the application which is 815e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * requesting access to browse media. 816e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param clientUid The uid of the application which is requesting access to 817e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * browse media. 818e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param rootHints An optional bundle of service-specific arguments to send 819e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * to the media browse service when connecting and retrieving the 820e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * root id for browsing, or null if none. The contents of this 821e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * bundle may affect the information returned when browsing. 822e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @return The {@link BrowserRoot} for accessing this app's content or null. 82326e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo * @see BrowserRoot#EXTRA_RECENT 82426e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo * @see BrowserRoot#EXTRA_OFFLINE 82526e88318c8f69f62f41591b0df0720cc48b4ce11Jae Seo * @see BrowserRoot#EXTRA_SUGGESTED 826ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * @see BrowserRoot#EXTRA_SUGGESTION_KEYWORDS 827e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 828e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName, 829e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo int clientUid, @Nullable Bundle rootHints); 830e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 831e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 832e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get information about the children of a media item. 833e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 834e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Implementations must call {@link Result#sendResult result.sendResult} 835e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * with the list of children. If loading the children will be an expensive 836e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * operation that should be performed on another thread, 837e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * {@link Result#detach result.detach} may be called before returning from 838e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * this function, and then {@link Result#sendResult result.sendResult} 839e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * called when the loading is complete. 840e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 841e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param parentId The id of the parent media item whose children are to be 842e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * queried. 843e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param result The Result to send the list of children to, or null if the 844e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * id is invalid. 845e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 846e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public abstract void onLoadChildren(@NonNull String parentId, 847096f2531cb790bc1106377d2da344614a3b88d39Jae Seo @NonNull Result<List<MediaBrowserCompat.MediaItem>> result); 848e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 849e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 85082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * Called to get information about the children of a media item. 85182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * <p> 85282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * Implementations must call {@link Result#sendResult result.sendResult} 85382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * with the list of children. If loading the children will be an expensive 85482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * operation that should be performed on another thread, 85582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * {@link Result#detach result.detach} may be called before returning from 85682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * this function, and then {@link Result#sendResult result.sendResult} 85782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * called when the loading is complete. 85882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * 85982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * @param parentId The id of the parent media item whose children are to be 86082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * queried. 86182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * @param result The Result to send the list of children to, or null if the 86282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * id is invalid. 86382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * @param options A bundle of service-specific arguments sent from the media 86482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * browse. The information returned through the result should be 86582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * affected by the contents of this bundle. 86682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim */ 86782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim public void onLoadChildren(@NonNull String parentId, 86882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim @NonNull Result<List<MediaBrowserCompat.MediaItem>> result, @NonNull Bundle options) { 86982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim // To support backward compatibility, when the implementation of MediaBrowserService doesn't 87082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim // override onLoadChildren() with options, onLoadChildren() without options will be used 87182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim // instead, and the options will be applied in the implementation of result.onResultSent(). 87282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim result.setFlags(RESULT_FLAG_OPTION_NOT_HANDLED); 87382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim onLoadChildren(parentId, result); 87482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 87582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 87682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim /** 877e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get information about a specific media item. 878e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 879e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Implementations must call {@link Result#sendResult result.sendResult}. If 880e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * loading the item will be an expensive operation {@link Result#detach 881e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * result.detach} may be called before returning from this function, and 882e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * then {@link Result#sendResult result.sendResult} called when the item has 883e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * been loaded. 8847ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo * </p><p> 8857ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo * When the given {@code itemId} is invalid, implementations must call 8867ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo * {@link Result#sendResult result.sendResult} with {@code null}. 8877ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo * </p><p> 8887ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo * The default implementation will invoke {@link MediaBrowserCompat.ItemCallback#onError}. 889e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 890fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * @param itemId The id for the specific {@link MediaBrowserCompat.MediaItem}. 891e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param result The Result to send the item to, or null if the id is 892e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * invalid. 893e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 894096f2531cb790bc1106377d2da344614a3b88d39Jae Seo public void onLoadItem(String itemId, Result<MediaBrowserCompat.MediaItem> result) { 8957ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo result.setFlags(RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED); 896e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo result.sendResult(null); 897e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 898e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 899e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 900e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Call to set the media session. 901e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 902e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * This should be called as soon as possible during the service's startup. 903e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * It may only be called once. 904e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 905096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @param token The token for the service's {@link MediaSessionCompat}. 906e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 9077a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim public void setSessionToken(MediaSessionCompat.Token token) { 908e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (token == null) { 909e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("Session token may not be null."); 910e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 911e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSession != null) { 912e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("The session token has already been set."); 913e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 914e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mSession = token; 9157a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim mImpl.setSessionToken(token); 916e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 917e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 918e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 919e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Gets the session token, or null if it has not yet been created 920e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * or if it has been destroyed. 921e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 922e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public @Nullable MediaSessionCompat.Token getSessionToken() { 923e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mSession; 924e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 925e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 926e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 927fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * Gets the root hints sent from the currently connected {@link MediaBrowserCompat}. 9287584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seo * The root hints are service-specific arguments included in an optional bundle sent to the 9297584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seo * media browser service when connecting and retrieving the root id for browsing, or null if 9307584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seo * none. The contents of this bundle may affect the information returned when browsing. 9317584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seo * <p> 932fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * Note that this will return null when connected to {@link android.media.browse.MediaBrowser} 933fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * and running on API 23 or lower. 934fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * 935fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * @throws IllegalStateException If this method is called outside of {@link #onLoadChildren} 936fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim * or {@link #onLoadItem} 9377584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seo * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_RECENT 9387584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seo * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_OFFLINE 9397584aa62c9a0b01631c70512899a51ea7ccdc27eJae Seo * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_SUGGESTED 940ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * @see MediaBrowserServiceCompat.BrowserRoot#EXTRA_SUGGESTION_KEYWORDS 941fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim */ 942fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim public final Bundle getBrowserRootHints() { 943fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim return mImpl.getBrowserRootHints(); 944fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim } 945fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim 946fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim /** 947e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Notifies all connected media browsers that the children of 948e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * the specified parent id have changed in some way. 949e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * This will cause browsers to fetch subscribed content again. 950e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 951e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param parentId The id of the parent media item whose 952e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * children changed. 953e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 95482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim public void notifyChildrenChanged(@NonNull String parentId) { 955900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (parentId == null) { 956900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged"); 957900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 958900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mImpl.notifyChildrenChanged(parentId, null); 95982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 96082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 96182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim /** 96282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * Notifies all connected media browsers that the children of 96382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * the specified parent id have changed in some way. 96482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * This will cause browsers to fetch subscribed content again. 96582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * 96682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * @param parentId The id of the parent media item whose 96782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * children changed. 96882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * @param options A bundle of service-specific arguments to send 96982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * to the media browse. The contents of this bundle may 97082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * contain the information about the change. 97182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim */ 97282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim public void notifyChildrenChanged(@NonNull String parentId, @NonNull Bundle options) { 973e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (parentId == null) { 974e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged"); 975e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 976900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim if (options == null) { 977900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim throw new IllegalArgumentException("options cannot be null in notifyChildrenChanged"); 978900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim } 979900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim mImpl.notifyChildrenChanged(parentId, options); 980e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 981e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 982e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 983e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Return whether the given package is one of the ones that is owned by the uid. 984e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 985b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas boolean isValidPackage(String pkg, int uid) { 986e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (pkg == null) { 987e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return false; 988e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 989e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final PackageManager pm = getPackageManager(); 990e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final String[] packages = pm.getPackagesForUid(uid); 991e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final int N = packages.length; 992e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo for (int i=0; i<N; i++) { 993e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (packages[i].equals(pkg)) { 994e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return true; 995e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 996e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 997e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return false; 998e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 999e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1000e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 1001e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Save the subscription and if it is a new subscription send the results. 1002e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1003b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas void addSubscription(String id, ConnectionRecord connection, IBinder token, 10047a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim Bundle options) { 1005e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // Save the subscription 10067a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id); 10077a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (callbackList == null) { 10087a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim callbackList = new ArrayList<>(); 100982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 10107a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim for (Pair<IBinder, Bundle> callback : callbackList) { 10117a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (token == callback.first 10127a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim && MediaBrowserCompatUtils.areSameOptions(options, callback.second)) { 101382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim return; 101482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 101582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 10167a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim callbackList.add(new Pair<>(token, options)); 10177a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim connection.subscriptions.put(id, callbackList); 1018e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // send the results 101982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim performLoadChildren(id, connection, options); 102082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 102182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 102282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim /** 102382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim * Remove the subscription. 102482387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim */ 1025b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas boolean removeSubscription(String id, ConnectionRecord connection, IBinder token) { 10267a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (token == null) { 10277a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return connection.subscriptions.remove(id) != null; 10287a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 102982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim boolean removed = false; 10307a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id); 10317a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (callbackList != null) { 10327528c2286abed5012e9759e3b122cfcf5e5b54bfSungsoo Lim Iterator<Pair<IBinder, Bundle>> iter = callbackList.iterator(); 10337528c2286abed5012e9759e3b122cfcf5e5b54bfSungsoo Lim while (iter.hasNext()){ 10347528c2286abed5012e9759e3b122cfcf5e5b54bfSungsoo Lim if (token == iter.next().first) { 103582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim removed = true; 10367528c2286abed5012e9759e3b122cfcf5e5b54bfSungsoo Lim iter.remove(); 103782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 103882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 10397a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (callbackList.size() == 0) { 104082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim connection.subscriptions.remove(id); 104182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 104282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 104382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim return removed; 1044e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1045e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1046e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 1047e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Call onLoadChildren and then send the results back to the connection. 1048e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 1049e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Callers must make sure that this connection is still connected. 1050e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1051b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas void performLoadChildren(final String parentId, final ConnectionRecord connection, 105282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim final Bundle options) { 1053096f2531cb790bc1106377d2da344614a3b88d39Jae Seo final Result<List<MediaBrowserCompat.MediaItem>> result 1054096f2531cb790bc1106377d2da344614a3b88d39Jae Seo = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) { 1055e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 1056900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim void onResultSent(List<MediaBrowserCompat.MediaItem> list, @ResultFlags int flags) { 1057e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mConnections.get(connection.callbacks.asBinder()) != connection) { 10587a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (DEBUG) { 1059e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.d(TAG, "Not sending onLoadChildren result for connection that has" 1060e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been disconnected. pkg=" + connection.pkg + " id=" + parentId); 1061e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1062e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 1063e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1064e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 106582387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim List<MediaBrowserCompat.MediaItem> filteredList = 1066900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim (flags & RESULT_FLAG_OPTION_NOT_HANDLED) != 0 10677a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim ? applyOptions(list, options) : list; 1068e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo try { 106982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim connection.callbacks.onLoadChildren(parentId, filteredList, options); 1070e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } catch (RemoteException ex) { 1071e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // The other side is in the process of crashing. 1072e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId 1073e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " package=" + connection.pkg); 1074e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1075e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1076e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }; 1077e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1078fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim mCurConnection = connection; 107982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim if (options == null) { 108082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim onLoadChildren(parentId, result); 108182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } else { 108282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim onLoadChildren(parentId, result, options); 108382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 1084fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim mCurConnection = null; 1085e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1086e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!result.isDone()) { 1087e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("onLoadChildren must call detach() or sendResult()" 1088e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " before returning for package=" + connection.pkg + " id=" + parentId); 1089e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1090e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1091e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1092b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas List<MediaBrowserCompat.MediaItem> applyOptions(List<MediaBrowserCompat.MediaItem> list, 109382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim final Bundle options) { 10947a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (list == null) { 10957a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return null; 10967a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim } 109782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim int page = options.getInt(MediaBrowserCompat.EXTRA_PAGE, -1); 109882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim int pageSize = options.getInt(MediaBrowserCompat.EXTRA_PAGE_SIZE, -1); 109982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim if (page == -1 && pageSize == -1) { 110082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim return list; 110182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 11027a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim int fromIndex = pageSize * page; 110382387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim int toIndex = fromIndex + pageSize; 11047a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim if (page < 0 || pageSize < 1 || fromIndex >= list.size()) { 11057a7ac26ee6d9ff4f5410991fa9cc97d0090ddaefSungsoo Lim return Collections.EMPTY_LIST; 110682387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 110782387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim if (toIndex > list.size()) { 110882387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim toIndex = list.size(); 110982387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 111082387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim return list.subList(fromIndex, toIndex); 111182387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim } 111282387d9f1b1ed30028e4c9090ec5fadce7d146f1Sungsoo Lim 1113b768ed3824de2c109411654b3830feabe564ff0aAurimas Liutikas void performLoadItem(String itemId, ConnectionRecord connection, 1114fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim final ResultReceiver receiver) { 1115096f2531cb790bc1106377d2da344614a3b88d39Jae Seo final Result<MediaBrowserCompat.MediaItem> result = 1116096f2531cb790bc1106377d2da344614a3b88d39Jae Seo new Result<MediaBrowserCompat.MediaItem>(itemId) { 1117a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim @Override 1118900e852d4f8b423ec2d8374f8e6743129e8f331bSungsoo Lim void onResultSent(MediaBrowserCompat.MediaItem item, @ResultFlags int flags) { 11197ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo if ((flags & RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED) != 0) { 11207ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo receiver.send(-1, null); 11217ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo return; 11227ce86ec087d5246c3b9a6f038bb538957606c311Sungsoo } 1123a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim Bundle bundle = new Bundle(); 1124a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim bundle.putParcelable(KEY_MEDIA_ITEM, item); 1125a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim receiver.send(0, bundle); 1126a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim } 1127a7a03ae00cf642cb470e04c9a2164bad35627dbfSungsoo Lim }; 1128e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1129fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim mCurConnection = connection; 1130fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim onLoadItem(itemId, result); 1131fda621da7916073852394d14fcd2cb37f202287dSungsoo Lim mCurConnection = null; 1132e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1133e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!result.isDone()) { 1134e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("onLoadItem must call detach() or sendResult()" 1135e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " before returning for id=" + itemId); 1136e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1137e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1138e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1139e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 1140e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Contains information that the browser service needs to send to the client 1141e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * when first connected. 1142e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1143e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public static final class BrowserRoot { 11448e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo /** 11458e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * The lookup key for a boolean that indicates whether the browser service should return a 11468e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * browser root for recently played media items. 11478e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 11488e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>When creating a media browser for a given media browser service, this key can be 11498e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * supplied as a root hint for retrieving media items that are recently played. 11508e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * If the media browser service can provide such media items, the implementation must return 11518e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back. 11528e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 11538e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>The root hint may contain multiple keys. 11548e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 11558e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_OFFLINE 11568e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_SUGGESTED 1157ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * @see #EXTRA_SUGGESTION_KEYWORDS 11588e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo */ 11598e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo public static final String EXTRA_RECENT = "android.service.media.extra.RECENT"; 11608e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo 11618e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo /** 11628e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * The lookup key for a boolean that indicates whether the browser service should return a 11638e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * browser root for offline media items. 11648e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 11658e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>When creating a media browser for a given media browser service, this key can be 11668e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * supplied as a root hint for retrieving media items that are can be played without an 11678e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * internet connection. 11688e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * If the media browser service can provide such media items, the implementation must return 11698e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back. 11708e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 11718e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>The root hint may contain multiple keys. 11728e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 11738e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_RECENT 11748e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_SUGGESTED 1175ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * @see #EXTRA_SUGGESTION_KEYWORDS 11768e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo */ 11778e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE"; 11788e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo 11798e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo /** 11808e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * The lookup key for a boolean that indicates whether the browser service should return a 11818e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * browser root for suggested media items. 11828e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 11838e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>When creating a media browser for a given media browser service, this key can be 11848e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * supplied as a root hint for retrieving the media items suggested by the media browser 11859763c3d83aeb160ad7c52f6e48aa4806477f1de0Jae Seo * service. The list of media items passed in {@link android.support.v4.media.MediaBrowserCompat.SubscriptionCallback#onChildrenLoaded(String, List)} 11869763c3d83aeb160ad7c52f6e48aa4806477f1de0Jae Seo * is considered ordered by relevance, first being the top suggestion. 11878e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * If the media browser service can provide such media items, the implementation must return 11888e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back. 11898e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 11908e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * <p>The root hint may contain multiple keys. 11918e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * 11928e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_RECENT 11938e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo * @see #EXTRA_OFFLINE 1194ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * @see #EXTRA_SUGGESTION_KEYWORDS 11958e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo */ 11968e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED"; 11978e16eac9d287d2b663c0000169503e83206bd9a7Jae Seo 1198ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim /** 1199ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * The lookup key for a string that indicates specific keywords which will be considered 1200ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * when the browser service suggests media items. 1201ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * 1202ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * <p>When creating a media browser for a given media browser service, this key can be 1203ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * supplied as a root hint together with {@link #EXTRA_SUGGESTED} for retrieving suggested 1204ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * media items related with the keywords. The list of media items passed in 1205ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)} 1206ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * is considered ordered by relevance, first being the top suggestion. 1207ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * If the media browser service can provide such media items, the implementation must return 1208ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back. 1209ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * 1210ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * <p>The root hint may contain multiple keys. 1211ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * 1212ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * @see #EXTRA_RECENT 1213ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * @see #EXTRA_OFFLINE 1214ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim * @see #EXTRA_SUGGESTED 1215ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim */ 1216ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim public static final String EXTRA_SUGGESTION_KEYWORDS 1217ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim = "android.service.media.extra.SUGGESTION_KEYWORDS"; 1218ae736327deea12ceb1929f2060acb76b31359c54Sungsoo Lim 1219e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final private String mRootId; 1220e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final private Bundle mExtras; 1221e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1222e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 1223e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Constructs a browser root. 1224e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param rootId The root id for browsing. 1225e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param extras Any extras about the browser service. 1226e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1227e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) { 1228e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (rootId == null) { 1229e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " + 1230e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo "Use null for BrowserRoot instead."); 1231e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1232e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mRootId = rootId; 1233e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mExtras = extras; 1234e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1235e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1236e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 1237e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Gets the root id for browsing. 1238e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1239e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public String getRootId() { 1240e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mRootId; 1241e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1242e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 1243e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 124423471681e408dfe4e44975e13e7575ab5a04bc8cJae Seo * Gets any extras about the browser service. 1245e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 1246e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public Bundle getExtras() { 1247e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mExtras; 1248e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1249e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 1250e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo} 1251