• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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