Add test for "All Services" option.

BUG:203562360

Test: atest PermissionAllServicesTest
Change-Id: Ie08d327b04c00812bdeba392ebd0495b91bb1fd2
diff --git a/tests/tests/permission3/Android.bp b/tests/tests/permission3/Android.bp
index 36d24af..4928598 100644
--- a/tests/tests/permission3/Android.bp
+++ b/tests/tests/permission3/Android.bp
@@ -55,6 +55,7 @@
         ":CtsAccessMicrophoneApp",
         ":CtsAccessMicrophoneApp2",
         ":CtsAccessMicrophoneAppLocationProvider",
+        ":CtsAppLocationProviderWithSummary",
         ":CtsHelperAppOverlay",
         ":CtsCreateNotificationChannelsApp31",
         ":CtsCreateNotificationChannelsApp33",
diff --git a/tests/tests/permission3/AndroidTest.xml b/tests/tests/permission3/AndroidTest.xml
index 9e54fc6..384ea0b 100644
--- a/tests/tests/permission3/AndroidTest.xml
+++ b/tests/tests/permission3/AndroidTest.xml
@@ -43,6 +43,7 @@
         <option name="push" value="CtsAccessMicrophoneApp.apk->/data/local/tmp/cts/permission3/CtsAccessMicrophoneApp.apk" />
         <option name="push" value="CtsAccessMicrophoneApp2.apk->/data/local/tmp/cts/permission3/CtsAccessMicrophoneApp2.apk" />
         <option name="push" value="CtsAccessMicrophoneAppLocationProvider.apk->/data/local/tmp/cts/permission3/CtsAccessMicrophoneAppLocationProvider.apk" />
+        <option name="push" value="CtsAppLocationProviderWithSummary.apk->/data/local/tmp/cts/permission3/CtsAppLocationProviderWithSummary.apk" />
         <option name="push" value="CtsPermissionPolicyApp25.apk->/data/local/tmp/cts/permission3/CtsPermissionPolicyApp25.apk" />
         <option name="push" value="CtsUsePermissionApp22.apk->/data/local/tmp/cts/permission3/CtsUsePermissionApp22.apk" />
         <option name="push" value="CtsUsePermissionApp22CalendarOnly.apk->/data/local/tmp/cts/permission3/CtsUsePermissionApp22CalendarOnly.apk" />
