1 package com.android.onboarding.bedsteadonboarding.contractutils 2 3 import android.content.Context 4 import android.util.Log 5 import com.android.onboarding.bedsteadonboarding.fakes.FakeActivityNodeHelper 6 import com.android.onboarding.bedsteadonboarding.permissions.TestPermissions 7 import com.android.onboarding.bedsteadonboarding.providers.ConfigProviderUtil 8 import com.android.onboarding.contracts.ContractResult 9 import com.android.onboarding.contracts.annotations.OnboardingNode 10 import com.android.onboarding.nodes.OnboardingGraphNode 11 12 /** Contains utility methods for node contracts. */ 13 object ContractUtils { 14 15 private const val contractIdentifierSeparator = "." 16 private const val TAG = "ContractUtils" 17 <lambda>null18 private val isRunningOnDebuggableDevice: Boolean by lazy { 19 TestPermissions.isRunningOnDebuggableDevice() 20 } 21 22 /** Returns a string uniquely identifying a node's contract given its [contractClass]. */ getContractIdentifiernull23 fun getContractIdentifier(contractClass: Class<*>) = 24 "${OnboardingNode.extractComponentNameFromClass(contractClass)}${contractIdentifierSeparator}${ 25 OnboardingNode.extractNodeNameFromClass(contractClass) 26 }" 27 28 /** Returns a string uniquely identifying the contract for the given [node]. */ 29 fun getContractIdentifierForNode(node: OnboardingGraphNode) = 30 "${node.component}$contractIdentifierSeparator${node.name}" 31 32 /** 33 * Returns a string uniquely identifying a node's contract given its [nodeComponent] and 34 * [nodeName]. 35 */ 36 fun getContractIdentifier(nodeComponent: String, nodeName: String) = 37 "${nodeComponent}$contractIdentifierSeparator${nodeName}" 38 39 fun getContractResultIfNodeIsFakedInTest(context: Context, contractClass: Class<*>) = 40 getContractResultIfNodeIsFakedInTest(context, getContractIdentifier(contractClass)) 41 42 /** 43 * Returns the [ContractResult] configured in test if the node identified by [contractIdentifier] 44 * is faked. This will always return null when the node is being executed in production. It will 45 * also return null when running in test environment if the node is not faked. 46 */ 47 fun getContractResultIfNodeIsFakedInTest( 48 context: Context, 49 contractIdentifier: String, 50 ): ContractResult? { 51 try { 52 if (isRunningOnDebuggableDevice) { 53 return getContractResultForContractIdentifier(context, contractIdentifier) 54 } 55 return null 56 } catch (t: Throwable) { 57 // For safety, ignore the exception since current function would run in production flow. 58 Log.e(TAG, "Error while fetching fake contract response of contract $contractIdentifier", t) 59 return null 60 } 61 } 62 63 /** 64 * Returns the [ContractResult] configured in test if the node identified by [contractIdentifier] 65 * is faked. This will always return null when the node is being executed in production. It will 66 * also return null when running in test environment if the node is not faked. 67 */ getContractResultForContractIdentifiernull68 fun getContractResultForContractIdentifier( 69 context: Context, 70 contractIdentifier: String, 71 ): ContractResult? { 72 try { 73 val uri = ConfigProviderUtil.getFakeActivityNodeConfigQueryUri(context, contractIdentifier) 74 75 val cursor = 76 context.contentResolver.query( 77 uri, 78 arrayOf(), 79 /* selection= */ null, 80 /* selectionArgs= */ null, 81 /* sortOrder= */ null, 82 /* cancellationSignal= */ null, 83 ) ?: return null 84 85 cursor.use { 86 if (it.extras != null) { 87 val contractResult = 88 FakeActivityNodeHelper.extractContractIdentifierAndContractResultFromBundle(it.extras) 89 if (contractResult != null) return contractResult.second 90 } 91 } 92 return null 93 } catch (t: Throwable) { 94 // For safety, ignore the exception since current function would run in production flow. 95 Log.e(TAG, "Error while fetching fake contract response of node $contractIdentifier", t) 96 return null 97 } 98 } 99 } 100