@capgo/capacitor-inappbrowser 8.15.2 → 8.16.2

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.
package/README.md CHANGED
@@ -1584,7 +1584,9 @@ See the README section "openSecureWindow (OAuth)" for full setup examples.
1584
1584
  | **`jsInterface`** | | JavaScript Interface: The webview automatically injects a JavaScript interface providing: - `window.mobileApp.close()`: Closes the webview from JavaScript - `window.mobileApp.postMessage(obj)`: Sends a message to the app (listen via "messageFromWebview" event) - `window.mobileApp.hide()` / `window.mobileApp.show()` when allowWebViewJsVisibilityControl is true in CapacitorConfig - `window.mobileApp.takeScreenshot()` when `allowScreenshotsFromWebPage` is true | | 6.10.0 |
1585
1585
  | **`allowScreenshotsFromWebPage`** | <code>boolean</code> | Allows page JavaScript to call `window.mobileApp.takeScreenshot()`. Disabled by default so only the host app can trigger native screenshots through the plugin API. | <code>false</code> | 8.4.0 |
1586
1586
  | **`captureConsoleLogs`** | <code>boolean</code> | Emits `consoleMessage` events for JavaScript `console.*` output coming from the managed page. Useful when the webview stays hidden and you still need page-level diagnostics. | <code>false</code> | 8.6.0 |
1587
- | **`persistWebViewData`** | <code>boolean</code> | Controls whether the webview should persist website data such as cache, cookies, local storage, IndexedDB, and session data. When false, iOS uses a non-persistent `WKWebsiteDataStore`. Android disables per-view cache and DOM/database storage where the system WebView supports it. Android cookies use the shared WebView cookie store; clearing them also affects the host WebView, so prefer per-URL cookie helpers instead of relying on process-global wipes. | <code>true</code> | 8.6.36 |
1587
+ | **`persistWebViewData`** | <code>boolean</code> | Controls whether the webview should persist website data such as cache, cookies, local storage, IndexedDB, and session data. When false, iOS uses a non-persistent `WKWebsiteDataStore`. Android disables per-view cache and database storage where the system WebView supports it while keeping DOM storage available so SPAs can use `localStorage`. Android cookies use the shared WebView cookie store; clearing them also affects the host WebView, so prefer per-URL cookie helpers instead of relying on process-global wipes. | <code>true</code> | 8.6.36 |
1588
+ | **`clearCookiesOnOpen`** | <code>boolean</code> | Clear all cookies from the InAppBrowser data store before the first navigation of this webview. Cordova `clearcache: 'yes'` parity. On Android, uses process-global `CookieManager.removeAllCookies()` and blocks until the wipe completes. On iOS, clears cookies from the webview's `WKWebsiteDataStore` (isolated plugin store by default). On Web this is a no-op. | <code>false</code> | 8.16.0 |
1589
+ | **`clearCacheOnOpen`** | <code>boolean</code> | Clear cached website data before the first navigation of this webview. Cordova `cleardata: 'yes'` parity. On Android, calls `WebView.clearCache(true)` after the webview is created. On iOS, removes disk and memory cache from the webview's `WKWebsiteDataStore`. On Web this is a no-op. | <code>false</code> | 8.16.0 |
1588
1590
  | **`useSharedDataStore`** | <code>boolean</code> | Share the host Capacitor WebView's website data store (cookies, local storage, etc.). On iOS 17+, InAppBrowser uses an isolated plugin-owned `WKWebsiteDataStore` by default so host and browser data stay separate. Set this to `true` to use `WKWebsiteDataStore.default()` instead, which shares session cookies with the Capacitor host WebView. Useful for SSO / OIDC silent login when the IdP session was established in the main app WebView. Requires `persistWebViewData: true` (the default). When `persistWebViewData` is false, a non-persistent store is used and this option has no effect. On Android this is a no-op: cookies are already process-global via `CookieManager`. On Web this is a no-op. Warning: clearing cookies/cache for a webview opened with this flag can affect the host WebView on iOS, because both share the same store. `clearAllBrowsingData()` still skips the host store. | <code>false</code> | 8.13.6 |
