Create SensorPrivacy test module

Test: atest CtsSensorPrivacyTestCases
Bug: 162549680
Change-Id: I3bd23491f910b3abd4f01fcb7e218459be011982
diff --git a/tests/tests/sensorprivacy/Android.bp b/tests/tests/sensorprivacy/Android.bp
new file mode 100644
index 0000000..89fd386
--- /dev/null
+++ b/tests/tests/sensorprivacy/Android.bp
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+android_test {
+    name: "CtsSensorPrivacyTestCases",
+    defaults: ["cts_defaults"],
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "general-tests",
+        "sts",
+    ],
+    compile_multilib: "both",
+    static_libs: [
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+        "androidx.annotation_annotation",
+        "androidx.test.uiautomator",
+    ],
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.aidl",
+        "src/**/*.kt",
+    ],
+    sdk_version: "test_current",
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+}
\ No newline at end of file
diff --git a/tests/tests/sensorprivacy/AndroidManifest.xml b/tests/tests/sensorprivacy/AndroidManifest.xml
new file mode 100644
index 0000000..1c378ec
--- /dev/null
+++ b/tests/tests/sensorprivacy/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="android.sensorprivacy.cts"
+     android:targetSandboxVersion="2">
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+         android:targetPackage="android.sensorprivacy.cts"
+         android:label="CTS tests of android.sensorprivacy">
+        <meta-data android:name="listener"
+             android:value="com.android.cts.runner.CtsTestRunListener"/>
+    </instrumentation>
+
+</manifest>
diff --git a/tests/tests/sensorprivacy/AndroidTest.xml b/tests/tests/sensorprivacy/AndroidTest.xml
new file mode 100644
index 0000000..412b1ee
--- /dev/null
+++ b/tests/tests/sensorprivacy/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for CTS Sensor Privacy test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user"/>
+
+    <!-- Install main test suite apk -->
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsSensorPrivacyTestCases.apk" />
+        <option name="test-file-name" value="CtsUseMicOrCameraForSensorPrivacy.apk" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.sensorprivacy.cts" />
+    </test>
+</configuration>
diff --git a/tests/tests/sensorprivacy/OWNERS b/tests/tests/sensorprivacy/OWNERS
new file mode 100644
index 0000000..3fb5fe2
--- /dev/null
+++ b/tests/tests/sensorprivacy/OWNERS
@@ -0,0 +1 @@
+file:platform/frameworks/native:/libs/sensorprivacy/OWNERS
\ No newline at end of file
diff --git a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
new file mode 100644
index 0000000..162abbd
--- /dev/null
+++ b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyBaseTest.kt
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.sensorprivacy.cts
+
+import android.content.Intent
+import android.hardware.SensorPrivacyManager
+import android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener
+import android.support.test.uiautomator.By
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.compatibility.common.util.SystemUtil
+import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
+import com.android.compatibility.common.util.UiAutomatorUtils
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+
+abstract class SensorPrivacyBaseTest(
+    val feature: String,
+    val sensor: Int,
+    vararg val extras: String
+) {
+
+    companion object {
+        const val MIC_CAM_ACTIVITY_ACTION =
+                "android.sensorprivacy.cts.usemiccamera.action.USE_MIC_CAM"
+        const val FINISH_MIC_CAM_ACTIVITY_ACTION =
+                "android.sensorprivacy.cts.usemiccamera.action.FINISH_USE_MIC_CAM"
+        const val USE_MIC_EXTRA =
+                "android.sensorprivacy.cts.usemiccamera.extra.USE_MICROPHONE"
+        const val USE_CAM_EXTRA =
+                "android.sensorprivacy.cts.usemiccamera.extra.USE_CAMERA"
+    }
+
+    protected val instrumentation = InstrumentationRegistry.getInstrumentation()!!
+    protected val uiAutomation = instrumentation.uiAutomation!!
+    protected val uiDevice = UiDevice.getInstance(instrumentation)!!
+    protected val context = instrumentation.targetContext!!
+    protected val spm = context.getSystemService(SensorPrivacyManager::class.java)!!
+    protected val packageManager = context.packageManager!!
+
+    @Before
+    fun init() {
+        Assume.assumeTrue(packageManager.hasSystemFeature(feature))
+        uiDevice.wakeUp()
+        runShellCommandOrThrow("wm dismiss-keyguard")
+        uiDevice.waitForIdle()
+    }
+
+    @Test
+    fun testSetSensor() {
+        setSensor(true)
+        assertTrue(spm.isSensorPrivacyEnabled(sensor))
+
+        setSensor(false)
+        assertFalse(spm.isSensorPrivacyEnabled(sensor))
+    }
+
+    @Test
+    fun testDialog() {
+        setSensor(true)
+        val intent = Intent(MIC_CAM_ACTIVITY_ACTION).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+        for (extra in extras) {
+            intent.putExtra(extra, true)
+        }
+        context.startActivity(intent)
+        UiAutomatorUtils.waitFindObject(By.text("Turn on")).click()
+        SystemUtil.eventually {
+            assertFalse(spm.isSensorPrivacyEnabled(sensor))
+        }
+        context.sendBroadcast(Intent(FINISH_MIC_CAM_ACTIVITY_ACTION))
+    }
+
+    @Test
+    fun testListener() {
+        val executor = Executors.newSingleThreadExecutor()
+        setSensor(false)
+        val latchEnabled = CountDownLatch(1)
+        SystemUtil.runWithShellPermissionIdentity {
+            spm.addSensorPrivacyListener(sensor, executor, OnSensorPrivacyChangedListener {
+                if (it) {
+                    latchEnabled.countDown()
+                }
+            })
+        }
+        setSensor(true)
+        latchEnabled.await(100, TimeUnit.MILLISECONDS)
+
+        val latchDisabled = CountDownLatch(1)
+        SystemUtil.runWithShellPermissionIdentity {
+            spm.addSensorPrivacyListener(sensor, executor, OnSensorPrivacyChangedListener {
+                if (!it) {
+                    latchDisabled.countDown()
+                }
+            })
+        }
+        setSensor(false)
+        latchEnabled.await(100, TimeUnit.MILLISECONDS)
+    }
+
+    fun setSensor(enable: Boolean) {
+        SystemUtil.runWithShellPermissionIdentity {
+            spm.setSensorPrivacy(sensor, enable)
+        }
+    }
+}
diff --git a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyCameraTest.kt b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyCameraTest.kt
new file mode 100644
index 0000000..d4a0082
--- /dev/null
+++ b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyCameraTest.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.sensorprivacy.cts
+
+import android.content.pm.PackageManager.FEATURE_CAMERA_TOGGLE
+import android.hardware.SensorPrivacyManager.Sensors.CAMERA
+
+class SensorPrivacyCameraTest : SensorPrivacyBaseTest(FEATURE_CAMERA_TOGGLE, CAMERA, USE_CAM_EXTRA)
diff --git a/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyMicrophoneTest.kt b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyMicrophoneTest.kt
new file mode 100644
index 0000000..a9bee33
--- /dev/null
+++ b/tests/tests/sensorprivacy/src/android/sensorprivacy/cts/SensorPrivacyMicrophoneTest.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.sensorprivacy.cts
+
+import android.content.pm.PackageManager.FEATURE_MICROPHONE_TOGGLE
+import android.hardware.SensorPrivacyManager.Sensors.MICROPHONE
+
+class SensorPrivacyMicrophoneTest : SensorPrivacyBaseTest(
+        FEATURE_MICROPHONE_TOGGLE,
+        MICROPHONE,
+        USE_MIC_EXTRA
+)
diff --git a/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/Android.bp b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/Android.bp
new file mode 100644
index 0000000..2f0c844
--- /dev/null
+++ b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test_helper_app {
+    name: "CtsUseMicOrCameraForSensorPrivacy",
+    defaults: ["cts_defaults"],
+
+    sdk_version: "test_current",
+
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    srcs: ["src/**/*.kt"],
+}
diff --git a/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/AndroidManifest.xml b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/AndroidManifest.xml
new file mode 100644
index 0000000..490773b
--- /dev/null
+++ b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.sensorprivacy.cts.usemiccamera"
+          android:versionCode="1">
+
+    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+    <uses-permission android:name="android.permission.CAMERA"/>
+
+    <application android:label="CtsUseMicOrCameraForSensorPrivacy">
+        <activity android:name=".UseMicCamera"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.sensorprivacy.cts.usemiccamera.action.USE_MIC_CAM" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt
new file mode 100644
index 0000000..d1c5c9f
--- /dev/null
+++ b/tests/tests/sensorprivacy/test-apps/CtsUseMicOrCameraForSensorPrivacy/src/android/sensorprivacy/cts/usemiccamera/UseMicCamera.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.sensorprivacy.cts.usemiccamera
+
+import android.app.Activity
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraDevice.StateCallback
+import android.hardware.camera2.CameraManager
+import android.media.AudioFormat
+import android.media.AudioRecord
+import android.media.MediaRecorder
+import android.os.Bundle
+import android.os.Handler
+
+private const val MIC = 1 shl 0
+private const val CAM = 1 shl 1
+
+private const val SAMPLING_RATE = 8000
+
+private const val finishMicCamActivityAction =
+        "android.sensorprivacy.cts.usemiccamera.action.FINISH_USE_MIC_CAM"
+private const val useMicExtra =
+        "android.sensorprivacy.cts.usemiccamera.extra.USE_MICROPHONE"
+private const val useCamExtra =
+        "android.sensorprivacy.cts.usemiccamera.extra.USE_CAMERA"
+
+class UseMicCamera : Activity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        val handler = Handler(mainLooper)
+
+        registerReceiver(object : BroadcastReceiver() {
+            override fun onReceive(context: Context?, intent: Intent?) {
+                unregisterReceiver(this)
+                finish()
+            }
+        }, IntentFilter(finishMicCamActivityAction))
+
+        val useMic = intent.getBooleanExtra(useMicExtra, false)
+        val useCam = intent.getBooleanExtra(useCamExtra, false)
+        if (useMic) {
+            handler.postDelayed({ openMic() }, 1000)
+        }
+        if (useCam) {
+            handler.postDelayed({ openCam() }, 1000)
+        }
+    }
+
+    private fun openMic() {
+        val audioRecord = AudioRecord.Builder()
+                .setAudioFormat(AudioFormat.Builder()
+                        .setSampleRate(SAMPLING_RATE)
+                        .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+                        .setChannelMask(AudioFormat.CHANNEL_IN_MONO).build())
+                .setAudioSource(MediaRecorder.AudioSource.DEFAULT)
+                .setBufferSizeInBytes(
+                        AudioRecord.getMinBufferSize(SAMPLING_RATE,
+                                AudioFormat.CHANNEL_IN_MONO,
+                                AudioFormat.ENCODING_PCM_16BIT) * 10)
+                .build()
+
+        audioRecord.startRecording()
+    }
+
+    private fun openCam() {
+        val cameraManager = getSystemService(CameraManager::class.java)!!
+        val cameraId = cameraManager.cameraIdList[0] ?: return
+        cameraManager.openCamera(cameraId, mainExecutor, object : StateCallback() {
+            override fun onOpened(camera: CameraDevice) {
+            }
+
+            override fun onDisconnected(camera: CameraDevice) {
+            }
+
+            override fun onError(camera: CameraDevice, error: Int) {
+            }
+        })
+    }
+}
\ No newline at end of file