aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGyumin Sim <gyumin@google.com>2019-06-26 06:52:20 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2019-06-26 06:52:20 +0000
commitd79ec005cb6d0110827473b750bea235c655018a (patch)
treedf95ed436629763779266d05e8ba81f6b1d7f093
parent20cc23ee4769e48b6ae315d4901555402f282d71 (diff)
parentefb401cf0da0fee8829a6e85d6f47fc6654333a4 (diff)
downloadsupport-d79ec005cb6d0110827473b750bea235c655018a.tar.gz
Merge "Test media2-widget with MediaController as well as SessionPlayer" into androidx-master-dev
-rw-r--r--media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithControllerTest.java40
-rw-r--r--media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithPlayerTest.java288
-rw-r--r--media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithSthTestBase.java316
-rw-r--r--media2/widget/src/androidTest/java/androidx/media2/widget/MediaTestBase.java70
-rw-r--r--media2/widget/src/androidTest/java/androidx/media2/widget/MediaWidgetTestBase.java67
-rw-r--r--media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithControllerTest.java39
-rw-r--r--media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithPlayerTest.java182
-rw-r--r--media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithSthTestBase.java221
8 files changed, 766 insertions, 457 deletions
diff --git a/media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithControllerTest.java b/media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithControllerTest.java
new file mode 100644
index 00000000000..8d7b96fdac7
--- /dev/null
+++ b/media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithControllerTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 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 androidx.media2.widget;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.media2.common.MediaItem;
+import androidx.media2.session.MediaController;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link MediaControlView} with a {@link MediaController}.
+ * Please place actual test cases in {@link MediaControlView_WithSthTestBase}.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class MediaControlView_WithControllerTest extends MediaControlView_WithSthTestBase {
+ @Override
+ PlayerWrapper createPlayerWrapper(@NonNull PlayerWrapper.PlayerCallback callback,
+ @Nullable MediaItem item) {
+ return createPlayerWrapperOfController(callback, item);
+ }
+}
diff --git a/media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithPlayerTest.java b/media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithPlayerTest.java
index 5ea2a6b1a2e..10bc8741509 100644
--- a/media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithPlayerTest.java
+++ b/media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithPlayerTest.java
@@ -16,299 +16,25 @@
package androidx.media2.widget;
-import static androidx.test.espresso.Espresso.onView;
-import static androidx.test.espresso.action.ViewActions.click;
-import static androidx.test.espresso.assertion.ViewAssertions.matches;
-import static androidx.test.espresso.matcher.RootMatchers.isPlatformPopup;
-import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
-import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
-import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static androidx.test.espresso.matcher.ViewMatchers.withId;
-import static androidx.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.net.Uri;
-
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.media2.common.MediaItem;
-import androidx.media2.common.MediaMetadata;
import androidx.media2.common.SessionPlayer;
-import androidx.media2.common.SessionPlayer.TrackInfo;
-import androidx.media2.player.MediaPlayer;
-import androidx.media2.widget.test.R;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
-import androidx.test.rule.ActivityTestRule;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
/**
* Test {@link MediaControlView} with a {@link SessionPlayer}.
+ * Please place actual test cases in {@link MediaControlView_WithSthTestBase}.
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
-public class MediaControlView_WithPlayerTest extends MediaWidgetTestBase {
- private static final long FFWD_MS = 30000L;
- private static final long REW_MS = 10000L;
-
- private SessionPlayer mPlayer;
- private MediaControlViewTestActivity mActivity;
- private MediaControlView mMediaControlView;
- private MediaItem mFileSchemeMediaItem;
-
- @Rule
- public ActivityTestRule<MediaControlViewTestActivity> mActivityRule =
- new ActivityTestRule<>(MediaControlViewTestActivity.class);
-
- @Before
- public void setup() throws Throwable {
- mPlayer = new MediaPlayer(mContext);
- mActivity = mActivityRule.getActivity();
- mMediaControlView = mActivity.findViewById(R.id.mediacontrolview);
- mActivityRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mMediaControlView.setPlayer(mPlayer);
- }
- });
-
- Uri fileSchemeUri = Uri.parse("android.resource://" + mContext.getPackageName() + "/"
- + R.raw.test_file_scheme_video);
- mFileSchemeMediaItem = createTestMediaItem(fileSchemeUri);
-
- setKeepScreenOn(mActivityRule);
- checkAttachedToWindow(mMediaControlView);
- }
-
- @After
- public void tearDown() throws Throwable {
- mActivityRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- try {
- mPlayer.close();
- } catch (Exception ex) {
- // ignore
- }
- }
- });
- }
-
- @Test
- public void testPlayPauseButtonClick() throws Throwable {
- final CountDownLatch latchForPausedState = new CountDownLatch(1);
- final CountDownLatch latchForPlayingState = new CountDownLatch(1);
- registerCallback(new SessionPlayer.PlayerCallback() {
- @Override
- public void onPlayerStateChanged(@NonNull SessionPlayer player, int state) {
- if (state == SessionPlayer.PLAYER_STATE_PAUSED) {
- latchForPausedState.countDown();
- } else if (state == SessionPlayer.PLAYER_STATE_PLAYING) {
- latchForPlayingState.countDown();
- }
- }
- });
- setAndPrepare(mFileSchemeMediaItem);
- assertTrue(latchForPausedState.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
- onView(allOf(withId(R.id.pause), isCompletelyDisplayed())).perform(click());
- assertTrue(latchForPlayingState.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
- }
-
- @Test
- public void testFfwdButtonClick() throws Throwable {
- final CountDownLatch latchForPausedState = new CountDownLatch(1);
- final CountDownLatch latchForFfwd = new CountDownLatch(1);
- registerCallback(new SessionPlayer.PlayerCallback() {
- @Override
- public void onSeekCompleted(@NonNull SessionPlayer player, long position) {
- if (position >= FFWD_MS) {
- latchForFfwd.countDown();
- }
- }
-
- @Override
- public void onPlayerStateChanged(@NonNull SessionPlayer player, int state) {
- if (state == SessionPlayer.PLAYER_STATE_PAUSED) {
- latchForPausedState.countDown();
- }
- }
- });
- setAndPrepare(mFileSchemeMediaItem);
- assertTrue(latchForPausedState.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
- onView(allOf(withId(R.id.ffwd), isCompletelyDisplayed())).perform(click());
- assertTrue(latchForFfwd.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
- }
-
- @Test
- public void testRewButtonClick() throws Throwable {
- final CountDownLatch latchForFfwd = new CountDownLatch(1);
- final CountDownLatch latchForRew = new CountDownLatch(1);
- registerCallback(new SessionPlayer.PlayerCallback() {
- long mExpectedPosition = FFWD_MS;
- final long mDelta = 1000L;
-
- @Override
- public void onPlayerStateChanged(@NonNull SessionPlayer player, int state) {
- if (state == SessionPlayer.PLAYER_STATE_PAUSED) {
- mExpectedPosition = FFWD_MS;
- player.seekTo(mExpectedPosition);
- }
- }
-
- @Override
- public void onSeekCompleted(@NonNull SessionPlayer player, long position) {
- // Ignore the initial seek. Internal MediaPlayer behavior can be changed.
- if (position == 0 && mExpectedPosition == FFWD_MS) {
- return;
- }
- assertTrue(equalsSeekPosition(mExpectedPosition, position, mDelta));
- if (mExpectedPosition == FFWD_MS) {
- mExpectedPosition = position - REW_MS;
- latchForFfwd.countDown();
- } else {
- latchForRew.countDown();
- }
- }
-
- private boolean equalsSeekPosition(long expected, long actual, long delta) {
- return (actual < expected + delta) && (actual > expected - delta);
- }
- });
- setAndPrepare(mFileSchemeMediaItem);
- assertTrue(latchForFfwd.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
- onView(allOf(withId(R.id.rew), isCompletelyDisplayed())).perform(click());
- assertTrue(latchForRew.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
- }
-
- @Test
- public void testSetMetadataForNonMusicFile() throws Throwable {
- final String title = "BigBuckBunny";
- final CountDownLatch latch = new CountDownLatch(1);
- final MediaMetadata metadata = new MediaMetadata.Builder()
- .putString(MediaMetadata.METADATA_KEY_TITLE, title).build();
- registerCallback(new SessionPlayer.PlayerCallback() {
- @Override
- public void onCurrentMediaItemChanged(@NonNull SessionPlayer player,
- @NonNull MediaItem item) {
- assertNotNull(item);
- assertNotNull(item.getMetadata());
- assertEquals(title, metadata.getString(MediaMetadata.METADATA_KEY_TITLE));
- latch.countDown();
- }
- });
- mFileSchemeMediaItem.setMetadata(metadata);
- mPlayer.setMediaItem(mFileSchemeMediaItem);
- assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
- onView(withId(R.id.title_text)).check(matches(withText(title)));
- }
-
- @Test
- public void testButtonVisibilityForMusicFile() throws Throwable {
- Uri uri = Uri.parse("android.resource://" + mContext.getPackageName() + "/"
- + R.raw.test_music);
- final MediaItem uriMediaItem = createTestMediaItem(uri);
-
- final CountDownLatch latch = new CountDownLatch(1);
- registerCallback(new SessionPlayer.PlayerCallback() {
- @Override
- public void onTrackInfoChanged(@NonNull SessionPlayer player,
- @NonNull List<TrackInfo> trackInfos) {
- latch.countDown();
- }
- });
- setAndPrepare(uriMediaItem);
- assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
- onView(withId(R.id.subtitle)).check(matches(not(isDisplayed())));
- }
-
- @Test
- public void testUpdateAndSelectSubtitleTrack() throws Throwable {
- Uri uri = Uri.parse("android.resource://" + mContext.getPackageName() + "/"
- + R.raw.testvideo_with_2_subtitle_tracks);
-
- final String subtitleTrackOffText = mContext.getResources().getString(
- R.string.MediaControlView_subtitle_off_text);
- final String subtitleTrack1Text = mContext.getResources().getString(
- R.string.MediaControlView_subtitle_track_number_text, 1);
-
- final MediaItem mediaItem = createTestMediaItem(uri);
-
- final CountDownLatch latchForTrackUpdate = new CountDownLatch(1);
- final CountDownLatch latchForSubtitleSelect = new CountDownLatch(1);
- final CountDownLatch latchForSubtitleDeselect = new CountDownLatch(1);
- registerCallback(new SessionPlayer.PlayerCallback() {
- private TrackInfo mFirstSubtitleTrack;
-
- @Override
- public void onTrackInfoChanged(@NonNull SessionPlayer player,
- @NonNull List<TrackInfo> trackInfos) {
- if (mFirstSubtitleTrack != null) {
- return;
- }
- assertNotNull(trackInfos);
- for (int i = 0; i < trackInfos.size(); i++) {
- TrackInfo trackInfo = trackInfos.get(i);
- if (trackInfo.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
- mFirstSubtitleTrack = trackInfo;
- latchForTrackUpdate.countDown();
- break;
- }
- }
- }
-
- @Override
- public void onTrackSelected(@NonNull SessionPlayer player,
- @NonNull TrackInfo trackInfo) {
- assertEquals(mFirstSubtitleTrack, trackInfo);
- latchForSubtitleSelect.countDown();
- }
-
- @Override
- public void onTrackDeselected(@NonNull SessionPlayer player,
- @NonNull TrackInfo trackInfo) {
- assertEquals(mFirstSubtitleTrack, trackInfo);
- latchForSubtitleDeselect.countDown();
- }
- });
- // MediaPlayer needs a surface to be set in order to produce subtitle tracks
- mPlayer.setSurfaceInternal(mActivity.getSurfaceHolder().getSurface());
- setAndPrepare(mediaItem);
- assertTrue(latchForTrackUpdate.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
-
- onView(withId(R.id.subtitle)).check(matches(isClickable()));
- onView(withId(R.id.subtitle)).perform(click());
- onView(withText(subtitleTrack1Text)).inRoot(isPlatformPopup())
- .check(matches(isCompletelyDisplayed()));
- onView(withText(subtitleTrack1Text)).inRoot(isPlatformPopup()).perform(click());
- assertTrue(latchForSubtitleSelect.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
-
- onView(withId(R.id.subtitle)).check(matches(isClickable()));
- onView(withId(R.id.subtitle)).perform(click());
- onView(withText(subtitleTrackOffText)).inRoot(isPlatformPopup())
- .check(matches(isCompletelyDisplayed()));
- onView(withText(subtitleTrackOffText)).inRoot(isPlatformPopup()).perform(click());
- assertTrue(latchForSubtitleDeselect.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
- }
-
- private void registerCallback(SessionPlayer.PlayerCallback callback) {
- mPlayer.registerPlayerCallback(mMainHandlerExecutor, callback);
- }
-
- private void setAndPrepare(MediaItem item) {
- mPlayer.setMediaItem(item);
- mPlayer.prepare();
+public class MediaControlView_WithPlayerTest extends MediaControlView_WithSthTestBase {
+ @Override
+ PlayerWrapper createPlayerWrapper(@NonNull PlayerWrapper.PlayerCallback callback,
+ @Nullable MediaItem item) {
+ return createPlayerWrapperOfPlayer(callback, item);
}
}
diff --git a/media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithSthTestBase.java b/media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithSthTestBase.java
new file mode 100644
index 00000000000..5ad0eb6a218
--- /dev/null
+++ b/media2/widget/src/androidTest/java/androidx/media2/widget/MediaControlView_WithSthTestBase.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2019 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 androidx.media2.widget;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.RootMatchers.isPlatformPopup;
+import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
+import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.net.Uri;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.media2.common.MediaItem;
+import androidx.media2.common.MediaMetadata;
+import androidx.media2.common.SessionPlayer;
+import androidx.media2.common.SessionPlayer.TrackInfo;
+import androidx.media2.session.MediaController;
+import androidx.media2.widget.test.R;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Base class for testing {@link MediaControlView} with a {@link SessionPlayer} or
+ * {@link MediaController}.
+ */
+public abstract class MediaControlView_WithSthTestBase extends MediaWidgetTestBase {
+ private static final long FFWD_MS = 30000L;
+ private static final long REW_MS = 10000L;
+
+ private MediaControlViewTestActivity mActivity;
+ private MediaControlView mMediaControlView;
+ private MediaItem mFileSchemeMediaItem;
+
+ @Rule
+ public ActivityTestRule<MediaControlViewTestActivity> mActivityRule =
+ new ActivityTestRule<>(MediaControlViewTestActivity.class);
+
+ @Before
+ public void setup() throws Throwable {
+ mActivity = mActivityRule.getActivity();
+ mMediaControlView = mActivity.findViewById(R.id.mediacontrolview);
+
+ Uri fileSchemeUri = Uri.parse("android.resource://" + mContext.getPackageName() + "/"
+ + R.raw.test_file_scheme_video);
+ mFileSchemeMediaItem = createTestMediaItem(fileSchemeUri);
+
+ setKeepScreenOn(mActivityRule);
+ checkAttachedToWindow(mMediaControlView);
+ }
+
+ @After
+ public void tearDown() throws Throwable {
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ closeAll();
+ }
+ });
+ }
+
+ @Test
+ public void testPlayPauseButtonClick() throws Throwable {
+ final CountDownLatch latchForPausedState = new CountDownLatch(1);
+ final CountDownLatch latchForPlayingState = new CountDownLatch(1);
+ final PlayerWrapper playerWrapper = createPlayerWrapper(new PlayerWrapper.PlayerCallback() {
+ @Override
+ public void onPlayerStateChanged(@NonNull PlayerWrapper player, int state) {
+ if (state == SessionPlayer.PLAYER_STATE_PAUSED) {
+ latchForPausedState.countDown();
+ } else if (state == SessionPlayer.PLAYER_STATE_PLAYING) {
+ latchForPlayingState.countDown();
+ }
+ }
+ }, mFileSchemeMediaItem);
+ setPlayerWrapper(playerWrapper);
+ assertTrue(latchForPausedState.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ onView(allOf(withId(R.id.pause), isCompletelyDisplayed())).perform(click());
+ assertTrue(latchForPlayingState.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testFfwdButtonClick() throws Throwable {
+ final CountDownLatch latchForPausedState = new CountDownLatch(1);
+ final CountDownLatch latchForFfwd = new CountDownLatch(1);
+ final PlayerWrapper playerWrapper = createPlayerWrapper(new PlayerWrapper.PlayerCallback() {
+ @Override
+ public void onSeekCompleted(@NonNull PlayerWrapper player, long position) {
+ if (position >= FFWD_MS) {
+ latchForFfwd.countDown();
+ }
+ }
+
+ @Override
+ public void onPlayerStateChanged(@NonNull PlayerWrapper player, int state) {
+ if (state == SessionPlayer.PLAYER_STATE_PAUSED) {
+ latchForPausedState.countDown();
+ }
+ }
+ }, mFileSchemeMediaItem);
+ setPlayerWrapper(playerWrapper);
+ assertTrue(latchForPausedState.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ onView(allOf(withId(R.id.ffwd), isCompletelyDisplayed())).perform(click());
+ assertTrue(latchForFfwd.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testRewButtonClick() throws Throwable {
+ final CountDownLatch latchForFfwd = new CountDownLatch(1);
+ final CountDownLatch latchForRew = new CountDownLatch(1);
+ final PlayerWrapper playerWrapper = createPlayerWrapper(new PlayerWrapper.PlayerCallback() {
+ long mExpectedPosition = FFWD_MS;
+ final long mDelta = 1000L;
+
+ @Override
+ public void onPlayerStateChanged(@NonNull PlayerWrapper player, int state) {
+ if (state == SessionPlayer.PLAYER_STATE_PAUSED) {
+ mExpectedPosition = FFWD_MS;
+ player.seekTo(mExpectedPosition);
+ }
+ }
+
+ @Override
+ public void onSeekCompleted(@NonNull PlayerWrapper player, long position) {
+ // Ignore the initial seek. Internal MediaPlayer behavior can be changed.
+ if (position == 0 && mExpectedPosition == FFWD_MS) {
+ return;
+ }
+ assertTrue(equalsSeekPosition(mExpectedPosition, position, mDelta));
+ if (mExpectedPosition == FFWD_MS) {
+ mExpectedPosition = position - REW_MS;
+ latchForFfwd.countDown();
+ } else {
+ latchForRew.countDown();
+ }
+ }
+
+ private boolean equalsSeekPosition(long expected, long actual, long delta) {
+ return (actual < expected + delta) && (actual > expected - delta);
+ }
+ }, mFileSchemeMediaItem);
+ setPlayerWrapper(playerWrapper);
+ assertTrue(latchForFfwd.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ onView(allOf(withId(R.id.rew), isCompletelyDisplayed())).perform(click());
+ assertTrue(latchForRew.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testSetMetadataForNonMusicFile() throws Throwable {
+ final String title = "BigBuckBunny";
+ final CountDownLatch latch = new CountDownLatch(1);
+ final MediaMetadata metadata = new MediaMetadata.Builder()
+ .putString(MediaMetadata.METADATA_KEY_TITLE, title).build();
+ mFileSchemeMediaItem.setMetadata(metadata);
+ final PlayerWrapper playerWrapper = createPlayerWrapper(new PlayerWrapper.PlayerCallback() {
+ @Override
+ public void onCurrentMediaItemChanged(@NonNull PlayerWrapper player,
+ @Nullable MediaItem item) {
+ if (item != null) {
+ assertNotNull(item.getMetadata());
+ assertEquals(title, metadata.getString(MediaMetadata.METADATA_KEY_TITLE));
+ latch.countDown();
+ }
+ }
+ }, mFileSchemeMediaItem);
+ setPlayerWrapper(playerWrapper);
+ assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ onView(withId(R.id.title_text)).check(matches(withText(title)));
+ }
+
+ @Test
+ public void testButtonVisibilityForMusicFile() throws Throwable {
+ Uri uri = Uri.parse("android.resource://" + mContext.getPackageName() + "/"
+ + R.raw.test_music);
+ final MediaItem uriMediaItem = createTestMediaItem(uri);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final PlayerWrapper playerWrapper = createPlayerWrapper(new PlayerWrapper.PlayerCallback() {
+ @Override
+ public void onTrackInfoChanged(@NonNull PlayerWrapper player,
+ @NonNull List<TrackInfo> trackInfos) {
+ latch.countDown();
+ }
+ }, uriMediaItem);
+ setPlayerWrapper(playerWrapper);
+ assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ onView(withId(R.id.subtitle)).check(matches(not(isDisplayed())));
+ }
+
+ @Test
+ public void testUpdateAndSelectSubtitleTrack() throws Throwable {
+ Uri uri = Uri.parse("android.resource://" + mContext.getPackageName() + "/"
+ + R.raw.testvideo_with_2_subtitle_tracks);
+
+ final String subtitleTrackOffText = mContext.getResources().getString(
+ R.string.MediaControlView_subtitle_off_text);
+ final String subtitleTrack1Text = mContext.getResources().getString(
+ R.string.MediaControlView_subtitle_track_number_text, 1);
+
+ final MediaItem mediaItem = createTestMediaItem(uri);
+
+ final CountDownLatch latchForReady = new CountDownLatch(1);
+ final CountDownLatch latchForTrackUpdate = new CountDownLatch(1);
+ final CountDownLatch latchForSubtitleSelect = new CountDownLatch(1);
+ final CountDownLatch latchForSubtitleDeselect = new CountDownLatch(1);
+ final PlayerWrapper playerWrapper = createPlayerWrapper(new PlayerWrapper.PlayerCallback() {
+ private TrackInfo mFirstSubtitleTrack;
+
+ @Override
+ public void onPlayerStateChanged(@NonNull PlayerWrapper player, int state) {
+ if (state == SessionPlayer.PLAYER_STATE_PAUSED) {
+ latchForReady.countDown();
+ }
+ }
+
+ @Override
+ public void onTrackInfoChanged(@NonNull PlayerWrapper player,
+ @NonNull List<TrackInfo> trackInfos) {
+ if (mFirstSubtitleTrack != null) {
+ return;
+ }
+ assertNotNull(trackInfos);
+ for (int i = 0; i < trackInfos.size(); i++) {
+ TrackInfo trackInfo = trackInfos.get(i);
+ if (trackInfo.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
+ mFirstSubtitleTrack = trackInfo;
+ latchForTrackUpdate.countDown();
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onTrackSelected(@NonNull PlayerWrapper player,
+ @NonNull TrackInfo trackInfo) {
+ assertEquals(mFirstSubtitleTrack, trackInfo);
+ latchForSubtitleSelect.countDown();
+ }
+
+ @Override
+ public void onTrackDeselected(@NonNull PlayerWrapper player,
+ @NonNull TrackInfo trackInfo) {
+ assertEquals(mFirstSubtitleTrack, trackInfo);
+ latchForSubtitleDeselect.countDown();
+ }
+ }, mediaItem);
+ setPlayerWrapper(playerWrapper);
+ assertTrue(latchForReady.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ // MediaPlayer needs a surface to be set in order to produce subtitle tracks
+ playerWrapper.setSurface(mActivity.getSurfaceHolder().getSurface());
+ assertTrue(latchForTrackUpdate.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+ onView(withId(R.id.subtitle)).check(matches(isClickable()));
+ onView(withId(R.id.subtitle)).perform(click());
+ onView(withText(subtitleTrack1Text)).inRoot(isPlatformPopup())
+ .check(matches(isCompletelyDisplayed()));
+ onView(withText(subtitleTrack1Text)).inRoot(isPlatformPopup()).perform(click());
+ assertTrue(latchForSubtitleSelect.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+ onView(withId(R.id.subtitle)).check(matches(isClickable()));
+ onView(withId(R.id.subtitle)).perform(click());
+ onView(withText(subtitleTrackOffText)).inRoot(isPlatformPopup())
+ .check(matches(isCompletelyDisplayed()));
+ onView(withText(subtitleTrackOffText)).inRoot(isPlatformPopup()).perform(click());
+ assertTrue(latchForSubtitleDeselect.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ private void setPlayerWrapper(final PlayerWrapper playerWrapper) throws Throwable {
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (playerWrapper.mPlayer != null) {
+ mMediaControlView.setPlayer(playerWrapper.mPlayer);
+ } else if (playerWrapper.mController != null) {
+ mMediaControlView.setMediaController(playerWrapper.mController);
+ }
+ }
+ });
+ }
+
+ abstract PlayerWrapper createPlayerWrapper(@NonNull PlayerWrapper.PlayerCallback callback,
+ @Nullable MediaItem item);
+}
diff --git a/media2/widget/src/androidTest/java/androidx/media2/widget/MediaTestBase.java b/media2/widget/src/androidTest/java/androidx/media2/widget/MediaTestBase.java
new file mode 100644
index 00000000000..e6d429f41c0
--- /dev/null
+++ b/media2/widget/src/androidTest/java/androidx/media2/widget/MediaTestBase.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2019 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 androidx.media2.widget;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.os.Looper;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.BeforeClass;
+
+/**
+ * Base class for all media tests.
+ */
+abstract class MediaTestBase {
+ /**
+ * All tests methods should start with this.
+ * <p>
+ * MediaControllerCompat, which is wrapped by the MediaSession, can be only created by the
+ * thread whose Looper is prepared. However, when the presubmit test runs on the server,
+ * test runs with the {@link org.junit.internal.runners.statements.FailOnTimeout} which creates
+ * dedicated thread for running test methods while methods annotated with @After or @Before
+ * runs on the normal test different thread. This ensures that the current Looper is prepared.
+ */
+ public static void prepareLooper() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ }
+
+ @BeforeClass
+ public static void setupMainLooper() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ // Prepare the main looper if it hasn't.
+ // Some framework APIs always run on the main looper.
+ if (Looper.getMainLooper() == null) {
+ Looper.prepareMainLooper();
+ }
+
+ // Initialize AudioManager on the main thread to workaround b/78617702 that
+ // audio focus listener is called on the thread where the AudioManager was
+ // originally initialized.
+ // Without posting this, audio focus listeners wouldn't be called because the
+ // listeners would be posted to the test thread (here) where it waits until the
+ // tests are finished.
+ Context context = ApplicationProvider.getApplicationContext();
+ AudioManager manager =
+ (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ }
+ });
+ }
+}
diff --git a/media2/widget/src/androidTest/java/androidx/media2/widget/MediaWidgetTestBase.java b/media2/widget/src/androidTest/java/androidx/media2/widget/MediaWidgetTestBase.java
index e93dced91e1..c6960d32056 100644
--- a/media2/widget/src/androidTest/java/androidx/media2/widget/MediaWidgetTestBase.java
+++ b/media2/widget/src/androidTest/java/androidx/media2/widget/MediaWidgetTestBase.java
@@ -29,9 +29,15 @@ import android.os.Build;
import android.view.View;
import android.view.WindowManager;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.media2.common.MediaItem;
+import androidx.media2.common.SessionPlayer;
import androidx.media2.common.UriMediaItem;
+import androidx.media2.player.MediaPlayer;
+import androidx.media2.session.MediaController;
+import androidx.media2.session.MediaSession;
import androidx.media2.widget.test.R;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -39,14 +45,20 @@ import androidx.test.rule.ActivityTestRule;
import org.junit.Before;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
-public class MediaWidgetTestBase {
+public class MediaWidgetTestBase extends MediaTestBase {
// Expected success time
static final int WAIT_TIME_MS = 1000;
+ private List<SessionPlayer> mPlayers = new ArrayList<>();
+ private List<MediaSession> mSessions = new ArrayList<>();
+ private List<MediaController> mControllers = new ArrayList<>();
+
Context mContext;
Executor mMainHandlerExecutor;
@@ -108,4 +120,57 @@ public class MediaWidgetTestBase {
MediaItem createTestMediaItem(Uri uri) {
return new UriMediaItem.Builder(uri).build();
}
+
+ PlayerWrapper createPlayerWrapperOfController(@NonNull PlayerWrapper.PlayerCallback callback,
+ @Nullable MediaItem item) {
+ prepareLooper();
+
+ SessionPlayer player = new MediaPlayer(mContext);
+ MediaSession session = new MediaSession.Builder(mContext, player).build();
+ MediaController controller = new MediaController.Builder(mContext)
+ .setSessionToken(session.getToken())
+ .build();
+ mPlayers.add(player);
+ mSessions.add(session);
+ mControllers.add(controller);
+ PlayerWrapper wrapper = new PlayerWrapper(controller, mMainHandlerExecutor, callback);
+ wrapper.attachCallback();
+ if (item != null) {
+ player.setMediaItem(item);
+ player.prepare();
+ }
+ return wrapper;
+ }
+
+ PlayerWrapper createPlayerWrapperOfPlayer(@NonNull PlayerWrapper.PlayerCallback callback,
+ @Nullable MediaItem item) {
+ SessionPlayer player = new MediaPlayer(mContext);
+ mPlayers.add(player);
+ PlayerWrapper wrapper = new PlayerWrapper(player, mMainHandlerExecutor, callback);
+ wrapper.attachCallback();
+ if (item != null) {
+ player.setMediaItem(item);
+ player.prepare();
+ }
+ return wrapper;
+ }
+
+ void closeAll() {
+ for (MediaController controller : mControllers) {
+ controller.close();
+ }
+ for (MediaSession session : mSessions) {
+ session.close();
+ }
+ for (SessionPlayer player : mPlayers) {
+ try {
+ player.close();
+ } catch (Exception ex) {
+ // ignore
+ }
+ }
+ mControllers.clear();
+ mSessions.clear();
+ mPlayers.clear();
+ }
}
diff --git a/media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithControllerTest.java b/media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithControllerTest.java
new file mode 100644
index 00000000000..8fd72f56141
--- /dev/null
+++ b/media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithControllerTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 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 androidx.media2.widget;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.media2.common.MediaItem;
+import androidx.media2.session.MediaController;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link VideoView} with a {@link MediaController}.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class VideoView_WithControllerTest extends VideoView_WithSthTestBase {
+ @Override
+ PlayerWrapper createPlayerWrapper(@NonNull PlayerWrapper.PlayerCallback callback,
+ @Nullable MediaItem item) {
+ return createPlayerWrapperOfController(callback, item);
+ }
+}
diff --git a/media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithPlayerTest.java b/media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithPlayerTest.java
index 1fa4b5c8888..9387a4197a1 100644
--- a/media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithPlayerTest.java
+++ b/media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithPlayerTest.java
@@ -16,31 +16,13 @@
package androidx.media2.widget;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-
-import android.app.Activity;
-import android.content.res.AssetFileDescriptor;
-import android.os.ParcelFileDescriptor;
-
-import androidx.media2.common.FileMediaItem;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.media2.common.MediaItem;
import androidx.media2.common.SessionPlayer;
-import androidx.media2.player.MediaPlayer;
-import androidx.media2.widget.test.R;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
-import androidx.test.rule.ActivityTestRule;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
import org.junit.runner.RunWith;
/**
@@ -48,160 +30,10 @@ import org.junit.runner.RunWith;
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
-public class VideoView_WithPlayerTest extends MediaWidgetTestBase {
- private Activity mActivity;
- private VideoView mVideoView;
- private MediaItem mMediaItem;
- private SessionPlayer.PlayerCallback mPlayerCallback;
- private SessionPlayer mPlayer;
-
- @Rule
- public ActivityTestRule<VideoViewTestActivity> mActivityRule =
- new ActivityTestRule<>(VideoViewTestActivity.class);
-
- @Before
- public void setup() throws Throwable {
- mActivity = mActivityRule.getActivity();
- mVideoView = mActivity.findViewById(R.id.videoview);
- mMediaItem = createTestMediaItem();
-
- setKeepScreenOn(mActivityRule);
- checkAttachedToWindow(mVideoView);
-
- mPlayerCallback = mock(SessionPlayer.PlayerCallback.class);
- mPlayer = new MediaPlayer(mContext);
- mPlayer.registerPlayerCallback(mMainHandlerExecutor, mPlayerCallback);
- mActivityRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mVideoView.setPlayer(mPlayer);
- }
- });
- }
-
- @After
- public void tearDown() throws Throwable {
- mActivityRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- try {
- mPlayer.close();
- } catch (Exception ex) {
- // ignore
- }
- }
- });
- }
-
- @Test
- public void testPlayVideo() throws Throwable {
- waitToPrepare(mMediaItem);
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeastOnce()).onCurrentMediaItemChanged(
- any(SessionPlayer.class), any(MediaItem.class));
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeastOnce()).onPlayerStateChanged(
- any(SessionPlayer.class), eq(SessionPlayer.PLAYER_STATE_PAUSED));
- verify(mPlayerCallback, after(WAIT_TIME_MS).never()).onPlayerStateChanged(
- any(SessionPlayer.class), eq(SessionPlayer.PLAYER_STATE_PLAYING));
- assertEquals(SessionPlayer.PLAYER_STATE_PAUSED, mPlayer.getPlayerState());
-
- mPlayer.play();
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeastOnce()).onPlayerStateChanged(
- any(SessionPlayer.class), eq(SessionPlayer.PLAYER_STATE_PLAYING));
- }
-
- @Test
- public void testPlayVideoWithMediaItemFromFileDescriptor() throws Throwable {
- AssetFileDescriptor afd = mContext.getResources()
- .openRawResourceFd(R.raw.testvideo_with_2_subtitle_tracks);
- final MediaItem item = new FileMediaItem.Builder(
- ParcelFileDescriptor.dup(afd.getFileDescriptor()))
- .setFileDescriptorOffset(afd.getStartOffset())
- .setFileDescriptorLength(afd.getLength())
- .build();
- afd.close();
-
- waitToPrepare(item);
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeastOnce()).onCurrentMediaItemChanged(
- any(SessionPlayer.class), eq(item));
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeastOnce()).onPlayerStateChanged(
- any(SessionPlayer.class), eq(SessionPlayer.PLAYER_STATE_PAUSED));
-
- mPlayer.play();
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeastOnce()).onPlayerStateChanged(
- any(SessionPlayer.class), eq(SessionPlayer.PLAYER_STATE_PLAYING));
- }
-
- @Test
- public void testPlayVideoOnTextureView() throws Throwable {
- final VideoView.OnViewTypeChangedListener mockViewTypeListener =
- mock(VideoView.OnViewTypeChangedListener.class);
-
- // The default view type is surface view.
- assertEquals(mVideoView.getViewType(), VideoView.VIEW_TYPE_SURFACEVIEW);
-
- mActivityRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mVideoView.setOnViewTypeChangedListener(mockViewTypeListener);
- mVideoView.setViewType(VideoView.VIEW_TYPE_TEXTUREVIEW);
- }
- });
- waitToPrepare(mMediaItem);
- verify(mockViewTypeListener, timeout(WAIT_TIME_MS))
- .onViewTypeChanged(mVideoView, VideoView.VIEW_TYPE_TEXTUREVIEW);
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeastOnce()).onCurrentMediaItemChanged(
- any(SessionPlayer.class), any(MediaItem.class));
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeast(1)).onPlayerStateChanged(
- any(SessionPlayer.class), eq(SessionPlayer.PLAYER_STATE_PAUSED));
-
- mPlayer.play();
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeast(1)).onPlayerStateChanged(
- any(SessionPlayer.class), eq(SessionPlayer.PLAYER_STATE_PLAYING));
- }
-
- @Test
- public void testSetViewType() throws Throwable {
- final VideoView.OnViewTypeChangedListener mockViewTypeListener =
- mock(VideoView.OnViewTypeChangedListener.class);
-
- // The default view type is surface view.
- assertEquals(mVideoView.getViewType(), VideoView.VIEW_TYPE_SURFACEVIEW);
-
- mActivityRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mVideoView.setOnViewTypeChangedListener(mockViewTypeListener);
- mVideoView.setViewType(VideoView.VIEW_TYPE_TEXTUREVIEW);
- mVideoView.setViewType(VideoView.VIEW_TYPE_SURFACEVIEW);
- mVideoView.setViewType(VideoView.VIEW_TYPE_TEXTUREVIEW);
- mVideoView.setViewType(VideoView.VIEW_TYPE_SURFACEVIEW);
- }
- });
-
- waitToPrepare(mMediaItem);
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeastOnce()).onCurrentMediaItemChanged(
- any(SessionPlayer.class), any(MediaItem.class));
- // WAIT_TIME_MS multiplied by the number of operations.
- verify(mPlayerCallback, timeout(WAIT_TIME_MS * 5).atLeast(1)).onPlayerStateChanged(
- any(SessionPlayer.class), eq(SessionPlayer.PLAYER_STATE_PAUSED));
- assertEquals(mVideoView.getViewType(), VideoView.VIEW_TYPE_SURFACEVIEW);
-
- mPlayer.play();
- verify(mPlayerCallback, timeout(WAIT_TIME_MS).atLeastOnce()).onPlayerStateChanged(
- any(SessionPlayer.class), eq(SessionPlayer.PLAYER_STATE_PLAYING));
-
- mActivityRule.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mVideoView.setViewType(VideoView.VIEW_TYPE_TEXTUREVIEW);
- }
- });
- verify(mockViewTypeListener, timeout(WAIT_TIME_MS))
- .onViewTypeChanged(mVideoView, VideoView.VIEW_TYPE_TEXTUREVIEW);
- }
-
- private void waitToPrepare(MediaItem item) throws Exception {
- mPlayer.setMediaItem(item);
- mPlayer.prepare().get();
+public class VideoView_WithPlayerTest extends VideoView_WithSthTestBase {
+ @Override
+ PlayerWrapper createPlayerWrapper(@NonNull PlayerWrapper.PlayerCallback callback,
+ @Nullable MediaItem item) {
+ return createPlayerWrapperOfPlayer(callback, item);
}
}
diff --git a/media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithSthTestBase.java b/media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithSthTestBase.java
new file mode 100644
index 00000000000..1996d0d5820
--- /dev/null
+++ b/media2/widget/src/androidTest/java/androidx/media2/widget/VideoView_WithSthTestBase.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2019 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 androidx.media2.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.content.res.AssetFileDescriptor;
+import android.os.ParcelFileDescriptor;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.media2.common.FileMediaItem;
+import androidx.media2.common.MediaItem;
+import androidx.media2.common.SessionPlayer;
+import androidx.media2.session.MediaController;
+import androidx.media2.widget.test.R;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Base class for testing {@link VideoView} with a {@link SessionPlayer} or
+ * {@link MediaController}.
+ */
+public abstract class VideoView_WithSthTestBase extends MediaWidgetTestBase {
+ private Activity mActivity;
+ private VideoView mVideoView;
+ private MediaItem mMediaItem;
+
+ @Rule
+ public ActivityTestRule<VideoViewTestActivity> mActivityRule =
+ new ActivityTestRule<>(VideoViewTestActivity.class);
+
+ @Before
+ public void setup() throws Throwable {
+ mActivity = mActivityRule.getActivity();
+ mVideoView = mActivity.findViewById(R.id.videoview);
+ mMediaItem = createTestMediaItem();
+
+ setKeepScreenOn(mActivityRule);
+ checkAttachedToWindow(mVideoView);
+ }
+
+ @After
+ public void tearDown() throws Throwable {
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ closeAll();
+ }
+ });
+ }
+
+ @Test
+ public void testPlayVideo() throws Throwable {
+ PlayerCallback callback = new PlayerCallback();
+ PlayerWrapper playerWrapper = createPlayerWrapper(callback, mMediaItem);
+ setPlayerWrapper(playerWrapper);
+ assertTrue(callback.mItemLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ assertTrue(callback.mPausedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ assertEquals(1, callback.mPlayingLatch.getCount());
+ assertEquals(SessionPlayer.PLAYER_STATE_PAUSED, playerWrapper.getPlayerState());
+
+ playerWrapper.play();
+ assertTrue(callback.mPlayingLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testPlayVideoWithMediaItemFromFileDescriptor() throws Throwable {
+ AssetFileDescriptor afd = mContext.getResources()
+ .openRawResourceFd(R.raw.testvideo_with_2_subtitle_tracks);
+ final MediaItem item = new FileMediaItem.Builder(
+ ParcelFileDescriptor.dup(afd.getFileDescriptor()))
+ .setFileDescriptorOffset(afd.getStartOffset())
+ .setFileDescriptorLength(afd.getLength())
+ .build();
+ afd.close();
+
+ PlayerCallback callback = new PlayerCallback();
+ PlayerWrapper playerWrapper = createPlayerWrapper(callback, item);
+ setPlayerWrapper(playerWrapper);
+ assertTrue(callback.mItemLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ assertTrue(callback.mPausedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+ playerWrapper.play();
+ assertTrue(callback.mPlayingLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testPlayVideoOnTextureView() throws Throwable {
+ final VideoView.OnViewTypeChangedListener mockViewTypeListener =
+ mock(VideoView.OnViewTypeChangedListener.class);
+
+ PlayerCallback callback = new PlayerCallback();
+ PlayerWrapper playerWrapper = createPlayerWrapper(callback, mMediaItem);
+ setPlayerWrapper(playerWrapper);
+
+ // The default view type is surface view.
+ assertEquals(mVideoView.getViewType(), VideoView.VIEW_TYPE_SURFACEVIEW);
+
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mVideoView.setOnViewTypeChangedListener(mockViewTypeListener);
+ mVideoView.setViewType(VideoView.VIEW_TYPE_TEXTUREVIEW);
+ }
+ });
+ verify(mockViewTypeListener, timeout(WAIT_TIME_MS))
+ .onViewTypeChanged(mVideoView, VideoView.VIEW_TYPE_TEXTUREVIEW);
+ assertTrue(callback.mItemLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ assertTrue(callback.mPausedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+ playerWrapper.play();
+ assertTrue(callback.mPlayingLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ }
+
+ @Test
+ public void testSetViewType() throws Throwable {
+ final VideoView.OnViewTypeChangedListener mockViewTypeListener =
+ mock(VideoView.OnViewTypeChangedListener.class);
+
+ PlayerCallback callback = new PlayerCallback();
+ PlayerWrapper playerWrapper = createPlayerWrapper(callback, mMediaItem);
+ setPlayerWrapper(playerWrapper);
+
+ // The default view type is surface view.
+ assertEquals(mVideoView.getViewType(), VideoView.VIEW_TYPE_SURFACEVIEW);
+
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mVideoView.setOnViewTypeChangedListener(mockViewTypeListener);
+ mVideoView.setViewType(VideoView.VIEW_TYPE_TEXTUREVIEW);
+ mVideoView.setViewType(VideoView.VIEW_TYPE_SURFACEVIEW);
+ mVideoView.setViewType(VideoView.VIEW_TYPE_TEXTUREVIEW);
+ mVideoView.setViewType(VideoView.VIEW_TYPE_SURFACEVIEW);
+ }
+ });
+
+ assertTrue(callback.mItemLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+ // WAIT_TIME_MS multiplied by the number of operations.
+ assertTrue(callback.mPausedLatch.await(WAIT_TIME_MS * 5, TimeUnit.MILLISECONDS));
+ assertEquals(mVideoView.getViewType(), VideoView.VIEW_TYPE_SURFACEVIEW);
+
+ playerWrapper.play();
+ assertTrue(callback.mPlayingLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mVideoView.setViewType(VideoView.VIEW_TYPE_TEXTUREVIEW);
+ }
+ });
+ verify(mockViewTypeListener, timeout(WAIT_TIME_MS))
+ .onViewTypeChanged(mVideoView, VideoView.VIEW_TYPE_TEXTUREVIEW);
+ }
+
+ private void setPlayerWrapper(final PlayerWrapper playerWrapper) throws Throwable {
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (playerWrapper.mPlayer != null) {
+ mVideoView.setPlayer(playerWrapper.mPlayer);
+ } else if (playerWrapper.mController != null) {
+ mVideoView.setMediaController(playerWrapper.mController);
+ }
+ }
+ });
+ }
+
+ private class PlayerCallback extends PlayerWrapper.PlayerCallback {
+ private CountDownLatch mItemLatch = new CountDownLatch(1);
+ private CountDownLatch mPausedLatch = new CountDownLatch(1);
+ private CountDownLatch mPlayingLatch = new CountDownLatch(1);
+
+ @Override
+ void onCurrentMediaItemChanged(@NonNull PlayerWrapper player,
+ @Nullable MediaItem item) {
+ if (item != null) {
+ mItemLatch.countDown();
+ }
+ }
+
+ @Override
+ void onPlayerStateChanged(@NonNull PlayerWrapper player, int state) {
+ if (state == SessionPlayer.PLAYER_STATE_PAUSED) {
+ mPausedLatch.countDown();
+ } else if (state == SessionPlayer.PLAYER_STATE_PLAYING) {
+ mPlayingLatch.countDown();
+ }
+ }
+ }
+
+ abstract PlayerWrapper createPlayerWrapper(@NonNull PlayerWrapper.PlayerCallback callback,
+ @Nullable MediaItem item);
+}