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 17 package com.android.cts.verifier.sensors.sixdof.Utils.TestPhase; 18 19 import com.android.cts.verifier.sensors.sixdof.Dialogs.BaseResultsDialog; 20 import com.android.cts.verifier.sensors.sixdof.Utils.Manager; 21 import com.android.cts.verifier.sensors.sixdof.Utils.MathsUtils; 22 import com.android.cts.verifier.sensors.sixdof.Utils.TestReport; 23 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointAreaCoveredException; 24 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointDistanceException; 25 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointRingNotEnteredException; 26 import com.android.cts.verifier.sensors.sixdof.Utils.Exceptions.WaypointStartPointException; 27 import com.android.cts.verifier.sensors.sixdof.Utils.Path.AccuracyPath; 28 import com.android.cts.verifier.sensors.sixdof.Utils.Path.Path; 29 import com.android.cts.verifier.sensors.sixdof.Utils.Path.ReferencePath; 30 import com.android.cts.verifier.sensors.sixdof.Utils.Path.PathUtilityClasses.Waypoint; 31 32 import android.util.Log; 33 34 import java.util.ArrayList; 35 import java.util.HashMap; 36 37 /** 38 * TestPhase generic class will be inherited by the other tests. 39 */ 40 public abstract class Test { 41 public static final int MAX_MARKER_NUMBER = 5; 42 private static final float FAILURE_TOLERANCE_PERCENTAGE = 0.025f; // 2.5% 43 private String mTestPhaseName; 44 45 protected ArrayList<Float> mMarkerAccuracy = new ArrayList<>(); 46 protected ArrayList<Float> mPathAccuracy = new ArrayList<>(); 47 protected ArrayList<Float> mReferencePathDistances = new ArrayList<>(); 48 private ArrayList<Float> mTestPathDistances = new ArrayList<>(); 49 50 protected ReferencePath mReferencePath; 51 protected Path mTestPath; 52 protected TestReport mTestReport; 53 protected Manager mManager; 54 55 /** 56 * Constructor for this class. 57 * 58 * @param referencePath Reference the the reference path. 59 * @param testReport The test report object to record the tests. 60 * @param manager The manager to call when the test is done. 61 */ Test(ReferencePath referencePath, TestReport testReport, Manager manager, String testPhase)62 public Test(ReferencePath referencePath, TestReport testReport, Manager manager, String testPhase) { 63 if (referencePath != null) { 64 mReferencePath = referencePath; 65 } else { 66 throw new AssertionError("TestPhase received a null referencePath", null); 67 } 68 mTestPhaseName = testPhase; 69 mTestReport = testReport; 70 mManager = manager; 71 mTestPath = new AccuracyPath(); 72 mReferencePathDistances = calculatePathDistance(mReferencePath.getCurrentPath(), mReferencePath.getPathMarkers()); 73 } 74 75 /** 76 * Adds the current waypoint to the test path. 77 * 78 * @param coordinates the coordinates to use for the waypoint. 79 * @param userGenerated indicates whether the data was user created or system created. 80 * @param currentLap the lap the data was created in. 81 * @throws WaypointDistanceException if the location is too close to another. 82 * @throws WaypointAreaCoveredException if the area covered by the user is too little. 83 * @throws WaypointStartPointException if the location is not close enough to the start. 84 */ addWaypointDataToPath( float[] coordinates, boolean userGenerated, Manager.Lap currentLap)85 public void addWaypointDataToPath( 86 float[] coordinates, boolean userGenerated, Manager.Lap currentLap) 87 throws WaypointAreaCoveredException, WaypointDistanceException, 88 WaypointStartPointException, WaypointRingNotEnteredException { 89 mTestPath.createWaypointAndAddToPath(coordinates, userGenerated, currentLap); 90 runAdditionalMethods(); 91 } 92 93 /** 94 * Abstract method that is used but subclasses. 95 */ runAdditionalMethods()96 protected abstract void runAdditionalMethods(); 97 98 /** 99 * Removes the last marker from the chosen lap. 100 * 101 * @return true of the first marker false if any other marker 102 */ removeLastAddedMarker()103 public boolean removeLastAddedMarker() { 104 return mTestPath.removeLastMarker(); 105 } 106 107 /** 108 * Performs the tests for this test phase. 109 * 110 * @return the state of the tests, true if they pass false if they fail. 111 */ executeTests(boolean includeMarkerTest, boolean includePathTest)112 protected HashMap<BaseResultsDialog.ResultType, Boolean> executeTests(boolean includeMarkerTest, boolean includePathTest) { 113 HashMap<BaseResultsDialog.ResultType, Boolean> testResults = new HashMap<>(); 114 if (includePathTest) { 115 testResults.put(BaseResultsDialog.ResultType.PATH, pathTest()); 116 } 117 if (includeMarkerTest) { 118 testResults.put(BaseResultsDialog.ResultType.WAYPOINT, markerTest()); 119 } 120 return testResults; 121 } 122 123 /** 124 * Calculates the difference between the markers of the laps and executes the marker related 125 * test. 126 * 127 * @return true if the test passes and false if the rest fails. 128 */ markerTest()129 private boolean markerTest() { 130 float distance; 131 for (int i = 0; i < mReferencePath.getPathMarkersSize(); i++) { 132 distance = MathsUtils.distanceCalculationInXYZSpace( 133 mReferencePath.getPathMarkers().get(i).getCoordinates(), 134 mTestPath.getPathMarkers().get(i).getCoordinates()); 135 mMarkerAccuracy.add(distance); 136 } 137 return markerAccuracyTest(); 138 } 139 140 /** 141 * Runs a check to find any markers that have failed the test and adds them to the test report. 142 * 143 * @return true if the test passes and false if the rest fails 144 */ markerAccuracyTest()145 private boolean markerAccuracyTest() { 146 boolean testState = true; 147 for (float markerDifference : mMarkerAccuracy) { 148 if (markerDifference > mReferencePath.getFailureTolerance()) { 149 recordMarkerTestResults(markerDifference); 150 testState = false; 151 } 152 } 153 return testState; 154 } 155 156 /** 157 * Formats the failed markers into a string to add it to the test report. 158 * 159 * @param markerDifference the difference which caused the marker to fail 160 */ recordMarkerTestResults(float markerDifference)161 private void recordMarkerTestResults(float markerDifference) { 162 int markerNumber = mMarkerAccuracy.indexOf(markerDifference); 163 String referenceMarker = MathsUtils.coordinatesToString( 164 mReferencePath.getPathMarkers().get(markerNumber).getCoordinates()); 165 String testMarker = MathsUtils.coordinatesToString( 166 mTestPath.getPathMarkers().get(markerNumber).getCoordinates()); 167 String testDetails = mTestPhaseName + 168 " Marker Accuracy: Distance between the markers too great. Marker: " + markerNumber + 169 " Difference: " + markerDifference + 170 " Coordinates " + referenceMarker + " " + testMarker + "\n"; 171 Log.e("Marker Result", testDetails); 172 mTestReport.setFailDetails(testDetails); 173 } 174 175 /** 176 * Executes the the path related tests. 177 * 178 * @return true if the test passes, false if the test fails 179 */ pathTest()180 private boolean pathTest() { 181 mTestPathDistances = calculatePathDistance(mTestPath.getCurrentPath(), mTestPath.getPathMarkers()); 182 calculatePathDifferences(); 183 return pathAccuracyTest(); 184 } 185 186 /** 187 * Calculates the distance between the markers for the given path. 188 * 189 * @param pathToCalculate The path that we want to calculate the distances for 190 * @param markers The locations of the user generated markers in that path 191 * @return the list of distances for that path 192 */ calculatePathDistance(ArrayList<Waypoint> pathToCalculate, ArrayList<Waypoint> markers)193 protected ArrayList<Float> calculatePathDistance(ArrayList<Waypoint> pathToCalculate, 194 ArrayList<Waypoint> markers) { 195 ArrayList<Float> pathDistances = new ArrayList<>(); 196 float totalDistance, distance; 197 int currentLocation = pathToCalculate.indexOf(markers.get(0)); 198 199 while (currentLocation < pathToCalculate.size() - 1) { 200 totalDistance = 0; 201 do { 202 distance = MathsUtils.distanceCalculationOnXYPlane( 203 pathToCalculate.get(currentLocation).getCoordinates(), 204 pathToCalculate.get(currentLocation + 1).getCoordinates()); 205 totalDistance += distance; 206 currentLocation++; 207 } while (!pathToCalculate.get(currentLocation).isUserGenerated()); 208 pathDistances.add(Math.abs(totalDistance)); 209 if (currentLocation == markers.size() - 1) { 210 break; 211 } 212 } 213 return pathDistances; 214 } 215 216 /** 217 * Calculates the difference between paths on different laps. 218 */ calculatePathDifferences()219 private void calculatePathDifferences() { 220 float difference; 221 222 if (!mReferencePathDistances.isEmpty() && !mTestPathDistances.isEmpty()) { 223 for (int i = 0; i < mReferencePathDistances.size(); i++) { 224 difference = mReferencePathDistances.get(i) - mTestPathDistances.get(i); 225 mPathAccuracy.add(Math.abs(difference)); 226 } 227 } else { 228 throw new AssertionError("calculatePathDifference has one of the arrays empty", null); 229 } 230 } 231 232 /** 233 * Checks to see if any of the path differences have failed the test and adds them to the test 234 * report. 235 * 236 * @return True if the test passes and false if there is a fail 237 */ pathAccuracyTest()238 private boolean pathAccuracyTest() { 239 boolean testState = true; 240 for (float path : mPathAccuracy) { 241 if (path > mReferencePath.getFailureTolerance()) { 242 recordPathTestResults(path); 243 testState = false; 244 } 245 } 246 return testState; 247 } 248 249 /** 250 * Formats the failed paths into a string to add it to the test report. 251 * 252 * @param difference The distance that failed the test 253 */ recordPathTestResults(float difference)254 private void recordPathTestResults(float difference) { 255 int pathNumber = mPathAccuracy.indexOf(difference); 256 String referencePath = String.valueOf(mReferencePathDistances.get(pathNumber)); 257 String testPath = String.valueOf(mTestPathDistances.get(pathNumber)); 258 String testDetails = mTestPhaseName + 259 " Path Length: Path length difference was too great. Path: " + pathNumber + 260 " Difference: " + difference + 261 " Paths: " + referencePath + " " + testPath + "\n"; 262 Log.e("Path Result", testDetails); 263 mTestReport.setFailDetails(testDetails); 264 } 265 266 /** 267 * Returns the makers in the test path. 268 */ getTestPathMarkers()269 public ArrayList<Waypoint> getTestPathMarkers() { 270 return mTestPath.getPathMarkers(); 271 } 272 273 /** 274 * Returns the size of the current path. 275 */ getTestPathMarkersSize()276 public int getTestPathMarkersSize() { 277 return mTestPath.getPathMarkers().size(); 278 } 279 } 280