1 /* 2 * Copyright (C) 2016 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 package com.android.cts.verifier.sensors.sixdof.Utils; 17 18 import com.android.cts.verifier.sensors.sixdof.Dialogs.BaseResultsDialog; 19 import com.android.cts.verifier.sensors.sixdof.Interfaces.AccuracyListener; 20 import com.android.cts.verifier.sensors.sixdof.Interfaces.BaseUiListener; 21 import com.android.cts.verifier.sensors.sixdof.Interfaces.ComplexMovementListener; 22 import com.android.cts.verifier.sensors.sixdof.Interfaces.RobustnessListener; 23 import com.android.cts.verifier.sensors.sixdof.Renderer.BaseRenderer; 24 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException; 25 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException; 26 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointException; 27 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException; 28 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException; 29 import com.android.cts.verifier.sensors.sixdof.Utils.Path.ReferencePath; 30 import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Ring; 31 import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.RotationData; 32 import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint; 33 import com.android.cts.verifier.sensors.sixdof.Utils.PoseProvider.PoseData; 34 import com.android.cts.verifier.sensors.sixdof.Utils.ResultObjects.ResultObject; 35 import com.android.cts.verifier.sensors.sixdof.Utils.TestPhase.AccuracyTest; 36 import com.android.cts.verifier.sensors.sixdof.Utils.TestPhase.ComplexMovementTest; 37 import com.android.cts.verifier.sensors.sixdof.Utils.TestPhase.RobustnessTest; 38 39 import android.content.Context; 40 41 import java.util.ArrayList; 42 import java.util.HashMap; 43 44 /** 45 * Manages all of the tests. 46 */ 47 public class Manager { 48 private Lap mLap = Lap.LAP_1; 49 public static final int MAX_MARKER_NUMBER = 5; 50 private ReferencePath mReferencePath = new ReferencePath(); 51 private AccuracyTest mAccuracyTest; 52 private RobustnessTest mRobustnessTest; 53 private ComplexMovementTest mComplexMovementTest; 54 private TestReport mTestReport; 55 private float mRemainingPath; 56 private long mTimeRemaining; 57 58 public enum Lap { 59 LAP_1, 60 LAP_2, 61 LAP_3, 62 LAP_4, 63 } 64 65 private ComplexMovementListener mComplexMovementListener; 66 private RobustnessListener mRobustnessListener; 67 private AccuracyListener mAccuracyListener; 68 private BaseUiListener mBaseUiListener; 69 70 /** 71 * Links the listeners to the activity. 72 * 73 * @param context reference to the activity. 74 */ setupListeners(Context context)75 public void setupListeners(Context context) { 76 mAccuracyListener = (AccuracyListener) context; 77 mRobustnessListener = (RobustnessListener) context; 78 mComplexMovementListener = (ComplexMovementListener) context; 79 mBaseUiListener = (BaseUiListener) context; 80 } 81 82 /** 83 * Removes the references to the activity so that the activity can be properly terminated. 84 */ stopListening()85 public void stopListening() { 86 mRobustnessListener = null; 87 mAccuracyListener = null; 88 mBaseUiListener = null; 89 mComplexMovementListener = null; 90 } 91 ringEntered(Ring ring)92 public void ringEntered(Ring ring) { 93 mComplexMovementListener.onRingEntered(ring); 94 } 95 96 /** 97 * Indicated that the pose provider is ready. 98 */ onPoseProviderReady()99 public void onPoseProviderReady() { 100 mBaseUiListener.onPoseProviderReady(); 101 } 102 103 /** 104 * Constructor for the class. 105 * 106 * @param testReport a reference to the test report to be used to record failures. 107 */ Manager(TestReport testReport)108 public Manager(TestReport testReport) { 109 mTestReport = testReport; 110 } 111 112 /** 113 * Adds the waypoint data to the appropriate path. 114 * 115 * @param coordinates the coordinates to use for the waypoint. 116 * @param userGenerated indicates whether the data was user created or system created. 117 * @throws WaypointDistanceException if the location is too close to another. 118 * @throws WaypointAreaCoveredException if the area covered by the user is too little. 119 * @throws WaypointStartPointException if the location is not close enough to the start. 120 */ addPoseDataToPath( float[] coordinates, boolean userGenerated)121 public void addPoseDataToPath( 122 float[] coordinates, boolean userGenerated) 123 throws WaypointAreaCoveredException, WaypointDistanceException, 124 WaypointStartPointException, WaypointRingNotEnteredException { 125 switch (mLap) { 126 case LAP_1: 127 try { 128 mReferencePath.createWaypointAndAddToPath(coordinates, userGenerated, mLap); 129 } catch (WaypointStartPointException exception) { 130 float[] initialCoords = mReferencePath.getPathMarkers().get(0).getCoordinates(); 131 String initialWaypointCoords = 132 MathsUtils.coordinatesToString(initialCoords); 133 String distance = String.valueOf( 134 MathsUtils.distanceCalculationInXYZSpace( 135 initialCoords, coordinates)); 136 String details = "Not close enough to initial waypoint:\n" 137 + "Distance:" 138 + distance 139 + "\nInitial Waypoint Coordinates: " 140 + initialWaypointCoords 141 + "\nAttempted placement coordinates: " 142 + MathsUtils.coordinatesToString(coordinates); 143 mTestReport.setFailDetails(details); 144 145 // We still need to give the exception to UI to display message. 146 throw exception; 147 } 148 149 if (mReferencePath.getPathMarkersSize() == MAX_MARKER_NUMBER) { 150 mAccuracyListener.lap1Complete(); 151 } 152 break; 153 case LAP_2: 154 mAccuracyTest.addWaypointDataToPath(coordinates, userGenerated, mLap); 155 break; 156 case LAP_3: 157 mRobustnessTest.addWaypointDataToPath(coordinates, userGenerated, mLap); 158 break; 159 case LAP_4: 160 mComplexMovementTest.addWaypointDataToPath(coordinates, userGenerated, mLap); 161 break; 162 default: 163 throw new AssertionError("addPoseDataToPath default: Unrecognised lap", null); 164 } 165 if (userGenerated) { 166 mBaseUiListener.onWaypointPlaced(); 167 } 168 } 169 170 /** 171 * Removes the last marker from the current lap. 172 */ removeLastAddedMarker()173 public void removeLastAddedMarker() { 174 boolean resetTest; 175 switch (mLap) { 176 case LAP_1: 177 resetTest = mReferencePath.removeLastMarker(); 178 break; 179 case LAP_2: 180 resetTest = mAccuracyTest.removeLastAddedMarker(); 181 break; 182 case LAP_3: 183 resetTest = mRobustnessTest.removeLastAddedMarker(); 184 break; 185 case LAP_4: 186 resetTest = mComplexMovementTest.removeLastAddedMarker(); 187 break; 188 default: 189 throw new AssertionError("removeLastAddedMarker default: Unrecognised lap", null); 190 } 191 if (resetTest) { 192 mAccuracyListener.onReset(); 193 } 194 } 195 196 /** 197 * Initiates the accuracy test. 198 */ startAccuracyTest()199 public void startAccuracyTest() { 200 mAccuracyTest = new AccuracyTest(mReferencePath, mTestReport, this); 201 mLap = Lap.LAP_2; 202 } 203 204 /** 205 * Initiates the robustness test. 206 */ startRobustnessTest()207 public void startRobustnessTest() { 208 mRobustnessTest = new RobustnessTest(mReferencePath, mTestReport, this, 209 BaseRenderer.getDeviceRotation((Context) mBaseUiListener)); 210 mLap = Lap.LAP_3; 211 212 } 213 214 /** 215 * Initiates the complex movement test. 216 */ startComplexMovementTest()217 public void startComplexMovementTest() { 218 mComplexMovementTest = new ComplexMovementTest(mReferencePath, mTestReport, this); 219 mLap = Lap.LAP_4; 220 } 221 222 /** 223 * Indicates that the accuracy test has been completed. 224 * 225 * @param passList A list to indicate whether the test passes or not. 226 */ onAccuracyTestCompleted(HashMap<BaseResultsDialog.ResultType, Boolean> passList)227 public void onAccuracyTestCompleted(HashMap<BaseResultsDialog.ResultType, Boolean> passList) { 228 mBaseUiListener.onResult(new ResultObject(passList)); 229 } 230 231 /** 232 * Indicates that the robustness test has been completed. 233 * 234 * @param robustnessTestResults List containing information about whether the tests failed or 235 * passed. 236 */ onRobustnessTestCompleted(HashMap<BaseResultsDialog.ResultType, Boolean> robustnessTestResults)237 public void onRobustnessTestCompleted(HashMap<BaseResultsDialog.ResultType, Boolean> robustnessTestResults) { 238 ResultObject robustnessResult = new ResultObject(robustnessTestResults); 239 mBaseUiListener.onResult(robustnessResult); 240 } 241 242 /** 243 * Indicates that the complex movement test has been completed. 244 * 245 * @param complexMovementTestResults List containing information about whether the tests failed 246 * or passed. 247 */ onComplexMovementTestCompleted(HashMap<BaseResultsDialog.ResultType, Boolean> complexMovementTestResults)248 public void onComplexMovementTestCompleted(HashMap<BaseResultsDialog.ResultType, Boolean> complexMovementTestResults) { 249 ResultObject complexMovementResult = new ResultObject(complexMovementTestResults); 250 251 if (complexMovementResult.hasPassed()) { 252 mTestReport.setTestState(TestReport.TestStatus.PASS); 253 } 254 255 mBaseUiListener.onResult(complexMovementResult); 256 } 257 258 /** 259 * Sets the path remaining for the user to travel. 260 */ calculateRemainingPath()261 public void calculateRemainingPath() { 262 mRemainingPath = mReferencePath.calculatePathRemaining(); 263 } 264 265 /** 266 * Uses the current rotation and location to calculate the rotation detail's. Also gives the UI 267 * information about the rotation. 268 * 269 * @param rotations Quaternion containing the current rotation. 270 * @param translation The location the rotation occurred. 271 */ calculateRotationData(float[] rotations, float[] translation)272 public void calculateRotationData(float[] rotations, float[] translation) { 273 RotationData rotationData = mRobustnessTest.getRotationData(rotations, translation); 274 if (rotationData != null) { 275 mRobustnessListener.onNewRotationData(rotationData); 276 } 277 } 278 279 /** 280 * Sets the time remaining to place a waypoint. 281 */ calculateTimeRemaining()282 public void calculateTimeRemaining() { 283 mTimeRemaining = mRobustnessTest.getTimeRemaining(); 284 } 285 286 /** 287 * Handles new pose data. 288 * 289 * @param currentPose The current pose data. 290 */ onNewPoseData(PoseData currentPose)291 public void onNewPoseData(PoseData currentPose) { 292 if (mReferencePath.getCurrentPathSize() != 0) { 293 switch (mLap) { 294 case LAP_1: 295 calculateRemainingPath(); 296 break; 297 case LAP_2: 298 break; 299 case LAP_3: 300 if (mRobustnessTest.getTestPathMarkersSize() > 0) { 301 calculateTimeRemaining(); 302 calculateRotationData(currentPose.getRotationAsFloats(), currentPose.getTranslationAsFloats()); 303 } 304 break; 305 case LAP_4: 306 mComplexMovementTest.checkIfARingHasBeenPassed(currentPose.getTranslationAsFloats()); 307 break; 308 } 309 try { 310 addPoseDataToPath(currentPose.getTranslationAsFloats(), 311 false); 312 } catch (WaypointException e) { 313 throw new AssertionError( 314 "System added waypoint should not be validated", e); 315 } 316 } 317 } 318 319 /** 320 * Returns the distance remaining to travel by the user. 321 */ getRemainingPath()322 public float getRemainingPath() { 323 return mRemainingPath; 324 } 325 326 /** 327 * Returns the makers in the reference path. 328 */ getReferencePathMarkers()329 public ArrayList<Waypoint> getReferencePathMarkers() { 330 return mReferencePath.getPathMarkers(); 331 } 332 333 /** 334 * Returns the makers in the accuracy test path. 335 */ getTestPathMarkers()336 public ArrayList<Waypoint> getTestPathMarkers() { 337 return mAccuracyTest.getTestPathMarkers(); 338 } 339 340 /** 341 * Returns the time remaining to place the marker. 342 */ getTimeRemaining()343 public long getTimeRemaining() { 344 return mTimeRemaining; 345 } 346 347 /** 348 * Returns the markers in the robustness test path. 349 */ getRobustnessMarker()350 public ArrayList<Waypoint> getRobustnessMarker() { 351 return mRobustnessTest.getTestPathMarkers(); 352 } 353 354 /** 355 * Returns the current phase of the test. 356 */ getLap()357 public Lap getLap() { 358 return mLap; 359 } 360 361 /** 362 * Returns the rings in the ComplexMovement path. 363 */ getRings()364 public ArrayList<Ring> getRings() { 365 return mComplexMovementTest.getRings(); 366 } 367 368 /** 369 * Returns the makers in the ComplexMovement test path. 370 */ getComplexMovementTestMarkers()371 public ArrayList<Waypoint> getComplexMovementTestMarkers() { 372 return mComplexMovementTest.getTestPathMarkers(); 373 } 374 } 375