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