1 /* 2 * Copyright (C) 2021 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.packagemanager.verify.domain.android 18 19 import android.app.Instrumentation 20 import android.content.ComponentName 21 import android.content.Intent 22 import android.content.pm.PackageManager 23 import android.content.pm.verify.domain.DomainVerificationManager 24 import android.net.Uri 25 import androidx.test.platform.app.InstrumentationRegistry 26 import com.android.compatibility.common.util.ShellUtils 27 import com.android.cts.packagemanager.verify.domain.android.DomainUtils.DECLARING_PKG_1_COMPONENT 28 import com.android.cts.packagemanager.verify.domain.android.DomainUtils.DECLARING_PKG_2_COMPONENT 29 import com.android.cts.packagemanager.verify.domain.java.DomainUtils 30 import com.android.cts.packagemanager.verify.domain.java.DomainUtils.DECLARING_PKG_NAME_1 31 import com.android.cts.packagemanager.verify.domain.java.DomainUtils.DECLARING_PKG_NAME_2 32 import com.android.cts.packagemanager.verify.domain.java.DomainUtils.DOMAIN_UNHANDLED 33 import com.google.common.truth.Truth.assertThat 34 import com.google.common.truth.Truth.assertWithMessage 35 import org.junit.After 36 import org.junit.Assume.assumeTrue 37 import org.junit.Before 38 import org.junit.runner.RunWith 39 import org.junit.runners.Parameterized 40 41 @RunWith(Parameterized::class) 42 abstract class DomainVerificationIntentTestBase( 43 private val domain: String, 44 private val assertResolvesToBrowsersInBefore: Boolean = true, 45 private val resetEnable: Boolean = false, 46 ) { 47 48 companion object { 49 50 @Parameterized.Parameters(name = "{0}") 51 @JvmStatic parametersnull52 fun parameters() = IntentVariant.values() 53 } 54 55 @Parameterized.Parameter(0) 56 lateinit var intentVariant: IntentVariant 57 58 protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() 59 protected val context = instrumentation.targetContext 60 protected val packageManager = context.packageManager 61 protected val userId = context.userId 62 protected val manager = context.getSystemService(DomainVerificationManager::class.java)!! 63 64 protected lateinit var browsers: List<ComponentName> 65 protected lateinit var allResults: List<ComponentName> 66 67 @Before 68 fun findBrowsers() { 69 SharedVerifications.reset(context, resetEnable) 70 71 browsers = Intent(Intent.ACTION_VIEW, Uri.parse("https://$DOMAIN_UNHANDLED")) 72 .applyIntentVariant(intentVariant) 73 .let { context.packageManager.queryIntentActivities(it, 0) } 74 .map { it.activityInfo } 75 .map { ComponentName(it.packageName, it.name) } 76 .also { assumeTrue(it.isNotEmpty()) } 77 78 val allResults = browsers.toMutableList() 79 try { 80 packageManager.getPackageInfo(DECLARING_PKG_NAME_1, 0) 81 allResults += DECLARING_PKG_1_COMPONENT 82 } catch (ignored: PackageManager.NameNotFoundException) { 83 } 84 try { 85 packageManager.getPackageInfo(DECLARING_PKG_NAME_2, 0) 86 allResults += DECLARING_PKG_2_COMPONENT 87 } catch (ignored: PackageManager.NameNotFoundException) { 88 } 89 90 this.allResults = allResults 91 92 if (assertResolvesToBrowsersInBefore) { 93 assertResolvesTo(browsers) 94 } 95 } 96 97 @After resetnull98 fun reset() { 99 SharedVerifications.reset(context, resetEnable) 100 } 101 runShellCommandnull102 protected fun runShellCommand(vararg commands: String) = commands.forEach { 103 assertThat(ShellUtils.runShellCommand(it)).isEmpty() 104 } 105 assertResolvesTonull106 protected fun assertResolvesTo(result: ComponentName, domain: String = this.domain) = 107 assertResolvesTo(listOf(result), domain) 108 109 protected fun assertResolvesTo( 110 components: Collection<ComponentName>, 111 domain: String = this.domain, 112 ) { 113 val message = ShellUtils.runShellCommand( 114 "pm get-app-links --user ${context.userId} $DECLARING_PKG_NAME_1" 115 ) + "\n" + ShellUtils.runShellCommand( 116 "pm get-app-links --user ${context.userId} $DECLARING_PKG_NAME_2" 117 ) 118 119 val intent = Intent(Intent.ACTION_VIEW, Uri.parse("http://$domain")) 120 .addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION) 121 .applyIntentVariant(intentVariant) 122 123 // Pass MATCH_DEFAULT_ONLY to mirror startActivity resolution 124 assertWithMessage(message) 125 .that(packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY) 126 .map { it.activityInfo } 127 .map { ComponentName(it.packageName, it.name) }) 128 .containsExactlyElementsIn(components) 129 130 if (intent.hasCategory(Intent.CATEGORY_DEFAULT)) { 131 // Verify explicit DEFAULT mirrors MATCH_DEFAULT_ONLY 132 assertWithMessage(message) 133 .that(packageManager.queryIntentActivities(intent, 0) 134 .map { it.activityInfo } 135 .map { ComponentName(it.packageName, it.name) }) 136 .containsExactlyElementsIn(components) 137 } else { 138 val expected = allResults.filter { 139 browsers.contains(it) || (isComponentEnabled( 140 packageManager.getApplicationEnabledSetting( 141 it.packageName 142 ) 143 ) && isComponentEnabled(packageManager.getComponentEnabledSetting(it))) 144 } 145 146 // Verify that non-DEFAULT match returns all results 147 assertWithMessage(message) 148 .that(packageManager.queryIntentActivities(intent, 0) 149 .map { it.activityInfo } 150 .map { ComponentName(it.packageName, it.name) }) 151 .containsExactlyElementsIn(expected) 152 } 153 } 154 isComponentEnablednull155 private fun isComponentEnabled(enabledSetting: Int) = when (enabledSetting) { 156 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 157 PackageManager.COMPONENT_ENABLED_STATE_ENABLED -> true 158 159 else -> false 160 } 161 resetAppLinksnull162 fun resetAppLinks(packageName: String) { 163 runShellCommand(DomainUtils.resetAppLinks(packageName)) 164 } 165 setAppLinksnull166 fun setAppLinks(packageName: String, enabled: Boolean, vararg domains: String) { 167 val state = "STATE_APPROVED".takeIf { enabled } ?: "STATE_DENIED" 168 runShellCommand(DomainUtils.setAppLinks(packageName, state, *domains)) 169 } 170 setAppLinksAllowednull171 fun setAppLinksAllowed(packageName: String, userId: Int, enabled: Boolean) { 172 runShellCommand(DomainUtils.setAppLinksAllowed(packageName, userId, enabled)) 173 } 174 setAppLinksUserSelectionnull175 fun setAppLinksUserSelection( 176 packageName: String, 177 userId: Int, 178 enabled: Boolean, 179 vararg domains: String 180 ) { 181 runShellCommand( 182 DomainUtils.setAppLinksUserSelection(packageName, userId, enabled, *domains) 183 ) 184 } 185 } 186