1 /*
2  * Copyright (C) 2011 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 com.android.camera.functional;
18 
19 import android.app.Activity;
20 import android.content.ContentResolver;
21 import android.content.Intent;
22 import android.database.Cursor;
23 import android.media.MediaMetadataRetriever;
24 import android.net.Uri;
25 import android.os.Environment;
26 import android.provider.MediaStore;
27 import android.provider.MediaStore.Video.VideoColumns;
28 import android.test.ActivityInstrumentationTestCase2;
29 import android.util.Log;
30 import android.view.KeyEvent;
31 
32 import androidx.test.filters.LargeTest;
33 
34 import com.android.camera.CameraActivity;
35 import com.android.camera2.R;
36 
37 import java.io.File;
38 
39 public class VideoCaptureIntentTest extends ActivityInstrumentationTestCase2 <CameraActivity> {
40     private static final String TAG = "VideoCaptureIntentTest";
41     private Intent mIntent;
42     private Uri mVideoUri;
43     private File mFile, mFile2;
44 
VideoCaptureIntentTest()45     public VideoCaptureIntentTest() {
46         super(CameraActivity.class);
47     }
48 
49     @Override
setUp()50     protected void setUp() throws Exception {
51         super.setUp();
52         mIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
53     }
54 
55     @Override
tearDown()56     protected void tearDown() throws Exception {
57         if (mVideoUri != null) {
58             ContentResolver resolver = getActivity().getContentResolver();
59             Uri query = mVideoUri.buildUpon().build();
60             String[] projection = new String[] {VideoColumns.DATA};
61 
62             Cursor cursor = null;
63             try {
64                 cursor = resolver.query(query, projection, null, null, null);
65                 if (cursor != null && cursor.moveToFirst()) {
66                     new File(cursor.getString(0)).delete();
67                 }
68             } finally {
69                 if (cursor != null) cursor.close();
70             }
71 
72             resolver.delete(mVideoUri, null, null);
73         }
74         if (mFile != null) mFile.delete();
75         if (mFile2 != null) mFile2.delete();
76         super.tearDown();
77     }
78 
79     @LargeTest
testNoExtraOutput()80     public void testNoExtraOutput() throws Exception {
81         setActivityIntent(mIntent);
82         getActivity();
83 
84         recordVideo();
85         pressDone();
86 
87         Intent resultData = getActivity().getResultData();
88         mVideoUri = resultData.getData();
89         assertNotNull(mVideoUri);
90         verify(getActivity(), mVideoUri);
91     }
92 
93     @LargeTest
testExtraOutput()94     public void testExtraOutput() throws Exception {
95         mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp");
96 
97         Uri uri = Uri.fromFile(mFile);
98         mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
99         setActivityIntent(mIntent);
100         getActivity();
101 
102         recordVideo();
103         pressDone();
104 
105         verify(getActivity(), uri);
106     }
107 
108     @LargeTest
testCancel()109     public void testCancel() throws Exception {
110         setActivityIntent(mIntent);
111         getActivity();
112 
113         pressCancel();
114 
115         assertTrue(getActivity().isFinishing());
116         assertEquals(Activity.RESULT_CANCELED, getActivity().getResultCode());
117     }
118 
119     @LargeTest
testRecordCancel()120     public void testRecordCancel() throws Exception {
121         setActivityIntent(mIntent);
122         getActivity();
123 
124         recordVideo();
125         pressCancel();
126 
127         assertTrue(getActivity().isFinishing());
128         assertEquals(Activity.RESULT_CANCELED, getActivity().getResultCode());
129     }
130 
131     @LargeTest
testExtraSizeLimit()132     public void testExtraSizeLimit() throws Exception {
133         mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp");
134         final long sizeLimit = 500000;  // bytes
135 
136         Uri uri = Uri.fromFile(mFile);
137         mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
138         mIntent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, sizeLimit);
139         mIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);  // use low quality to speed up
140         setActivityIntent(mIntent);
141         getActivity();
142 
143         recordVideo(5000);
144         pressDone();
145 
146         verify(getActivity(), uri);
147         long length = mFile.length();
148         Log.v(TAG, "Video size is " + length + " bytes.");
149         assertTrue(length > 0);
150         assertTrue("Actual size=" + length, length <= sizeLimit);
151     }
152 
153     @LargeTest
testExtraDurationLimit()154     public void testExtraDurationLimit() throws Exception {
155         mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp");
156         final int durationLimit = 2;  // seconds
157 
158         Uri uri = Uri.fromFile(mFile);
159         mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
160         mIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, durationLimit);
161         setActivityIntent(mIntent);
162         getActivity();
163 
164         recordVideo(5000);
165         pressDone();
166 
167         int duration = verify(getActivity(), uri);
168         // The duraion should be close to to the limit. The last video duration
169         // also has duration, so the total duration may exceeds the limit a
170         // little bit.
171         Log.v(TAG, "Video length is " + duration + " ms.");
172         assertTrue(duration  < (durationLimit + 1) * 1000);
173     }
174 
175     @LargeTest
176     public void testExtraVideoQuality() throws Exception {
177         mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp");
178         mFile2 = new File(Environment.getExternalStorageDirectory(), "video2.tmp");
179 
180         Uri uri = Uri.fromFile(mFile);
181         mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
182         mIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);  // low quality
183         setActivityIntent(mIntent);
184         getActivity();
185 
186         recordVideo();
187         pressDone();
188 
189         verify(getActivity(), uri);
190         setActivity(null);
191 
192         uri = Uri.fromFile(mFile2);
193         mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
194         mIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);  // high quality
195         setActivityIntent(mIntent);
196         getActivity();
197 
198         recordVideo();
199         pressDone();
200 
201         verify(getActivity(), uri);
202         assertTrue(mFile.length() <= mFile2.length());
203     }
204 
205     // Verify result code, result data, and the duration.
206     private int verify(CameraActivity activity, Uri uri) throws Exception {
207         assertTrue(activity.isFinishing());
208         assertEquals(Activity.RESULT_OK, activity.getResultCode());
209 
210         // Verify the video file
211         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
212         retriever.setDataSource(activity, uri);
213         String duration = retriever.extractMetadata(
214                 MediaMetadataRetriever.METADATA_KEY_DURATION);
215         assertNotNull(duration);
216         int durationValue = Integer.parseInt(duration);
217         Log.v(TAG, "Video duration is " + durationValue);
218         assertTrue(durationValue > 0);
219         return durationValue;
220     }
221 
222     private void recordVideo(int ms) throws Exception {
223         getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_CAMERA);
224         Thread.sleep(ms);
225         getInstrumentation().runOnMainSync(new Runnable() {
226             @Override
227             public void run() {
228                 // If recording is in progress, stop it. Run these atomically in
229                 // UI thread.
230                 CameraActivity activity = getActivity();
231                 if (activity.isRecording()) {
232                     activity.findViewById(R.id.shutter_button).performClick();
233                 }
234             }
235         });
236     }
237 
238     private void recordVideo() throws Exception {
239         recordVideo(2000);
240     }
241 
242     private void pressDone() {
243         getInstrumentation().runOnMainSync(new Runnable() {
244             @Override
245             public void run() {
246                 getActivity().findViewById(R.id.btn_done).performClick();
247             }
248         });
249     }
250 
251     private void pressCancel() {
252         getInstrumentation().runOnMainSync(new Runnable() {
253             @Override
254             public void run() {
255                 getActivity().findViewById(R.id.btn_cancel).performClick();
256             }
257         });
258     }
259 }
260