Loading android/app/src/com/android/bluetooth/audio_util/BrowsedPlayerWrapper.java +32 −4 Original line number Diff line number Diff line Loading @@ -261,7 +261,7 @@ class BrowsedPlayerWrapper { // Internal function to call once the Browser is connected private boolean getFolderItemsInternal(String mediaId, BrowseCallback cb) { mWrappedBrowser.subscribe(mediaId, new BrowserSubscriptionCallback(cb)); mWrappedBrowser.subscribe(mediaId, new BrowserSubscriptionCallback(cb, mLooper, mediaId)); return true; } Loading Loading @@ -302,14 +302,23 @@ class BrowsedPlayerWrapper { class TimeoutHandler extends Handler { static final int MSG_TIMEOUT = 0; static final long CALLBACK_TIMEOUT_MS = 5000; static final long SUBSCRIPTION_TIMEOUT_MS = 3000; private PlaybackCallback mPlaybackCallback = null; private BrowseCallback mBrowseCallback = null; private String mId = ""; TimeoutHandler(Looper looper, PlaybackCallback cb) { super(looper); mPlaybackCallback = cb; } TimeoutHandler(Looper looper, BrowseCallback cb, String mediaId) { super(looper); mBrowseCallback = cb; mId = mediaId; } @Override public void handleMessage(Message msg) { if (msg.what != MSG_TIMEOUT) { Loading @@ -317,8 +326,14 @@ class BrowsedPlayerWrapper { return; } if (mPlaybackCallback != null) { Log.e(TAG, "Timeout while waiting for playback to begin on " + mPackageName); mPlaybackCallback.run(STATUS_PLAYBACK_TIMEOUT_ERROR); } else { Log.e(TAG, "Timeout while waiting subscription result for " + mPackageName); mBrowseCallback.run(STATUS_LOOKUP_ERROR, mId, new ArrayList<ListItem>()); disconnect(); } } } Loading Loading @@ -391,9 +406,20 @@ class BrowsedPlayerWrapper { */ private class BrowserSubscriptionCallback extends MediaBrowser.SubscriptionCallback { BrowseCallback mBrowseCallback = null; private Looper mLooper = null; private TimeoutHandler mTimeoutHandler = null; BrowserSubscriptionCallback(BrowseCallback cb) { BrowserSubscriptionCallback(BrowseCallback cb, Looper looper, String mediaId) { mBrowseCallback = cb; mLooper = looper; mTimeoutHandler = new TimeoutHandler(mLooper, cb, mediaId); mTimeoutHandler.sendEmptyMessageDelayed(TimeoutHandler.MSG_TIMEOUT, TimeoutHandler.SUBSCRIPTION_TIMEOUT_MS); } @Override public Handler getTimeoutHandler() { return mTimeoutHandler; } @Override Loading Loading @@ -439,6 +465,7 @@ class BrowsedPlayerWrapper { } mCachedFolders.put(parentId, return_list); mTimeoutHandler.removeMessages(TimeoutHandler.MSG_TIMEOUT); // Clone the list so that the callee can mutate it without affecting the cached data mBrowseCallback.run(STATUS_SUCCESS, parentId, Util.cloneList(return_list)); Loading @@ -450,6 +477,7 @@ class BrowsedPlayerWrapper { @Override public void onError(String id) { Log.e(TAG, "BrowserSubscriptionCallback: Could not get folder items"); mTimeoutHandler.removeMessages(TimeoutHandler.MSG_TIMEOUT); mBrowseCallback.run(STATUS_LOOKUP_ERROR, id, new ArrayList<ListItem>()); disconnect(); } Loading android/app/src/com/android/bluetooth/audio_util/mockable/MediaBrowser.java +7 −1 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.content.Context; import android.media.session.MediaSession; import android.os.Bundle; import android.os.Handler; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -65,7 +66,12 @@ public class MediaBrowser { * Wrapper for MediaBrowser.SubscriptionCallback */ public abstract static class SubscriptionCallback extends android.media.browse.MediaBrowser.SubscriptionCallback {} android.media.browse.MediaBrowser.SubscriptionCallback { /** * Wrapper for MediaBrowser.SubscriptionCallback.getTimeoutHandler() */ public abstract Handler getTimeoutHandler(); } /** * Wrapper for MediaBrowser.connect() Loading android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java +18 −0 Original line number Diff line number Diff line Loading @@ -410,4 +410,22 @@ public class BrowserPlayerWrapperTest { verify(mMockBrowser).disconnect(); } @Test public void testGetFolderItems_Timeout() { BrowsedPlayerWrapper wrapper = BrowsedPlayerWrapper.wrap(mMockContext, mThread.getLooper(), "test", "test"); verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); wrapper.getFolderItems("test_folder", mBrowseCb); browserConnCb.onConnected(); verify(mMockBrowser).subscribe(any(), mSubscriptionCb.capture()); MediaBrowser.SubscriptionCallback subscriptionCb = mSubscriptionCb.getValue(); Handler timeoutHandler = subscriptionCb.getTimeoutHandler(); timeoutHandler.sendEmptyMessage(BrowsedPlayerWrapper.TimeoutHandler.MSG_TIMEOUT); verify(mMockBrowser, timeout(2000).times(1)).disconnect(); } } Loading
android/app/src/com/android/bluetooth/audio_util/BrowsedPlayerWrapper.java +32 −4 Original line number Diff line number Diff line Loading @@ -261,7 +261,7 @@ class BrowsedPlayerWrapper { // Internal function to call once the Browser is connected private boolean getFolderItemsInternal(String mediaId, BrowseCallback cb) { mWrappedBrowser.subscribe(mediaId, new BrowserSubscriptionCallback(cb)); mWrappedBrowser.subscribe(mediaId, new BrowserSubscriptionCallback(cb, mLooper, mediaId)); return true; } Loading Loading @@ -302,14 +302,23 @@ class BrowsedPlayerWrapper { class TimeoutHandler extends Handler { static final int MSG_TIMEOUT = 0; static final long CALLBACK_TIMEOUT_MS = 5000; static final long SUBSCRIPTION_TIMEOUT_MS = 3000; private PlaybackCallback mPlaybackCallback = null; private BrowseCallback mBrowseCallback = null; private String mId = ""; TimeoutHandler(Looper looper, PlaybackCallback cb) { super(looper); mPlaybackCallback = cb; } TimeoutHandler(Looper looper, BrowseCallback cb, String mediaId) { super(looper); mBrowseCallback = cb; mId = mediaId; } @Override public void handleMessage(Message msg) { if (msg.what != MSG_TIMEOUT) { Loading @@ -317,8 +326,14 @@ class BrowsedPlayerWrapper { return; } if (mPlaybackCallback != null) { Log.e(TAG, "Timeout while waiting for playback to begin on " + mPackageName); mPlaybackCallback.run(STATUS_PLAYBACK_TIMEOUT_ERROR); } else { Log.e(TAG, "Timeout while waiting subscription result for " + mPackageName); mBrowseCallback.run(STATUS_LOOKUP_ERROR, mId, new ArrayList<ListItem>()); disconnect(); } } } Loading Loading @@ -391,9 +406,20 @@ class BrowsedPlayerWrapper { */ private class BrowserSubscriptionCallback extends MediaBrowser.SubscriptionCallback { BrowseCallback mBrowseCallback = null; private Looper mLooper = null; private TimeoutHandler mTimeoutHandler = null; BrowserSubscriptionCallback(BrowseCallback cb) { BrowserSubscriptionCallback(BrowseCallback cb, Looper looper, String mediaId) { mBrowseCallback = cb; mLooper = looper; mTimeoutHandler = new TimeoutHandler(mLooper, cb, mediaId); mTimeoutHandler.sendEmptyMessageDelayed(TimeoutHandler.MSG_TIMEOUT, TimeoutHandler.SUBSCRIPTION_TIMEOUT_MS); } @Override public Handler getTimeoutHandler() { return mTimeoutHandler; } @Override Loading Loading @@ -439,6 +465,7 @@ class BrowsedPlayerWrapper { } mCachedFolders.put(parentId, return_list); mTimeoutHandler.removeMessages(TimeoutHandler.MSG_TIMEOUT); // Clone the list so that the callee can mutate it without affecting the cached data mBrowseCallback.run(STATUS_SUCCESS, parentId, Util.cloneList(return_list)); Loading @@ -450,6 +477,7 @@ class BrowsedPlayerWrapper { @Override public void onError(String id) { Log.e(TAG, "BrowserSubscriptionCallback: Could not get folder items"); mTimeoutHandler.removeMessages(TimeoutHandler.MSG_TIMEOUT); mBrowseCallback.run(STATUS_LOOKUP_ERROR, id, new ArrayList<ListItem>()); disconnect(); } Loading
android/app/src/com/android/bluetooth/audio_util/mockable/MediaBrowser.java +7 −1 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.content.Context; import android.media.session.MediaSession; import android.os.Bundle; import android.os.Handler; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -65,7 +66,12 @@ public class MediaBrowser { * Wrapper for MediaBrowser.SubscriptionCallback */ public abstract static class SubscriptionCallback extends android.media.browse.MediaBrowser.SubscriptionCallback {} android.media.browse.MediaBrowser.SubscriptionCallback { /** * Wrapper for MediaBrowser.SubscriptionCallback.getTimeoutHandler() */ public abstract Handler getTimeoutHandler(); } /** * Wrapper for MediaBrowser.connect() Loading
android/app/tests/unit/src/com/android/bluetooth/audio_util/BrowserPlayerWrapperTest.java +18 −0 Original line number Diff line number Diff line Loading @@ -410,4 +410,22 @@ public class BrowserPlayerWrapperTest { verify(mMockBrowser).disconnect(); } @Test public void testGetFolderItems_Timeout() { BrowsedPlayerWrapper wrapper = BrowsedPlayerWrapper.wrap(mMockContext, mThread.getLooper(), "test", "test"); verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); wrapper.getFolderItems("test_folder", mBrowseCb); browserConnCb.onConnected(); verify(mMockBrowser).subscribe(any(), mSubscriptionCb.capture()); MediaBrowser.SubscriptionCallback subscriptionCb = mSubscriptionCb.getValue(); Handler timeoutHandler = subscriptionCb.getTimeoutHandler(); timeoutHandler.sendEmptyMessage(BrowsedPlayerWrapper.TimeoutHandler.MSG_TIMEOUT); verify(mMockBrowser, timeout(2000).times(1)).disconnect(); } }