1 package com.android.onboarding.versions.testing 2 3 import com.android.onboarding.versions.ComplianceDate 4 import com.android.onboarding.versions.OnboardingChanges 5 import com.android.onboarding.versions.annotations.ChangeId 6 import com.android.onboarding.versions.annotations.ChangeRadius 7 import com.android.onboarding.versions.changes.ALL_CHANGE_IDS 8 import java.lang.IllegalArgumentException 9 import java.lang.IllegalStateException 10 import java.lang.UnsupportedOperationException 11 12 /** Fake implementation of [OnboardingChanges]. */ 13 class FakeOnboardingChanges(private val component: String) : OnboardingChanges { 14 15 private val supportedChanges = mutableMapOf<String, MutableMap<Long, Boolean>>() 16 private val packageComplianceDates = mutableMapOf<String, ComplianceDate>() 17 18 /** Set the compliance date of a component. Defaults to [ComplianceDate.EARLIEST]. */ setComplianceDatenull19 fun setComplianceDate(component: String, complianceDate: ComplianceDate) { 20 packageComplianceDates[extractPackageFromComponent(component)] = complianceDate 21 } 22 23 /** Get the compliance date of a component. Defaults to [ComplianceDate.EARLIEST]. */ getComplianceDatenull24 fun getComplianceDate(component: String) = 25 packageComplianceDates.computeIfAbsent(extractPackageFromComponent(component)) { 26 ComplianceDate.EARLIEST 27 } 28 29 /** The compliance date of the executing component. */ 30 var complianceDate: ComplianceDate 31 get() = getComplianceDate(extractPackageFromComponent(component)) 32 set(value) { 33 setComplianceDate(extractPackageFromComponent(component), value) 34 } 35 36 /** Forces a change to be enabled. */ enableChangenull37 fun enableChange(changeId: Long) { 38 enableChange(component, changeId) 39 } 40 41 /** Forces a change to be enabled. */ enableChangenull42 fun enableChange(component: String, changeId: Long) { 43 supportedChanges 44 .computeIfAbsent(extractPackageFromComponent(component)) { mutableMapOf() }[changeId] = true 45 } 46 47 /** Forces a change to be disabled. */ disableChangenull48 fun disableChange(changeId: Long) { 49 disableChange(component, changeId) 50 } 51 52 /** Forces a change to be disabled. */ disableChangenull53 fun disableChange(component: String, changeId: Long) { 54 supportedChanges 55 .computeIfAbsent(extractPackageFromComponent(component)) { mutableMapOf() }[changeId] = false 56 } 57 58 /** Resets a change's availability to whatever is correct for the [complianceDate]. */ resetChangenull59 fun resetChange(changeId: Long) { 60 resetChange(component, changeId) 61 } 62 63 /** Resets a change's availability to whatever is correct for the [complianceDate]. */ resetChangenull64 fun resetChange(component: String, changeId: Long) { 65 supportedChanges 66 .computeIfAbsent(extractPackageFromComponent(component)) { mutableMapOf() } 67 .remove(changeId) 68 } 69 currentProcessSupportsChangenull70 override fun currentProcessSupportsChange(changeId: Long): Boolean { 71 return componentSupportsChange(component, changeId) 72 } 73 requireCurrentProcessSupportsChangenull74 override fun requireCurrentProcessSupportsChange(changeId: Long) { 75 if (currentProcessSupportsChange(changeId)) { 76 return 77 } 78 79 // currentProcessSupportsChange will throw if this is null 80 val changeData = ALL_CHANGE_IDS[changeId]!! 81 82 if (changeData.available == ChangeId.NOT_AVAILABLE) { 83 throw UnsupportedOperationException( 84 "This API is not available. The change ($changeId) is set to not available. See OnboardingChanges for options for enabling this change during test and development." 85 ) 86 } 87 88 throw UnsupportedOperationException( 89 "This API is not available. The change ($changeId) is available as of ${changeData.available} but the compliance date of this package is ${complianceDate}" 90 ) 91 } 92 93 /** This is non-functional on the fake. Set compliance dates directly. */ loadSupportedChangesnull94 override fun loadSupportedChanges(component: String) {} 95 componentSupportsChangenull96 override fun componentSupportsChange(component: String, changeId: Long): Boolean { 97 val packageName = extractPackageFromComponent(component) 98 99 val changeData = 100 ALL_CHANGE_IDS[changeId] 101 ?: throw IllegalStateException( 102 "Invalid change ID $changeId - this should have been blocked by the conformance checker" 103 ) 104 105 if ( 106 changeData.changeRadius == ChangeRadius.SINGLE_COMPONENT && 107 packageName != extractPackageFromComponent(this.component) 108 ) { 109 // This should be blocked by conformance 110 throw IllegalArgumentException( 111 "You cannot query changes which are SINGLE_COMPONENT across process boundaries." 112 ) 113 } 114 115 val overrideSupport = supportedChanges[packageName]?.get(changeId) 116 if (overrideSupport != null) { 117 return overrideSupport 118 } 119 120 // (this call should be blocked by conformance) 121 if (changeData.released != ChangeId.NOT_RELEASED) { 122 return true 123 } 124 125 // The fake does not support the "if it cannot be found then we assume no support" functionality 126 127 return getComplianceDate(packageName).isAvailable(changeData) 128 } 129 extractPackageFromComponentnull130 private fun extractPackageFromComponent(component: String) = component.split("/", limit = 2)[0] 131 } 132