16
16
17
17
package com.duckduckgo.app.referral
18
18
19
- import android.content.ComponentName
20
- import android.content.Context
21
- import android.content.Intent
22
- import android.content.pm.PackageManager
23
- import com.android.installreferrer.api.InstallReferrerClient
24
- import com.android.installreferrer.api.InstallReferrerClient.InstallReferrerResponse.*
25
- import com.android.installreferrer.api.InstallReferrerStateListener
26
- import com.duckduckgo.app.playstore.PlayStoreAndroidUtils.Companion.PLAY_STORE_PACKAGE
27
- import com.duckduckgo.app.playstore.PlayStoreAndroidUtils.Companion.PLAY_STORE_REFERRAL_SERVICE
28
- import com.duckduckgo.app.referral.AppInstallationReferrerStateListener.Companion.MAX_REFERRER_WAIT_TIME_MS
29
- import com.duckduckgo.app.referral.ParseFailureReason.*
30
- import com.duckduckgo.app.referral.ParsedReferrerResult.*
31
- import com.duckduckgo.app.statistics.AtbInitializerListener
32
- import com.duckduckgo.app.statistics.VariantManager
33
- import kotlinx.coroutines.delay
34
- import timber.log.Timber
35
- import javax.inject.Inject
36
- import javax.inject.Singleton
37
-
38
19
interface AppInstallationReferrerStateListener {
39
20
40
21
fun initialiseReferralRetrieval ()
@@ -45,151 +26,3 @@ interface AppInstallationReferrerStateListener {
45
26
}
46
27
47
28
}
48
-
49
- @Singleton
50
- class PlayStoreAppReferrerStateListener @Inject constructor(
51
- val context : Context ,
52
- private val packageManager : PackageManager ,
53
- private val appInstallationReferrerParser : AppInstallationReferrerParser ,
54
- private val appReferrerDataStore : AppReferrerDataStore ,
55
- private val variantManager : VariantManager
56
- ) : InstallReferrerStateListener, AppInstallationReferrerStateListener, AtbInitializerListener {
57
-
58
- private val referralClient = InstallReferrerClient .newBuilder(context).build()
59
- private var initialisationStartTime: Long = 0
60
-
61
- private var referralResult: ParsedReferrerResult = ReferrerInitialising
62
-
63
- /* *
64
- * Initialises the referrer service. This should only be called once.
65
- */
66
- override fun initialiseReferralRetrieval () {
67
- try {
68
- initialisationStartTime = System .currentTimeMillis()
69
-
70
- if (appReferrerDataStore.referrerCheckedPreviously) {
71
-
72
- referralResult = if (appReferrerDataStore.installedFromEuAuction) {
73
- EuAuctionReferrerFound (fromCache = true )
74
- } else {
75
- loadPreviousReferrerData()
76
- }
77
-
78
- Timber .i(" Already inspected this referrer data" )
79
- return
80
- }
81
-
82
- if (playStoreReferralServiceInstalled()) {
83
- referralClient.startConnection(this )
84
- } else {
85
- referralResult = ParseFailure (ReferralServiceUnavailable )
86
- }
87
- } catch (e: RuntimeException ) {
88
- Timber .w(e, " Failed to obtain referrer information" )
89
- referralResult = ParseFailure (UnknownError )
90
- }
91
- }
92
-
93
- private fun loadPreviousReferrerData (): ParsedReferrerResult {
94
- val suffix = loadFromDataStore()
95
- return if (suffix == null ) {
96
- Timber .i(" Already saw referrer data, but no campaign suffix saved" )
97
- ReferrerNotFound (fromCache = true )
98
- } else {
99
- Timber .i(" Already have referrer data from previous run - $suffix " )
100
- CampaignReferrerFound (suffix, fromCache = true )
101
- }
102
- }
103
-
104
- override fun onInstallReferrerSetupFinished (responseCode : Int ) {
105
- val referrerRetrievalDurationMs = System .currentTimeMillis() - initialisationStartTime
106
- Timber .i(" Took ${referrerRetrievalDurationMs} ms to get initial referral data callback" )
107
- try {
108
- when (responseCode) {
109
- OK -> {
110
- Timber .d(" Successfully connected to Referrer service" )
111
- val response = referralClient.installReferrer
112
- val referrer = response.installReferrer
113
- val parsedResult = appInstallationReferrerParser.parse(referrer)
114
- referralResultReceived(parsedResult)
115
- }
116
- FEATURE_NOT_SUPPORTED -> referralResultFailed(FeatureNotSupported )
117
- SERVICE_UNAVAILABLE -> referralResultFailed(ServiceUnavailable )
118
- DEVELOPER_ERROR -> referralResultFailed(DeveloperError )
119
- SERVICE_DISCONNECTED -> referralResultFailed(ServiceDisconnected )
120
- else -> referralResultFailed(UnknownError )
121
-
122
- }
123
-
124
- referralClient.endConnection()
125
- } catch (e: RuntimeException ) {
126
- Timber .w(e, " Failed to retrieve referrer data" )
127
- referralResultFailed(UnknownError )
128
- }
129
- }
130
-
131
- /* *
132
- * Retrieves the app installation referral code.
133
- * This might return a result immediately or might wait for a result to become available. There is no guarantee that a result will ever be returned.
134
- *
135
- * It is the caller's responsibility to guard against this function not returning a result in a timely manner, or not returning a result ever.
136
- */
137
- override suspend fun waitForReferrerCode (): ParsedReferrerResult {
138
- if (referralResult != ReferrerInitialising ) {
139
- Timber .d(" Referrer already determined; immediately answering" )
140
- return referralResult
141
- }
142
-
143
- Timber .i(" Referrer: Retrieving referral code from Play Store referrer service" )
144
-
145
- // poll, awaiting referral result to become available
146
- while (referralResult == ReferrerInitialising ) {
147
- Timber .v(" Still initialising - waiting" )
148
- delay(10 )
149
- }
150
-
151
- return referralResult
152
- }
153
-
154
- private fun loadFromDataStore (): String? {
155
- return appReferrerDataStore.campaignSuffix
156
- }
157
-
158
- private fun playStoreReferralServiceInstalled (): Boolean {
159
- val playStoreConnectionServiceIntent = Intent ()
160
- playStoreConnectionServiceIntent.component = ComponentName (PLAY_STORE_PACKAGE , PLAY_STORE_REFERRAL_SERVICE )
161
- val matchingServices = packageManager.queryIntentServices(playStoreConnectionServiceIntent, 0 )
162
- return matchingServices.size > 0
163
- }
164
-
165
- private fun referralResultReceived (result : ParsedReferrerResult ) {
166
- referralResult = result
167
-
168
- when (result) {
169
- is CampaignReferrerFound -> {
170
- variantManager.updateAppReferrerVariant(result.campaignSuffix)
171
- appReferrerDataStore.campaignSuffix = result.campaignSuffix
172
- }
173
- is EuAuctionReferrerFound -> {
174
- variantManager.updateAppReferrerVariant(VariantManager .RESERVED_EU_AUCTION_VARIANT )
175
- appReferrerDataStore.installedFromEuAuction = true
176
- }
177
- }
178
-
179
- appReferrerDataStore.referrerCheckedPreviously = true
180
- }
181
-
182
- private fun referralResultFailed (reason : ParseFailureReason ) {
183
- referralResult = ParseFailure (reason)
184
- }
185
-
186
- override fun onInstallReferrerServiceDisconnected () {
187
- Timber .i(" Referrer: ServiceDisconnected" )
188
- }
189
-
190
- override suspend fun beforeAtbInit () {
191
- waitForReferrerCode()
192
- }
193
-
194
- override fun beforeAtbInitTimeoutMillis (): Long = MAX_REFERRER_WAIT_TIME_MS
195
- }
0 commit comments