1 /* 2 * Copyright (C) 2021 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 android.platform.helpers; 18 19 import android.app.Instrumentation; 20 import android.app.UiAutomation; 21 import android.content.Context; 22 import android.media.session.MediaController; 23 import android.media.session.MediaSessionManager; 24 import android.media.session.PlaybackState; 25 import android.os.SystemClock; 26 import android.platform.helpers.exceptions.UnknownUiException; 27 import android.support.test.uiautomator.By; 28 import android.support.test.uiautomator.Direction; 29 import android.support.test.uiautomator.UiObject2; 30 import android.support.test.uiautomator.UiObject; 31 import android.support.test.uiautomator.UiObjectNotFoundException; 32 import android.support.test.uiautomator.UiScrollable; 33 import android.support.test.uiautomator.UiSelector; 34 35 import java.util.List; 36 37 public class MediaCenterHelperImpl extends AbstractAutoStandardAppHelper 38 implements IAutoMediaHelper { 39 // Wait Time 40 private static final int UI_RESPONSE_WAIT_MS = 5000; 41 private static final int SHORT_RESPONSE_WAIT_MS = 1000; 42 43 private static final String MEDIA_LAUNCH_COMMAND = 44 "am start -a android.car.intent.action.MEDIA_TEMPLATE -e " 45 + "android.car.intent.extra.MEDIA_COMPONENT "; 46 47 private MediaSessionManager mMediaSessionManager; 48 private UiAutomation mUiAutomation; 49 MediaCenterHelperImpl(Instrumentation instr)50 public MediaCenterHelperImpl(Instrumentation instr) { 51 super(instr); 52 mUiAutomation = instr.getUiAutomation(); 53 mUiAutomation.adoptShellPermissionIdentity("android.permission.MEDIA_CONTENT_CONTROL"); 54 mMediaSessionManager = 55 (MediaSessionManager) 56 instr.getContext().getSystemService(Context.MEDIA_SESSION_SERVICE); 57 } 58 59 /** {@inheritDoc} */ 60 @Override getPackage()61 public String getPackage() { 62 return getApplicationConfig(AutoConfigConstants.MEDIA_CENTER_PACKAGE); 63 } 64 65 /** {@inheritDoc} */ open()66 public void open() { 67 openMediaApp(getApplicationConfig(AutoConfigConstants.MEDIA_ACTIVITY)); 68 } 69 openMediaApp(String packagename)70 private void openMediaApp(String packagename) { 71 pressHome(); 72 waitForIdle(); 73 executeShellCommand(MEDIA_LAUNCH_COMMAND + packagename); 74 } 75 76 /** {@inheritDoc} */ playMedia()77 public void playMedia() { 78 if (!isPlaying()) { 79 UiObject2 playButton = 80 findUiObject( 81 getResourceFromConfig( 82 AutoConfigConstants.MEDIA_CENTER, 83 AutoConfigConstants.MEDIA_CENTER_SCREEN, 84 AutoConfigConstants.PLAY_PAUSE_BUTTON)); 85 if (playButton == null) { 86 throw new UnknownUiException("Unable to find play/pause button"); 87 } 88 clickAndWaitForIdleScreen(playButton); 89 SystemClock.sleep(UI_RESPONSE_WAIT_MS); 90 } 91 } 92 93 /** {@inheritDoc} */ playPauseMediaFromHomeScreen()94 public void playPauseMediaFromHomeScreen() { 95 UiObject2 playButton = 96 findUiObject( 97 getResourceFromConfig( 98 AutoConfigConstants.MEDIA_CENTER, 99 AutoConfigConstants.MEDIA_CENTER_ON_HOME_SCREEN, 100 AutoConfigConstants.PLAY_PAUSE_BUTTON)); 101 if (playButton == null) { 102 throw new UnknownUiException("Unable to find play button from home screen"); 103 } 104 clickAndWaitForIdleScreen(playButton); 105 SystemClock.sleep(UI_RESPONSE_WAIT_MS); 106 } 107 108 /** {@inheritDoc} */ pauseMedia()109 public void pauseMedia() { 110 if (isPlaying()) { 111 UiObject2 pauseButton = 112 findUiObject( 113 getResourceFromConfig( 114 AutoConfigConstants.MEDIA_CENTER, 115 AutoConfigConstants.MEDIA_CENTER_SCREEN, 116 AutoConfigConstants.PLAY_PAUSE_BUTTON)); 117 if (pauseButton == null) { 118 throw new UnknownUiException("Unable to find pause button"); 119 } 120 clickAndWaitForIdleScreen(pauseButton); 121 SystemClock.sleep(UI_RESPONSE_WAIT_MS); 122 } 123 } 124 125 /** {@inheritDoc} */ clickNextTrack()126 public void clickNextTrack() { 127 UiObject2 nextTrackButton = 128 findUiObject( 129 getResourceFromConfig( 130 AutoConfigConstants.MEDIA_CENTER, 131 AutoConfigConstants.MEDIA_CENTER_SCREEN, 132 AutoConfigConstants.NEXT_BUTTON)); 133 if (nextTrackButton == null) { 134 throw new UnknownUiException("Unable to find next track button"); 135 } 136 clickAndWaitForIdleScreen(nextTrackButton); 137 SystemClock.sleep(UI_RESPONSE_WAIT_MS); 138 } 139 140 /** {@inheritDoc} */ clickNextTrackFromHomeScreen()141 public void clickNextTrackFromHomeScreen() { 142 UiObject2 nextTrackButton = 143 findUiObject( 144 getResourceFromConfig( 145 AutoConfigConstants.MEDIA_CENTER, 146 AutoConfigConstants.MEDIA_CENTER_ON_HOME_SCREEN, 147 AutoConfigConstants.NEXT_BUTTON)); 148 if (nextTrackButton == null) { 149 throw new UnknownUiException("Unable to find next track button from home screen"); 150 } 151 clickAndWaitForIdleScreen(nextTrackButton); 152 SystemClock.sleep(UI_RESPONSE_WAIT_MS); 153 } 154 155 /** {@inheritDoc} */ clickPreviousTrack()156 public void clickPreviousTrack() { 157 UiObject2 previousTrackButton = 158 findUiObject( 159 getResourceFromConfig( 160 AutoConfigConstants.MEDIA_CENTER, 161 AutoConfigConstants.MEDIA_CENTER_SCREEN, 162 AutoConfigConstants.PREVIOUS_BUTTON)); 163 if (previousTrackButton == null) { 164 throw new UnknownUiException("Unable to find previous track button"); 165 } 166 clickAndWaitForIdleScreen(previousTrackButton); 167 SystemClock.sleep(UI_RESPONSE_WAIT_MS); 168 } 169 170 /** {@inheritDoc} */ clickPreviousTrackFromHomeScreen()171 public void clickPreviousTrackFromHomeScreen() { 172 UiObject2 previousTrackButton = 173 findUiObject( 174 getResourceFromConfig( 175 AutoConfigConstants.MEDIA_CENTER, 176 AutoConfigConstants.MEDIA_CENTER_ON_HOME_SCREEN, 177 AutoConfigConstants.PREVIOUS_BUTTON)); 178 if (previousTrackButton == null) { 179 throw new UnknownUiException("Unable to find previous track button"); 180 } 181 clickAndWaitForIdleScreen(previousTrackButton); 182 SystemClock.sleep(UI_RESPONSE_WAIT_MS); 183 } 184 185 /** {@inheritDoc} */ clickShuffleAll()186 public void clickShuffleAll() { 187 UiObject2 shufflePlaylistButton = 188 findUiObject( 189 getResourceFromConfig( 190 AutoConfigConstants.MEDIA_CENTER, 191 AutoConfigConstants.MEDIA_CENTER_SCREEN, 192 AutoConfigConstants.SHUFFLE_BUTTON)); 193 if (shufflePlaylistButton == null) { 194 throw new UnknownUiException("Unable to find shuffle playlist button"); 195 } 196 clickAndWaitForIdleScreen(shufflePlaylistButton); 197 } 198 199 /** Click the nth instance among the visible menu items */ clickMenuItem(int instance)200 public void clickMenuItem(int instance) { 201 if (!mDevice.hasObject(By.scrollable(true))) { 202 // Menu is not open 203 return; 204 } 205 UiScrollable menuList = new UiScrollable(new UiSelector().scrollable(true)); 206 menuList.setAsVerticalList(); 207 try { 208 UiObject menuListItem = 209 menuList.getChildByInstance(new UiSelector().clickable(true), instance); 210 menuListItem.clickAndWaitForNewWindow(UI_RESPONSE_WAIT_MS); 211 waitForIdle(); 212 } catch (UiObjectNotFoundException e) { 213 throw new UnknownUiException("Unable to find menu item", e); 214 } 215 } 216 217 /** {@inheritDoc} */ openMenuWith(String... menuOptions)218 public void openMenuWith(String... menuOptions) { 219 for (String menu : menuOptions) { 220 UiObject2 menuButton = findUiObject(By.text(menu)); 221 if (menuButton != null) { 222 clickAndWaitForIdleScreen(menuButton); 223 waitForGone(By.text(menu)); 224 } else { 225 try { 226 UiObject menuItem_object = selectByName(menu); 227 menuItem_object.clickAndWaitForNewWindow(); 228 } catch (UiObjectNotFoundException exception) { 229 throw new UnknownUiException("Unable to find the menu item"); 230 } 231 } 232 SystemClock.sleep(SHORT_RESPONSE_WAIT_MS); 233 } 234 } 235 236 /** {@inheritDoc} */ openNowPlayingWith(String trackName)237 public void openNowPlayingWith(String trackName) { 238 UiObject2 nowPlayingButton = 239 findUiObject( 240 getResourceFromConfig( 241 AutoConfigConstants.MEDIA_CENTER, 242 AutoConfigConstants.MEDIA_CENTER_SCREEN, 243 AutoConfigConstants.PLAY_QUEUE_BUTTON)); 244 if (nowPlayingButton == null) { 245 throw new UnknownUiException("Unable to find Now playing button"); 246 } 247 clickAndWaitForIdleScreen(nowPlayingButton); 248 waitForWindowUpdate(getApplicationConfig(AutoConfigConstants.MEDIA_CENTER_PACKAGE)); 249 UiObject2 playTrackName = findUiObject(By.text(trackName)); 250 if (playTrackName != null) { 251 clickAndWaitForIdleScreen(playTrackName); 252 } else { 253 try { 254 UiObject menuItem_object = selectByName(trackName); 255 menuItem_object.clickAndWaitForNewWindow(); 256 } catch (UiObjectNotFoundException exception) { 257 throw new UnknownUiException("Unable to find the trackname from Now playing list"); 258 } 259 } 260 } 261 262 /** {@inheritDoc} */ getMediaTrackName()263 public String getMediaTrackName() { 264 String track; 265 UiObject2 mediaControl = 266 findUiObject( 267 getResourceFromConfig( 268 AutoConfigConstants.MEDIA_CENTER, 269 AutoConfigConstants.MEDIA_CENTER_SCREEN, 270 AutoConfigConstants.MINIMIZED_MEDIA_CONTROLS)); 271 if (mediaControl != null) { 272 track = getMediaTrackNameFromMinimizedControl(); 273 } else { 274 track = getMediaTrackNameFromPlayback(); 275 } 276 return track; 277 } 278 279 /** {@inheritDoc} */ getMediaTrackNameFromHomeScreen()280 public String getMediaTrackNameFromHomeScreen() { 281 String trackName; 282 UiObject2 trackNameText = 283 findUiObject( 284 getResourceFromConfig( 285 AutoConfigConstants.MEDIA_CENTER, 286 AutoConfigConstants.MEDIA_CENTER_ON_HOME_SCREEN, 287 AutoConfigConstants.TRACK_NAME)); 288 if (trackNameText == null) { 289 throw new UnknownUiException("Unable to find track name from Home Screen"); 290 } 291 trackName = trackNameText.getText(); 292 return trackName; 293 } 294 getMediaTrackNameFromMinimizedControl()295 private String getMediaTrackNameFromMinimizedControl() { 296 String trackName; 297 UiObject2 trackNameText = 298 findUiObject( 299 getResourceFromConfig( 300 AutoConfigConstants.MEDIA_CENTER, 301 AutoConfigConstants.MEDIA_CENTER_SCREEN, 302 AutoConfigConstants.TRACK_NAME_MINIMIZED_CONTROL)); 303 if (trackNameText == null) { 304 throw new UnknownUiException("Unable to find track name from minimized control"); 305 } 306 trackName = trackNameText.getText(); 307 return trackName; 308 } 309 getMediaTrackNameFromPlayback()310 private String getMediaTrackNameFromPlayback() { 311 String trackName; 312 waitForIdle(); 313 UiObject2 trackNameText = 314 findUiObject( 315 getResourceFromConfig( 316 AutoConfigConstants.MEDIA_CENTER, 317 AutoConfigConstants.MEDIA_CENTER_SCREEN, 318 AutoConfigConstants.TRACK_NAME)); 319 if (trackNameText == null) { 320 throw new UnknownUiException("Unable to find track name from now playing"); 321 } 322 trackName = trackNameText.getText(); 323 return trackName; 324 } 325 326 /** {@inheritDoc} */ goBackToMediaHomePage()327 public void goBackToMediaHomePage() { 328 minimizeNowPlaying(); 329 UiObject2 back_btn = 330 findUiObject( 331 getResourceFromConfig( 332 AutoConfigConstants.MEDIA_CENTER, 333 AutoConfigConstants.MEDIA_CENTER_SCREEN, 334 AutoConfigConstants.BACK_BUTTON)); 335 while (back_btn != null) { 336 clickAndWaitForIdleScreen(back_btn); 337 back_btn = 338 findUiObject( 339 getResourceFromConfig( 340 AutoConfigConstants.MEDIA_CENTER, 341 AutoConfigConstants.MEDIA_CENTER_SCREEN, 342 AutoConfigConstants.BACK_BUTTON)); 343 } 344 } 345 346 /** Minimize the Now Playing window. */ minimizeNowPlaying()347 private void minimizeNowPlaying() { 348 UiObject2 trackNameText = 349 findUiObject( 350 getResourceFromConfig( 351 AutoConfigConstants.MEDIA_CENTER, 352 AutoConfigConstants.MEDIA_CENTER_SCREEN, 353 AutoConfigConstants.TRACK_NAME)); 354 if (trackNameText != null) { 355 trackNameText.swipe(Direction.DOWN, 1.0f, 500); 356 } 357 } 358 359 /** 360 * Scrolls through the list in search of the provided menu 361 * 362 * @param menu : menu to search 363 * @return UiObject found for the menu searched 364 */ selectByName(String menu)365 private UiObject selectByName(String menu) throws UiObjectNotFoundException { 366 UiObject menuListItem = null; 367 UiScrollable menuList = new UiScrollable(new UiSelector().scrollable(true)); 368 menuList.setAsVerticalList(); 369 menuListItem = 370 menuList.getChildByText( 371 new UiSelector().className(android.widget.TextView.class.getName()), menu); 372 mDevice.waitForIdle(); 373 return menuListItem; 374 } 375 376 /** {@inheritDoc} */ 377 @Override isPlaying()378 public boolean isPlaying() { 379 List<MediaController> controllers = mMediaSessionManager.getActiveSessions(null); 380 if (controllers.size() == 0) { 381 throw new RuntimeException("Unable to find Media Controller"); 382 } 383 PlaybackState state = controllers.get(0).getPlaybackState(); 384 return state.getState() == PlaybackState.STATE_PLAYING; 385 } 386 } 387