I'm basically starting a foreground media-service from an activity and then move the activity to Lifecycle.State.DESTROYED
. ServiceTestRule
is not really sufficient for testing bound services, which may require testing the bound service notification.
@RunWith(AndroidJUnit4.class)
public class MainActivityTest extends BaseActivityTestCase {
protected ActivityScenario<MainActivity> mScenario;
@Before
public void setupTest() {
this.setScenario(this.activityScenarioRule.getScenario());
this.getScenario().onActivity(activity -> { /* ... */ });
}
@Test
public void testActivityLifecycle() {
/* Destroy the Activity. */
this.getScenario().moveToState(Lifecycle.State.DESTROYED);
/* TODO: Use UiAutomator to click media-controls. */
}
@NonNull
protected ActivityScenario<MainActivity> getScenario() {
return this.mScenario;
}
protected void setScenario(@NonNull ActivityScenario<MainActivity> scenario) {
this.mScenario = scenario;
}
@Override
public void tearDown() throws Exception {
this.getScenario().close();
super.tearDown();
}
}
How to access media-service notification controls with UiAutomator?
I've wrote some methods, in order to get a handle to the media-service notification.
a) This open the notification panel - and returns the notification panel ScrollView
:
static final UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
UiObject openNotificationPanel() {
synchronized (mDevice) {
if (mDevice.openNotification()) {
mDevice.wait(Until.hasObject(By.pkg("com.android.systemui")), 10000);
UiObject item = mDevice.findObject(new UiSelector().resourceId("com.android.systemui:id/notification_stack_scroller"));
assertTrue(item.exists());
return item;
} else {
return null;
}
}
}
b) This returns child-node android:id/notification_media_content
from the ScrollView
:
UiObject getMediaServiceNotification(@NonNull UiObject scrollView) {
try {
UiObject item = scrollView
.getChild(new UiSelector().resourceId("android:id/notification_media_content"));
assertTrue(item.exists());
return item;
} catch (UiObjectNotFoundException e) {
Log.e(LOG_TAG,"UiObjectNotFoundException: " + e.getMessage());
return null;
}
}
c) And this ultimately clicks the media-action button inside the notification.
The relevant child-nodes are: mediaActions, mainColumn, mediaProgress
.
Boolean clickMediaActionAtIndex(@NonNull UiObject notification, int index) {
try {
UiObject mediaActions = notification.getChild(new UiSelector().resourceId("android:id/media_actions"));
assertTrue(mediaActions.exists());
UiObject mainColumn = notification.getChild(new UiSelector().resourceId("android:id/notification_main_column"));
assertTrue(mainColumn.exists());
UiObject mediaProgress = notification.getChild(new UiSelector().resourceId("android:id/notification_media_progress"));
assertTrue(mediaProgress.exists());
if (index < mediaActions.getChildCount()) {
UiObject mediaAction = mediaActions.getChild(new UiSelector().className("android.widget.ImageButton").index(index));
assertTrue(mediaAction.exists());
mediaAction.click();
return true;
}
} catch (UiObjectNotFoundException e) {
Log.e(LOG_TAG,"UiObjectNotFoundException: " + e.getMessage());
}
return false;
}
And the test-case looks about alike this:
@RunWith(AndroidJUnit4.class)
public class MainActivityTest extends TestCase {
@Test
public void testActivityLifecycle() {
/* Destroy the Activity. */
this.getScenario().moveToState(Lifecycle.State.DESTROYED);
/* UiAutomator: Media Service Notification. */
UiObject scrollView = this.openNotificationPanel();
UiObject notification = this.getMediaServiceNotification(scrollView);
/* Click Media Action: Play/Pause. */
assertTrue(this.clickMediaActionAtIndex(notification, 2));
}
}