1589
1591
  | **`clientCertificate`** | <code>'none' \| 'prompt'</code> | Controls Android TLS client certificate prompts during HTTPS handshakes. Use `prompt` to show the system certificate picker; omit or use `none` to cancel silently (default). | <code>"none"</code> | 8.7.5 |
1590
1592
  | **`clientCertificatePrompt`** | <code>boolean</code> | | | |
@@ -1628,7 +1630,7 @@ See the README section "openSecureWindow (OAuth)" for full setup examples.
1628
1630
  | **`preventDeeplink`** | <code>boolean</code> | If true, deeplinks and external app hand-off are blocked and stay in the webview. If false (default), custom schemes such as `tel:`, `mailto:`, and `sms:` open natively. On iOS, listing a custom scheme under `LSApplicationQueriesSchemes` is only required when you rely on `canOpenURL` for that scheme (for example `instagram://`). It is not required for HTTPS `authorizedAppLinks`, and `mailto`/`tel`/`sms` open without that Info.plist entry. | <code>false</code> | 0.1.0 |
1629
1631
  | **`openBlankTargetInWebView`** | <code>boolean</code> | When true, HTTP and HTTPS links opened from `target="_blank"` anchors stay in the current webview instead of spawning a popup or opening in the system browser. By default, blank-target HTTP(S) links stay inside the plugin as managed popups that share cookies with the opener; enabling this option keeps everything in the same tab. Custom schemes such as `tel:` and `mailto:` and authorized app links still prefer their native handlers unless `preventDeeplink` is enabled. | <code>false</code> | 8.5.6 |
1630
1632
  | **`authorizedAppLinks`** | <code>string[]</code> | List of base URLs whose hosts are treated as authorized App Links (Android) and Universal Links (iOS). - On both platforms, only HTTP(S) links whose host matches any entry in this list will attempt to leave the in-app browser for the native / system handler. - iOS tries a Universal Link first (`universalLinksOnly`), then falls back to a normal system open (App Store, Safari, etc.). Only if both fail does the URL stay in-webview. - Android uses an `ACTION_VIEW` intent for matching hosts. - Matching is host-based (case-insensitive), ignoring the "www." prefix. - HTTPS hosts do not need `LSApplicationQueriesSchemes`; that Info.plist key is for custom schemes like `instagram://`, not `https://instagram.com`. - When `preventDeeplink` is enabled, all external handling is blocked regardless of this list. | <code>[]</code> | 7.12.0 |
1631
- | **`enabledSafeBottomMargin`** | <code>boolean</code> | If true, the webView is inset by the bottom system bar (navigation bar) so bottom-anchored content stays reachable. On Android 15+ the browser window is always edge-to-edge, so the bottom inset is applied there regardless of this option. | <code>false</code> | 7.13.0 |
1633
+ | **`enabledSafeBottomMargin`** | <code>boolean</code> | If true, the webView is inset by the bottom system bar (navigation bar) so bottom-anchored content stays reachable. When false (default), the webView can extend behind the navigation bar and apps can use `env(safe-area-inset-*)` for layout, matching the main Capacitor WebView. On pre-API 30 devices with a transparent navigation bar, bottom padding may still be applied when the window lays out behind the navigation bar regardless of this option. | <code>false</code> | 7.13.0 |
1632
1634
  | **`enabledSafeTopMargin`** | <code>boolean</code> | If false, the webView will extend behind the status bar for true full-screen immersive content. When true (default), respects the safe area at the top of the screen. Works independently of toolbarType - use for full-screen video players, games, or immersive web apps. On Android, when a toolbar is visible the toolbar itself provides that safe area; with `toolbarType: 'blank'` on Android 15+ the status bar inset is applied to the webView instead. | <code>true</code> | 8.2.0 |
1633
1635
  | **`useTopInset`** | <code>boolean</code> | When true, applies the system status bar inset to the top of the WebView on Android even when the window is not edge-to-edge (before Android 15). Keeps the legacy 0px inset by default for apps that handle padding themselves. On Android 15+ this is not needed: without a visible toolbar the status bar inset already follows `enabledSafeTopMargin`. | <code>false</code> | |
