@exodus/react-native-webview 11.26.1-exodus.9 → 13.16.0-exodus.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +36 -63
  2. package/android/build.gradle +83 -110
  3. package/android/gradle.properties +3 -4
  4. package/android/src/main/AndroidManifest.xml +12 -0
  5. package/android/src/main/AndroidManifestNew.xml +26 -0
  6. package/android/src/main/java/com/reactnativecommunity/webview/RNCBasicAuthCredential.java +11 -0
  7. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java +407 -0
  8. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java +468 -0
  9. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +330 -0
  10. package/android/src/main/java/com/reactnativecommunity/webview/{WebViewConfig.java → RNCWebViewConfig.java} +3 -4
  11. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java +1 -1
  12. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt +746 -0
  13. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMessagingModule.kt +9 -0
  14. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModuleImpl.java +554 -0
  15. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java +57 -12
  16. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewWrapper.kt +39 -0
  17. package/android/src/main/java/com/reactnativecommunity/webview/events/SubResourceErrorEvent.kt +25 -0
  18. package/android/src/main/java/com/reactnativecommunity/webview/events/TopCustomMenuSelectionEvent.kt +24 -0
  19. package/android/src/main/java/com/reactnativecommunity/webview/events/TopHttpErrorEvent.kt +25 -0
  20. package/android/src/main/java/com/reactnativecommunity/webview/events/TopNewWindowEvent.kt +25 -0
  21. package/android/src/main/java/com/reactnativecommunity/webview/events/TopRenderProcessGoneEvent.kt +25 -0
  22. package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java +570 -0
  23. package/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewModule.java +57 -0
  24. package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java +341 -0
  25. package/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewModule.java +59 -0
  26. package/apple/RCTConvert+WKDataDetectorTypes.h +11 -0
  27. package/apple/RCTConvert+WKDataDetectorTypes.m +27 -0
  28. package/apple/RNCWebView.h +26 -100
  29. package/apple/RNCWebView.mm +555 -0
  30. package/apple/RNCWebViewDecisionManager.h +20 -0
  31. package/apple/RNCWebViewDecisionManager.m +47 -0
  32. package/apple/RNCWebViewImpl.h +164 -0
  33. package/apple/{RNCWebView.m → RNCWebViewImpl.m} +802 -225
  34. package/apple/RNCWebViewManager.h +4 -8
  35. package/apple/RNCWebViewManager.mm +221 -0
  36. package/apple/RNCWebViewModule.h +23 -0
  37. package/apple/RNCWebViewModule.mm +34 -0
  38. package/index.d.ts +2 -3
  39. package/lib/NativeRNCWebViewModule.d.ts +8 -0
  40. package/lib/NativeRNCWebViewModule.js +1 -0
  41. package/lib/RNCWebViewNativeComponent.d.ts +245 -0
  42. package/lib/RNCWebViewNativeComponent.js +1 -0
  43. package/lib/WebView.android.d.ts +0 -1
  44. package/lib/WebView.android.js +1 -135
  45. package/lib/WebView.d.ts +2 -3
  46. package/lib/WebView.ios.d.ts +0 -1
  47. package/lib/WebView.ios.js +1 -114
  48. package/lib/WebView.js +1 -11
  49. package/lib/WebView.macos.d.ts +6 -0
  50. package/lib/WebView.macos.js +1 -0
  51. package/lib/WebView.styles.d.ts +37 -11
  52. package/lib/WebView.styles.js +1 -33
  53. package/lib/WebView.windows.d.ts +17 -0
  54. package/lib/WebView.windows.js +1 -0
  55. package/lib/WebViewNativeComponent.macos.d.ts +3 -0
  56. package/lib/WebViewNativeComponent.macos.js +1 -0
  57. package/lib/WebViewNativeComponent.windows.d.ts +3 -0
  58. package/lib/WebViewNativeComponent.windows.js +1 -0
  59. package/lib/WebViewShared.d.ts +30 -9
  60. package/lib/WebViewShared.js +1 -174
  61. package/lib/WebViewTypes.d.ts +514 -98
  62. package/lib/WebViewTypes.js +1 -6
  63. package/lib/index.d.ts +0 -1
  64. package/lib/index.js +1 -3
  65. package/lib/validation.d.ts +3 -0
  66. package/lib/validation.js +1 -0
  67. package/package.json +57 -33
  68. package/react-native-webview.podspec +32 -5
  69. package/react-native.config.js +22 -18
  70. package/src/NativeRNCWebViewModule.ts +13 -0
  71. package/src/RNCWebViewNativeComponent.ts +348 -0
  72. package/src/WebView.android.tsx +345 -0
  73. package/src/WebView.ios.tsx +341 -0
  74. package/src/WebView.macos.tsx +252 -0
  75. package/src/WebView.styles.ts +41 -0
  76. package/src/WebView.tsx +25 -0
  77. package/src/WebView.windows.tsx +217 -0
  78. package/src/WebViewNativeComponent.macos.ts +7 -0
  79. package/src/WebViewNativeComponent.windows.ts +8 -0
  80. package/src/WebViewShared.tsx +476 -0
  81. package/src/WebViewTypes.ts +1402 -0
  82. package/src/__tests__/WebViewShared-test.js +323 -0
  83. package/src/__tests__/__snapshots__/WebViewShared-test.js.snap +8 -0
  84. package/src/__tests__/validation-test.js +38 -0
  85. package/src/index.ts +4 -0
  86. package/src/validation.ts +20 -0
  87. package/android/.editorconfig +0 -6
  88. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +0 -1408
  89. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java +0 -506
  90. package/apple/RNCWebViewManager.m +0 -278
  91. package/lib/WebViewNativeComponent.android.d.ts +0 -4
  92. package/lib/WebViewNativeComponent.android.js +0 -3
  93. package/lib/WebViewNativeComponent.ios.d.ts +0 -4
  94. package/lib/WebViewNativeComponent.ios.js +0 -3
