Skip to content

Commit f30438b

Browse files
committed
Vending: Expand payment methods (microg#2881)
Add multi-window support in the billing webview. This allows to use or set-up additional payment methods like PayPal that need to launch a popup window.
1 parent 448c6b9 commit f30438b

2 files changed

Lines changed: 73 additions & 5 deletions

File tree

vending-app/src/main/java/org/microg/vending/billing/ui/PlayWebViewActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class PlayWebViewActivity : ComponentActivity() {
8787
}
8888
layout.addView(webView)
8989
setContentView(layout)
90-
WebViewHelper(this, webView, ALLOWED_WEB_PREFIXES).openWebView(openUrl, account)
90+
WebViewHelper(this, webView, ALLOWED_WEB_PREFIXES).openWebView(openUrl, account, action)
9191
setResult(RESULT_OK)
9292
}
9393

vending-app/src/main/java/org/microg/vending/billing/ui/WebViewHelper.kt

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,24 @@ package org.microg.vending.billing.ui
77

88
import android.accounts.Account
99
import android.accounts.AccountManager
10+
import android.graphics.Bitmap
1011
import android.net.Uri
1112
import android.os.Build.VERSION.SDK_INT
13+
import android.os.Message
1214
import android.util.Log
1315
import android.view.View
1416
import android.webkit.CookieManager
17+
import android.webkit.WebChromeClient
1518
import android.webkit.WebResourceRequest
1619
import android.webkit.WebSettings
1720
import android.webkit.WebView
21+
import android.widget.ProgressBar
22+
import android.widget.RelativeLayout
1823
import androidx.activity.ComponentActivity
1924
import androidx.lifecycle.lifecycleScope
2025
import androidx.webkit.WebResourceErrorCompat
2126
import androidx.webkit.WebViewClientCompat
27+
import com.google.android.material.bottomsheet.BottomSheetDialog
2228
import kotlinx.coroutines.Dispatchers
2329
import kotlinx.coroutines.launch
2430
import org.microg.gms.profile.Build
@@ -32,8 +38,9 @@ class WebViewHelper(
3238
private val webView: WebView,
3339
private val allowedPrefixes: Set<String> = emptySet()
3440
) {
35-
fun openWebView(url: String, account: Account?) {
36-
prepareWebViewSettings(webView.settings)
41+
fun openWebView(url: String, account: Account?, webAction: WebViewAction) {
42+
prepareWebViewSettings(webView.settings, webAction == WebViewAction.ADD_PAYMENT_METHOD)
43+
webView.webChromeClient = PayWebChromeClient(webAction)
3744
webView.webViewClient = object : WebViewClientCompat() {
3845
override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceErrorCompat) {
3946
Log.e(TAG, "Error loading: $error")
@@ -113,9 +120,9 @@ class WebViewHelper(
113120
}
114121
}
115122

116-
private fun prepareWebViewSettings(settings: WebSettings) {
123+
private fun prepareWebViewSettings(settings: WebSettings, enableMultiWindow: Boolean = false) {
117124
settings.javaScriptEnabled = true
118-
settings.setSupportMultipleWindows(false)
125+
settings.setSupportMultipleWindows(enableMultiWindow)
119126
settings.allowFileAccess = false
120127
settings.databaseEnabled = false
121128
settings.setNeedInitialFocus(false)
@@ -124,4 +131,65 @@ class WebViewHelper(
124131
settings.javaScriptCanOpenWindowsAutomatically = false
125132
settings.userAgentString = Build.generateWebViewUserAgentString(settings.userAgentString)
126133
}
134+
135+
private class PayWebChromeClient(val webAction: WebViewAction) : WebChromeClient() {
136+
137+
override fun onCreateWindow(view: WebView?, isDialog: Boolean, isUserGesture: Boolean, resultMsg: Message?): Boolean {
138+
Log.d(TAG, "onCreateWindow: isDialog:$isDialog isUserGesture:$isUserGesture resultMsg: ${resultMsg.toString()}")
139+
if (webAction != WebViewAction.ADD_PAYMENT_METHOD) {
140+
return super.onCreateWindow(view, isDialog, isUserGesture, resultMsg)
141+
}
142+
// Add third-party payment methods, such as PayPal/GrabPay/Alipay.
143+
// WebView needs to support multi-window mode, and the child view will call the js method registered by the parent view
144+
// to refresh the page and close it by itself.
145+
var bottomSheetDialog: BottomSheetDialog? = null
146+
val parentContext = view!!.context
147+
val subWebView = WebView(parentContext).apply {
148+
settings.apply {
149+
javaScriptEnabled = true
150+
domStorageEnabled = true
151+
}
152+
webViewClient = object : WebViewClientCompat() {
153+
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
154+
super.onPageStarted(view, url, favicon)
155+
Log.d(TAG, "sub_window starts loading: $url")
156+
}
157+
158+
override fun onPageFinished(view: WebView?, url: String?) {
159+
super.onPageFinished(view, url)
160+
Log.d(TAG, "sub_window loaded : $url")
161+
visibility = View.VISIBLE
162+
}
163+
}
164+
webChromeClient = object : WebChromeClient() {
165+
override fun onCloseWindow(window: WebView?) {
166+
Log.d(TAG, "sub_window closed")
167+
bottomSheetDialog?.dismiss()
168+
}
169+
}
170+
layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)
171+
visibility = View.INVISIBLE
172+
}
173+
bottomSheetDialog = BottomSheetDialog(parentContext).apply {
174+
setOnDismissListener { subWebView.destroy() }
175+
}
176+
val layout = RelativeLayout(parentContext)
177+
layout.addView(ProgressBar(parentContext).apply {
178+
layoutParams = RelativeLayout.LayoutParams(
179+
RelativeLayout.LayoutParams.WRAP_CONTENT,
180+
RelativeLayout.LayoutParams.WRAP_CONTENT
181+
).apply {
182+
addRule(RelativeLayout.CENTER_HORIZONTAL)
183+
addRule(RelativeLayout.CENTER_VERTICAL)
184+
}
185+
isIndeterminate = true
186+
})
187+
bottomSheetDialog.setContentView(layout.apply { addView(subWebView) })
188+
bottomSheetDialog.show()
189+
190+
(resultMsg?.obj as? WebView.WebViewTransport)?.webView = subWebView
191+
resultMsg?.sendToTarget()
192+
return true
193+
}
194+
}
127195
}

0 commit comments

Comments
 (0)