1 /*
2  * Copyright (C) 2009 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.widget.cts;
18 
19 import com.android.cts.widget.R;
20 
21 import android.app.Activity;
22 import android.app.Instrumentation;
23 import android.content.Context;
24 import android.cts.util.MediaUtils;
25 import android.cts.util.PollingCheck;
26 import android.media.MediaCodecInfo;
27 import android.media.MediaCodecList;
28 import android.media.MediaPlayer;
29 import android.media.MediaPlayer.OnCompletionListener;
30 import android.media.MediaPlayer.OnErrorListener;
31 import android.media.MediaPlayer.OnPreparedListener;
32 import android.test.ActivityInstrumentationTestCase2;
33 import android.test.UiThreadTest;
34 import android.util.Log;
35 import android.view.View.MeasureSpec;
36 import android.widget.MediaController;
37 import android.widget.VideoView;
38 
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.io.OutputStream;
42 
43 /**
44  * Test {@link VideoView}.
45  */
46 public class VideoViewTest extends ActivityInstrumentationTestCase2<VideoViewCtsActivity> {
47     /** Debug TAG. **/
48     private static final String TAG = "VideoViewTest";
49     /** The maximum time to wait for an operation. */
50     private static final long   TIME_OUT = 15000L;
51     /** The interval time to wait for completing an operation. */
52     private static final long   OPERATION_INTERVAL  = 1500L;
53     /** The duration of R.raw.testvideo. */
54     private static final int    TEST_VIDEO_DURATION = 11047;
55     /** The full name of R.raw.testvideo. */
56     private static final String VIDEO_NAME   = "testvideo.3gp";
57     /** delta for duration in case user uses different decoders on different
58         hardware that report a duration that's different by a few milliseconds */
59     private static final int DURATION_DELTA = 100;
60 
61     private VideoView mVideoView;
62     private Activity mActivity;
63     private Instrumentation mInstrumentation;
64     private String mVideoPath;
65 
66     private static class MockListener {
67         private boolean mTriggered;
68 
MockListener()69         MockListener() {
70             mTriggered = false;
71         }
72 
isTriggered()73         public boolean isTriggered() {
74             return mTriggered;
75         }
76 
onEvent()77         protected void onEvent() {
78             mTriggered = true;
79         }
80     }
81 
82     private static class MockOnPreparedListener extends MockListener
83             implements OnPreparedListener {
onPrepared(MediaPlayer mp)84         public void onPrepared(MediaPlayer mp) {
85             super.onEvent();
86         }
87     }
88 
89     private static class MockOnErrorListener extends MockListener implements OnErrorListener {
onError(MediaPlayer mp, int what, int extra)90         public boolean onError(MediaPlayer mp, int what, int extra) {
91             super.onEvent();
92             return false;
93         }
94     }
95 
96     private static class MockOnCompletionListener extends MockListener
97             implements OnCompletionListener {
onCompletion(MediaPlayer mp)98         public void onCompletion(MediaPlayer mp) {
99             super.onEvent();
100         }
101     }
102 
hasCodec()103     private boolean hasCodec() {
104         return MediaUtils.hasCodecsForResource(mActivity, R.raw.testvideo);
105     }
106 
107     /**
108      * Instantiates a new video view test.
109      */
VideoViewTest()110     public VideoViewTest() {
111         super("com.android.cts.widget", VideoViewCtsActivity.class);
112     }
113 
114     /**
115      * Find the video view specified by id.
116      *
117      * @param id the id
118      * @return the video view
119      */
findVideoViewById(int id)120     private VideoView findVideoViewById(int id) {
121         return (VideoView) mActivity.findViewById(id);
122     }
123 
prepareSampleVideo()124     private String prepareSampleVideo() throws IOException {
125         InputStream source = null;
126         OutputStream target = null;
127 
128         try {
129             source = mActivity.getResources().openRawResource(R.raw.testvideo);
130             target = mActivity.openFileOutput(VIDEO_NAME, Context.MODE_WORLD_READABLE);
131 
132             final byte[] buffer = new byte[1024];
133             for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
134                 target.write(buffer, 0, len);
135             }
136         } finally {
137             if (source != null) {
138                 source.close();
139             }
140             if (target != null) {
141                 target.close();
142             }
143         }
144 
145         return mActivity.getFileStreamPath(VIDEO_NAME).getAbsolutePath();
146     }
147 
148     /**
149      * Wait for an asynchronous media operation complete.
150      * @throws InterruptedException
151      */
waitForOperationComplete()152     private void waitForOperationComplete() throws InterruptedException {
153         Thread.sleep(OPERATION_INTERVAL);
154     }
155 
156     @Override
setUp()157     protected void setUp() throws Exception {
158         super.setUp();
159         mActivity = getActivity();
160         mInstrumentation = getInstrumentation();
161         mVideoPath = prepareSampleVideo();
162         assertNotNull(mVideoPath);
163         mVideoView = findVideoViewById(R.id.videoview);
164     }
165 
makeVideoView()166     private void makeVideoView() {
167         mActivity.runOnUiThread(new Runnable() {
168             public void run() {
169                 MediaController mediaController = new MediaController(mActivity);
170                 mVideoView.setMediaController(mediaController);
171             }
172         });
173         mInstrumentation.waitForIdleSync();
174     }
175 
176     @UiThreadTest
testConstructor()177     public void testConstructor() {
178         new VideoView(mActivity);
179 
180         new VideoView(mActivity, null);
181 
182         new VideoView(mActivity, null, 0);
183     }
184 
testPlayVideo1()185     public void testPlayVideo1() throws Throwable {
186         makeVideoView();
187         // Don't run the test if the codec isn't supported.
188         if (!hasCodec()) {
189             Log.i(TAG, "SKIPPING testPlayVideo1(): codec is not supported");
190             return;
191         }
192 
193         final MockOnPreparedListener preparedListener = new MockOnPreparedListener();
194         mVideoView.setOnPreparedListener(preparedListener);
195         final MockOnCompletionListener completionListener = new MockOnCompletionListener();
196         mVideoView.setOnCompletionListener(completionListener);
197 
198         runTestOnUiThread(new Runnable() {
199             public void run() {
200                 mVideoView.setVideoPath(mVideoPath);
201             }
202         });
203         new PollingCheck(TIME_OUT) {
204             @Override
205             protected boolean check() {
206                 return preparedListener.isTriggered();
207             }
208         }.run();
209         assertFalse(completionListener.isTriggered());
210 
211         runTestOnUiThread(new Runnable() {
212             public void run() {
213                 mVideoView.start();
214             }
215         });
216         // wait time is longer than duration in case system is sluggish
217         new PollingCheck(mVideoView.getDuration() + TIME_OUT) {
218             @Override
219             protected boolean check() {
220                 return completionListener.isTriggered();
221             }
222         }.run();
223     }
224 
testSetOnErrorListener()225     public void testSetOnErrorListener() throws Throwable {
226         makeVideoView();
227         final MockOnErrorListener listener = new MockOnErrorListener();
228         mVideoView.setOnErrorListener(listener);
229 
230         runTestOnUiThread(new Runnable() {
231             public void run() {
232                 String path = "unknown path";
233                 mVideoView.setVideoPath(path);
234                 mVideoView.start();
235             }
236         });
237         mInstrumentation.waitForIdleSync();
238 
239         new PollingCheck(TIME_OUT) {
240             @Override
241             protected boolean check() {
242                 return listener.isTriggered();
243             }
244         }.run();
245     }
246 
testGetBufferPercentage()247     public void testGetBufferPercentage() throws Throwable {
248         makeVideoView();
249         // Don't run the test if the codec isn't supported.
250         if (!hasCodec()) {
251             Log.i(TAG, "SKIPPING testGetBufferPercentage(): codec is not supported");
252             return;
253         }
254 
255         final MockOnPreparedListener prepareListener = new MockOnPreparedListener();
256         mVideoView.setOnPreparedListener(prepareListener);
257 
258         runTestOnUiThread(new Runnable() {
259             public void run() {
260                 mVideoView.setVideoPath(mVideoPath);
261             }
262         });
263         mInstrumentation.waitForIdleSync();
264 
265         new PollingCheck(TIME_OUT) {
266             @Override
267             protected boolean check() {
268                 return prepareListener.isTriggered();
269             }
270         }.run();
271         int percent = mVideoView.getBufferPercentage();
272         assertTrue(percent >= 0 && percent <= 100);
273     }
274 
275     @UiThreadTest
testResolveAdjustedSize()276     public void testResolveAdjustedSize() {
277         mVideoView = new VideoView(mActivity);
278 
279         final int desiredSize = 100;
280         int resolvedSize = mVideoView.resolveAdjustedSize(desiredSize, MeasureSpec.UNSPECIFIED);
281         assertEquals(desiredSize, resolvedSize);
282 
283         final int specSize = MeasureSpec.getSize(MeasureSpec.AT_MOST);
284         resolvedSize = mVideoView.resolveAdjustedSize(desiredSize, MeasureSpec.AT_MOST);
285         assertEquals(Math.min(desiredSize, specSize), resolvedSize);
286 
287         resolvedSize = mVideoView.resolveAdjustedSize(desiredSize, MeasureSpec.EXACTLY);
288         assertEquals(specSize, resolvedSize);
289     }
290 
testGetDuration()291     public void testGetDuration() throws Throwable {
292         // Don't run the test if the codec isn't supported.
293         if (!hasCodec()) {
294             Log.i(TAG, "SKIPPING testGetDuration(): codec is not supported");
295             return;
296         }
297 
298         runTestOnUiThread(new Runnable() {
299             public void run() {
300                 mVideoView.setVideoPath(mVideoPath);
301             }
302         });
303         waitForOperationComplete();
304         assertTrue(Math.abs(mVideoView.getDuration() - TEST_VIDEO_DURATION) < DURATION_DELTA);
305     }
306 
307     @UiThreadTest
308     public void testSetMediaController() {
309         final MediaController ctlr = new MediaController(mActivity);
310         mVideoView.setMediaController(ctlr);
311     }
312 }
313