MediaBrowserServiceCompat.java revision d4c131eea07dc2593f70523979929e52cf80e31e
1e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo/* 2e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Copyright (C) 2015 The Android Open Source Project 3e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 4e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Licensed under the Apache License, Version 2.0 (the "License"); 5e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * you may not use this file except in compliance with the License. 6e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * You may obtain a copy of the License at 7e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 8e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * http://www.apache.org/licenses/LICENSE-2.0 9e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 10e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Unless required by applicable law or agreed to in writing, software 11e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * distributed under the License is distributed on an "AS IS" BASIS, 12e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * See the License for the specific language governing permissions and 14e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * limitations under the License. 15e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 16e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 17e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seopackage android.support.v4.media; 18e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 19e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.app.Service; 20e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.content.Intent; 21e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.content.pm.PackageManager; 22e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Binder; 239703a1e215168b6b580430ec490ca616b6490c80Sungsoo Limimport android.os.Build; 24e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Bundle; 25e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.Handler; 26e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.IBinder; 273f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Limimport android.os.Message; 283f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Limimport android.os.Messenger; 299703a1e215168b6b580430ec490ca616b6490c80Sungsoo Limimport android.os.Parcel; 30e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.os.RemoteException; 31e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.NonNull; 32e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.annotation.Nullable; 3382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Limimport android.support.v4.app.BundleCompat; 34e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.media.session.MediaSessionCompat; 35e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.os.ResultReceiver; 36e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.support.v4.util.ArrayMap; 37e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.text.TextUtils; 38e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport android.util.Log; 39e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 40e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.io.FileDescriptor; 41e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.io.PrintWriter; 429703a1e215168b6b580430ec490ca616b6490c80Sungsoo Limimport java.util.ArrayList; 43e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.util.HashSet; 44e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seoimport java.util.List; 45e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 4682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Limimport static android.support.v4.media.MediaBrowserProtocol.*; 4782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim 48e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo/** 49e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Base class for media browse services. 50e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 51e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Media browse services enable applications to browse media content provided by an application 52e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * and ask the application to start playing it. They may also be used to control content that 53096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * is already playing by way of a {@link MediaSessionCompat}. 54e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p> 55e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 56e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * To extend this class, you must declare the service in your manifest file with 57e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * an intent filter with the {@link #SERVICE_INTERFACE} action. 58e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 59e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * For example: 60e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p><pre> 61096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * <service android:name=".MyMediaBrowserServiceCompat" 62e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * android:label="@string/service_name" > 63e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <intent-filter> 649703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim * <action android:name="android.media.browse.MediaBrowserService" /> 65e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </intent-filter> 66e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </service> 67e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </pre> 68e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 69096f2531cb790bc1106377d2da344614a3b88d39Jae Seopublic abstract class MediaBrowserServiceCompat extends Service { 70096f2531cb790bc1106377d2da344614a3b88d39Jae Seo private static final String TAG = "MediaBrowserServiceCompat"; 71e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private static final boolean DBG = false; 72e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 739703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private MediaBrowserServiceImpl mImpl; 749703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 75e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 76e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The {@link Intent} that must be declared as handled by the service. 77e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 789703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService"; 79e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 80e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 81e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * A key for passing the MediaItem to the ResultReceiver in getItem. 82e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 83e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @hide 84e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 85e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public static final String KEY_MEDIA_ITEM = "media_item"; 86e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 87e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap(); 883f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim private final ServiceHandler mHandler = new ServiceHandler(); 89e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo MediaSessionCompat.Token mSession; 90e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 919703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim interface MediaBrowserServiceImpl { 923f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim void onCreate(); 939703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim IBinder onBind(Intent intent); 949703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 959703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 969703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim class MediaBrowserServiceImplBase implements MediaBrowserServiceImpl { 973f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim private Messenger mMessenger; 989703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 999703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 1009703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onCreate() { 1013f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mMessenger = new Messenger(mHandler); 1029703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1039703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1049703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 1059703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public IBinder onBind(Intent intent) { 1069703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (SERVICE_INTERFACE.equals(intent.getAction())) { 1073f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim return mMessenger.getBinder(); 1089703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1099703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return null; 1109703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1119703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1129703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1139703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim class MediaBrowserServiceImplApi21 implements MediaBrowserServiceImpl { 1149703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private Object mServiceObj; 1159703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1169703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 1179703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onCreate() { 1189703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mServiceObj = MediaBrowserServiceCompatApi21.createService(); 11982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim MediaBrowserServiceCompatApi21.onCreate(mServiceObj, new ServiceImplApi21()); 1209703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1219703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 1229703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 1239703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public IBinder onBind(Intent intent) { 1249703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return MediaBrowserServiceCompatApi21.onBind(mServiceObj, intent); 1259703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1269703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 1279703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 12882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim class MediaBrowserServiceImplApi23 implements MediaBrowserServiceImpl { 12982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim private Object mServiceObj; 13082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim 13182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim @Override 13282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim public void onCreate() { 13382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim mServiceObj = MediaBrowserServiceCompatApi23.createService(); 13482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim MediaBrowserServiceCompatApi23.onCreate(mServiceObj, new ServiceImplApi23()); 13582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 13682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim 13782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim @Override 13882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim public IBinder onBind(Intent intent) { 13982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim return MediaBrowserServiceCompatApi23.onBind(mServiceObj, intent); 14082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 14182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 14282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim 1433f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim private final class ServiceHandler extends Handler { 1443f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim private final ServiceImpl mServiceImpl = new ServiceImpl(); 1453f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 1463f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim @Override 1473f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim public void handleMessage(Message msg) { 148094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim Bundle data = msg.getData(); 1493f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim switch (msg.what) { 15082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_CONNECT: 151094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim mServiceImpl.connect(data.getString(DATA_PACKAGE_NAME), 152094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.getInt(DATA_CALLING_UID), data.getBundle(DATA_ROOT_HINTS), 1533f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 1543f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 15582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_DISCONNECT: 1563f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mServiceImpl.disconnect(new ServiceCallbacksCompat(msg.replyTo)); 1573f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 15882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_ADD_SUBSCRIPTION: 159094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim mServiceImpl.addSubscription(data.getString(DATA_MEDIA_ITEM_ID), 1603f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 1613f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 16282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_REMOVE_SUBSCRIPTION: 163094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim mServiceImpl.removeSubscription(data.getString(DATA_MEDIA_ITEM_ID), 1643f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim new ServiceCallbacksCompat(msg.replyTo)); 1653f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 16682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim case CLIENT_MSG_GET_MEDIA_ITEM: 167094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim mServiceImpl.getMediaItem(data.getString(DATA_MEDIA_ITEM_ID), 168094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim (ResultReceiver) data.getParcelable(DATA_RESULT_RECEIVER)); 1693f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim break; 1703f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim default: 17182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim Log.w(TAG, "Unhandled message: " + msg 17282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim + "\n Service version: " + SERVICE_VERSION_CURRENT 17382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim + "\n Client version: " + msg.arg1); 1743f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 1753f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 1763f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 177094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim @Override 178094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 179094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim // Binder.getCallingUid() in handleMessage will return the uid of this process. 180094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim // In order to get the right calling uid, Binder.getCallingUid() should be called here. 181094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim Bundle data = msg.getData(); 182d4c131eea07dc2593f70523979929e52cf80e31eSungsoo Lim data.setClassLoader(MediaBrowserCompat.class.getClassLoader()); 183094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putInt(DATA_CALLING_UID, Binder.getCallingUid()); 184094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim return super.sendMessageAtTime(msg, uptimeMillis); 185094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim } 186094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim 1873f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim public void postOrRun(Runnable r) { 1883f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim if (Thread.currentThread() == getLooper().getThread()) { 1893f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim r.run(); 1903f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } else { 1913f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim post(r); 1923f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 1933f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 1943f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 1953f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim public ServiceImpl getServiceImpl() { 1963f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim return mServiceImpl; 1973f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 1983f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 1993f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 200e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 201e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * All the info about a connection. 202e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 203e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private class ConnectionRecord { 204e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo String pkg; 205e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Bundle rootHints; 2069703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim ServiceCallbacks callbacks; 207e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo BrowserRoot root; 208e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo HashSet<String> subscriptions = new HashSet(); 209e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 210e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 211e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 212096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * Completion handler for asynchronous callback methods in {@link MediaBrowserServiceCompat}. 213e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 214e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Each of the methods that takes one of these to send the result must call 215e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * {@link #sendResult} to respond to the caller with the given results. If those 216e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * functions return without calling {@link #sendResult}, they must instead call 217e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * {@link #detach} before returning, and then may call {@link #sendResult} when 218e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * they are done. If more than one of those methods is called, an exception will 219e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * be thrown. 220e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 221096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @see MediaBrowserServiceCompat#onLoadChildren 222096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @see MediaBrowserServiceCompat#onLoadItem 223e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 2249703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public static class Result<T> { 225e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private Object mDebug; 226e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean mDetachCalled; 227e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean mSendResultCalled; 228e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 229e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Result(Object debug) { 230e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mDebug = debug; 231e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 232e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 233e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 234e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Send the result back to the caller. 235e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 236e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void sendResult(T result) { 237e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSendResultCalled) { 238e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("sendResult() called twice for: " + mDebug); 239e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 240e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mSendResultCalled = true; 241e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo onResultSent(result); 242e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 243e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 244e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 245e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Detach this message from the current thread and allow the {@link #sendResult} 246e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * call to happen later. 247e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 248e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void detach() { 249e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mDetachCalled) { 250e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("detach() called when detach() had already" 251e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been called for: " + mDebug); 252e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 253e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSendResultCalled) { 254e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("detach() called when sendResult() had already" 255e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been called for: " + mDebug); 256e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 257e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mDetachCalled = true; 258e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 259e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 260e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo boolean isDone() { 261e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mDetachCalled || mSendResultCalled; 262e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 263e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 264e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 265e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called when the result is sent, after assertions about not being called twice 266e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * have happened. 267e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 268e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo void onResultSent(T result) { 269e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 270e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 271e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 2723f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim private class ServiceImpl { 273094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim public void connect(final String pkg, final int uid, final Bundle rootHints, 2749703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ServiceCallbacks callbacks) { 275e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 276e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!isValidPackage(pkg, uid)) { 277e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid 278e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " package=" + pkg); 279e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 280e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 2813f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 2829703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 2839703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void run() { 2849703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final IBinder b = callbacks.asBinder(); 2859703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 2869703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // Clear out the old subscriptions. We are getting new ones. 2879703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mConnections.remove(b); 2889703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 2899703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ConnectionRecord connection = new ConnectionRecord(); 2909703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.pkg = pkg; 2919703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.rootHints = rootHints; 2929703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.callbacks = callbacks; 2939703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 2949703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim connection.root = 2959703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim MediaBrowserServiceCompat.this.onGetRoot(pkg, uid, rootHints); 2969703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 2979703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // If they didn't return something, don't allow this client. 2989703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (connection.root == null) { 2999703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.i(TAG, "No root for client " + pkg + " from service " 3009703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + getClass().getName()); 3019703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim try { 3029703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim callbacks.onConnectFailed(); 3039703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } catch (RemoteException ex) { 3049703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. " 3059703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + "pkg=" + pkg); 3069703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 3079703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } else { 3089703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim try { 3099703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mConnections.put(b, connection); 3109703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (mSession != null) { 3119703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim callbacks.onConnect(connection.root.getRootId(), 3129703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mSession, connection.root.getExtras()); 313e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 3149703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } catch (RemoteException ex) { 3159703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.w(TAG, "Calling onConnect() failed. Dropping client. " 3169703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + "pkg=" + pkg); 3179703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mConnections.remove(b); 318e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 319e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 3209703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 3219703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim }); 322e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 323e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 3249703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void disconnect(final ServiceCallbacks callbacks) { 3253f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 3269703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 3279703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void run() { 3289703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final IBinder b = callbacks.asBinder(); 3299703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 3309703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // Clear out the old subscriptions. We are getting new ones. 3319703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ConnectionRecord old = mConnections.remove(b); 3329703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (old != null) { 3339703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // TODO 334e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 3359703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 3369703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim }); 337e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 338e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 339e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 3409703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void addSubscription(final String id, final ServiceCallbacks callbacks) { 3413f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 3429703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 3439703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void run() { 3449703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final IBinder b = callbacks.asBinder(); 3456a4150834d679d66abef50aff74d30ae2e846a32Sungsoo Lim 3469703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim // Get the record for the connection 3479703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final ConnectionRecord connection = mConnections.get(b); 3489703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (connection == null) { 3499703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Log.w(TAG, "addSubscription for callback that isn't registered id=" 3509703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim + id); 3519703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return; 352493571364635be0190cea8ee230a601070391e6fIan Pedowitz } 3539703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 3549703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim MediaBrowserServiceCompat.this.addSubscription(id, connection); 3559703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 3569703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim }); 357e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 358e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 3599703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void removeSubscription(final String id, final ServiceCallbacks callbacks) { 3603f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 361e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 362e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 363e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final IBinder b = callbacks.asBinder(); 364e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 365e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo ConnectionRecord connection = mConnections.get(b); 366e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (connection == null) { 367e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "removeSubscription for callback that isn't registered id=" 368e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + id); 369e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 370e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 371e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!connection.subscriptions.remove(id)) { 372e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "removeSubscription called for " + id 373e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " which is not subscribed"); 374e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 375e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 376e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 377e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 378e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 379e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void getMediaItem(final String mediaId, final ResultReceiver receiver) { 380e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (TextUtils.isEmpty(mediaId) || receiver == null) { 381e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 382e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 383e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 3843f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mHandler.postOrRun(new Runnable() { 385e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 386e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 387e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo performLoadItem(mediaId, receiver); 388e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 389e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 390e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 391e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 392e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 39382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim private class ServiceImplApi21 implements MediaBrowserServiceCompatApi21.ServiceImplApi21 { 3943f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim final ServiceImpl mServiceImpl; 3959703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 39682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim ServiceImplApi21() { 39782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim mServiceImpl = mHandler.getServiceImpl(); 3989703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 3999703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4009703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 4019703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void connect(final String pkg, final Bundle rootHints, 4029703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { 403094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim mServiceImpl.connect(pkg, Binder.getCallingUid(), rootHints, 404094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim new ServiceCallbacksApi21(callbacks)); 4059703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4069703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4079703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 4089703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void disconnect(final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { 4093f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mServiceImpl.disconnect(new ServiceCallbacksApi21(callbacks)); 4109703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4119703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4129703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4139703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 4149703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void addSubscription( 4159703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final String id, final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { 4163f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mServiceImpl.addSubscription(id, new ServiceCallbacksApi21(callbacks)); 4179703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4189703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4199703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 4209703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void removeSubscription(final String id, 4219703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { 4223f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mServiceImpl.removeSubscription(id, new ServiceCallbacksApi21(callbacks)); 4239703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 42482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 4259703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 42682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim private class ServiceImplApi23 extends ServiceImplApi21 42782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim implements MediaBrowserServiceCompatApi23.ServiceImplApi23 { 4289703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 42982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim public void getMediaItem(final String mediaId, 43082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim final MediaBrowserServiceCompatApi23.ItemCallback cb) { 4319703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim ResultReceiver receiverCompat = new ResultReceiver(mHandler) { 4329703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim @Override 4339703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim protected void onReceiveResult(int resultCode, Bundle resultData) { 43482cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim MediaBrowserCompat.MediaItem item = resultData.getParcelable(KEY_MEDIA_ITEM); 43582cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim Parcel itemParcel = null; 43682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim if (item != null) { 43782cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim itemParcel = Parcel.obtain(); 43882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim item.writeToParcel(itemParcel, 0); 43982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 44082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim cb.onItemLoaded(resultCode, resultData, itemParcel); 4419703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4429703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim }; 4433f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mServiceImpl.getMediaItem(mediaId, receiverCompat); 4449703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4459703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4469703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4479703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private interface ServiceCallbacks { 4489703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim IBinder asBinder(); 4499703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) 4509703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException; 4519703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim void onConnectFailed() throws RemoteException; 4529703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list) 4539703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException; 4549703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4559703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4569703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private class ServiceCallbacksCompat implements ServiceCallbacks { 4573f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim final Messenger mCallbacks; 4589703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4593f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim ServiceCallbacksCompat(Messenger callbacks) { 4609703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mCallbacks = callbacks; 4619703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4629703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4639703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public IBinder asBinder() { 4643f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim return mCallbacks.getBinder(); 4659703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4669703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4679703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) 4689703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException { 46982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim if (extras == null) { 47082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim extras = new Bundle(); 47182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 47282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim extras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT); 4733f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim Bundle data = new Bundle(); 474094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putString(DATA_MEDIA_ITEM_ID, root); 475094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putParcelable(DATA_MEDIA_SESSION_TOKEN, session); 476094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putBundle(DATA_ROOT_HINTS, extras); 477094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim sendRequest(SERVICE_MSG_ON_CONNECT, data); 4789703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4799703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4809703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onConnectFailed() throws RemoteException { 481094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim sendRequest(SERVICE_MSG_ON_CONNECT_FAILED, null); 4829703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 4839703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 4849703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list) 4859703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException { 486094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim Bundle data = new Bundle(); 487094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putString(DATA_MEDIA_ITEM_ID, mediaId); 488ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim if (list != null) { 489094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim data.putParcelableArrayList(DATA_MEDIA_ITEM_LIST, 490ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim list instanceof ArrayList ? (ArrayList) list : new ArrayList<>(list)); 491ae6d147640b8a868d2edff8ebac8d2a6bb03c594Sungsoo Lim } 492094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim sendRequest(SERVICE_MSG_ON_LOAD_CHILDREN, data); 4933f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim } 4943f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim 495094c558a8a4f9be922846da811568d2970064e43Sungsoo Lim private void sendRequest(int what, Bundle data) throws RemoteException { 4963f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim Message msg = Message.obtain(); 4973f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim msg.what = what; 49882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim msg.arg1 = SERVICE_VERSION_CURRENT; 4993f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim msg.setData(data); 5003f61f1657d13dacf4eb42d9371595b8075cff222Sungsoo Lim mCallbacks.send(msg); 5019703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5029703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5039703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5049703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim private class ServiceCallbacksApi21 implements ServiceCallbacks { 5059703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim final MediaBrowserServiceCompatApi21.ServiceCallbacks mCallbacks; 50682cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim Messenger mMessenger; 5079703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5089703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim ServiceCallbacksApi21(MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { 5099703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mCallbacks = callbacks; 5109703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5119703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5129703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public IBinder asBinder() { 5139703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return mCallbacks.asBinder(); 5149703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5159703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5169703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) 5179703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException { 51882cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim if (extras == null) { 51982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim extras = new Bundle(); 52082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } 52182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim mMessenger = new Messenger(mHandler); 52282cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim BundleCompat.putBinder(extras, EXTRA_MESSENGER_BINDER, mMessenger.getBinder()); 52382cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim extras.putInt(EXTRA_SERVICE_VERSION, SERVICE_VERSION_CURRENT); 5249703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mCallbacks.onConnect(root, session.getToken(), extras); 5259703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5269703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5279703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onConnectFailed() throws RemoteException { 5289703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mCallbacks.onConnectFailed(); 5299703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5309703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 5319703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list) 5329703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim throws RemoteException { 5339703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim List<Parcel> parcelList = null; 5349703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim if (list != null) { 5359703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim parcelList = new ArrayList<>(); 5369703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim for (MediaBrowserCompat.MediaItem item : list) { 5379703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim Parcel parcel = Parcel.obtain(); 5389703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim item.writeToParcel(parcel, 0); 5399703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim parcelList.add(parcel); 5409703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5419703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5429703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mCallbacks.onLoadChildren(mediaId, parcelList); 5439703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5449703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5459703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim 546e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 547e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void onCreate() { 548e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo super.onCreate(); 54982cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim if (Build.VERSION.SDK_INT >= 23) { 55082cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim mImpl = new MediaBrowserServiceImplApi23(); 55182cf659fd8dcc28e182274b17a401023ab879deaSungsoo Lim } else if (Build.VERSION.SDK_INT >= 21) { 5529703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mImpl = new MediaBrowserServiceImplApi21(); 5539703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } else { 5549703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mImpl = new MediaBrowserServiceImplBase(); 5559703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim } 5569703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim mImpl.onCreate(); 557e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 558e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 559e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 560e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public IBinder onBind(Intent intent) { 5619703a1e215168b6b580430ec490ca616b6490c80Sungsoo Lim return mImpl.onBind(intent); 562e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 563e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 564e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 565e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 566e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 567e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 568e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 569e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get the root information for browsing by a particular client. 570e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 571e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The implementation should verify that the client package has permission 572e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * to access browse media information before returning the root id; it 573e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * should return null if the client is not allowed to access this 574e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * information. 575e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * </p> 576e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 577e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param clientPackageName The package name of the application which is 578e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * requesting access to browse media. 579e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param clientUid The uid of the application which is requesting access to 580e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * browse media. 581e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param rootHints An optional bundle of service-specific arguments to send 582e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * to the media browse service when connecting and retrieving the 583e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * root id for browsing, or null if none. The contents of this 584e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * bundle may affect the information returned when browsing. 585e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @return The {@link BrowserRoot} for accessing this app's content or null. 586e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 587e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName, 588e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo int clientUid, @Nullable Bundle rootHints); 589e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 590e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 591e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get information about the children of a media item. 592e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 593e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Implementations must call {@link Result#sendResult result.sendResult} 594e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * with the list of children. If loading the children will be an expensive 595e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * operation that should be performed on another thread, 596e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * {@link Result#detach result.detach} may be called before returning from 597e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * this function, and then {@link Result#sendResult result.sendResult} 598e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * called when the loading is complete. 599e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 600e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param parentId The id of the parent media item whose children are to be 601e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * queried. 602e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param result The Result to send the list of children to, or null if the 603e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * id is invalid. 604e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 605e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public abstract void onLoadChildren(@NonNull String parentId, 606096f2531cb790bc1106377d2da344614a3b88d39Jae Seo @NonNull Result<List<MediaBrowserCompat.MediaItem>> result); 607e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 608e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 609e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Called to get information about a specific media item. 610e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 611e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Implementations must call {@link Result#sendResult result.sendResult}. If 612e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * loading the item will be an expensive operation {@link Result#detach 613e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * result.detach} may be called before returning from this function, and 614e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * then {@link Result#sendResult result.sendResult} called when the item has 615e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * been loaded. 616e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 617e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * The default implementation sends a null result. 618e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 619e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param itemId The id for the specific 620096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * {@link MediaBrowserCompat.MediaItem}. 621e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param result The Result to send the item to, or null if the id is 622e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * invalid. 623e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 624096f2531cb790bc1106377d2da344614a3b88d39Jae Seo public void onLoadItem(String itemId, Result<MediaBrowserCompat.MediaItem> result) { 625e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo result.sendResult(null); 626e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 627e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 628e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 629e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Call to set the media session. 630e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 631e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * This should be called as soon as possible during the service's startup. 632e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * It may only be called once. 633e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 634096f2531cb790bc1106377d2da344614a3b88d39Jae Seo * @param token The token for the service's {@link MediaSessionCompat}. 635e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 636e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void setSessionToken(final MediaSessionCompat.Token token) { 637e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (token == null) { 638e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("Session token may not be null."); 639e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 640e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mSession != null) { 641e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("The session token has already been set."); 642e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 643e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mSession = token; 644e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mHandler.post(new Runnable() { 645e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 646e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 647e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo for (IBinder key : mConnections.keySet()) { 648e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo ConnectionRecord connection = mConnections.get(key); 649e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo try { 650e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo connection.callbacks.onConnect(connection.root.getRootId(), token, 651e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo connection.root.getExtras()); 652e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } catch (RemoteException e) { 653e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid."); 654e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mConnections.remove(key); 655e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 656e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 657e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 658e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 659e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 660e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 661e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 662e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Gets the session token, or null if it has not yet been created 663e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * or if it has been destroyed. 664e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 665e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public @Nullable MediaSessionCompat.Token getSessionToken() { 666e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mSession; 667e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 668e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 669e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 670e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Notifies all connected media browsers that the children of 671e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * the specified parent id have changed in some way. 672e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * This will cause browsers to fetch subscribed content again. 673e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * 674e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param parentId The id of the parent media item whose 675e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * children changed. 676e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 677e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void notifyChildrenChanged(@NonNull final String parentId) { 678e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (parentId == null) { 679e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged"); 680e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 681e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mHandler.post(new Runnable() { 682e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 683e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public void run() { 684e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo for (IBinder binder : mConnections.keySet()) { 685e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo ConnectionRecord connection = mConnections.get(binder); 686e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (connection.subscriptions.contains(parentId)) { 687e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo performLoadChildren(parentId, connection); 688e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 689e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 690e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 691e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }); 692e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 693e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 694e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 695e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Return whether the given package is one of the ones that is owned by the uid. 696e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 697e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private boolean isValidPackage(String pkg, int uid) { 698e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (pkg == null) { 699e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return false; 700e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 701e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final PackageManager pm = getPackageManager(); 702e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final String[] packages = pm.getPackagesForUid(uid); 703e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final int N = packages.length; 704e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo for (int i=0; i<N; i++) { 705e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (packages[i].equals(pkg)) { 706e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return true; 707e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 708e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 709e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return false; 710e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 711e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 712e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 713e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Save the subscription and if it is a new subscription send the results. 714e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 715e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private void addSubscription(String id, ConnectionRecord connection) { 716e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // Save the subscription 717e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo connection.subscriptions.add(id); 718e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 719e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // send the results 720e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo performLoadChildren(id, connection); 721e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 722e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 723e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 724e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Call onLoadChildren and then send the results back to the connection. 725e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * <p> 726e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Callers must make sure that this connection is still connected. 727e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 728e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private void performLoadChildren(final String parentId, final ConnectionRecord connection) { 729096f2531cb790bc1106377d2da344614a3b88d39Jae Seo final Result<List<MediaBrowserCompat.MediaItem>> result 730096f2531cb790bc1106377d2da344614a3b88d39Jae Seo = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) { 731e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 732096f2531cb790bc1106377d2da344614a3b88d39Jae Seo void onResultSent(List<MediaBrowserCompat.MediaItem> list) { 733e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (mConnections.get(connection.callbacks.asBinder()) != connection) { 734e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (DBG) { 735e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.d(TAG, "Not sending onLoadChildren result for connection that has" 736e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " been disconnected. pkg=" + connection.pkg + " id=" + parentId); 737e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 738e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return; 739e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 740e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 741e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo try { 742e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo connection.callbacks.onLoadChildren(parentId, list); 743e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } catch (RemoteException ex) { 744e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo // The other side is in the process of crashing. 745e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId 746e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " package=" + connection.pkg); 747e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 748e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 749e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }; 750e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 751e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo onLoadChildren(parentId, result); 752e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 753e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!result.isDone()) { 754e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("onLoadChildren must call detach() or sendResult()" 755e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " before returning for package=" + connection.pkg + " id=" + parentId); 756e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 757e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 758e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 759e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo private void performLoadItem(String itemId, final ResultReceiver receiver) { 760096f2531cb790bc1106377d2da344614a3b88d39Jae Seo final Result<MediaBrowserCompat.MediaItem> result = 761096f2531cb790bc1106377d2da344614a3b88d39Jae Seo new Result<MediaBrowserCompat.MediaItem>(itemId) { 762e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo @Override 763096f2531cb790bc1106377d2da344614a3b88d39Jae Seo void onResultSent(MediaBrowserCompat.MediaItem item) { 764e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo Bundle bundle = new Bundle(); 765e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo bundle.putParcelable(KEY_MEDIA_ITEM, item); 766e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo receiver.send(0, bundle); 767e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 768e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo }; 769e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 770096f2531cb790bc1106377d2da344614a3b88d39Jae Seo MediaBrowserServiceCompat.this.onLoadItem(itemId, result); 771e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 772e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (!result.isDone()) { 773e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalStateException("onLoadItem must call detach() or sendResult()" 774e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo + " before returning for id=" + itemId); 775e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 776e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 777e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 778e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 779e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Contains information that the browser service needs to send to the client 780e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * when first connected. 781e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 782e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public static final class BrowserRoot { 783e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final private String mRootId; 784e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo final private Bundle mExtras; 785e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 786e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 787e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Constructs a browser root. 788e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param rootId The root id for browsing. 789e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * @param extras Any extras about the browser service. 790e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 791e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) { 792e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo if (rootId == null) { 793e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " + 794e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo "Use null for BrowserRoot instead."); 795e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 796e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mRootId = rootId; 797e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo mExtras = extras; 798e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 799e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 800e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 801e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo * Gets the root id for browsing. 802e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 803e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public String getRootId() { 804e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mRootId; 805e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 806e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo 807e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo /** 80823471681e408dfe4e44975e13e7575ab5a04bc8cJae Seo * Gets any extras about the browser service. 809e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo */ 810e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo public Bundle getExtras() { 811e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo return mExtras; 812e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 813e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo } 814e2dc54fb995a75eab424aafe4960799ed5512f4dJae Seo} 815