Skip to content

Commit

Permalink
grant camera permissions for verification apps
Browse files Browse the repository at this point in the history
  • Loading branch information
kiftio committed Jul 26, 2024
1 parent 35f6ec5 commit a836c3d
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 2 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 3.0.2 Jul 26, 2024

- Implements `webChromeClient.onPermissionRequest()` to grant permission to the camera to allow apps that require the camera to verify identity to function correctly.
- Relevant camera permissions must be added to the client's `AndroidManifest.xml`

## 3.0.1 May 31, 2024

- Call `onPause()` on the WebView as it's created if preloading, and `onResume()` when it's presented, so the Page Visibility API reports correct values.
Expand Down
2 changes: 1 addition & 1 deletion lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def resolveEnvVarValue(name, defaultValue) {
return rawValue ? rawValue : defaultValue
}

def versionName = resolveEnvVarValue("CHECKOUT_SHEET_KIT_VERSION", "3.0.1")
def versionName = resolveEnvVarValue("CHECKOUT_SHEET_KIT_VERSION", "3.0.2")

ext {
app_compat_version = '1.6.1'
Expand Down
32 changes: 32 additions & 0 deletions lib/src/main/java/com/shopify/checkoutsheetkit/BaseWebView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,27 @@
*/
package com.shopify.checkoutsheetkit

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Color.TRANSPARENT
import android.os.Build
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.View
import android.view.ViewGroup.LayoutParams
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.webkit.PermissionRequest
import android.webkit.RenderProcessGoneDetail
import android.webkit.WebChromeClient
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.ComponentActivity
import androidx.core.app.ActivityCompat
import java.net.HttpURLConnection.HTTP_GONE
import java.net.HttpURLConnection.HTTP_NOT_FOUND

Expand Down Expand Up @@ -65,6 +70,32 @@ internal abstract class BaseWebView(context: Context, attributeSet: AttributeSet
super.onProgressChanged(view, newProgress)
getEventProcessor().updateProgressBar(newProgress)
}
override fun onPermissionRequest(request: PermissionRequest) {
request.resources?.forEach { resource ->
if (resource == PermissionRequest.RESOURCE_VIDEO_CAPTURE) {
if (!hasCameraPermission()) {
requestPermissions()
request.deny()
} else {
request.grant(request.resources)
}
}
}
}

private fun hasCameraPermission() =
ActivityCompat.checkSelfPermission(
context,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED

private fun requestPermissions() {
ActivityCompat.requestPermissions(
context as ComponentActivity,
arrayOf(Manifest.permission.CAMERA),
CAMERA_PERMISSION_REQUEST
)
}
}
isHorizontalScrollBarEnabled = false
requestDisallowInterceptTouchEvent(true)
Expand Down Expand Up @@ -194,6 +225,7 @@ internal abstract class BaseWebView(context: Context, attributeSet: AttributeSet
companion object {
private const val DEPRECATED_REASON_HEADER = "X-Shopify-API-Deprecated-Reason"
private const val LIQUID_NOT_SUPPORTED = "checkout_liquid_not_supported"
private const val CAMERA_PERMISSION_REQUEST = 1

private const val TOO_MANY_REQUESTS = 429
private val CLIENT_ERROR = 400..499
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
*/
package com.shopify.checkoutsheetkit

import android.Manifest
import android.graphics.Color
import android.os.Looper
import android.view.View.VISIBLE
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.webkit.PermissionRequest
import androidx.activity.ComponentActivity
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
Expand All @@ -37,6 +39,7 @@ import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.kotlin.whenever
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.Shadows.shadowOf
Expand Down Expand Up @@ -201,6 +204,35 @@ class CheckoutWebViewTest {
verify(webViewEventProcessor).updateProgressBar(50)
}

@Test
fun `calls grant when video capture resource permission requested and app has camera permission`() {
val application = shadowOf(activity.application)
application.grantPermissions(Manifest.permission.CAMERA)

val view = CheckoutWebView.cacheableCheckoutView(URL, activity)
val permissionRequest = mock<PermissionRequest>()
val requestedResources = arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE)
whenever(permissionRequest.resources).thenReturn(requestedResources)

val shadow = shadowOf(view)
shadow.webChromeClient?.onPermissionRequest(permissionRequest)

verify(permissionRequest).grant(requestedResources)
}

@Test
fun `calls deny when video capture resource permission requested and app does not have camera permission`() {
val view = CheckoutWebView.cacheableCheckoutView(URL, activity)
val permissionRequest = mock<PermissionRequest>()
val requestedResources = arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE)
whenever(permissionRequest.resources).thenReturn(requestedResources)

val shadow = shadowOf(view)
shadow.webChromeClient?.onPermissionRequest(permissionRequest)

verify(permissionRequest).deny()
}

@Test
fun `should recover from errors`() {
Robolectric.buildActivity(ComponentActivity::class.java).use { activityController ->
Expand Down
2 changes: 1 addition & 1 deletion samples/MobileBuyIntegration/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ android {
applicationId "com.shopify.checkout_sdk_mobile_buy_integration_sample"
minSdk 23
targetSdk 34
versionCode 31
versionCode 32
versionName "0.0.${versionCode}"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
2 changes: 2 additions & 0 deletions samples/MobileBuyIntegration/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-feature android:name="android.hardware.camera.any" android:required="false"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<application
android:name=".MobileBuyIntegration"
android:allowBackup="true"
Expand Down

0 comments on commit a836c3d

Please sign in to comment.