1634
1636
  | **`enableGooglePaySupport`** | <code>boolean</code> | enableGooglePaySupport: if true, enables support for Google Pay popups and Payment Request API. This fixes OR_BIBED_15 errors by allowing popup windows and configuring Cross-Origin-Opener-Policy. Only enable this if you need Google Pay functionality as it allows popup windows. When enabled: - Allows popup windows for Google Pay authentication - Sets proper CORS headers for Payment Request API - Enables multiple window support in WebView - Configures secure context for payment processing | <code>false</code> | 7.13.0 |
@@ -20,7 +20,6 @@ import android.util.Log;
20
20
  import android.webkit.CookieManager;
21
21
  import android.webkit.PermissionRequest;
22
22
  import android.webkit.WebView;
23
- import androidx.activity.result.ActivityResult;
24
23
  import androidx.activity.result.ActivityResultLauncher;
25
24
  import androidx.activity.result.contract.ActivityResultContracts;
26
25
  import androidx.annotation.NonNull;
@@ -63,8 +62,7 @@ import org.json.JSONObject;
63
62
  @Permission(alias = "camera", strings = { Manifest.permission.CAMERA }),
64
63
  @Permission(alias = "microphone", strings = { Manifest.permission.RECORD_AUDIO }),
65
64
  @Permission(alias = "storage", strings = { Manifest.permission.READ_EXTERNAL_STORAGE })
66
- },
67
- requestCodes = { WebViewDialog.FILE_CHOOSER_REQUEST_CODE }
65
+ }
68
66
  )
69
67
  public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.PermissionHandler {
70
68
 
@@ -108,7 +106,6 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
108
106
  private boolean currentPermissionNeedsCamera = false;
109
107
  private boolean currentPermissionNeedsMicrophone = false;
110
108
 
111
- private ActivityResultLauncher<Intent> fileChooserLauncher;
112
109
  private ActivityResultLauncher<String[]> webPermissionLauncher;
113
110
  private PluginCall pendingCameraPermissionCall;
114
111
 
@@ -118,10 +115,6 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
118
115
  @Override
119
116
  public void load() {
120
117
  super.load();
121
- fileChooserLauncher = getActivity().registerForActivityResult(
122
- new ActivityResultContracts.StartActivityForResult(),
123
- this::handleFileChooserResult
124
- );
125
118
  webPermissionLauncher = getActivity().registerForActivityResult(
126
119
  new ActivityResultContracts.RequestMultiplePermissions(),
127
120
  this::handleWebPermissionResult
@@ -355,6 +348,7 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
355
348
  );
356
349
  dialog.setInstanceId(webViewId);
357
350
  dialog.activity = CapgoInAppBrowserPlugin.this.getActivity();
351
+ dialog.bindToHostActivity();
358
352
  registerWebView(webViewId, dialog, makeActive);
359
353
  return dialog;
360
354
  }
@@ -525,59 +519,6 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
525
519
  return targetWebViews;
526
520
  }
527
521
 
528
- private WebViewDialog findFileChooserDialog() {
529
- if (activeWebViewId != null) {
530
- WebViewDialog dialog = webViewDialogs.get(activeWebViewId);
531
- if (dialog != null && dialog.mFilePathCallback != null) {
532
- return dialog;
533
- }
534
- }
535
-
536
- if (webViewDialog != null && webViewDialog.mFilePathCallback != null) {
537
- return webViewDialog;
538
- }
539
-
540
- for (WebViewDialog dialog : webViewDialogs.values()) {
541
- if (dialog != null && dialog.mFilePathCallback != null) {
542
- return dialog;
543
- }
544
- }
545
-
546
- return null;
547
- }
548
-
549
- private void handleFileChooserResult(ActivityResult result) {
550
- WebViewDialog webViewDialog = findFileChooserDialog();
551
- if (webViewDialog != null && webViewDialog.mFilePathCallback != null) {
552
- Uri[] results = null;
553
- Intent data = result.getData();
554
-
555
- if (result.getResultCode() == Activity.RESULT_OK) {
556
- // Handle camera capture result
557
- if (webViewDialog.tempCameraUri != null && (data == null || data.getData() == null)) {
558
- results = new Uri[] { webViewDialog.tempCameraUri };
559
- }
560
- // Handle regular file picker result
561
- else if (data != null) {
562
- if (data.getClipData() != null) {
563
- // Handle multiple files
564
- int count = data.getClipData().getItemCount();
565
- results = new Uri[count];
566
- for (int i = 0; i < count; i++) {
567
- results[i] = data.getClipData().getItemAt(i).getUri();
568
- }
569
- } else if (data.getData() != null) {
570
- // Handle single file
571
- results = new Uri[] { data.getData() };
572
- }
573
- }
574
- }
575
-
576
- // Send the result to WebView and clean up
577
- webViewDialog.completeLegacyFileChooserResult(results);
578
- }
579
- }
580
-
581
522
  public void handleMicrophonePermissionRequest(PermissionRequest request) {
582
523
  if (request == null) {
583
524
  return;
@@ -796,6 +737,16 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
796
737
  );
797
738
  }
