Skip to content

Commit 1ea86d1

Browse files
feat(android): add adjustMarginsForEdgeToEdge configuration option (#7885)
Co-authored-by: jcesarmobile <[email protected]>
1 parent ee55f6c commit 1ea86d1

File tree

4 files changed

+51
-15
lines changed

4 files changed

+51
-15
lines changed

android/capacitor/src/main/java/com/getcapacitor/Bridge.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,9 +1605,9 @@ public Bridge create() {
16051605
config
16061606
);
16071607

1608-
if (webView instanceof CapacitorWebView) {
1609-
CapacitorWebView capacitorWebView = (CapacitorWebView) webView;
1608+
if (webView instanceof CapacitorWebView capacitorWebView) {
16101609
capacitorWebView.setBridge(bridge);
1610+
capacitorWebView.edgeToEdgeHandler(bridge);
16111611
}
16121612

16131613
bridge.setCordovaWebView(mockWebView);

android/capacitor/src/main/java/com/getcapacitor/CapConfig.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public class CapConfig {
5454
private String errorPath;
5555
private boolean zoomableWebView = false;
5656
private boolean resolveServiceWorkerRequests = true;
57+
private String adjustMarginsForEdgeToEdge = "disable";
5758

5859
// Embedded
5960
private String startPath;
@@ -181,6 +182,7 @@ private CapConfig(Builder builder) {
181182
this.errorPath = builder.errorPath;
182183
this.zoomableWebView = builder.zoomableWebView;
183184
this.resolveServiceWorkerRequests = builder.resolveServiceWorkerRequests;
185+
this.adjustMarginsForEdgeToEdge = builder.adjustMarginsForEdgeToEdge;
184186

185187
// Embedded
186188
this.startPath = builder.startPath;
@@ -285,6 +287,7 @@ private void deserializeConfig(@Nullable Context context) {
285287
webContentsDebuggingEnabled = JSONUtils.getBoolean(configJSON, "android.webContentsDebuggingEnabled", isDebug);
286288
zoomableWebView = JSONUtils.getBoolean(configJSON, "android.zoomEnabled", JSONUtils.getBoolean(configJSON, "zoomEnabled", false));
287289
resolveServiceWorkerRequests = JSONUtils.getBoolean(configJSON, "android.resolveServiceWorkerRequests", true);
290+
adjustMarginsForEdgeToEdge = JSONUtils.getString(configJSON, "android.adjustMarginsForEdgeToEdge", "disable");
288291

289292
String logBehavior = JSONUtils.getString(
290293
configJSON,
@@ -401,6 +404,10 @@ public boolean isUsingLegacyBridge() {
401404
return useLegacyBridge;
402405
}
403406

407+
public String adjustMarginsForEdgeToEdge() {
408+
return adjustMarginsForEdgeToEdge;
409+
}
410+
404411
public int getMinWebViewVersion() {
405412
if (minWebViewVersion < MINIMUM_ANDROID_WEBVIEW_VERSION) {
406413
Logger.warn("Specified minimum webview version is too low, defaulting to " + MINIMUM_ANDROID_WEBVIEW_VERSION);
@@ -581,6 +588,7 @@ public static class Builder {
581588
private int minHuaweiWebViewVersion = DEFAULT_HUAWEI_WEBVIEW_VERSION;
582589
private boolean zoomableWebView = false;
583590
private boolean resolveServiceWorkerRequests = true;
591+
private String adjustMarginsForEdgeToEdge = "disable";
584592

585593
// Embedded
586594
private String startPath = null;

android/capacitor/src/main/java/com/getcapacitor/CapacitorWebView.java

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.getcapacitor;
22

33
import android.content.Context;
4+
import android.os.Build;
45
import android.util.AttributeSet;
6+
import android.util.TypedValue;
57
import android.view.KeyEvent;
68
import android.view.inputmethod.BaseInputConnection;
79
import android.view.inputmethod.EditorInfo;
@@ -18,7 +20,6 @@ public class CapacitorWebView extends WebView {
1820

1921
public CapacitorWebView(Context context, AttributeSet attrs) {
2022
super(context, attrs);
21-
edgeToEdgeHandler();
2223
}
2324

2425
public void setBridge(Bridge bridge) {
@@ -54,19 +55,35 @@ public boolean dispatchKeyEvent(KeyEvent event) {
5455
return super.dispatchKeyEvent(event);
5556
}
5657

57-
private void edgeToEdgeHandler() {
58-
ViewCompat.setOnApplyWindowInsetsListener(this, (v, windowInsets) -> {
59-
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
58+
public void edgeToEdgeHandler(Bridge bridge) {
59+
String configEdgeToEdge = bridge.getConfig().adjustMarginsForEdgeToEdge();
6060

61-
MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
62-
mlp.leftMargin = insets.left;
63-
mlp.bottomMargin = insets.bottom;
64-
mlp.rightMargin = insets.right;
65-
mlp.topMargin = insets.top;
66-
v.setLayoutParams(mlp);
61+
if (configEdgeToEdge.equals("disable")) return;
6762

68-
// Don't pass window insets to children
69-
return WindowInsetsCompat.CONSUMED;
70-
});
63+
boolean autoMargins = false;
64+
boolean forceMargins = configEdgeToEdge.equals("force");
65+
66+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && configEdgeToEdge.equals("auto")) {
67+
TypedValue value = new TypedValue();
68+
boolean foundOptOut = getContext().getTheme().resolveAttribute(android.R.attr.windowOptOutEdgeToEdgeEnforcement, value, true);
69+
boolean optOutValue = value.data != 0; // value is set to -1 on true as of Android 15, so we have to do this.
70+
71+
autoMargins = !(foundOptOut && optOutValue);
72+
}
73+
74+
if (forceMargins || autoMargins) {
75+
ViewCompat.setOnApplyWindowInsetsListener(this, (v, windowInsets) -> {
76+
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
77+
MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
78+
mlp.leftMargin = insets.left;
79+
mlp.bottomMargin = insets.bottom;
80+
mlp.rightMargin = insets.right;
81+
mlp.topMargin = insets.top;
82+
v.setLayoutParams(mlp);
83+
84+
// Don't pass window insets to children
85+
return WindowInsetsCompat.CONSUMED;
86+
});
87+
}
7188
}
7289
}

cli/src/declarations.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,17 @@ export interface CapacitorConfig {
297297
* @default true
298298
*/
299299
resolveServiceWorkerRequests?: boolean;
300+
301+
/**
302+
* If set to "force", margins will be adjusted for edge to edge regardless of any other settings.
303+
* If set to "auto", or is missing, will check for Android 15 and the setting of [windowOptOutEdgeToEdgeEnforcement](https://developer.android.com/reference/android/R.attr#windowOptOutEdgeToEdgeEnforcement) and will adjust margins if on Android 15 and windowOptOutEdgeToEdgeEnforcement is false/missing.
304+
* If set to "disable", will not adjust margins at all.
305+
* In Capacitor 8, this default will be changed to 'auto'
306+
*
307+
* @since 7.1.0
308+
* @default disable
309+
*/
310+
adjustMarginsForEdgeToEdge?: 'auto' | 'force' | 'disable';
300311
};
301312

302313
ios?: {

0 commit comments

Comments
 (0)