| /* |
| * Copyright (C) 2009 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 android.widget.cts; |
| |
| import static com.android.compatibility.common.util.CtsMockitoUtils.within; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.mockito.Matchers.any; |
| import static org.mockito.Matchers.anyInt; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.verifyZeroInteractions; |
| |
| import android.app.Activity; |
| import android.app.Instrumentation; |
| import android.content.Context; |
| import android.media.AudioAttributes; |
| import android.media.AudioManager; |
| import android.media.AudioPlaybackConfiguration; |
| import android.media.MediaPlayer; |
| import android.os.SystemClock; |
| import android.util.Log; |
| import android.view.View.MeasureSpec; |
| import android.widget.MediaController; |
| import android.widget.VideoView; |
| |
| import androidx.test.InstrumentationRegistry; |
| import androidx.test.annotation.UiThreadTest; |
| import androidx.test.filters.LargeTest; |
| import androidx.test.rule.ActivityTestRule; |
| import androidx.test.runner.AndroidJUnit4; |
| |
| import com.android.compatibility.common.util.MediaUtils; |
| |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.util.List; |
| |
| /** |
| * Test {@link VideoView}. |
| */ |
| @LargeTest |
| @RunWith(AndroidJUnit4.class) |
| public class VideoViewTest { |
| /** Debug TAG. **/ |
| private static final String TAG = "VideoViewTest"; |
| /** The maximum time to wait for an operation. */ |
| private static final long TIME_OUT = 15000L; |
| /** The interval time to wait for completing an operation. */ |
| private static final long OPERATION_INTERVAL = 1500L; |
| /** The duration of R.raw.testvideo. */ |
| private static final int TEST_VIDEO_DURATION = 11047; |
| /** The full name of R.raw.testvideo. */ |
| private static final String VIDEO_NAME = "testvideo.3gp"; |
| /** delta for duration in case user uses different decoders on different |
| hardware that report a duration that's different by a few milliseconds */ |
| private static final int DURATION_DELTA = 100; |
| /** AudioAttributes to be used by this player */ |
| private static final AudioAttributes AUDIO_ATTR = new AudioAttributes.Builder() |
| .setUsage(AudioAttributes.USAGE_GAME) |
| .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) |
| .build(); |
| |
| private Instrumentation mInstrumentation; |
| private Activity mActivity; |
| private VideoView mVideoView; |
| private String mVideoPath; |
| |
| @Rule |
| public ActivityTestRule<VideoViewCtsActivity> mActivityRule = |
| new ActivityTestRule<>(VideoViewCtsActivity.class); |
| |
| @Before |
| public void setup() throws Throwable { |
| mInstrumentation = InstrumentationRegistry.getInstrumentation(); |
| mActivity = mActivityRule.getActivity(); |
| mVideoView = (VideoView) mActivity.findViewById(R.id.videoview); |
| |
| mVideoPath = prepareSampleVideo(); |
| assertNotNull(mVideoPath); |
| } |
| |
| private boolean hasCodec() { |
| return MediaUtils.hasCodecsForResource(mActivity, R.raw.testvideo); |
| } |
| |
| private String prepareSampleVideo() throws IOException { |
| try (InputStream source = mActivity.getResources().openRawResource(R.raw.testvideo); |
| OutputStream target = mActivity.openFileOutput(VIDEO_NAME, Context.MODE_PRIVATE)) { |
| final byte[] buffer = new byte[1024]; |
| for (int len = source.read(buffer); len > 0; len = source.read(buffer)) { |
| target.write(buffer, 0, len); |
| } |
| } |
| |
| return mActivity.getFileStreamPath(VIDEO_NAME).getAbsolutePath(); |
| } |
| |
| private void makeVideoView() throws Throwable { |
| mActivityRule.runOnUiThread(() -> { |
| MediaController mediaController = new MediaController(mActivity); |
| mVideoView.setMediaController(mediaController); |
| }); |
| mInstrumentation.waitForIdleSync(); |
| } |
| |
| @UiThreadTest |
| @Test |
| public void testConstructor() { |
| new VideoView(mActivity); |
| |
| new VideoView(mActivity, null); |
| |
| new VideoView(mActivity, null, 0); |
| } |
| |
| @Test |
| public void testPlayVideo() throws Throwable { |
| makeVideoView(); |
| // Don't run the test if the codec isn't supported. |
| if (!hasCodec()) { |
| Log.i(TAG, "SKIPPING testPlayVideo1(): codec is not supported"); |
| return; |
| } |
| |
| final MediaPlayer.OnPreparedListener mockPreparedListener = |
| mock(MediaPlayer.OnPreparedListener.class); |
| mVideoView.setOnPreparedListener(mockPreparedListener); |
| |
| final MediaPlayer.OnCompletionListener mockCompletionListener = |
| mock(MediaPlayer.OnCompletionListener.class); |
| mVideoView.setOnCompletionListener(mockCompletionListener); |
| |
| mActivityRule.runOnUiThread(() -> mVideoView.setVideoPath(mVideoPath)); |
| verify(mockPreparedListener, within(TIME_OUT)).onPrepared(any(MediaPlayer.class)); |
| verify(mockPreparedListener, times(1)).onPrepared(any(MediaPlayer.class)); |
| verifyZeroInteractions(mockCompletionListener); |
| |
| mActivityRule.runOnUiThread(mVideoView::start); |
| // wait time is longer than duration in case system is sluggish |
| verify(mockCompletionListener, within(TIME_OUT)).onCompletion(any(MediaPlayer.class)); |
| verify(mockCompletionListener, times(1)).onCompletion(any(MediaPlayer.class)); |
| } |
| |
| private static final class MyPlaybackCallback extends AudioManager.AudioPlaybackCallback { |
| boolean mMatchingPlayerFound = false; |
| |
| @Override |
| public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) { |
| for (AudioPlaybackConfiguration apc : configs) { |
| if (apc.getAudioAttributes().getUsage() == AUDIO_ATTR.getUsage() |
| && apc.getAudioAttributes().getContentType() |
| == AUDIO_ATTR.getContentType()) { |
| mMatchingPlayerFound = true; |
| break; |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testAudioAttributes() throws Throwable { |
| makeVideoView(); |
| // Don't run the test if the codec isn't supported. |
| if (!hasCodec()) { |
| Log.i(TAG, "SKIPPING testAudioAttributes(): codec is not supported"); |
| return; |
| } |
| |
| final MediaPlayer.OnCompletionListener mockCompletionListener = |
| mock(MediaPlayer.OnCompletionListener.class); |
| mVideoView.setOnCompletionListener(mockCompletionListener); |
| |
| mVideoView.setAudioAttributes(AUDIO_ATTR); |
| mVideoView.setAudioFocusRequest(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); |
| |
| final AudioManager am = (AudioManager) mActivity.getSystemService(Context.AUDIO_SERVICE); |
| final MyPlaybackCallback myCb = new MyPlaybackCallback(); |
| mActivityRule.runOnUiThread(() -> am.registerAudioPlaybackCallback(myCb, null)); |
| mActivityRule.runOnUiThread(() -> mVideoView.setVideoPath(mVideoPath)); |
| mActivityRule.runOnUiThread(mVideoView::start); |
| // wait time is longer than duration in case system is sluggish |
| verify(mockCompletionListener, within(TIME_OUT)).onCompletion(any(MediaPlayer.class)); |
| verify(mockCompletionListener, times(1)).onCompletion(any(MediaPlayer.class)); |
| |
| // TODO is there a more compact way to test this with mockito? |
| assertTrue("Audio playback configuration not found for VideoView", |
| myCb.mMatchingPlayerFound); |
| } |
| |
| @Test |
| public void testSetOnErrorListener() throws Throwable { |
| makeVideoView(); |
| |
| final MediaPlayer.OnErrorListener mockErrorListener = |
| mock(MediaPlayer.OnErrorListener.class); |
| mVideoView.setOnErrorListener(mockErrorListener); |
| |
| mActivityRule.runOnUiThread(() -> { |
| String path = "unknown path"; |
| mVideoView.setVideoPath(path); |
| mVideoView.start(); |
| }); |
| mInstrumentation.waitForIdleSync(); |
| |
| verify(mockErrorListener, within(TIME_OUT)).onError( |
| any(MediaPlayer.class), anyInt(), anyInt()); |
| verify(mockErrorListener, times(1)).onError(any(MediaPlayer.class), anyInt(), anyInt()); |
| } |
| |
| @Test |
| public void testGetBufferPercentage() throws Throwable { |
| makeVideoView(); |
| // Don't run the test if the codec isn't supported. |
| if (!hasCodec()) { |
| Log.i(TAG, "SKIPPING testGetBufferPercentage(): codec is not supported"); |
| return; |
| } |
| |
| final MediaPlayer.OnPreparedListener mockPreparedListener = |
| mock(MediaPlayer.OnPreparedListener.class); |
| mVideoView.setOnPreparedListener(mockPreparedListener); |
| |
| mActivityRule.runOnUiThread(() -> mVideoView.setVideoPath(mVideoPath)); |
| mInstrumentation.waitForIdleSync(); |
| |
| verify(mockPreparedListener, within(TIME_OUT)).onPrepared(any(MediaPlayer.class)); |
| verify(mockPreparedListener, times(1)).onPrepared(any(MediaPlayer.class)); |
| int percent = mVideoView.getBufferPercentage(); |
| assertTrue(percent >= 0 && percent <= 100); |
| } |
| |
| @UiThreadTest |
| @Test |
| public void testResolveAdjustedSize() { |
| mVideoView = new VideoView(mActivity); |
| |
| final int desiredSize = 100; |
| int resolvedSize = mVideoView.resolveAdjustedSize(desiredSize, MeasureSpec.UNSPECIFIED); |
| assertEquals(desiredSize, resolvedSize); |
| |
| final int specSize = MeasureSpec.getSize(MeasureSpec.AT_MOST); |
| resolvedSize = mVideoView.resolveAdjustedSize(desiredSize, MeasureSpec.AT_MOST); |
| assertEquals(Math.min(desiredSize, specSize), resolvedSize); |
| |
| resolvedSize = mVideoView.resolveAdjustedSize(desiredSize, MeasureSpec.EXACTLY); |
| assertEquals(specSize, resolvedSize); |
| } |
| |
| @Test |
| public void testGetDuration() throws Throwable { |
| // Don't run the test if the codec isn't supported. |
| if (!hasCodec()) { |
| Log.i(TAG, "SKIPPING testGetDuration(): codec is not supported"); |
| return; |
| } |
| |
| mActivityRule.runOnUiThread(() -> mVideoView.setVideoPath(mVideoPath)); |
| SystemClock.sleep(OPERATION_INTERVAL); |
| assertTrue(Math.abs(mVideoView.getDuration() - TEST_VIDEO_DURATION) < DURATION_DELTA); |
| } |
| |
| @UiThreadTest |
| @Test |
| public void testSetMediaController() { |
| final MediaController ctlr = new MediaController(mActivity); |
| mVideoView.setMediaController(ctlr); |
| } |
| } |