@capgo/capacitor-inappbrowser 8.15.3 → 8.16.0
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 +3 -1
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/CapgoInAppBrowserPlugin.java +15 -65
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/InAppBrowserPlugin.java +1 -2
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/OpenTimeBrowsingDataClearSupport.java +40 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/Options.java +20 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/SafeAreaInsetsSupport.java +7 -2
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/SystemUiChromeSupport.java +109 -0
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +203 -199
- package/dist/docs.json +33 -1
- package/dist/esm/definitions.d.ts +26 -3
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift +36 -1
- package/ios/Sources/InAppBrowserPlugin/WKWebViewController.swift +13 -1
- package/package.json +1 -1
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
|
|
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> | | | |
|
|
@@ -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 =
|
|
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 {}
|
package/android/src/main/java/ee/forgr/capacitor_inappbrowser/OpenTimeBrowsingDataClearSupport.java
ADDED
|
@@ -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);
|
|
@@ -122,9 +122,14 @@ final class SafeAreaInsetsSupport {
|
|
|
122
122
|
* Whether the WebView container must be inset for the bottom system bar. On Android 15+ the dialog
|
|
123
123
|
* is forced edge-to-edge (decorFitsSystemWindows=false), so the window always draws under the
|
|
124
124
|
* navigation bar and insetting is mandatory to keep bottom content on-screen, regardless of the
|
|
125
|
-
* enabledSafeBottomMargin opt-in that older versions honour.
|
|
125
|
+
* enabledSafeBottomMargin opt-in that older versions honour. Pre-API 30 windows that lay out behind
|
|
126
|
+
* a transparent navigation bar need the same treatment.
|
|
126
127
|
*/
|
|
128
|
+
static boolean shouldInsetBottomForContainer(boolean enabledSafeBottomMargin, boolean isEdgeToEdge, boolean layoutBehindNavigationBar) {
|
|
129
|
+
return enabledSafeBottomMargin || isEdgeToEdge || layoutBehindNavigationBar;
|
|
130
|
+
}
|
|
131
|
+
|
|
127
132
|
static boolean shouldInsetBottomForContainer(boolean enabledSafeBottomMargin, boolean isEdgeToEdge) {
|
|
128
|
-
return enabledSafeBottomMargin
|
|
133
|
+
return shouldInsetBottomForContainer(enabledSafeBottomMargin, isEdgeToEdge, false);
|
|
129
134
|
}
|
|
130
135
|
}
|
|
@@ -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
|
+
}
|