1 /* 2 * Copyright (C) 2019 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; 18 19 import com.android.cts.verifier.sensors.base.SensorCtsVerifierTestActivity; 20 21 import android.Manifest; 22 import com.android.cts.verifier.R; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.PackageManager; 26 import android.hardware.Sensor; 27 import android.hardware.SensorEvent; 28 import android.hardware.SensorEventListener; 29 import android.hardware.SensorManager; 30 import android.net.Uri; 31 import android.provider.Settings; 32 33 import java.util.ArrayList; 34 import java.util.concurrent.CountDownLatch; 35 import java.util.concurrent.TimeUnit; 36 37 import static org.junit.Assert.assertFalse; 38 import static org.junit.Assert.assertTrue; 39 40 /** 41 * Test cases to verify step sensor permissions 42 */ 43 public class StepSensorPermissionTestActivity extends SensorCtsVerifierTestActivity 44 implements SensorEventListener { 45 private static final int STEP_DETECT_DELAY_SECONDS = 30; 46 private static final int STEP_COUNT_DELAY_SECONDS = 30; 47 // Additional amount of time to give for receiving either a step detect or 48 // count event in case the user hasn't started walking at the time the test 49 // starts. 50 private static final int ADDITIONAL_EVENT_DELAY_SECONDS = 2; 51 52 private SensorManager mSensorManager; 53 54 private boolean mHasAccelFeature = false; 55 private boolean mHasStepCounterFeature = false; 56 private boolean mHasStepDetectorFeature = false; 57 private CountDownLatch mEventReceivedLatch = null; 58 private Sensor mSensorUnderTest = null; 59 private AccelRecorder mAccelRecorder = null; 60 StepSensorPermissionTestActivity()61 public StepSensorPermissionTestActivity() { 62 super(StepSensorPermissionTestActivity.class); 63 } 64 65 @Override activitySetUp()66 protected void activitySetUp() { 67 mSensorManager = (SensorManager) getApplicationContext() 68 .getSystemService(Context.SENSOR_SERVICE); 69 70 mHasAccelFeature = getApplicationContext().getPackageManager().hasSystemFeature( 71 PackageManager.FEATURE_SENSOR_ACCELEROMETER); 72 mHasStepCounterFeature = getApplicationContext().getPackageManager().hasSystemFeature( 73 PackageManager.FEATURE_SENSOR_STEP_COUNTER); 74 mHasStepDetectorFeature = getApplicationContext().getPackageManager().hasSystemFeature( 75 PackageManager.FEATURE_SENSOR_STEP_DETECTOR); 76 77 mAccelRecorder = new AccelRecorder(mSensorManager); 78 } 79 80 @Override activityCleanUp()81 protected void activityCleanUp() { 82 mSensorManager.unregisterListener(this); 83 mAccelRecorder.stop(); 84 85 // Notify the user that the test has concluded. This will play in both the pass 86 // and fail case 87 try { 88 playSound(); 89 } catch (InterruptedException e) { 90 // Ignored 91 } 92 } 93 94 /** 95 * Test cases. 96 */ 97 @SuppressWarnings("unused") testStepEvents()98 public String testStepEvents() throws Throwable { 99 if (mHasStepCounterFeature || mHasStepDetectorFeature) { 100 // Verify that sensors cannot be registered when the permission is not granted 101 runTest(false /* permissionGranted */); 102 103 // Signal to the user that the first part of the test is over 104 try { 105 playSound(); 106 } catch (InterruptedException e) { 107 // Ignored 108 } 109 110 // Verify that the sensors can be registered when the permission is not granted 111 runTest(true /* permissionGranted */); 112 } 113 114 return "Pass"; 115 } 116 runTest(boolean permissionGranted)117 private void runTest(boolean permissionGranted) throws InterruptedException { 118 if (hasPermission(Manifest.permission.ACTIVITY_RECOGNITION) != permissionGranted) { 119 requestChangePermission(permissionGranted); 120 } 121 122 waitForUser(R.string.snsr_step_permission_walk); 123 checkPermission(Manifest.permission.ACTIVITY_RECOGNITION, permissionGranted); 124 125 if (mHasStepDetectorFeature) { 126 checkSensor(Sensor.TYPE_STEP_DETECTOR, permissionGranted, STEP_DETECT_DELAY_SECONDS); 127 } 128 129 if (mHasStepCounterFeature) { 130 checkSensor(Sensor.TYPE_STEP_COUNTER, permissionGranted, STEP_COUNT_DELAY_SECONDS); 131 } 132 } 133 requestChangePermission(boolean enable)134 private void requestChangePermission(boolean enable) throws InterruptedException { 135 SensorTestLogger logger = getTestLogger(); 136 if (enable) { 137 logger.logInstructions(R.string.snsr_step_permission_enable); 138 } else { 139 logger.logInstructions(R.string.snsr_step_permission_disable); 140 } 141 waitForUserToContinue(); 142 Intent intent = new Intent(); 143 intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 144 Uri uri = Uri.fromParts("package", getPackageName(), null); 145 intent.setData(uri); 146 startActivity(intent); 147 } 148 hasPermission(String permission)149 private boolean hasPermission(String permission) { 150 return getApplicationContext().checkSelfPermission(permission) == 151 PackageManager.PERMISSION_GRANTED; 152 } 153 checkPermission(String permission, boolean expected)154 private void checkPermission(String permission, boolean expected) { 155 if (expected && !hasPermission(permission)) { 156 throw new AssertionError(String.format("Should not have '%s' permission", permission)); 157 } else if (!expected && hasPermission(permission)) { 158 throw new AssertionError(String.format("Should have '%s' permission", permission)); 159 } 160 } 161 checkSensor(int sensorType, boolean expected, int eventDelaySeconds)162 private void checkSensor(int sensorType, boolean expected, int eventDelaySeconds) 163 throws InterruptedException { 164 if (mHasAccelFeature && !expected) { 165 // Record accel when no events are expected to ensure that the device is moving during 166 // the test. 167 mAccelRecorder.start(); 168 } 169 170 mEventReceivedLatch = new CountDownLatch(1); 171 Sensor sensor = mSensorManager.getDefaultSensor(sensorType); 172 mSensorUnderTest = sensor; 173 174 String msg = String.format("Should %sbe able to register for '%s' events", 175 expected ? "" : "not ", sensor.getName()); 176 assertTrue(msg, mSensorManager.registerListener(this, sensor, 0, 0) == expected); 177 178 boolean eventReceived = mEventReceivedLatch.await( 179 eventDelaySeconds + ADDITIONAL_EVENT_DELAY_SECONDS, TimeUnit.SECONDS); 180 181 // Ensure that events are only received when the application has permission 182 if (expected) { 183 assertTrue("Failed to receive event for " + sensor.getName(), eventReceived); 184 } else { 185 assertFalse("Should not have received event for " + sensor.getName(), eventReceived); 186 187 if (mHasAccelFeature) { 188 // Verify that the device was moving during the test 189 mAccelRecorder.stop(); 190 assertTrue("Walking not detected", mAccelRecorder.variance() > 1.0f); 191 } 192 } 193 } 194 195 @Override onSensorChanged(SensorEvent sensorEvent)196 public void onSensorChanged(SensorEvent sensorEvent) { 197 if (sensorEvent.sensor == mSensorUnderTest) { 198 mEventReceivedLatch.countDown(); 199 } 200 } 201 202 @Override onAccuracyChanged(Sensor sensor, int i)203 public void onAccuracyChanged(Sensor sensor, int i) { 204 } 205 206 class AccelRecorder implements SensorEventListener { 207 208 private SensorManager mSensorManager; 209 private Sensor mAccel; 210 private ArrayList<Float> mMagnitudes = new ArrayList<>(); 211 AccelRecorder(SensorManager sensorManager)212 public AccelRecorder(SensorManager sensorManager) { 213 mSensorManager = sensorManager; 214 mAccel = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 215 } 216 start()217 public void start() { 218 mMagnitudes.clear(); 219 mSensorManager.registerListener( 220 this, mAccel, (int)TimeUnit.MILLISECONDS.toMicros(20), 0); 221 } 222 stop()223 public void stop() { 224 mSensorManager.unregisterListener(this); 225 } 226 variance()227 public float variance() { 228 if (mMagnitudes.size() <= 1) { 229 return 0.0f; 230 } 231 232 float mean = 0; 233 for (float val : mMagnitudes) { 234 mean += val; 235 } 236 mean /= mMagnitudes.size(); 237 238 float var = 0; 239 for (float val : mMagnitudes) { 240 var += (val - mean) * (val - mean); 241 } 242 return var / (mMagnitudes.size() - 1); 243 } 244 245 @Override onSensorChanged(SensorEvent sensorEvent)246 public void onSensorChanged(SensorEvent sensorEvent) { 247 if (sensorEvent.sensor == mAccel) { 248 float magnitude = sensorEvent.values[0] * sensorEvent.values[0] + 249 sensorEvent.values[1] * sensorEvent.values[1] + 250 sensorEvent.values[2] * sensorEvent.values[2]; 251 mMagnitudes.add((float)Math.sqrt(magnitude)); 252 } 253 } 254 255 @Override onAccuracyChanged(Sensor sensor, int i)256 public void onAccuracyChanged(Sensor sensor, int i) { 257 258 } 259 } 260 } 261