diff options
| author | Sungsoo Lim <sungsoo@google.com> | 2015-10-21 15:49:43 +0900 |
|---|---|---|
| committer | Sungsoo Lim <sungsoo@google.com> | 2015-10-29 09:20:28 +0900 |
| commit | 3f61f1657d13dacf4eb42d9371595b8075cff222 (patch) | |
| tree | f5a964dc45a5a1218c4d548a37e78bc268266ee9 /v4/java/android | |
| parent | f6081819cc7f8cef772d6a614e006994ec19e368 (diff) | |
| download | android_frameworks_support-3f61f1657d13dacf4eb42d9371595b8075cff222.tar.gz android_frameworks_support-3f61f1657d13dacf4eb42d9371595b8075cff222.tar.bz2 android_frameworks_support-3f61f1657d13dacf4eb42d9371595b8075cff222.zip | |
Use Messenger instead of AIDL between MBC and MBSC
MediaBrowserCompat (MBC) and MediaBrowserServiceCompat (MBSC) can
live in separated APKs and their support lib versions can be
different. Therefore, the AIDL approach could lead to unexpected
breaks in some cases.
Bug: 22917960
Change-Id: Ie18eef8c9ea120467d40de01a9c7fa2329e82681
Diffstat (limited to 'v4/java/android')
4 files changed, 269 insertions, 308 deletions
diff --git a/v4/java/android/support/v4/media/IMediaBrowserServiceCompat.aidl b/v4/java/android/support/v4/media/IMediaBrowserServiceCompat.aidl deleted file mode 100644 index 96155cd4f0..0000000000 --- a/v4/java/android/support/v4/media/IMediaBrowserServiceCompat.aidl +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2015, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.media; - -import android.content.res.Configuration; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.media.IMediaBrowserServiceCompatCallbacks; -import android.support.v4.os.ResultReceiver; - -/** - * Media API allows clients to browse through hierarchy of a user’s media collection, - * playback a specific media entry and interact with the now playing queue. - * @hide - */ -oneway interface IMediaBrowserServiceCompat { - void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCompatCallbacks callbacks); - void disconnect(IMediaBrowserServiceCompatCallbacks callbacks); - - void addSubscription(String uri, IMediaBrowserServiceCompatCallbacks callbacks); - void removeSubscription(String uri, IMediaBrowserServiceCompatCallbacks callbacks); - void getMediaItem(String uri, in ResultReceiver cb); -} diff --git a/v4/java/android/support/v4/media/IMediaBrowserServiceCompatCallbacks.aidl b/v4/java/android/support/v4/media/IMediaBrowserServiceCompatCallbacks.aidl deleted file mode 100644 index d2c7fd9500..0000000000 --- a/v4/java/android/support/v4/media/IMediaBrowserServiceCompatCallbacks.aidl +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2015, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.media; - -import android.graphics.Bitmap; -import android.os.Bundle; -import android.support.v4.media.session.MediaSessionCompat; - -import java.util.List; - -/** - * Media API allows clients to browse through hierarchy of a user’s media collection, - * playback a specific media entry and interact with the now playing queue. - * @hide - */ -oneway interface IMediaBrowserServiceCompatCallbacks { - /** - * Invoked when the connected has been established. - * @param root The root media id for browsing. - * @param session The {@link MediaSessionCompat.Token media session token} that can be used to - * control the playback of the media app. - * @param extra Extras returned by the media service. - */ - void onConnect(String root, in MediaSessionCompat.Token session, in Bundle extras); - void onConnectFailed(); - void onLoadChildren(String mediaId, in List list); -} diff --git a/v4/java/android/support/v4/media/MediaBrowserCompat.java b/v4/java/android/support/v4/media/MediaBrowserCompat.java index be7c4d76e3..a50a0596e9 100644 --- a/v4/java/android/support/v4/media/MediaBrowserCompat.java +++ b/v4/java/android/support/v4/media/MediaBrowserCompat.java @@ -23,14 +23,14 @@ import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.media.IMediaBrowserServiceCompat; -import android.support.v4.media.IMediaBrowserServiceCompatCallbacks; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.os.ResultReceiver; import android.support.v4.util.ArrayMap; @@ -39,7 +39,6 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -53,6 +52,14 @@ import java.util.List; * @hide */ public final class MediaBrowserCompat { + public static final String DATA_RESULT_RECEIVER = "data_result_receiver"; + + // TODO: Consider introducing version numbers for MediaBrowserCompat and + // MediaBrowserServiceCompat. + public static final int MSG_ON_CONNECT = 1; + public static final int MSG_ON_CONNECT_FAILED = 2; + public static final int MSG_ON_LOAD_CHILDREN = 3; + private final MediaBrowserImpl mImpl; /** @@ -478,13 +485,13 @@ public final class MediaBrowserCompat { private final ComponentName mServiceComponent; private final ConnectionCallback mCallback; private final Bundle mRootHints; - private final Handler mHandler = new Handler(); + private final CallbackHandler mHandler = new CallbackHandler(); private final ArrayMap<String,Subscription> mSubscriptions = new ArrayMap<>(); private int mState = CONNECT_STATE_DISCONNECTED; private MediaServiceConnection mServiceConnection; - private IMediaBrowserServiceCompat mServiceBinder; - private IMediaBrowserServiceCompatCallbacks mServiceCallbacks; + private ServiceBinderWrapper mServiceBinderWrapper; + private Messenger mCallbacksMessenger; private String mRootId; private MediaSessionCompat.Token mMediaSessionToken; private Bundle mExtras; @@ -518,13 +525,13 @@ public final class MediaBrowserCompat { + mServiceConnection); } } - if (mServiceBinder != null) { - throw new RuntimeException("mServiceBinder should be null. Instead it is " - + mServiceBinder); + if (mServiceBinderWrapper != null) { + throw new RuntimeException("mServiceBinderWrapper should be null. Instead it is " + + mServiceBinderWrapper); } - if (mServiceCallbacks != null) { - throw new RuntimeException("mServiceCallbacks should be null. Instead it is " - + mServiceCallbacks); + if (mCallbacksMessenger != null) { + throw new RuntimeException("mCallbacksMessenger should be null. Instead it is " + + mCallbacksMessenger); } mState = CONNECT_STATE_CONNECTING; @@ -570,9 +577,9 @@ public final class MediaBrowserCompat { // It's ok to call this any state, because allowing this lets apps not have // to check isConnected() unnecessarily. They won't appreciate the extra // assertions for this. We do everything we can here to go back to a sane state. - if (mServiceCallbacks != null) { + if (mCallbacksMessenger != null) { try { - mServiceBinder.disconnect(mServiceCallbacks); + mServiceBinderWrapper.disconnect(); } catch (RemoteException ex) { // We are disconnecting anyway. Log, just for posterity but it's not // a big problem. @@ -603,8 +610,8 @@ public final class MediaBrowserCompat { } mState = CONNECT_STATE_DISCONNECTED; mServiceConnection = null; - mServiceBinder = null; - mServiceCallbacks = null; + mServiceBinderWrapper = null; + mCallbacksMessenger = null; mRootId = null; mMediaSessionToken = null; } @@ -669,7 +676,7 @@ public final class MediaBrowserCompat { // connected, the service will be told when we connect. if (mState == CONNECT_STATE_CONNECTED) { try { - mServiceBinder.addSubscription(parentId, mServiceCallbacks); + mServiceBinderWrapper.addSubscription(parentId); } catch (RemoteException ex) { // Process is crashing. We will disconnect, and upon reconnect we will // automatically reregister. So nothing to do here. @@ -690,7 +697,7 @@ public final class MediaBrowserCompat { // Tell the service if necessary. if (mState == CONNECT_STATE_CONNECTED && sub != null) { try { - mServiceBinder.removeSubscription(parentId, mServiceCallbacks); + mServiceBinderWrapper.removeSubscription(parentId); } catch (RemoteException ex) { // Process is crashing. We will disconnect, and upon reconnect we will // automatically reregister. So nothing to do here. @@ -735,7 +742,7 @@ public final class MediaBrowserCompat { } }; try { - mServiceBinder.getMediaItem(mediaId, receiver); + mServiceBinderWrapper.getMediaItem(mediaId, receiver); } catch (RemoteException e) { Log.i(TAG, "Remote error getting media item."); mHandler.post(new Runnable() { @@ -765,129 +772,105 @@ public final class MediaBrowserCompat { } } - private final void onServiceConnected(final IMediaBrowserServiceCompatCallbacks callback, - final String root, final MediaSessionCompat.Token session, final Bundle extra) { - mHandler.post(new Runnable() { - @Override - public void run() { - // Check to make sure there hasn't been a disconnect or a different - // ServiceConnection. - if (!isCurrent(callback, "onConnect")) { - return; - } - // Don't allow them to call us twice. - if (mState != CONNECT_STATE_CONNECTING) { - Log.w(TAG, "onConnect from service while mState=" - + getStateLabel(mState) + "... ignoring"); - return; - } - mRootId = root; - mMediaSessionToken = session; - mExtras = extra; - mState = CONNECT_STATE_CONNECTED; + private final void onServiceConnected(final Messenger callback, final String root, + final MediaSessionCompat.Token session, final Bundle extra) { + // Check to make sure there hasn't been a disconnect or a different ServiceConnection. + if (!isCurrent(callback, "onConnect")) { + return; + } + // Don't allow them to call us twice. + if (mState != CONNECT_STATE_CONNECTING) { + Log.w(TAG, "onConnect from service while mState=" + getStateLabel(mState) + + "... ignoring"); + return; + } + mRootId = root; + mMediaSessionToken = session; + mExtras = extra; + mState = CONNECT_STATE_CONNECTED; - if (DBG) { - Log.d(TAG, "ServiceCallbacks.onConnect..."); - dump(); - } - mCallback.onConnected(); - - // we may receive some subscriptions before we are connected, so re-subscribe - // everything now - for (String id : mSubscriptions.keySet()) { - try { - mServiceBinder.addSubscription(id, mServiceCallbacks); - } catch (RemoteException ex) { - // Process is crashing. We will disconnect, and upon reconnect we will - // automatically reregister. So nothing to do here. - Log.d(TAG, "addSubscription failed with RemoteException parentId=" - + id); - } - } + if (DBG) { + Log.d(TAG, "ServiceCallbacks.onConnect..."); + dump(); + } + mCallback.onConnected(); + + // we may receive some subscriptions before we are connected, so re-subscribe + // everything now + for (String id : mSubscriptions.keySet()) { + try { + mServiceBinderWrapper.addSubscription(id); + } catch (RemoteException ex) { + // Process is crashing. We will disconnect, and upon reconnect we will + // automatically reregister. So nothing to do here. + Log.d(TAG, "addSubscription failed with RemoteException parentId=" + id); } - }); + } } - private final void onConnectionFailed(final IMediaBrowserServiceCompatCallbacks callback) { - mHandler.post(new Runnable() { - @Override - public void run() { - Log.e(TAG, "onConnectFailed for " + mServiceComponent); + private final void onConnectionFailed(final Messenger callback) { + Log.e(TAG, "onConnectFailed for " + mServiceComponent); - // Check to make sure there hasn't been a disconnect or a different - // ServiceConnection. - if (!isCurrent(callback, "onConnectFailed")) { - return; - } - // Don't allow them to call us twice. - if (mState != CONNECT_STATE_CONNECTING) { - Log.w(TAG, "onConnect from service while mState=" - + getStateLabel(mState) + "... ignoring"); - return; - } + // Check to make sure there hasn't been a disconnect or a different ServiceConnection. + if (!isCurrent(callback, "onConnectFailed")) { + return; + } + // Don't allow them to call us twice. + if (mState != CONNECT_STATE_CONNECTING) { + Log.w(TAG, "onConnect from service while mState=" + getStateLabel(mState) + + "... ignoring"); + return; + } - // Clean up - forceCloseConnection(); + // Clean up + forceCloseConnection(); - // Tell the app. - mCallback.onConnectionFailed(); - } - }); + // Tell the app. + mCallback.onConnectionFailed(); } - private final void onLoadChildren(final IMediaBrowserServiceCompatCallbacks callback, - final String parentId, final List list) { - mHandler.post(new Runnable() { - @Override - public void run() { - // Check that there hasn't been a disconnect or a different - // ServiceConnection. - if (!isCurrent(callback, "onLoadChildren")) { - return; - } + private final void onLoadChildren(final Messenger callback, final String parentId, + final List list) { + // Check that there hasn't been a disconnect or a different ServiceConnection. + if (!isCurrent(callback, "onLoadChildren")) { + return; + } - List<MediaItem> data = list; - if (DBG) { - Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId); - } - if (data == null) { - data = Collections.emptyList(); - } + List<MediaItem> data = list; + if (DBG) { + Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId); + } + if (data == null) { + data = Collections.emptyList(); + } - // Check that the subscription is still subscribed. - final Subscription subscription = mSubscriptions.get(parentId); - if (subscription == null) { - if (DBG) { - Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" - + parentId); - } - return; - } + // Check that the subscription is still subscribed. + final Subscription subscription = mSubscriptions.get(parentId); + if (subscription == null) { + if (DBG) { + Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId); + } + return; + } - // Tell the app. - subscription.callback.onChildrenLoaded(parentId, data); - } - }); + // Tell the app. + subscription.callback.onChildrenLoaded(parentId, data); } /** * Return true if {@code callback} is the current ServiceCallbacks. Also logs if it's not. */ - private boolean isCurrent(IMediaBrowserServiceCompatCallbacks callback, String funcName) { - if (mServiceCallbacks != callback) { + private boolean isCurrent(Messenger callback, String funcName) { + if (mCallbacksMessenger != callback) { if (mState != CONNECT_STATE_DISCONNECTED) { - Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection=" - + mServiceCallbacks + " this=" + this); + Log.i(TAG, funcName + " for " + mServiceComponent + " with mCallbacksMessenger=" + + mCallbacksMessenger + " this=" + this); } return false; } return true; } - private ServiceCallbacks getNewServiceCallbacks() { - return new ServiceCallbacks(this); - } - /** * Log internal state. * @hide @@ -899,12 +882,56 @@ public final class MediaBrowserCompat { Log.d(TAG, " mRootHints=" + mRootHints); Log.d(TAG, " mState=" + getStateLabel(mState)); Log.d(TAG, " mServiceConnection=" + mServiceConnection); - Log.d(TAG, " mServiceBinder=" + mServiceBinder); - Log.d(TAG, " mServiceCallbacks=" + mServiceCallbacks); + Log.d(TAG, " mServiceBinderWrapper=" + mServiceBinderWrapper); + Log.d(TAG, " mCallbacksMessenger=" + mCallbacksMessenger); Log.d(TAG, " mRootId=" + mRootId); Log.d(TAG, " mMediaSessionToken=" + mMediaSessionToken); } + private class ServiceBinderWrapper { + private Messenger mMessenger; + + public ServiceBinderWrapper(IBinder target) { + mMessenger = new Messenger(target); + } + + void connect() throws RemoteException { + sendRequest(MediaBrowserServiceCompat.MSG_CONNECT, mContext.getPackageName(), + mRootHints, mCallbacksMessenger); + } + + void disconnect() throws RemoteException { + sendRequest(MediaBrowserServiceCompat.MSG_DISCONNECT, null, null, + mCallbacksMessenger); + } + + void addSubscription(String parentId) throws RemoteException { + sendRequest(MediaBrowserServiceCompat.MSG_ADD_SUBSCRIPTION, parentId, null, + mCallbacksMessenger); + } + + void removeSubscription(String parentId) throws RemoteException { + sendRequest(MediaBrowserServiceCompat.MSG_REMOVE_SUBSCRIPTION, parentId, null, + mCallbacksMessenger); + } + + void getMediaItem(String mediaId, ResultReceiver receiver) throws RemoteException { + Bundle data = new Bundle(); + data.putParcelable(DATA_RESULT_RECEIVER, receiver); + sendRequest(MediaBrowserServiceCompat.MSG_GET_MEDIA_ITEM, mediaId, data, null); + } + + private void sendRequest(int what, Object obj, Bundle data, Messenger cbMessenger) + throws RemoteException { + Message msg = Message.obtain(); + msg.what = what; + msg.obj = obj; + msg.setData(data); + msg.replyTo = cbMessenger; + mMessenger.send(msg); + } + } + /** * ServiceConnection to the other app. */ @@ -924,11 +951,12 @@ public final class MediaBrowserCompat { } // Save their binder - mServiceBinder = IMediaBrowserServiceCompat.Stub.asInterface(binder); + mServiceBinderWrapper = new ServiceBinderWrapper(binder); // We make a new mServiceCallbacks each time we connect so that we can drop // responses from previous connections. - mServiceCallbacks = getNewServiceCallbacks(); + mCallbacksMessenger = new Messenger(mHandler); + mState = CONNECT_STATE_CONNECTING; // Call connect, which is async. When we get a response from that we will @@ -938,8 +966,7 @@ public final class MediaBrowserCompat { Log.d(TAG, "ServiceCallbacks.onConnect..."); dump(); } - mServiceBinder.connect( - mContext.getPackageName(), mRootHints, mServiceCallbacks); + mServiceBinderWrapper.connect(); } catch (RemoteException ex) { // Connect failed, which isn't good. But the auto-reconnect on the service // will take over and we will come back. We will also get the @@ -967,8 +994,8 @@ public final class MediaBrowserCompat { } // Clear out what we set in onServiceConnected - mServiceBinder = null; - mServiceCallbacks = null; + mServiceBinderWrapper = null; + mCallbacksMessenger = null; // And tell the app that it's suspended. mState = CONNECT_STATE_SUSPENDED; @@ -991,45 +1018,27 @@ public final class MediaBrowserCompat { } } - /** - * Callbacks from the service. - */ - private static class ServiceCallbacks extends IMediaBrowserServiceCompatCallbacks.Stub { - private WeakReference<MediaBrowserImplBase> mMediaBrowser; - - public ServiceCallbacks(MediaBrowserImplBase mediaBrowser) { - mMediaBrowser = new WeakReference<>(mediaBrowser); - } - - /** - * The other side has acknowledged our connection. The parameters to this function - * are the initial data as requested. - */ - @Override - public void onConnect(final String root, final MediaSessionCompat.Token session, - final Bundle extras) { - MediaBrowserImplBase mediaBrowser = mMediaBrowser.get(); - if (mediaBrowser != null) { - mediaBrowser.onServiceConnected(this, root, session, extras); - } - } - - /** - * The other side does not like us. Tell the app via onConnectionFailed. - */ - @Override - public void onConnectFailed() { - MediaBrowserImplBase mediaBrowser = mMediaBrowser.get(); - if (mediaBrowser != null) { - mediaBrowser.onConnectionFailed(this); - } - } - + private class CallbackHandler extends Handler { @Override - public void onLoadChildren(final String parentId, final List list) { - MediaBrowserImplBase mediaBrowser = mMediaBrowser.get(); - if (mediaBrowser != null) { - mediaBrowser.onLoadChildren(this, parentId, list); + public void handleMessage(Message msg) { + Bundle data = msg.getData(); + switch (msg.what) { + case MSG_ON_CONNECT: + onServiceConnected(mCallbacksMessenger, (String) msg.obj, + (MediaSessionCompat.Token) data.getParcelable( + MediaBrowserServiceCompat.DATA_MEDIA_SESSION_TOKEN), + data.getBundle(MediaBrowserServiceCompat.DATA_EXTRAS)); + break; + case MSG_ON_CONNECT_FAILED: + onConnectionFailed(mCallbacksMessenger); + break; + case MSG_ON_LOAD_CHILDREN: + onLoadChildren(mCallbacksMessenger, (String) msg.obj, + data.getParcelableArrayList( + MediaBrowserServiceCompat.DATA_MEDIA_ITEM_LIST)); + break; + default: + super.handleMessage(msg); } } } diff --git a/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java b/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java index 5d5f1f771d..ded7e7ef24 100644 --- a/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java +++ b/v4/java/android/support/v4/media/MediaBrowserServiceCompat.java @@ -24,6 +24,8 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; import android.os.Parcel; import android.os.RemoteException; import android.support.annotation.NonNull; @@ -66,6 +68,16 @@ public abstract class MediaBrowserServiceCompat extends Service { private static final String TAG = "MediaBrowserServiceCompat"; private static final boolean DBG = false; + public static final String DATA_MEDIA_SESSION_TOKEN = "data_media_session_token"; + public static final String DATA_EXTRAS = "data_extras"; + public static final String DATA_MEDIA_ITEM_LIST = "data_media_item_list"; + + public static final int MSG_CONNECT = 1; + public static final int MSG_DISCONNECT = 2; + public static final int MSG_ADD_SUBSCRIPTION = 3; + public static final int MSG_REMOVE_SUBSCRIPTION = 4; + public static final int MSG_GET_MEDIA_ITEM = 5; + private MediaBrowserServiceImpl mImpl; /** @@ -81,27 +93,26 @@ public abstract class MediaBrowserServiceCompat extends Service { public static final String KEY_MEDIA_ITEM = "media_item"; private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap(); - private final Handler mHandler = new Handler(); + private final ServiceHandler mHandler = new ServiceHandler(); MediaSessionCompat.Token mSession; interface MediaBrowserServiceImpl { - public void onCreate(); + void onCreate(); IBinder onBind(Intent intent); } class MediaBrowserServiceImplBase implements MediaBrowserServiceImpl { - private ServiceBinderCompat mBinder; + private Messenger mMessenger; @Override public void onCreate() { - mBinder = new ServiceBinderCompat(new ServiceStub()); + mMessenger = new Messenger(mHandler); } @Override public IBinder onBind(Intent intent) { - // STOPSHIP: Use messenger or version management for further extension if (SERVICE_INTERFACE.equals(intent.getAction())) { - return mBinder; + return mMessenger.getBinder(); } return null; } @@ -114,7 +125,7 @@ public abstract class MediaBrowserServiceCompat extends Service { public void onCreate() { mServiceObj = MediaBrowserServiceCompatApi21.createService(); MediaBrowserServiceCompatApi21.onCreate(mServiceObj, - new ServiceStubApi21(new ServiceStub())); + new ServiceImplApi21(mHandler.getServiceImpl())); } @Override @@ -123,6 +134,49 @@ public abstract class MediaBrowserServiceCompat extends Service { } } + private final class ServiceHandler extends Handler { + private final ServiceImpl mServiceImpl = new ServiceImpl(); + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_CONNECT: + mServiceImpl.connect((String) msg.obj, msg.getData(), + new ServiceCallbacksCompat(msg.replyTo)); + break; + case MSG_DISCONNECT: + mServiceImpl.disconnect(new ServiceCallbacksCompat(msg.replyTo)); + break; + case MSG_ADD_SUBSCRIPTION: + mServiceImpl.addSubscription((String) msg.obj, + new ServiceCallbacksCompat(msg.replyTo)); + break; + case MSG_REMOVE_SUBSCRIPTION: + mServiceImpl.removeSubscription((String) msg.obj, + new ServiceCallbacksCompat(msg.replyTo)); + break; + case MSG_GET_MEDIA_ITEM: + mServiceImpl.getMediaItem((String) msg.obj, (ResultReceiver) msg.getData() + .getParcelable(MediaBrowserCompat.DATA_RESULT_RECEIVER)); + break; + default: + super.handleMessage(msg); + } + } + + public void postOrRun(Runnable r) { + if (Thread.currentThread() == getLooper().getThread()) { + r.run(); + } else { + post(r); + } + } + + public ServiceImpl getServiceImpl() { + return mServiceImpl; + } + } + /** * All the info about a connection. */ @@ -195,7 +249,7 @@ public abstract class MediaBrowserServiceCompat extends Service { } } - private class ServiceStub { + private class ServiceImpl { public void connect(final String pkg, final Bundle rootHints, final ServiceCallbacks callbacks) { @@ -205,7 +259,7 @@ public abstract class MediaBrowserServiceCompat extends Service { + " package=" + pkg); } - mHandler.post(new Runnable() { + mHandler.postOrRun(new Runnable() { @Override public void run() { final IBinder b = callbacks.asBinder(); @@ -249,7 +303,7 @@ public abstract class MediaBrowserServiceCompat extends Service { } public void disconnect(final ServiceCallbacks callbacks) { - mHandler.post(new Runnable() { + mHandler.postOrRun(new Runnable() { @Override public void run() { final IBinder b = callbacks.asBinder(); @@ -265,7 +319,7 @@ public abstract class MediaBrowserServiceCompat extends Service { public void addSubscription(final String id, final ServiceCallbacks callbacks) { - mHandler.post(new Runnable() { + mHandler.postOrRun(new Runnable() { @Override public void run() { final IBinder b = callbacks.asBinder(); @@ -284,7 +338,7 @@ public abstract class MediaBrowserServiceCompat extends Service { } public void removeSubscription(final String id, final ServiceCallbacks callbacks) { - mHandler.post(new Runnable() { + mHandler.postOrRun(new Runnable() { @Override public void run() { final IBinder b = callbacks.asBinder(); @@ -308,7 +362,7 @@ public abstract class MediaBrowserServiceCompat extends Service { return; } - mHandler.post(new Runnable() { + mHandler.postOrRun(new Runnable() { @Override public void run() { performLoadItem(mediaId, receiver); @@ -317,73 +371,35 @@ public abstract class MediaBrowserServiceCompat extends Service { } } - private class ServiceBinderCompat extends IMediaBrowserServiceCompat.Stub { - final ServiceStub mServiceStub; + private class ServiceImplApi21 implements MediaBrowserServiceCompatApi21.ServiceImpl { + final ServiceImpl mServiceImpl; - ServiceBinderCompat(ServiceStub binder) { - mServiceStub = binder; - } - - @Override - public void connect(final String pkg, final Bundle rootHints, - final IMediaBrowserServiceCompatCallbacks callbacks) { - mServiceStub.connect(pkg, rootHints, new ServiceCallbacksCompat(callbacks)); - } - - @Override - public void disconnect(final IMediaBrowserServiceCompatCallbacks callbacks) { - mConnections.get(callbacks.asBinder()); - mServiceStub.disconnect(new ServiceCallbacksCompat(callbacks)); - } - - - @Override - public void addSubscription( - final String id, final IMediaBrowserServiceCompatCallbacks callbacks) { - mServiceStub.addSubscription(id, new ServiceCallbacksCompat(callbacks)); - } - - @Override - public void removeSubscription(final String id, - final IMediaBrowserServiceCompatCallbacks callbacks) { - mServiceStub.removeSubscription(id, new ServiceCallbacksCompat(callbacks)); - } - - @Override - public void getMediaItem(final String mediaId, final ResultReceiver receiver) { - mServiceStub.getMediaItem(mediaId, receiver); - } - } - - private class ServiceStubApi21 implements MediaBrowserServiceCompatApi21.ServiceStub { - final ServiceStub mBinder; - - ServiceStubApi21(ServiceStub binder) { - mBinder = binder; + ServiceImplApi21(ServiceImpl serviceImpl) { + mServiceImpl = serviceImpl; } @Override public void connect(final String pkg, final Bundle rootHints, final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { - mBinder.connect(pkg, rootHints, new ServiceCallbacksApi21(callbacks)); + mServiceImpl.connect(pkg, rootHints, new ServiceCallbacksApi21(callbacks)); } @Override public void disconnect(final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { - mBinder.disconnect(new ServiceCallbacksApi21(callbacks)); + mServiceImpl.disconnect(new ServiceCallbacksApi21(callbacks)); } @Override public void addSubscription( final String id, final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { - mBinder.addSubscription(id, new ServiceCallbacksApi21(callbacks)); + mServiceImpl.addSubscription(id, new ServiceCallbacksApi21(callbacks)); } @Override public void removeSubscription(final String id, final MediaBrowserServiceCompatApi21.ServiceCallbacks callbacks) { - mBinder.removeSubscription(id, new ServiceCallbacksApi21(callbacks)); + mServiceImpl.removeSubscription(id, new ServiceCallbacksApi21(callbacks)); } @Override @@ -394,7 +410,7 @@ public abstract class MediaBrowserServiceCompat extends Service { receiver.send(resultCode, resultData); } }; - mBinder.getMediaItem(mediaId, receiverCompat); + mServiceImpl.getMediaItem(mediaId, receiverCompat); } } @@ -408,28 +424,42 @@ public abstract class MediaBrowserServiceCompat extends Service { } private class ServiceCallbacksCompat implements ServiceCallbacks { - final IMediaBrowserServiceCompatCallbacks mCallbacks; + final Messenger mCallbacks; - ServiceCallbacksCompat(IMediaBrowserServiceCompatCallbacks callbacks) { + ServiceCallbacksCompat(Messenger callbacks) { mCallbacks = callbacks; } public IBinder asBinder() { - return mCallbacks.asBinder(); + return mCallbacks.getBinder(); } public void onConnect(String root, MediaSessionCompat.Token session, Bundle extras) throws RemoteException { - mCallbacks.onConnect(root, session, extras); + Bundle data = new Bundle(); + data.putParcelable(DATA_MEDIA_SESSION_TOKEN, session); + data.putBundle(DATA_EXTRAS, extras); + sendRequest(MediaBrowserCompat.MSG_ON_CONNECT, root, data); } public void onConnectFailed() throws RemoteException { - mCallbacks.onConnectFailed(); + sendRequest(MediaBrowserCompat.MSG_ON_CONNECT_FAILED, null, null); } public void onLoadChildren(String mediaId, List<MediaBrowserCompat.MediaItem> list) throws RemoteException { - mCallbacks.onLoadChildren(mediaId, list); + Bundle data = new Bundle(); + data.putParcelableArrayList(DATA_MEDIA_ITEM_LIST, + list instanceof ArrayList ? (ArrayList) list : new ArrayList<>(list)); + sendRequest(MediaBrowserCompat.MSG_ON_LOAD_CHILDREN, mediaId, data); + } + + private void sendRequest(int what, Object obj, Bundle data) throws RemoteException { + Message msg = Message.obtain(); + msg.what = what; + msg.obj = obj; + msg.setData(data); + mCallbacks.send(msg); } } |
