blob: 35c4d5632f6c415e489ab8fa09b0fd3aa8ad9c34 [file] [log] [blame]
Peng Xuc14f0122015-04-28 18:38:38 -07001/*
2 * Copyright (C) 2014 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
17package com.android.cts.verifier.sensors;
18
Peng Xua4be74b2015-09-08 19:43:30 -070019import android.content.Context;
Peng Xuc14f0122015-04-28 18:38:38 -070020import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
21import android.os.Bundle;
Peng Xua4be74b2015-09-08 19:43:30 -070022import android.os.PowerManager;
Peng Xuc14f0122015-04-28 18:38:38 -070023
24import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity;
25import com.android.cts.verifier.sensors.helpers.OpenCVLibrary;
26
27import junit.framework.Assert;
28
29import android.content.Intent;
30
31import java.util.concurrent.CountDownLatch;
32
33/**
34 * This test (Rotation Vector - Computer Vision Cross Check, or RXCVXCheck for short) verifies that
35 * mobile device can detect the orientation of itself in a relatively accurate manner.
36 *
37 * Currently only ROTATION_VECTOR sensor is used.
38 *
39 */
40public class RVCVXCheckTestActivity
41 extends SensorCtsVerifierTestActivity {
42 public RVCVXCheckTestActivity() {
43 super(RVCVXCheckTestActivity.class);
44 }
45
46 CountDownLatch mRecordActivityFinishedSignal = null;
47
48 private static final int REQ_CODE_TXCVRECORD = 0x012345678;
49 private static final boolean TEST_USING_DEBUGGING_DATA = false;
50 private static final String PATH_DEBUGGING_DATA = "/sdcard/RXCVRecData/150313-014443/";
51
52 private String mRecPath;
53
54 RVCVXCheckAnalyzer.AnalyzeReport mReport = null;
55
56 private boolean mRecordSuccessful = false;
57 private boolean mOpenCVLoadSuccessful = false;
58
Peng Xu66ba59f2015-06-12 11:59:07 -070059 private static class Criterion {
60 public static final float roll_rms_error = 0.15f;
61 public static final float pitch_rms_error = 0.15f;
62 public static final float yaw_rms_error = 0.25f;
63
64 public static final float roll_max_error = 0.30f;
65 public static final float pitch_max_error = 0.30f;
66 public static final float yaw_max_error = 0.45f;
67
68 public static final float sensor_period_stdev = 0.25e-3f;
69 };
70
Peng Xuc14f0122015-04-28 18:38:38 -070071
72 /**
73 * The activity setup collects all the required data for test cases.
74 * This approach allows to test all sensors at once.
75 */
76 @Override
77 protected void activitySetUp() throws InterruptedException {
78
79 mRecPath = "";
80
81 showUserMessage("Loading OpenCV Library...");
82 int retry = 10;
83
84 while(retry-->0) {
85 try {
Peng Xua4be74b2015-09-08 19:43:30 -070086 Thread.sleep(250);
Peng Xuc14f0122015-04-28 18:38:38 -070087 } catch (InterruptedException e) {
88 //
89 }
90 if (OpenCVLibrary.isLoaded()) {
91 break;
92 }
93 }
94 if (!OpenCVLibrary.isLoaded()) {
95 // failed requirement test
96 clearText();
97 return;
98 }
99 showUserMessage("OpenCV Library Successfully Loaded");
100
101 mOpenCVLoadSuccessful = true;
102
103 if (TEST_USING_DEBUGGING_DATA) {
104 mRecPath = PATH_DEBUGGING_DATA;
105
106 // assume the data is there already
107 mRecordSuccessful = true;
108 } else {
109 showUserMessage("Take the test as instructed below:\n" +
110 "1. Print out the test pattern and place it on a "+
111 "horizontal surface.\n" +
112 "2. Start the test and align the yellow square on the screen "+
113 "roughly to the yellow sqaure.\n" +
114 "3. Follow the prompt to rotate the phone while keeping the "+
115 "entire test pattern inside view of camera. This requires " +
116 "orbiting the phone around and aiming the "+
117 "camera at the test pattern at the same time.\n" +
118 "4. Wait patiently for the analysis to finish.\n");
119
120 waitForUserToContinue();
121
122 // prepare sync signal
123 mRecordActivityFinishedSignal = new CountDownLatch(1);
124
125 // record both sensor and camera
126 Intent intent = new Intent(this, RVCVRecordActivity.class);
127 startActivityForResult(intent, REQ_CODE_TXCVRECORD);
128
129 // wait for record finish
130 mRecordActivityFinishedSignal.await();
131
132 if ("".equals(mRecPath)) {
133 showUserMessage("Recording failed or exited prematurely.");
134 waitForUserToContinue();
135 } else {
136 showUserMessage("Recording is done!");
137 showUserMessage("Result are in path: " + mRecPath);
138 mRecordSuccessful = true;
139 }
140 }
141
142
143 if (mRecordSuccessful) {
144 showUserMessage("Please wait for the analysis ... \n"+
145 "It may take a few minutes, you will be noted when "+
146 "its finished by sound and vibration. ");
147
148 // Analysis of recorded video and sensor data using RVCXAnalyzer
149 RVCVXCheckAnalyzer analyzer = new RVCVXCheckAnalyzer(mRecPath);
Peng Xua4be74b2015-09-08 19:43:30 -0700150
151 // acquire a partial wake lock just in case CPU fall asleep
152 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
153 PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
154 "RVCVXCheckAnalyzer");
155
156 wl.acquire();
Peng Xuc14f0122015-04-28 18:38:38 -0700157 mReport = analyzer.processDataSet();
Peng Xua4be74b2015-09-08 19:43:30 -0700158 wl.release();
Peng Xuc14f0122015-04-28 18:38:38 -0700159
160 playSound();
161 vibrate(500);
162
163 if (mReport == null) {
164 showUserMessage("Analysis failed due to unknown reason!");
165 } else {
166 if (mReport.error) {
167 showUserMessage("Analysis failed: " + mReport.reason);
168 } else {
169 showUserMessage(String.format("Analysis finished!\n" +
170 "Roll error (Rms, max) = %4.3f, %4.3f rad\n" +
171 "Pitch error (Rms, max) = %4.3f, %4.3f rad\n" +
172 "Yaw error (Rms, max) = %4.3f, %4.3f rad\n" +
173 "N of Frame (valid, total) = %d, %d\n" +
174 "Sensor period (mean, stdev) = %4.3f, %4.3f ms\n" +
175 "Time offset: %4.3f s \n" +
176 "Yaw offset: %4.3f rad \n\n",
177 mReport.roll_rms_error, mReport.roll_max_error,
178 mReport.pitch_rms_error, mReport.pitch_max_error,
179 mReport.yaw_rms_error, mReport.yaw_max_error,
180 mReport.n_of_valid_frame, mReport.n_of_frame,
181 mReport.sensor_period_avg * 1000.0, mReport.sensor_period_stdev*1000.0,
182 mReport.optimal_delta_t, mReport.yaw_offset));
183 showUserMessage("Please click next after details reviewed.");
184 waitForUserToContinue();
185 }
186 }
187 }
188 clearText();
189 }
190
191 /**
192 Receiving the results from the RVCVRecordActivity, which is a patch where the recorded
193 video and sensor data is stored.
194 */
195 @Override
196 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
197 // Check which request we're responding to
198 if (requestCode == REQ_CODE_TXCVRECORD) {
199 // Make sure the request was successful
200
201 if (resultCode == RESULT_OK) {
202 mRecPath = data.getData().getPath();
203 }
204
205 // notify it is finished
206 mRecordActivityFinishedSignal.countDown();
207 }
208 super.onActivityResult(requestCode, resultCode, data);
209 }
210
211 /**
212 * Test cases.
213 */
214
215 public String test00OpenCV() throws Throwable {
216
217 String message = "OpenCV is loaded";
218 Assert.assertTrue("OpenCV library cannot be loaded.", mOpenCVLoadSuccessful);
219 return message;
220 }
221
222
223 public String test01Recording() throws Throwable {
224
225 loadOpenCVSuccessfulOrSkip();
226
227 String message = "Record is successful.";
228 Assert.assertTrue("Record is not successful.", mRecordSuccessful);
229 return message;
230 }
231
232 public String test02Analysis() throws Throwable {
233
234 loadOpenCVSuccessfulOrSkip();
235 recordSuccessfulOrSkip();
236
237 String message = "Analysis result: " + mReport.reason;
238 Assert.assertTrue(message, (mReport!=null && !mReport.error));
239 return message;
240 }
241
242 public String test1RollAxis() throws Throwable {
243
244 loadOpenCVSuccessfulOrSkip();
245 recordSuccessfulOrSkip();
246 analyzeSuccessfulOrSkip();
247
248 String message = "Test Roll Axis Accuracy";
249
Peng Xu66ba59f2015-06-12 11:59:07 -0700250 Assert.assertEquals("Roll RMS error", 0.0, mReport.roll_rms_error,
251 Criterion.roll_rms_error);
252 Assert.assertEquals("Roll max error", 0.0, mReport.roll_max_error,
253 Criterion.roll_max_error);
Peng Xuc14f0122015-04-28 18:38:38 -0700254 return message;
255 }
256
257 public String test2PitchAxis() throws Throwable {
258
259 loadOpenCVSuccessfulOrSkip();
260 recordSuccessfulOrSkip();
261 analyzeSuccessfulOrSkip();
262
263 String message = "Test Pitch Axis Accuracy";
264
Peng Xu66ba59f2015-06-12 11:59:07 -0700265 Assert.assertEquals("Pitch RMS error", 0.0, mReport.pitch_rms_error,
266 Criterion.pitch_rms_error);
267 Assert.assertEquals("Pitch max error", 0.0, mReport.pitch_max_error,
268 Criterion.pitch_max_error);
Peng Xuc14f0122015-04-28 18:38:38 -0700269 return message;
270 }
271
272 public String test3YawAxis() throws Throwable {
273
274 loadOpenCVSuccessfulOrSkip();
275 recordSuccessfulOrSkip();
276 analyzeSuccessfulOrSkip();
277
278 String message = "Test Yaw Axis Accuracy";
279
Peng Xu66ba59f2015-06-12 11:59:07 -0700280 Assert.assertEquals("Yaw RMS error", 0.0, mReport.yaw_rms_error,
281 Criterion.yaw_rms_error);
282 Assert.assertEquals("Yaw max error", 0.0, mReport.yaw_max_error,
283 Criterion.yaw_max_error);
Peng Xuc14f0122015-04-28 18:38:38 -0700284 return message;
285 }
286
287 public String test4SensorPeriod() throws Throwable {
288
289 loadOpenCVSuccessfulOrSkip();
290 recordSuccessfulOrSkip();
291 analyzeSuccessfulOrSkip();
292
293 String message = "Test Sensor Period";
294
Peng Xu66ba59f2015-06-12 11:59:07 -0700295 // we do not know what the maximum frequency can be, so just test the stdev value
296 Assert.assertEquals("Sensor sample period stdev.", 0.0, mReport.sensor_period_stdev,
297 Criterion.sensor_period_stdev);
Peng Xuc14f0122015-04-28 18:38:38 -0700298 return message;
299 }
300
301 private void loadOpenCVSuccessfulOrSkip() throws SensorTestStateNotSupportedException {
302 if (!mOpenCVLoadSuccessful)
303 throw new SensorTestStateNotSupportedException("Skipped due to OpenCV cannot be loaded");
304 }
305
306 private void recordSuccessfulOrSkip() throws SensorTestStateNotSupportedException {
307 if (!mRecordSuccessful)
308 throw new SensorTestStateNotSupportedException("Skipped due to record failure.");
309 }
310
311 private void analyzeSuccessfulOrSkip() throws SensorTestStateNotSupportedException {
312 if (mReport == null || mReport.error)
313 throw new SensorTestStateNotSupportedException("Skipped due to CV Analysis failure.");
314 }
315
316 /*
317 * This function serves as a proxy as showUserMessage is marked to be deprecated.
318 * When appendText is removed, this function will have a different implementation.
319 *
320 */
321 void showUserMessage(String s) {
322 appendText(s);
323 }
324
325 @Override
326 protected void onCreate(Bundle savedInstanceState) {
327
328 super.onCreate(savedInstanceState);
329
330 // GlSurfaceView is not necessary for this test
331 closeGlSurfaceView();
332
333 OpenCVLibrary.loadAsync(this);
334 }
335
336 @Override
337 protected void onPause() {
338 super.onPause();
339 }
340
341 @Override
342 protected void onResume() {
343 super.onResume();
344
345 }
346}