diff --git a/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/Android.bp b/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/Android.bp
new file mode 100644
index 0000000..91143ae
--- /dev/null
+++ b/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2022 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test_helper_app {
+    name: "CtsAppLocationProviderWithSummary",
+    defaults: ["mts-target-sdk-version-current"],
+    min_sdk_version: "31",
+    srcs: [
+        "src/**/*.kt",
+    ],
+    static_libs: [
+        "kotlin-stdlib",
+    ],
+}
diff --git a/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/AndroidManifest.xml b/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/AndroidManifest.xml
new file mode 100644
index 0000000..020f613
--- /dev/null
+++ b/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2022 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.permission3.cts.applocationproviderwithsummary">
+
+  <application
+      android:label="LocationProviderWithSummaryApp">
+    <activity android:name=".AddLocationProviderActivity" android:exported="true">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.LAUNCHER" />
+      </intent-filter>
+    </activity>
+    <activity android:name=".AllServicesActivity" android:exported="true">
+      <intent-filter>
+        <action android:name="android.intent.action.VIEW_APP_FEATURES" />
+      </intent-filter>
+      <meta-data
+          android:name="app_features_preference_summary"
+          android:resource="@string/summary_label"/>
+    </activity>
+  </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/res/values/strings.xml b/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/res/values/strings.xml
new file mode 100644
index 0000000..d6f150a
--- /dev/null
+++ b/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+<resources>
+  <string name="attribution_label">Attribution label.</string>
+  <string name="summary_label">Services summary.</string>
+</resources>
diff --git a/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/src/AddLocationProviderActivity.kt b/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/src/AddLocationProviderActivity.kt
new file mode 100644
index 0000000..632bbb6
--- /dev/null
+++ b/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/src/AddLocationProviderActivity.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 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.permission3.cts.applocationproviderwithsummary
+
+import android.app.Activity
+import android.location.Criteria
+import android.location.LocationManager
+import android.os.Bundle
+
+/**
+ * An activity that adds this package as a test location provider.
+ */
+class AddLocationProviderActivity : Activity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        val attrContext = createAttributionContext("test.tag")
+        val locationManager = attrContext.getSystemService(LocationManager::class.java)
+        locationManager.addTestProvider(
+            packageName, false, false, false, false, false, false, false, Criteria.POWER_LOW,
+            Criteria.ACCURACY_COARSE
+        )
+
+        setResult(RESULT_OK)
+        finish()
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/src/AllServicesActivity.kt b/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/src/AllServicesActivity.kt
new file mode 100644
index 0000000..94939de
--- /dev/null
+++ b/tests/tests/permission3/UsePermissionAppLocationProviderWithSummary/src/AllServicesActivity.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+import android.app.Activity
+import android.os.Bundle
+
+class AllServicesActivity : Activity() {
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionAllServicesTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionAllServicesTest.kt
new file mode 100644
index 0000000..727a22f
--- /dev/null
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionAllServicesTest.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2022 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.permission3.cts
+
+import android.app.Activity
+import android.app.AppOpsManager
+import com.android.compatibility.common.util.AppOpsUtils.setOpMode
+import android.content.ComponentName
+import android.content.Intent
+import android.location.LocationManager
+import android.net.Uri
+import android.provider.Settings
+import com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity
+import org.junit.Test
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Assert.assertNull
+import android.support.test.uiautomator.By
+import com.android.compatibility.common.util.SystemUtil.eventually
+
+class PermissionAllServicesTest : BasePermissionTest() {
+    val locationManager = context.getSystemService(LocationManager::class.java)!!
+
+    @Test
+    fun testAllServicesPreferenceShownWhenAppIsLocationProviderAndCanHandleClick() {
+        installPackage(LOCATION_PROVIDER_APP_APK_PATH_2, grantRuntimePermissions = true)
+        allowPackagesToMockLocation(LOCATION_PROVIDER_APP_PACKAGE_NAME_2)
+        enableAppAsLocationProvider(LOCATION_PROVIDER_APP_PACKAGE_NAME_2)
+
+        eventually({
+            try {
+                launchAppInfoActivity(LOCATION_PROVIDER_APP_PACKAGE_NAME_2)
+                waitFindObject(By.textContains(ALL_SERVICES_LABEL))
+            } catch (e: Exception) {
+                pressBack()
+                throw e
+            } }, 1000L)
+
+        uninstallPackage(LOCATION_PROVIDER_APP_PACKAGE_NAME_2, requireSuccess = false)
+        locationManager.removeTestProvider(LOCATION_PROVIDER_APP_APK_PATH_2)
+    }
+
+    @Test
+    fun testAllServicesSummaryShowsWhenAppIsLocationProviderAndCanHandleClick() {
+        installPackage(LOCATION_PROVIDER_APP_APK_PATH_2, grantRuntimePermissions = true)
+        allowPackagesToMockLocation(LOCATION_PROVIDER_APP_PACKAGE_NAME_2)
+        enableAppAsLocationProvider(LOCATION_PROVIDER_APP_PACKAGE_NAME_2)
+
+        eventually({
+            try {
+                launchAppInfoActivity(LOCATION_PROVIDER_APP_PACKAGE_NAME_2)
+                waitFindObject(By.textContains(SUMMARY))
+            } catch (e: Exception) {
+                pressBack()
+                throw e
+            } }, 1000L)
+
+        uninstallPackage(LOCATION_PROVIDER_APP_PACKAGE_NAME_2, requireSuccess = false)
+        locationManager.removeTestProvider(LOCATION_PROVIDER_APP_APK_PATH_2)
+    }
+
+    @Test
+    fun testAllServicesPreferenceNotShownWhenAppCannotHandleClick() {
+        installPackage(LOCATION_PROVIDER_APP_APK_PATH_1, grantRuntimePermissions = true)
+        allowPackagesToMockLocation(LOCATION_PROVIDER_APP_PACKAGE_NAME_1)
+        enableAppAsLocationProvider(LOCATION_PROVIDER_APP_PACKAGE_NAME_1)
+
+        eventually({
+            try {
+                launchAppInfoActivity(LOCATION_PROVIDER_APP_PACKAGE_NAME_1)
+                assertNull(waitFindObjectOrNull(By.textContains(ALL_SERVICES_LABEL)))
+            } catch (e: Exception) {
+                pressBack()
+                throw e
+            } }, 1000L)
+
+        uninstallPackage(LOCATION_PROVIDER_APP_PACKAGE_NAME_1, requireSuccess = false)
+        locationManager.removeTestProvider(LOCATION_PROVIDER_APP_APK_PATH_1)
+    }
+
+    @Test
+    fun testAllServicesPreferenceNotShownWhenAppIsNotLocationProvider() {
+        installPackage(NON_LOCATION_APP_APK_PATH, grantRuntimePermissions = true)
+
+        eventually({
+            try {
+                launchAppInfoActivity(NON_LOCATION_APP_PACKAGE_NAME)
+                assertNull(waitFindObjectOrNull(By.textContains(ALL_SERVICES_LABEL)))
+            } catch (e: Exception) {
+                pressBack()
+                throw e
+            } }, 1000L)
+
+        uninstallPackage(NON_LOCATION_APP_APK_PATH, requireSuccess = false)
+    }
+
+    private fun allowPackagesToMockLocation(packageName: String) {
+        setOpMode(packageName, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpsManager.MODE_ALLOWED)
+        setOpMode(
+            context.packageName, AppOpsManager.OPSTR_MOCK_LOCATION, AppOpsManager.MODE_ALLOWED
+        )
+    }
+
+    private fun launchAppInfoActivity(packageName: String) {
+        context.startActivity(
+            Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
+                data = Uri.parse("package:$packageName")
+                addCategory(Intent.CATEGORY_DEFAULT)
+                addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
+            })
+    }
+
+    private fun enableAppAsLocationProvider(appPackageName: String) {
+        // Add the test app as location provider.
+        val future = startActivityForFuture(
+            Intent().apply {
+                component = ComponentName(
+                    appPackageName, "$appPackageName.AddLocationProviderActivity"
+                )
+            })
+
+        val result = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+        assertEquals(Activity.RESULT_OK, result.resultCode)
+        assertTrue(
+            callWithShellPermissionIdentity {
+                locationManager.isProviderPackage(appPackageName)
+            }
+        )
+    }
+
+    companion object {
+        const val LOCATION_PROVIDER_APP_APK_PATH_1 =
+            "$APK_DIRECTORY/CtsAccessMicrophoneAppLocationProvider.apk"
+        const val NON_LOCATION_APP_APK_PATH = "$APK_DIRECTORY/CtsUsePermissionApp22.apk"
+        const val LOCATION_PROVIDER_APP_APK_PATH_2 =
+            "$APK_DIRECTORY/CtsAppLocationProviderWithSummary.apk"
+        const val NON_LOCATION_APP_PACKAGE_NAME = "android.permission3.cts.usepermission"
+        const val LOCATION_PROVIDER_APP_PACKAGE_NAME_1 =
+            "android.permission3.cts.accessmicrophoneapplocationprovider"
+        const val LOCATION_PROVIDER_APP_PACKAGE_NAME_2 =
+            "android.permission3.cts.applocationproviderwithsummary"
+        const val APP_LABEL = "LocationProviderWithSummaryApp"
+        const val ALL_SERVICES_LABEL = "All Services"
+        const val SUMMARY = "Services summary."
+    }
+}
\ No newline at end of file