15
15
*/
16
16
package im.vector.app.features.widgets.webview
17
17
18
- import android.annotation.SuppressLint
18
+ import android.Manifest
19
19
import android.content.Context
20
20
import android.webkit.PermissionRequest
21
+ import androidx.activity.result.ActivityResultLauncher
21
22
import androidx.annotation.StringRes
23
+ import androidx.annotation.VisibleForTesting
24
+ import androidx.fragment.app.FragmentActivity
22
25
import com.google.android.material.dialog.MaterialAlertDialogBuilder
23
26
import im.vector.app.R
27
+ import im.vector.app.core.utils.checkPermissions
28
+ import java.lang.NullPointerException
29
+ import javax.inject.Inject
24
30
25
- object WebviewPermissionUtils {
31
+ class WebviewPermissionUtils @Inject constructor() {
26
32
27
- @SuppressLint(" NewApi" )
28
- fun promptForPermissions (@StringRes title : Int , request : PermissionRequest , context : Context ) {
33
+ private var permissionRequest: PermissionRequest ? = null
34
+ private var selectedPermissions = listOf<String >()
35
+
36
+ fun promptForPermissions (
37
+ @StringRes title : Int ,
38
+ request : PermissionRequest ,
39
+ context : Context ,
40
+ activity : FragmentActivity ,
41
+ activityResultLauncher : ActivityResultLauncher <Array <String >>
42
+ ) {
29
43
val allowedPermissions = request.resources.map {
30
44
it to false
31
45
}.toMutableList()
@@ -37,16 +51,56 @@ object WebviewPermissionUtils {
37
51
allowedPermissions[which] = allowedPermissions[which].first to isChecked
38
52
}
39
53
.setPositiveButton(R .string.room_widget_resource_grant_permission) { _, _ ->
40
- request.grant(allowedPermissions.mapNotNull { perm ->
54
+ permissionRequest = request
55
+ selectedPermissions = allowedPermissions.mapNotNull { perm ->
41
56
perm.first.takeIf { perm.second }
42
- }.toTypedArray())
57
+ }
58
+
59
+ val requiredAndroidPermissions = selectedPermissions.mapNotNull { permission ->
60
+ webPermissionToAndroidPermission(permission)
61
+ }
62
+
63
+ // When checkPermissions returns false, some of the required Android permissions will
64
+ // have to be requested and the flow completes asynchronously via onPermissionResult
65
+ if (checkPermissions(requiredAndroidPermissions, activity, activityResultLauncher)) {
66
+ request.grant(selectedPermissions.toTypedArray())
67
+ reset()
68
+ }
43
69
}
44
70
.setNegativeButton(R .string.room_widget_resource_decline_permission) { _, _ ->
45
71
request.deny()
46
72
}
47
73
.show()
48
74
}
49
75
76
+ fun onPermissionResult (result : Map <String , Boolean >) {
77
+ if (permissionRequest == null ) {
78
+ throw NullPointerException (" permissionRequest was null! Make sure to call promptForPermissions first." )
79
+ }
80
+ val grantedPermissions = filterPermissionsToBeGranted(selectedPermissions, result)
81
+ if (grantedPermissions.isNotEmpty()) {
82
+ permissionRequest?.grant(grantedPermissions.toTypedArray())
83
+ } else {
84
+ permissionRequest?.deny()
85
+ }
86
+ reset()
87
+ }
88
+
89
+ @VisibleForTesting(otherwise = VisibleForTesting .PRIVATE )
90
+ fun filterPermissionsToBeGranted (selectedWebPermissions : List <String >, androidPermissionResult : Map <String , Boolean >): List <String > {
91
+ return selectedWebPermissions.filter { webPermission ->
92
+ val androidPermission = webPermissionToAndroidPermission(webPermission)
93
+ ? : return @filter true // No corresponding Android permission exists
94
+ return @filter androidPermissionResult[androidPermission]
95
+ ? : return @filter true // Android permission already granted before
96
+ }
97
+ }
98
+
99
+ private fun reset () {
100
+ permissionRequest = null
101
+ selectedPermissions = listOf ()
102
+ }
103
+
50
104
private fun webPermissionToHumanReadable (permission : String , context : Context ): String {
51
105
return when (permission) {
52
106
PermissionRequest .RESOURCE_AUDIO_CAPTURE -> context.getString(R .string.room_widget_webview_access_microphone)
@@ -55,4 +109,12 @@ object WebviewPermissionUtils {
55
109
else -> permission
56
110
}
57
111
}
112
+
113
+ private fun webPermissionToAndroidPermission (permission : String ): String? {
114
+ return when (permission) {
115
+ PermissionRequest .RESOURCE_AUDIO_CAPTURE -> Manifest .permission.RECORD_AUDIO
116
+ PermissionRequest .RESOURCE_VIDEO_CAPTURE -> Manifest .permission.CAMERA
117
+ else -> null
118
+ }
119
+ }
58
120
}
0 commit comments