798
739
 
740
+ private CustomTabColorSchemeParams buildCustomTabColorScheme(int colorInt) {
741
+ return applyCustomTabNavigationBarColor(new CustomTabColorSchemeParams.Builder().setToolbarColor(colorInt), colorInt).build();
742
+ }
743
+
744
+ @SuppressWarnings("deprecation")
745
+ private CustomTabColorSchemeParams.Builder applyCustomTabNavigationBarColor(CustomTabColorSchemeParams.Builder builder, int colorInt) {
746
+ // androidx.browser 1.9.0 still exposes only setNavigationBarColor; no non-deprecated replacement.
747
+ return builder.setNavigationBarColor(colorInt);
748
+ }
749
+
799
750
  @PluginMethod
800
751
  public void open(PluginCall call) {
801
752
  String url = call.getString("url");
@@ -828,10 +779,7 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
828
779
  if (toolbarColor != null) {
829
780
  try {
830
781
  int colorInt = Color.parseColor(toolbarColor);
831
- CustomTabColorSchemeParams colorParams = new CustomTabColorSchemeParams.Builder()
832
- .setToolbarColor(colorInt)
833
- .setNavigationBarColor(colorInt)
834
- .build();
782
+ CustomTabColorSchemeParams colorParams = buildCustomTabColorScheme(colorInt);
835
783
  builder.setDefaultColorSchemeParams(colorParams);
836
784
  builder.setColorSchemeParams(CustomTabsIntent.COLOR_SCHEME_DARK, colorParams);
837
785
  } catch (IllegalArgumentException e) {
@@ -1152,6 +1100,8 @@ public class CapgoInAppBrowserPlugin extends Plugin implements WebViewDialog.Per
1152
1100
  options.setHandleDownloads(Boolean.TRUE.equals(call.getBoolean("handleDownloads", false)));
1153
1101
 
1154
1102
  options.setPersistWebViewData(call.getBoolean("persistWebViewData", true));
1103
+ options.setClearCookiesOnOpen(Boolean.TRUE.equals(call.getBoolean("clearCookiesOnOpen", false)));
1104
+ options.setClearCacheOnOpen(Boolean.TRUE.equals(call.getBoolean("clearCacheOnOpen", false)));
1155
1105
  // No-op on Android: CookieManager is already process-global (API parity with iOS).
1156
1106
  options.setUseSharedDataStore(Boolean.TRUE.equals(call.getBoolean("useSharedDataStore", false)));
1157
1107
  // Set text zoom if specified in options (default is 100)
@@ -11,7 +11,6 @@ import com.getcapacitor.annotation.Permission;
11
11
  @Permission(alias = "camera", strings = { Manifest.permission.CAMERA }),
12
12
  @Permission(alias = "microphone", strings = { Manifest.permission.RECORD_AUDIO }),
13
13
  @Permission(alias = "storage", strings = { Manifest.permission.READ_EXTERNAL_STORAGE })
14
- },
15
- requestCodes = { WebViewDialog.FILE_CHOOSER_REQUEST_CODE }
14
+ }
16
15
  )
