-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathOSIABCustomTabsRouterAdapter.kt
More file actions
228 lines (201 loc) · 8.7 KB
/
OSIABCustomTabsRouterAdapter.kt
File metadata and controls
228 lines (201 loc) · 8.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
@file:OptIn(com.outsystems.plugins.inappbrowser.osinappbrowserlib.RequiresEventBridgeRegistration::class)
package com.outsystems.plugins.inappbrowser.osinappbrowserlib.routeradapters
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent
import androidx.browser.customtabs.CustomTabsSession
import com.outsystems.plugins.inappbrowser.osinappbrowserlib.OSIABEvents
import com.outsystems.plugins.inappbrowser.osinappbrowserlib.helpers.OSIABCustomTabsSessionHelper
import com.outsystems.plugins.inappbrowser.osinappbrowserlib.helpers.OSIABCustomTabsSessionHelperInterface
import com.outsystems.plugins.inappbrowser.osinappbrowserlib.helpers.OSIABFlowHelperInterface
import com.outsystems.plugins.inappbrowser.osinappbrowserlib.models.OSIABAnimation
import com.outsystems.plugins.inappbrowser.osinappbrowserlib.models.OSIABCustomTabsOptions
import com.outsystems.plugins.inappbrowser.osinappbrowserlib.models.OSIABViewStyle
import com.outsystems.plugins.inappbrowser.osinappbrowserlib.views.OSIABCustomTabsControllerActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import java.util.UUID
class OSIABCustomTabsRouterAdapter(
context: Context,
lifecycleScope: CoroutineScope,
options: OSIABCustomTabsOptions,
flowHelper: OSIABFlowHelperInterface,
onBrowserPageLoaded: () -> Unit,
onBrowserFinished: () -> Unit,
private val customTabsSessionHelper: OSIABCustomTabsSessionHelperInterface = OSIABCustomTabsSessionHelper(),
) : OSIABBaseRouterAdapter<OSIABCustomTabsOptions, Boolean>(
context = context,
lifecycleScope = lifecycleScope,
options = options,
flowHelper = flowHelper,
onBrowserPageLoaded = onBrowserPageLoaded,
onBrowserFinished = onBrowserFinished
) {
private val browserId = UUID.randomUUID().toString()
// for the browserPageLoaded event, which we only want to trigger on the first URL loaded in the CustomTabs instance
private var isFirstLoad = true
private var isFinished = false
override fun close(completionHandler: (Boolean) -> Unit) {
if (isFinished) {
completionHandler(true)
return
}
var closeEventJob: Job? = null
closeEventJob = flowHelper.listenToEvents(browserId, lifecycleScope) { event ->
if(event is OSIABEvents.OSIABCustomTabsEvent) {
when(event.action) {
OSIABCustomTabsControllerActivity.EVENT_CUSTOM_TABS_READY -> {
completionHandler(false)
}
OSIABCustomTabsControllerActivity.EVENT_CUSTOM_TABS_DESTROYED -> {
completionHandler(true)
}
else -> {
return@listenToEvents
}
}
closeEventJob?.cancel()
}
}
startCustomTabsControllerActivity(true)
}
private fun buildCustomTabsIntent(customTabsSession: CustomTabsSession?): CustomTabsIntent {
val builder = CustomTabsIntent.Builder(customTabsSession)
builder.setShowTitle(options.showTitle)
builder.setUrlBarHidingEnabled(options.hideToolbarOnScroll)
when (options.startAnimation) {
OSIABAnimation.FADE_IN -> builder.setStartAnimations(
context,
android.R.anim.fade_in,
android.R.anim.fade_out
)
OSIABAnimation.FADE_OUT -> builder.setStartAnimations(
context,
android.R.anim.fade_out,
android.R.anim.fade_in
)
OSIABAnimation.SLIDE_IN_LEFT -> builder.setStartAnimations(
context,
android.R.anim.slide_in_left,
android.R.anim.slide_out_right
)
OSIABAnimation.SLIDE_OUT_RIGHT -> builder.setStartAnimations(
context,
android.R.anim.slide_out_right,
android.R.anim.slide_in_left
)
}
when (options.exitAnimation) {
OSIABAnimation.FADE_IN -> builder.setExitAnimations(
context,
android.R.anim.fade_out,
android.R.anim.fade_in
)
OSIABAnimation.FADE_OUT -> builder.setExitAnimations(
context,
android.R.anim.fade_in,
android.R.anim.fade_out
)
OSIABAnimation.SLIDE_IN_LEFT -> builder.setExitAnimations(
context,
android.R.anim.slide_out_right,
android.R.anim.slide_in_left
)
OSIABAnimation.SLIDE_OUT_RIGHT -> builder.setExitAnimations(
context,
android.R.anim.slide_in_left,
android.R.anim.slide_out_right
)
}
if (options.viewStyle == OSIABViewStyle.BOTTOM_SHEET) {
options.bottomSheetOptions?.let { bottomSheetOptions ->
val height = bottomSheetOptions.height.coerceAtLeast(1)
if (bottomSheetOptions.isFixed) {
builder.setInitialActivityHeightPx(
height,
CustomTabsIntent.ACTIVITY_HEIGHT_FIXED
)
} else {
builder.setInitialActivityHeightPx(height)
}
}
}
builder.setBackgroundInteractionEnabled(true)
return builder.build()
}
override fun handleOpen(url: String, completionHandler: (Boolean) -> Unit) {
lifecycleScope.launch {
try {
val uri = Uri.parse(url)
customTabsSessionHelper.generateNewCustomTabsSession(
browserId,
context,
lifecycleScope,
flowHelper,
customTabsSessionCallback = {
if(it == null) {
completionHandler(false)
return@generateNewCustomTabsSession
}
openCustomTabsIntent(it, uri, completionHandler)
startCustomTabsControllerActivity()
}
)
} catch (e: Exception) {
completionHandler(false)
}
}
}
private fun openCustomTabsIntent(session: CustomTabsSession, uri: Uri, completionHandler: (Boolean) -> Unit) {
val customTabsIntent = buildCustomTabsIntent(session)
var eventsJob: Job? = null
eventsJob = flowHelper.listenToEvents(browserId, lifecycleScope) { event ->
when (event) {
is OSIABEvents.OSIABCustomTabsEvent -> {
if(event.action == OSIABCustomTabsControllerActivity.EVENT_CUSTOM_TABS_READY) {
try {
event.context?.let { ctx ->
customTabsIntent.launchUrl(ctx, uri)
completionHandler(true)
} ?: completionHandler(false)
} catch (e: Exception) {
completionHandler(false)
}
}
else if(event.action == OSIABCustomTabsControllerActivity.EVENT_CUSTOM_TABS_DESTROYED) {
isFinished = true
onBrowserFinished()
eventsJob?.cancel()
}
}
is OSIABEvents.BrowserPageLoaded -> {
if (isFirstLoad) {
onBrowserPageLoaded()
isFirstLoad = false
}
}
is OSIABEvents.BrowserFinished -> {
// Ensure that custom tabs controller activity is fully destroyed
startCustomTabsControllerActivity(true)
isFinished = true
onBrowserFinished()
eventsJob?.cancel()
}
else -> {}
}
}
}
private fun startCustomTabsControllerActivity(doClose: Boolean = false) {
val intent = Intent(context, OSIABCustomTabsControllerActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
putExtra(OSIABEvents.EXTRA_BROWSER_ID, browserId)
}
if(doClose) {
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
intent.putExtra(OSIABCustomTabsControllerActivity.ACTION_CLOSE_CUSTOM_TABS, true)
}
context.startActivity(intent)
}
}