1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.avrcp; 18 19 import static org.mockito.Mockito.*; 20 21 import android.media.MediaDescription; 22 import android.media.browse.MediaBrowser.MediaItem; 23 import android.media.session.PlaybackState; 24 import android.os.Handler; 25 import android.os.HandlerThread; 26 27 import androidx.test.filters.SmallTest; 28 import androidx.test.runner.AndroidJUnit4; 29 30 import org.junit.Assert; 31 import org.junit.Before; 32 import org.junit.Test; 33 import org.junit.runner.RunWith; 34 import org.mockito.ArgumentCaptor; 35 import org.mockito.Captor; 36 import org.mockito.Mock; 37 import org.mockito.MockitoAnnotations; 38 39 import java.util.ArrayList; 40 import java.util.List; 41 42 @SmallTest 43 @RunWith(AndroidJUnit4.class) 44 public class BrowserPlayerWrapperTest { 45 46 @Captor ArgumentCaptor<MediaBrowser.ConnectionCallback> mBrowserConnCb; 47 @Captor ArgumentCaptor<MediaBrowser.SubscriptionCallback> mSubscriptionCb; 48 @Captor ArgumentCaptor<MediaController.Callback> mControllerCb; 49 @Captor ArgumentCaptor<Handler> mTimeoutHandler; 50 @Captor ArgumentCaptor<List<ListItem>> mWrapperBrowseCb; 51 @Mock MediaBrowser mMockBrowser; 52 @Mock BrowsedPlayerWrapper.ConnectionCallback mConnCb; 53 @Mock BrowsedPlayerWrapper.BrowseCallback mBrowseCb; 54 private HandlerThread mThread; 55 56 @Before setUp()57 public void setUp() { 58 MockitoAnnotations.initMocks(this); 59 60 // Set up Looper thread for the timeout handler 61 mThread = new HandlerThread("MediaPlayerWrapperTestThread"); 62 mThread.start(); 63 64 when(mMockBrowser.getRoot()).thenReturn("root_folder"); 65 66 MediaBrowserFactory.inject(mMockBrowser); 67 } 68 69 @Test testWrap()70 public void testWrap() { 71 BrowsedPlayerWrapper wrapper = 72 BrowsedPlayerWrapper.wrap(null, mThread.getLooper(), "test", "test"); 73 wrapper.connect(mConnCb); 74 verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); 75 verify(mMockBrowser).connect(); 76 77 MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); 78 browserConnCb.onConnected(); 79 80 verify(mConnCb).run(eq(BrowsedPlayerWrapper.STATUS_SUCCESS), eq(wrapper)); 81 verify(mMockBrowser).disconnect(); 82 } 83 84 @Test testConnect_Successful()85 public void testConnect_Successful() { 86 BrowsedPlayerWrapper wrapper = 87 BrowsedPlayerWrapper.wrap(null, mThread.getLooper(), "test", "test"); 88 wrapper.connect(mConnCb); 89 verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); 90 MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); 91 92 verify(mMockBrowser, times(1)).connect(); 93 browserConnCb.onConnected(); 94 verify(mConnCb).run(eq(BrowsedPlayerWrapper.STATUS_SUCCESS), eq(wrapper)); 95 verify(mMockBrowser, times(1)).disconnect(); 96 } 97 98 @Test testConnect_Suspended()99 public void testConnect_Suspended() { 100 BrowsedPlayerWrapper wrapper = 101 BrowsedPlayerWrapper.wrap(null, mThread.getLooper(), "test", "test"); 102 wrapper.connect(mConnCb); 103 verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); 104 MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); 105 106 verify(mMockBrowser, times(1)).connect(); 107 browserConnCb.onConnectionSuspended(); 108 verify(mConnCb).run(eq(BrowsedPlayerWrapper.STATUS_CONN_ERROR), eq(wrapper)); 109 // Twice because our mConnCb is wrapped when using the plain connect() call and disconnect 110 // is called for us when the callback is invoked in addition to error handling calling 111 // disconnect. 112 verify(mMockBrowser, times(2)).disconnect(); 113 } 114 115 @Test testConnect_Failed()116 public void testConnect_Failed() { 117 BrowsedPlayerWrapper wrapper = 118 BrowsedPlayerWrapper.wrap(null, mThread.getLooper(), "test", "test"); 119 wrapper.connect(mConnCb); 120 verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); 121 MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); 122 123 verify(mMockBrowser, times(1)).connect(); 124 browserConnCb.onConnectionFailed(); 125 verify(mConnCb).run(eq(BrowsedPlayerWrapper.STATUS_CONN_ERROR), eq(wrapper)); 126 verify(mMockBrowser, times(1)).disconnect(); 127 } 128 129 @Test testEmptyRoot()130 public void testEmptyRoot() { 131 BrowsedPlayerWrapper wrapper = 132 BrowsedPlayerWrapper.wrap(null, mThread.getLooper(), "test", "test"); 133 134 doReturn("").when(mMockBrowser).getRoot(); 135 136 wrapper.connect(mConnCb); 137 verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); 138 MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); 139 140 verify(mMockBrowser, times(1)).connect(); 141 142 browserConnCb.onConnected(); 143 verify(mConnCb).run(eq(BrowsedPlayerWrapper.STATUS_CONN_ERROR), eq(wrapper)); 144 verify(mMockBrowser, times(1)).disconnect(); 145 } 146 147 @Test testDisconnect()148 public void testDisconnect() { 149 BrowsedPlayerWrapper wrapper = 150 BrowsedPlayerWrapper.wrap(null, mThread.getLooper(), "test", "test"); 151 wrapper.connect(mConnCb); 152 verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); 153 MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); 154 browserConnCb.onConnected(); 155 verify(mMockBrowser).disconnect(); 156 } 157 158 @Test testGetRootId()159 public void testGetRootId() { 160 BrowsedPlayerWrapper wrapper = 161 BrowsedPlayerWrapper.wrap(null, mThread.getLooper(), "test", "test"); 162 wrapper.connect(mConnCb); 163 verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); 164 MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); 165 browserConnCb.onConnected(); 166 167 Assert.assertEquals("root_folder", wrapper.getRootId()); 168 verify(mMockBrowser).disconnect(); 169 } 170 171 @Test testPlayItem()172 public void testPlayItem() { 173 BrowsedPlayerWrapper wrapper = 174 BrowsedPlayerWrapper.wrap(null, mThread.getLooper(), "test", "test"); 175 verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); 176 MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); 177 178 wrapper.playItem("test_item"); 179 verify(mMockBrowser, times(1)).connect(); 180 181 MediaController mockController = mock(MediaController.class); 182 MediaController.TransportControls mockTransport = 183 mock(MediaController.TransportControls.class); 184 when(mockController.getTransportControls()).thenReturn(mockTransport); 185 MediaControllerFactory.inject(mockController); 186 187 browserConnCb.onConnected(); 188 verify(mockTransport).playFromMediaId(eq("test_item"), eq(null)); 189 190 // Do not immediately disconnect. Non-foreground playback serves will likely fail 191 verify(mMockBrowser, times(0)).disconnect(); 192 193 verify(mockController).registerCallback(mControllerCb.capture(), any()); 194 MediaController.Callback controllerCb = mControllerCb.getValue(); 195 PlaybackState.Builder builder = new PlaybackState.Builder(); 196 197 // Do not disconnect on an event that isn't "playing" 198 builder.setState(PlaybackState.STATE_PAUSED, 0, 1); 199 controllerCb.onPlaybackStateChanged(builder.build()); 200 verify(mMockBrowser, times(0)).disconnect(); 201 202 // Once we're told we're playing, make sure we disconnect 203 builder.setState(PlaybackState.STATE_PLAYING, 0, 1); 204 controllerCb.onPlaybackStateChanged(builder.build()); 205 verify(mMockBrowser, times(1)).disconnect(); 206 } 207 208 @Test testPlayItem_Timeout()209 public void testPlayItem_Timeout() { 210 BrowsedPlayerWrapper wrapper = 211 BrowsedPlayerWrapper.wrap(null, mThread.getLooper(), "test", "test"); 212 verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); 213 MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); 214 215 wrapper.playItem("test_item"); 216 verify(mMockBrowser, times(1)).connect(); 217 218 MediaController mockController = mock(MediaController.class); 219 MediaController.TransportControls mockTransport = 220 mock(MediaController.TransportControls.class); 221 when(mockController.getTransportControls()).thenReturn(mockTransport); 222 MediaControllerFactory.inject(mockController); 223 224 browserConnCb.onConnected(); 225 verify(mockTransport).playFromMediaId(eq("test_item"), eq(null)); 226 227 verify(mockController).registerCallback(any(), mTimeoutHandler.capture()); 228 Handler timeoutHandler = mTimeoutHandler.getValue(); 229 230 timeoutHandler.sendEmptyMessage(BrowsedPlayerWrapper.TimeoutHandler.MSG_TIMEOUT); 231 232 verify(mMockBrowser, timeout(2000).times(1)).disconnect(); 233 } 234 235 @Test testGetFolderItems()236 public void testGetFolderItems() { 237 BrowsedPlayerWrapper wrapper = 238 BrowsedPlayerWrapper.wrap(null, mThread.getLooper(), "test", "test"); 239 verify(mMockBrowser).testInit(any(), any(), mBrowserConnCb.capture(), any()); 240 MediaBrowser.ConnectionCallback browserConnCb = mBrowserConnCb.getValue(); 241 242 wrapper.getFolderItems("test_folder", mBrowseCb); 243 244 245 browserConnCb.onConnected(); 246 verify(mMockBrowser).subscribe(any(), mSubscriptionCb.capture()); 247 MediaBrowser.SubscriptionCallback subscriptionCb = mSubscriptionCb.getValue(); 248 249 ArrayList<MediaItem> items = new ArrayList<MediaItem>(); 250 MediaDescription.Builder bob = new MediaDescription.Builder(); 251 bob.setTitle("test_song1"); 252 bob.setMediaId("ts1"); 253 items.add(new MediaItem(bob.build(), 0)); 254 bob.setTitle("test_song2"); 255 bob.setMediaId("ts2"); 256 items.add(new MediaItem(bob.build(), 0)); 257 258 subscriptionCb.onChildrenLoaded("test_folder", items); 259 verify(mMockBrowser).unsubscribe(eq("test_folder")); 260 verify(mBrowseCb).run(eq(BrowsedPlayerWrapper.STATUS_SUCCESS), eq("test_folder"), 261 mWrapperBrowseCb.capture()); 262 263 List<ListItem> item_list = mWrapperBrowseCb.getValue(); 264 for (int i = 0; i < item_list.size(); i++) { 265 Assert.assertFalse(item_list.get(i).isFolder); 266 Assert.assertEquals(item_list.get(i).song, Util.toMetadata(items.get(i))); 267 } 268 269 verify(mMockBrowser).disconnect(); 270 } 271 } 272