17
16
  public class InAppBrowserPlugin extends CapgoInAppBrowserPlugin {}
@@ -0,0 +1,40 @@
1
+ package ee.forgr.capacitor_inappbrowser;
2
+
3
+ import android.webkit.CookieManager;
4
+ import android.webkit.WebView;
5
+ import java.util.concurrent.CountDownLatch;
6
+ import java.util.concurrent.TimeUnit;
7
+
8
+ /**
9
+ * Applies cordova-style open-time cookie/cache clearing before the first navigation.
10
+ */
11
+ final class OpenTimeBrowsingDataClearSupport {
12
+
13
+ private static final long COOKIE_CLEAR_TIMEOUT_SECONDS = 10;
14
+
15
+ private OpenTimeBrowsingDataClearSupport() {}
16
+
17
+ static void applyBeforeFirstNavigation(
18
+ CookieManager cookieManager,
19
+ WebView webView,
20
+ boolean clearCookiesOnOpen,
21
+ boolean clearCacheOnOpen
22
+ ) {
23
+ if (clearCookiesOnOpen) {
24
+ final CountDownLatch latch = new CountDownLatch(1);
25
+ cookieManager.removeAllCookies((value) -> latch.countDown());
26
+ try {
27
+ if (!latch.await(COOKIE_CLEAR_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
28
+ throw new IllegalStateException("Timed out waiting for cookie clear");
29
+ }
30
+ } catch (InterruptedException e) {
31
+ Thread.currentThread().interrupt();
32
+ }
33
+ cookieManager.flush();
34
+ }
35
+
36
+ if (clearCacheOnOpen && webView != null) {
37
+ webView.clearCache(true);
38
+ }
39
+ }
40
+ }
@@ -204,6 +204,8 @@ public class Options {
204
204
  private boolean captureConsoleLogs = false;
205
205
  private boolean handleDownloads = false;
206
206
  private boolean persistWebViewData = true;
207
+ private boolean clearCookiesOnOpen = false;
208
+ private boolean clearCacheOnOpen = false;
207
209
  /** Accepted for API parity with iOS; Android cookies are already process-global. */
208
210
  private boolean useSharedDataStore = false;
209
211
  private InvisibilityMode invisibilityMode = InvisibilityMode.AWARE;
@@ -320,6 +322,22 @@ public class Options {
320
322
  this.persistWebViewData = persistWebViewData;
321
323
  }
322
324
 
325
+ public boolean getClearCookiesOnOpen() {
326
+ return clearCookiesOnOpen;
327
+ }
328
+
329
+ public void setClearCookiesOnOpen(boolean clearCookiesOnOpen) {
330
+ this.clearCookiesOnOpen = clearCookiesOnOpen;
331
+ }
332
+
333
+ public boolean getClearCacheOnOpen() {
334
+ return clearCacheOnOpen;
335
+ }
336
+
337
+ public void setClearCacheOnOpen(boolean clearCacheOnOpen) {
338
+ this.clearCacheOnOpen = clearCacheOnOpen;
339
+ }
340
+
323
341
  public boolean getUseSharedDataStore() {
324
342
  return useSharedDataStore;
325
343
  }
@@ -857,6 +875,8 @@ public class Options {
857
875
  copy.setBlockedHosts(new ArrayList<>(getBlockedHosts()));
858
876
  copy.setWidth(width);
859
877
  copy.setPersistWebViewData(persistWebViewData);
878
+ copy.setClearCookiesOnOpen(clearCookiesOnOpen);
879
+ copy.setClearCacheOnOpen(clearCacheOnOpen);
860
880
  copy.setUseSharedDataStore(useSharedDataStore);
861
881
  copy.setHeight(height);
862
882
  copy.setToBack(toBack);
@@ -119,12 +119,32 @@ final class SafeAreaInsetsSupport {
119
119
  }
120
120
 
121
121
  /**
122
- * Whether the WebView container must be inset for the bottom system bar. On Android 15+ the dialog
123
- * is forced edge-to-edge (decorFitsSystemWindows=false), so the window always draws under the
124
- * navigation bar and insetting is mandatory to keep bottom content on-screen, regardless of the
125
- * enabledSafeBottomMargin opt-in that older versions honour.
122
+ * Whether the WebView container must be inset for the bottom system bar. Follows the
123
+ * enabledSafeBottomMargin opt-in on all API levels, including Android 15+ edge-to-edge windows,
124
+ * so disabling the flag matches Capacitor full-screen behaviour (#672). Pre-API 30 windows that
125
+ * lay out behind a transparent navigation bar still need the inset regardless of the opt-in.
126
126
  */
127
+ static boolean shouldInsetBottomForContainer(boolean enabledSafeBottomMargin, boolean isEdgeToEdge, boolean layoutBehindNavigationBar) {
128
+ return enabledSafeBottomMargin || layoutBehindNavigationBar;
129
+ }
130
+
127
131
  static boolean shouldInsetBottomForContainer(boolean enabledSafeBottomMargin, boolean isEdgeToEdge) {
128
- return enabledSafeBottomMargin || isEdgeToEdge;
132
+ return shouldInsetBottomForContainer(enabledSafeBottomMargin, isEdgeToEdge, false);
133
+ }
134
+
135
+ /**
136
+ * CSS custom-property inset for the top safe area. Only published when enabledSafeTopMargin is
137
+ * on; otherwise apps rely on env(safe-area-inset-*) like the main Capacitor WebView (#672).
138
+ */
139
+ static int cssTopInset(boolean enabledSafeTopMargin, int containerTopPadding) {
140
+ return enabledSafeTopMargin ? Math.max(0, containerTopPadding) : 0;
141
+ }
142
+
143
+ /**
144
+ * CSS custom-property inset for the bottom safe area. Only published when enabledSafeBottomMargin
145
+ * is on; container padding and env() insets are handled separately (#672).
146
+ */
147
+ static int cssBottomInset(boolean enabledSafeBottomMargin, int safeBottomInset) {
148
+ return enabledSafeBottomMargin ? Math.max(0, safeBottomInset) : 0;
129
149
  }
130
150
  }
@@ -0,0 +1,109 @@
1
+ package ee.forgr.capacitor_inappbrowser;
2
+
3
+ import android.graphics.Color;
4
+ import android.os.Build;
5
+ import android.view.View;
6
+ import android.view.Window;
7
+ import android.view.WindowManager;
8
+ import androidx.core.view.WindowCompat;
9
+ import androidx.core.view.WindowInsetsControllerCompat;
10
+
11
+ /**
12
+ * Centralizes window chrome decisions so WebViewDialog can avoid deprecated system UI APIs on
13
+ * Android 15+ while keeping API 24–34 behavior unchanged.
14
+ */
15
+ final class SystemUiChromeSupport {
16
+
17
+ static final int EDGE_TO_EDGE_SDK = Build.VERSION_CODES.VANILLA_ICE_CREAM;
18
+
19
+ private SystemUiChromeSupport() {}
20
+
21
+ static boolean requiresEdgeToEdgeChrome(int sdkInt) {
22
+ return sdkInt >= EDGE_TO_EDGE_SDK;
23
+ }
24
+
25
+ static boolean shouldApplyLegacySystemBarColors(int sdkInt) {
26
+ return sdkInt < EDGE_TO_EDGE_SDK;
27
+ }
28
+
29
+ static boolean shouldUsePreApi30LayoutFlags(int sdkInt) {
30
+ return sdkInt < Build.VERSION_CODES.R;
31
+ }
32
+
33
+ static boolean usesLayoutBehindNavigationBar(int sdkInt, boolean edgeToEdge) {
34
+ return !edgeToEdge && shouldUsePreApi30LayoutFlags(sdkInt);
35
+ }
36
+
37
+ static void setDecorFitsSystemWindows(Window window, boolean decorFitsSystemWindows) {
38
+ if (window == null) {
39
+ return;
40
+ }
41
+ WindowCompat.setDecorFitsSystemWindows(window, decorFitsSystemWindows);
42
+ }
43
+
44
+ static void prepareInitialDialogWindow(Window window) {
45
+ if (window == null) {
46
+ return;
47
+ }
48
+
49
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
50
+ if (shouldApplyLegacySystemBarColors(Build.VERSION.SDK_INT)) {
51
+ applyLegacySystemBarColors(window, Color.TRANSPARENT, null);
52
+ clearLegacyTranslucentStatusFlag(window);
53
+ }
54
+ }
55
+
56
+ static void applyDialogWindowChrome(
57
+ Window window,
58
+ View decorView,
59
+ boolean edgeToEdge,
60
+ Integer statusBarColor,
61
+ Integer navigationBarColor,
62
+ Boolean lightStatusBars
63
+ ) {
64
+ if (window == null || decorView == null) {
65
+ return;
66
+ }
67
+
68
+ if (edgeToEdge) {
69
+ setDecorFitsSystemWindows(window, false);
70
+ } else if (!shouldUsePreApi30LayoutFlags(Build.VERSION.SDK_INT)) {
71
+ setDecorFitsSystemWindows(window, true);
72
+ applyLegacySystemBarColors(window, statusBarColor, navigationBarColor);
73
+ } else {
74
+ applyPreApi30LayoutBehindNavigationBar(decorView);
75
+ applyLegacySystemBarColors(window, statusBarColor, navigationBarColor);
76
+ }
77
+
78
+ WindowInsetsControllerCompat controller = new WindowInsetsControllerCompat(window, decorView);
79
+ if (lightStatusBars != null) {
80
+ controller.setAppearanceLightStatusBars(lightStatusBars);
81
+ }
82
+ }
83
+
84
+ @SuppressWarnings("deprecation")
85
+ private static void applyPreApi30LayoutBehindNavigationBar(View decorView) {
86
+ decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
87
+ }
88
+
89
+ @SuppressWarnings("deprecation")
90
+ static void applyLegacySystemBarColors(Window window, Integer statusBarColor, Integer navigationBarColor) {
91
+ if (window == null || !shouldApplyLegacySystemBarColors(Build.VERSION.SDK_INT)) {
92
+ return;
93
+ }
94
+
95
+ if (statusBarColor != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
96
+ window.setStatusBarColor(statusBarColor);
97
+ }
98
+ if (navigationBarColor != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
99
+ window.setNavigationBarColor(navigationBarColor);
100
+ }
101
+ }
102
+
103
+ @SuppressWarnings("deprecation")
104
+ private static void clearLegacyTranslucentStatusFlag(Window window) {
105
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
106
+ window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,49 @@
1
+ package ee.forgr.capacitor_inappbrowser;
2
+
3
+ import android.view.View;
4
+
5
+ /**
6
+ * Testable helpers for HTML5/iframe fullscreen routed through WebChromeClient custom views
7
+ * (e.g. embedded YouTube fullscreen).
8
+ */
9
+ final class WebViewCustomFullscreenSupport {
10
+
11
+ private WebViewCustomFullscreenSupport() {}
12
+
13
+ static boolean isCustomFullscreenActive(Object customFullscreenView) {
14
+ return customFullscreenView != null;
15
+ }
16
+
17
+ static boolean shouldRejectDuplicateShow(boolean isActive) {
18
+ return isActive;
19
+ }
20
+
21
+ static boolean shouldConsumeBackPress(boolean isActive) {
22
+ return isActive;
23
+ }
24
+
25
+ @SuppressWarnings("deprecation")
26
+ static int immersiveFullscreenSystemUiVisibility() {
27
+ return (
28
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
29
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
30
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
31
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
32
+ View.SYSTEM_UI_FLAG_FULLSCREEN |
33
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
34
+ );
35
+ }
36
+
37
+ static boolean shouldUseHostActivityWindow(boolean backLayerActive) {
38
+ return backLayerActive;
39
+ }
40
+
41
+ static boolean shouldRegisterHostBackHandler(boolean backLayerActive) {
42
+ return backLayerActive;
43
+ }
44
+
45
+ @SuppressWarnings("deprecation")
46
+ static int restoredSystemUiVisibility() {
47
+ return View.SYSTEM_UI_FLAG_VISIBLE;
48
+ }
49
+ }