@@ -0,0 +1,407 @@
1
+ package com.reactnativecommunity.webview;
2
+
3
+ import android.Manifest;
4
+ import android.annotation.TargetApi;
5
+ import android.app.Activity;
6
+ import android.content.pm.PackageManager;
7
+ import android.net.Uri;
8
+ import android.os.Build;
9
+ import android.os.Message;
10
+ import android.view.Gravity;
11
+ import android.view.View;
12
+ import android.view.ViewGroup;
13
+ import android.webkit.ConsoleMessage;
14
+ import android.webkit.GeolocationPermissions;
15
+ import android.webkit.PermissionRequest;
16
+ import android.webkit.ValueCallback;
17
+ import android.webkit.WebChromeClient;
18
+ import android.webkit.WebView;
19
+ import android.webkit.WebViewClient;
20
+ import android.widget.FrameLayout;
21
+
22
+ import androidx.annotation.RequiresApi;
23
+ import androidx.core.content.ContextCompat;
24
+
25
+ import com.facebook.react.bridge.Arguments;
26
+ import com.facebook.react.bridge.LifecycleEventListener;
27
+ import com.facebook.react.bridge.WritableMap;
28
+ import com.facebook.react.common.build.ReactBuildConfig;
29
+ import com.facebook.react.modules.core.PermissionAwareActivity;
30
+ import com.facebook.react.modules.core.PermissionListener;
31
+ import com.facebook.react.uimanager.UIManagerHelper;
32
+ import com.reactnativecommunity.webview.events.TopLoadingProgressEvent;
33
+ import com.reactnativecommunity.webview.events.TopOpenWindowEvent;
34
+
35
+ import java.util.ArrayList;
36
+ import java.util.Collections;
37
+ import java.util.HashSet;
38
+ import java.util.List;
39
+ import java.util.Set;
40
+
41
+ public class RNCWebChromeClient extends WebChromeClient implements LifecycleEventListener {
42
+ protected static final FrameLayout.LayoutParams FULLSCREEN_LAYOUT_PARAMS = new FrameLayout.LayoutParams(
43
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER);
44
+
45
+ protected static final int FULLSCREEN_SYSTEM_UI_VISIBILITY = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
46
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
47
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
48
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
49
+ View.SYSTEM_UI_FLAG_FULLSCREEN |
50
+ View.SYSTEM_UI_FLAG_IMMERSIVE |
51
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
52
+
53
+ protected static final int COMMON_PERMISSION_REQUEST = 3;
54
+
55
+ protected RNCWebView mWebView;
56
+
57
+ protected View mVideoView;
58
+ protected WebChromeClient.CustomViewCallback mCustomViewCallback;
59
+
60
+ /*
61
+ * - Permissions -
62
+ * As native permissions are asynchronously handled by the PermissionListener, many fields have
63
+ * to be stored to send permissions results to the webview
64
+ */
65
+
66
+ // Webview camera & audio permission callback
67
+ protected PermissionRequest permissionRequest;
68
+ // Webview camera & audio permission already granted
69
+ protected List<String> grantedPermissions;
70
+
71
+ // Webview geolocation permission callback
72
+ protected GeolocationPermissions.Callback geolocationPermissionCallback;
73
+ // Webview geolocation permission origin callback
74
+ protected String geolocationPermissionOrigin;
75
+
76
+ // true if native permissions dialog is shown, false otherwise
77
+ protected boolean permissionsRequestShown = false;
78
+ // Pending Android permissions for the next request
79
+ protected List<String> pendingPermissions = new ArrayList<>();
80
+
81
+ protected RNCWebView.ProgressChangedFilter progressChangedFilter = null;
82
+ protected boolean mAllowsProtectedMedia = false;
83
+
84
+ protected boolean mHasOnOpenWindowEvent = false;
85
+
86
+ // Exodus: Camera permission origin whitelist for security
87
+ protected Set<String> cameraPermissionOriginWhitelist = new HashSet<>();
88
+
89
+ public RNCWebChromeClient(RNCWebView webView) {
90
+ this.mWebView = webView;
91
+ }
92
+
93
+ @Override
94
+ public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
95
+
96
+ final WebView newWebView = new WebView(view.getContext());
97
+
98
+ if(mHasOnOpenWindowEvent) {
99
+ newWebView.setWebViewClient(new WebViewClient(){
100
+ @Override
101
+ public boolean shouldOverrideUrlLoading (WebView subview, String url) {
102
+ WritableMap event = Arguments.createMap();
103
+ event.putString("targetUrl", url);
104
+
105
+ ((RNCWebView) view).dispatchEvent(
106
+ view,
107
+ new TopOpenWindowEvent(RNCWebViewWrapper.getReactTagFromWebView(view), event)
108
+ );
109
+
110
+ return true;
111
+ }
112
+ });
113
+ }
114
+
115
+ final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
116
+ transport.setWebView(newWebView);
117
+ resultMsg.sendToTarget();
118
+
119
+ return true;
120
+ }
121
+
122
+ @Override
123
+ public boolean onConsoleMessage(ConsoleMessage message) {
124
+ if (ReactBuildConfig.DEBUG) {
125
+ return super.onConsoleMessage(message);
126
+ }
127
+ // Ignore console logs in non debug builds.
128
+ return true;
129
+ }
130
+
131
+ @Override
132
+ public void onProgressChanged(WebView webView, int newProgress) {
133
+ super.onProgressChanged(webView, newProgress);
134
+ final String url = webView.getUrl();
135
+ if (progressChangedFilter.isWaitingForCommandLoadUrl()) {
136
+ return;
137
+ }
138
+ int reactTag = RNCWebViewWrapper.getReactTagFromWebView(webView);
139
+ WritableMap event = Arguments.createMap();
140
+ event.putDouble("target", reactTag);
141
+ event.putString("title", webView.getTitle());
142
+ event.putString("url", url);
143
+ event.putBoolean("canGoBack", webView.canGoBack());
144
+ event.putBoolean("canGoForward", webView.canGoForward());
145
+ event.putDouble("progress", (float) newProgress / 100);
146
+
147
+ UIManagerHelper.getEventDispatcherForReactTag(this.mWebView.getThemedReactContext(), reactTag).dispatchEvent(new TopLoadingProgressEvent(reactTag, event));
148
+ }
149
+
150
+ @Override
151
+ public void onPermissionRequest(final PermissionRequest request) {
152
+
153
+ grantedPermissions = new ArrayList<>();
154
+
155
+ ArrayList<String> requestedAndroidPermissions = new ArrayList<>();
156
+
157
+ // Exodus: Build origin string for whitelist check
158
+ final Uri originUri = request.getOrigin();
159
+ final String scheme = originUri.getScheme();
160
+ final int port = originUri.getPort();
161
+ String origin = scheme + "://" + originUri.getHost();
162
+
163
+ if (port > 0 && (("http".equals(scheme) && port != 80) || ("https".equals(scheme) && port != 443))) {
164
+ origin += ":" + port;
165
+ }
166
+
167
+ for (String requestedResource : request.getResources()) {
168
+ String androidPermission = null;
169
+
170
+ // Exodus: Only allow camera/microphone permissions for whitelisted origins
171
+ if (requestedResource.equals(PermissionRequest.RESOURCE_AUDIO_CAPTURE)) {
172
+ if (this.cameraPermissionOriginWhitelist.contains(origin)) {
173
+ androidPermission = Manifest.permission.RECORD_AUDIO;
174
+ }
175
+ } else if (requestedResource.equals(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
176
+ if (this.cameraPermissionOriginWhitelist.contains(origin)) {
177
+ androidPermission = Manifest.permission.CAMERA;
178
+ }
179
+ } else if(requestedResource.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) {
180
+ if (mAllowsProtectedMedia) {
181
+ grantedPermissions.add(requestedResource);
182
+ } else {
183
+ /**
184
+ * Legacy handling (Kept in case it was working under some conditions (given Android version or something))
185
+ *
186
+ * Try to ask user to grant permission using Activity.requestPermissions
187
+ *
188
+ * Find more details here: https://github.com/react-native-webview/react-native-webview/pull/2732
189
+ */
190
+ androidPermission = PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID;
191
+ }
192
+ }
193
+ // TODO: RESOURCE_MIDI_SYSEX, RESOURCE_PROTECTED_MEDIA_ID.
194
+ if (androidPermission != null) {
195
+ if (ContextCompat.checkSelfPermission(this.mWebView.getThemedReactContext(), androidPermission) == PackageManager.PERMISSION_GRANTED) {
196
+ grantedPermissions.add(requestedResource);
197
+ } else {
198
+ requestedAndroidPermissions.add(androidPermission);
199
+ }
200
+ }
201
+ }
202
+
203
+ // If all the permissions are already granted, send the response to the WebView synchronously
204
+ if (requestedAndroidPermissions.isEmpty()) {
205
+ // Exodus: Deny if no permissions were granted (origin not in whitelist)
206
+ if (grantedPermissions.isEmpty()) {
207
+ request.deny();
208
+ } else {
209
+ request.grant(grantedPermissions.toArray(new String[0]));
210
+ }
211
+ grantedPermissions = null;
212
+ return;
213
+ }
214
+
215
+ // Otherwise, ask to Android System for native permissions asynchronously
216
+
217
+ this.permissionRequest = request;
218
+
219
+ requestPermissions(requestedAndroidPermissions);
220
+ }
221
+
222
+
223
+ @Override
224
+ public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
225
+
226
+ if (ContextCompat.checkSelfPermission(this.mWebView.getThemedReactContext(), Manifest.permission.ACCESS_FINE_LOCATION)
227
+ != PackageManager.PERMISSION_GRANTED) {
228
+
229
+ /*
230
+ * Keep the trace of callback and origin for the async permission request
231
+ */
232
+ geolocationPermissionCallback = callback;
233
+ geolocationPermissionOrigin = origin;
234
+
235
+ requestPermissions(Collections.singletonList(Manifest.permission.ACCESS_FINE_LOCATION));
236
+
237
+ } else {
238
+ callback.invoke(origin, true, false);
239
+ }
240
+ }
241
+
242
+ private PermissionAwareActivity getPermissionAwareActivity() {
243
+ Activity activity = this.mWebView.getThemedReactContext().getCurrentActivity();
244
+ if (activity == null) {
245
+ throw new IllegalStateException("Tried to use permissions API while not attached to an Activity.");
246
+ } else if (!(activity instanceof PermissionAwareActivity)) {
247
+ throw new IllegalStateException("Tried to use permissions API but the host Activity doesn't implement PermissionAwareActivity.");
248
+ }
249
+ return (PermissionAwareActivity) activity;
250
+ }
251
+
252
+ private synchronized void requestPermissions(List<String> permissions) {
253
+
254
+ /*
255
+ * If permissions request dialog is displayed on the screen and another request is sent to the
256
+ * activity, the last permission asked is skipped. As a work-around, we use pendingPermissions
257
+ * to store next required permissions.
258
+ */
259
+
260
+ if (permissionsRequestShown) {
261
+ pendingPermissions.addAll(permissions);
262
+ return;
263
+ }
264
+
265
+ PermissionAwareActivity activity = getPermissionAwareActivity();
266
+ permissionsRequestShown = true;
267
+
268
+ activity.requestPermissions(
269
+ permissions.toArray(new String[0]),
270
+ COMMON_PERMISSION_REQUEST,
271
+ webviewPermissionsListener
272
+ );
273
+
274
+ // Pending permissions have been sent, the list can be cleared
275
+ pendingPermissions.clear();
276
+ }
277
+
278
+
279
+ private PermissionListener webviewPermissionsListener = (requestCode, permissions, grantResults) -> {
280
+
281
+ permissionsRequestShown = false;
282
+
283
+ /*
284
+ * As a "pending requests" approach is used, requestCode cannot help to define if the request
285
+ * came from geolocation or camera/audio. This is why shouldAnswerToPermissionRequest is used
286
+ */
287
+ boolean shouldAnswerToPermissionRequest = false;
288
+
289
+ for (int i = 0; i < permissions.length; i++) {
290
+
291
+ String permission = permissions[i];
292
+ boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
293
+
294
+ if (permission.equals(Manifest.permission.ACCESS_FINE_LOCATION)
295
+ && geolocationPermissionCallback != null
296
+ && geolocationPermissionOrigin != null) {
297
+
298
+ if (granted) {
299
+ geolocationPermissionCallback.invoke(geolocationPermissionOrigin, true, false);
300
+ } else {
301
+ geolocationPermissionCallback.invoke(geolocationPermissionOrigin, false, false);
302
+ }
303
+
304
+ geolocationPermissionCallback = null;
305
+ geolocationPermissionOrigin = null;
306
+ }
307
+
308
+ if (permission.equals(Manifest.permission.RECORD_AUDIO)) {
309
+ if (granted && grantedPermissions != null) {
310
+ grantedPermissions.add(PermissionRequest.RESOURCE_AUDIO_CAPTURE);
311
+ }
312
+ shouldAnswerToPermissionRequest = true;
313
+ }
314
+
315
+ if (permission.equals(Manifest.permission.CAMERA)) {
316
+ if (granted && grantedPermissions != null) {
317
+ grantedPermissions.add(PermissionRequest.RESOURCE_VIDEO_CAPTURE);
318
+ }
319
+ shouldAnswerToPermissionRequest = true;
320
+ }
321
+
322
+ if (permission.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) {
323
+ if (granted && grantedPermissions != null) {
324
+ grantedPermissions.add(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID);
325
+ }
326
+ shouldAnswerToPermissionRequest = true;
327
+ }
328
+ }
329
+
330
+ if (shouldAnswerToPermissionRequest
331
+ && permissionRequest != null
332
+ && grantedPermissions != null) {
333
+ permissionRequest.grant(grantedPermissions.toArray(new String[0]));
334
+ permissionRequest = null;
335
+ grantedPermissions = null;
336
+ }
337
+
338
+ if (!pendingPermissions.isEmpty()) {
339
+ requestPermissions(pendingPermissions);
340
+ return false;
341
+ }
342
+
343
+ return true;
344
+ };
345
+
346
+ protected void openFileChooser(ValueCallback<Uri> filePathCallback, String acceptType) {
347
+ this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, acceptType);
348
+ }
349
+
350
+ protected void openFileChooser(ValueCallback<Uri> filePathCallback) {
351
+ this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, "");
352
+ }
353
+
354
+ protected void openFileChooser(ValueCallback<Uri> filePathCallback, String acceptType, String capture) {
355
+ this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, acceptType);
356
+ }
357
+
358
+ @Override
359
+ public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
360
+ String[] acceptTypes = fileChooserParams.getAcceptTypes();
361
+ boolean allowMultiple = fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE;
362
+
363
+ return this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, acceptTypes, allowMultiple, fileChooserParams.isCaptureEnabled());
364
+ }
365
+
366
+ @Override
367
+ public void onHostResume() {
368
+ if (mVideoView != null && mVideoView.getSystemUiVisibility() != FULLSCREEN_SYSTEM_UI_VISIBILITY) {
369
+ mVideoView.setSystemUiVisibility(FULLSCREEN_SYSTEM_UI_VISIBILITY);
370
+ }
371
+ }
372
+
373
+ @Override
374
+ public void onHostPause() { }
375
+
376
+ @Override
377
+ public void onHostDestroy() { }
378
+
379
+ protected ViewGroup getRootView() {
380
+ return this.mWebView.getThemedReactContext().getCurrentActivity().findViewById(android.R.id.content);
381
+ }
382
+
383
+ public void setProgressChangedFilter(RNCWebView.ProgressChangedFilter filter) {
384
+ progressChangedFilter = filter;
385
+ }
386
+
387
+ /**
388
+ * Set whether or not protected media should be allowed
389
+ * /!\ Setting this to false won't revoke permission already granted to the current webpage.
390
+ * In order to do so, you'd need to reload the page /!\
391
+ */
392
+ public void setAllowsProtectedMedia(boolean enabled) {
393
+ mAllowsProtectedMedia = enabled;
394
+ }
395
+
396
+ public void setHasOnOpenWindowEvent(boolean hasEvent) {
397
+ mHasOnOpenWindowEvent = hasEvent;
398
+ }
399
+
400
+ /**
401
+ * Exodus: Set the camera permission origin whitelist.
402
+ * Only origins in this whitelist will be allowed to request camera/microphone permissions.
403
+ */
404
+ public void setCameraPermissionOriginWhitelist(Set<String> whitelist) {
405
+ this.cameraPermissionOriginWhitelist = whitelist;
406
+ }
407
+ }