@@ -153,9 +153,14 @@ public void onProgressChanged(WebView webView, int newProgress) {
153153 @ Override
154154 public void onPermissionRequest (final PermissionRequest request ) {
155155
156+ // Reset state to handle new request
156157 grantedPermissions = new ArrayList <>();
158+ permissionRequest = null ;
157159
158160 ArrayList <String > requestedAndroidPermissions = new ArrayList <>();
161+ ArrayList <String > permissionsNeedingDialog = new ArrayList <>();
162+ ArrayList <String > permissionLabels = new ArrayList <>();
163+
159164 for (String requestedResource : request .getResources ()) {
160165 String androidPermission = null ;
161166 String requestPermissionIdentifier = null ;
@@ -179,37 +184,83 @@ public void onPermissionRequest(final PermissionRequest request) {
179184 */
180185 androidPermission = PermissionRequest .RESOURCE_PROTECTED_MEDIA_ID ;
181186 } }
182- Uri originUri = request .getOrigin ();
183- String host = originUri .getHost ();
184- // TODO: RESOURCE_MIDI_SYSEX, RESOURCE_PROTECTED_MEDIA_ID.
185- String alertMessage = String .format ("Allow " + host + " to use your " + requestPermissionIdentifier + "?" );
187+
186188 if (androidPermission != null ) {
187189 if (ContextCompat .checkSelfPermission (this .mWebView .getThemedReactContext (), androidPermission ) == PackageManager .PERMISSION_GRANTED ) {
188- AlertDialog .Builder builder = new AlertDialog .Builder (this .mWebView .getContext ());
189- builder .setMessage (alertMessage );
190- builder .setCancelable (false );
191- String finalAndroidPermission = androidPermission ;
192- builder .setPositiveButton ("Allow" , (dialog , which ) -> {
193- permissionRequest = request ;
194- grantedPermissions .add (finalAndroidPermission );
195- requestPermissions (grantedPermissions );
196- });
197- builder .setNegativeButton ("Don't allow" , (dialog , which ) -> {
198- request .deny ();
199- });
200- AlertDialog alertDialog = builder .create ();
201- alertDialog .show ();
202- //Delay making `allow` clickable for 500ms to avoid unwanted presses.
203- Button posButton = alertDialog .getButton (AlertDialog .BUTTON_POSITIVE );
204- posButton .setEnabled (false );
205- this .runDelayed (() -> posButton .setEnabled (true ), 500 );
190+ // Permission already granted at OS level, but still need user confirmation
191+ permissionsNeedingDialog .add (androidPermission );
192+ permissionLabels .add (requestPermissionIdentifier );
206193 } else {
194+ // Permission not granted at OS level, need to request it
207195 requestedAndroidPermissions .add (androidPermission );
208196 }
209197 }
210198 }
211199
212- // If all the permissions are already granted, send the response to the WebView synchronously
200+ // Show a SINGLE dialog for all permissions that are already granted at OS level
201+ if (!permissionsNeedingDialog .isEmpty ()) {
202+ Uri originUri = request .getOrigin ();
203+ String host = originUri .getHost ();
204+
205+ // Build message for all requested permissions
206+ String permissionList = String .join (" and " , permissionLabels );
207+ String alertMessage = String .format ("Allow %s to use your %s?" , host , permissionList );
208+
209+ AlertDialog .Builder builder = new AlertDialog .Builder (this .mWebView .getContext ());
210+ builder .setMessage (alertMessage );
211+ builder .setCancelable (false );
212+
213+ builder .setPositiveButton ("Allow" , (dialog , which ) -> {
214+ // Add all permissions to granted list
215+ for (String permission : permissionsNeedingDialog ) {
216+ if (permission .equals (Manifest .permission .CAMERA )) {
217+ grantedPermissions .add (PermissionRequest .RESOURCE_VIDEO_CAPTURE );
218+ } else if (permission .equals (Manifest .permission .RECORD_AUDIO )) {
219+ grantedPermissions .add (PermissionRequest .RESOURCE_AUDIO_CAPTURE );
220+ } else if (permission .equals (PermissionRequest .RESOURCE_PROTECTED_MEDIA_ID )) {
221+ grantedPermissions .add (PermissionRequest .RESOURCE_PROTECTED_MEDIA_ID );
222+ }
223+ }
224+
225+ // If no additional system permissions needed, grant immediately
226+ if (requestedAndroidPermissions .isEmpty ()) {
227+ if (!grantedPermissions .isEmpty ()) {
228+ try {
229+ request .grant (grantedPermissions .toArray (new String [0 ]));
230+ } catch (IllegalStateException e ) {
231+ // Request was already granted or denied, ignore
232+ } finally {
233+ grantedPermissions = null ;
234+ permissionRequest = null ;
235+ }
236+ }
237+ // DO NOT set permissionRequest since we're handling it entirely here
238+ } else {
239+ // Still need to request system permissions - set permissionRequest for listener callback
240+ permissionRequest = request ;
241+ requestPermissions (requestedAndroidPermissions );
242+ }
243+ });
244+
245+ builder .setNegativeButton ("Don't allow" , (dialog , which ) -> {
246+ request .deny ();
247+ // Clean up state
248+ grantedPermissions = null ;
249+ permissionRequest = null ;
250+ });
251+
252+ AlertDialog alertDialog = builder .create ();
253+ alertDialog .show ();
254+
255+ //Delay making `allow` clickable for 500ms to avoid unwanted presses.
256+ Button posButton = alertDialog .getButton (AlertDialog .BUTTON_POSITIVE );
257+ posButton .setEnabled (false );
258+ this .runDelayed (() -> posButton .setEnabled (true ), 500 );
259+
260+ return ;
261+ }
262+
263+ // If all the permissions are already granted (no dialog needed), send the response to the WebView synchronously
213264 if (requestedAndroidPermissions .isEmpty ()) {
214265 if (!grantedPermissions .isEmpty ()) {
215266 request .grant (grantedPermissions .toArray (new String [0 ]));
@@ -219,9 +270,7 @@ public void onPermissionRequest(final PermissionRequest request) {
219270 }
220271
221272 // Otherwise, ask to Android System for native permissions asynchronously
222-
223273 this .permissionRequest = request ;
224-
225274 requestPermissions (requestedAndroidPermissions );
226275 }
227276
@@ -356,9 +405,14 @@ private synchronized void requestPermissions(List<String> permissions) {
356405 if (shouldAnswerToPermissionRequest
357406 && permissionRequest != null
358407 && grantedPermissions != null ) {
359- permissionRequest .grant (grantedPermissions .toArray (new String [0 ]));
360- permissionRequest = null ;
361- grantedPermissions = null ;
408+ try {
409+ permissionRequest .grant (grantedPermissions .toArray (new String [0 ]));
410+ } catch (IllegalStateException e ) {
411+ // Request was already granted or denied, ignore
412+ } finally {
413+ permissionRequest = null ;
414+ grantedPermissions = null ;
415+ }
362416 }
363417
364418 if (!pendingPermissions .isEmpty ()) {
0 commit comments