@capacitor/android 9.0.0-alpha.6 → 9.0.0-alpha.8

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.
@@ -4,11 +4,9 @@ import android.content.Context;
4
4
  import android.content.pm.PackageInfo;
5
5
  import android.content.res.Configuration;
6
6
  import android.content.res.Resources;
7
- import android.os.Build;
8
7
  import android.util.TypedValue;
9
8
  import android.view.View;
10
9
  import android.view.Window;
11
- import android.webkit.JavascriptInterface;
12
10
  import android.webkit.WebView;
13
11
  import androidx.core.graphics.Insets;
14
12
  import androidx.core.view.ViewCompat;
@@ -33,9 +31,9 @@ public class SystemBars extends Plugin {
33
31
  static final String BAR_STATUS_BAR = "StatusBar";
34
32
  static final String BAR_GESTURE_BAR = "NavigationBar";
35
33
 
36
- // TODO: In Cap 9, add an additional option "full"
37
34
  static final String INSETS_HANDLING_CSS = "css";
38
35
  static final String INSETS_HANDLING_DISABLE = "disable";
36
+ static final String INSETS_HANDLING_NATIVE = "native";
39
37
 
40
38
  // https://issues.chromium.org/issues/40699457
41
39
  private static final int WEBVIEW_VERSION_WITH_SAFE_AREA_FIX = 140;
@@ -43,27 +41,40 @@ public class SystemBars extends Plugin {
43
41
  private static final int WEBVIEW_VERSION_WITH_SAFE_AREA_KEYBOARD_FIX = 144;
44
42
 
45
43
  static final String viewportMetaJSFunction = """
46
- function capacitorSystemBarsCheckMetaViewport() {
47
- const meta = document.querySelectorAll("meta[name=viewport]");
48
- if (meta.length == 0) {
49
- return false;
50
- }
51
- // get the last found meta viewport tag
52
- const metaContent = meta[meta.length - 1].content;
53
- return metaContent.includes("viewport-fit=cover");
44
+ function capacitorSystemBarsCheckMetaViewport() {
45
+ const meta = document.querySelectorAll("meta[name=viewport]");
46
+ if (meta.length == 0) {
47
+ return false;
54
48
  }
55
- capacitorSystemBarsCheckMetaViewport();
56
- """;
49
+ // get the last found meta viewport tag
50
+ const metaContent = meta[meta.length - 1].content;
51
+ return metaContent.includes("viewport-fit=cover");
52
+ }
53
+ capacitorSystemBarsCheckMetaViewport();
54
+ """;
57
55
 
58
- private String insetsHandling = INSETS_HANDLING_CSS;
56
+ private String insetsHandling = INSETS_HANDLING_NATIVE;
59
57
  private boolean hasViewportCover = false;
60
58
 
61
59
  private String currentStatusBarStyle = STYLE_DEFAULT;
62
60
  private String currentGestureBarStyle = STYLE_DEFAULT;
63
61
 
62
+ // Declare variable at this scope to help prevent adding multiple listeners.
63
+ private WebViewListener webViewListener;
64
+
65
+ private void warnAboutUnsupportedConfigurationValues() {
66
+ boolean keyboardResizeOnFullScreen = bridge.getConfig().getPluginConfiguration("Keyboard").getBoolean("resizeOnFullScreen", false);
67
+
68
+ if (!INSETS_HANDLING_DISABLE.equals(insetsHandling) && keyboardResizeOnFullScreen) {
69
+ Logger.warn(
70
+ "SystemBars",
71
+ "You should omit `Keyboard.resizeOnFullScreen` in your `capacitor.config.json`. Other values can lead to unexpected behavior."
72
+ );
73
+ }
74
+ }
75
+
64
76
  @Override
65
77
  public void load() {
66
- getBridge().getWebView().addJavascriptInterface(this, "CapacitorSystemBarsAndroidInterface");
67
78
  super.load();
68
79
 
69
80
  initSystemBars();
@@ -73,15 +84,25 @@ public class SystemBars extends Plugin {
73
84
  protected void handleOnStart() {
74
85
  super.handleOnStart();
75
86
 
76
- this.getBridge().addWebViewListener(
77
- new WebViewListener() {
87
+ if (INSETS_HANDLING_DISABLE.equals(insetsHandling)) {
88
+ return;
89
+ }
90
+
91
+ if (webViewListener == null) {
92
+ webViewListener = new WebViewListener() {
78
93
  @Override
79
94
  public void onPageCommitVisible(WebView view, String url) {
80
95
  super.onPageCommitVisible(view, url);
81
- getBridge().getWebView().requestApplyInsets();
96
+ bridge.getWebView().evaluateJavascript(viewportMetaJSFunction, (res) -> {
97
+ hasViewportCover = res.equals("true");
98
+
99
+ // Request new execution tree of `setOnApplyWindowInsetsListener`
100
+ bridge.getWebView().requestApplyInsets();
101
+ });
82
102
  }
83
- }
84
- );
103
+ };
104
+ this.getBridge().addWebViewListener(webViewListener);
105
+ }
85
106
  }
86
107
 
87
108
  @Override
@@ -93,22 +114,32 @@ public class SystemBars extends Plugin {
93
114
  }
94
115
 
95
116
  private void initSystemBars() {
117
+ // If you already know what the value of the `viewport-fit=` meta tag is going to be,
118
+ // passing it here through `initialViewportFitValueHint` can help prevent layout shifting.
119
+ String configuredInitialViewportFitValueHint = getConfig().getString("initialViewportFitValueHint", "");
120
+ hasViewportCover = "cover".equals(configuredInitialViewportFitValueHint);
121
+
96
122
  String style = getConfig().getString("style", STYLE_DEFAULT).toUpperCase(Locale.US);
97
123
  boolean hidden = getConfig().getBoolean("hidden", false);
98
124
 
99
- String configuredInsetsHandling = getConfig().getString("insetsHandling", INSETS_HANDLING_CSS);
100
- if (INSETS_HANDLING_CSS.equals(configuredInsetsHandling) || INSETS_HANDLING_DISABLE.equals(configuredInsetsHandling)) {
125
+ String configuredInsetsHandling = getConfig().getString("insetsHandling", INSETS_HANDLING_NATIVE);
126
+ if (
127
+ INSETS_HANDLING_CSS.equals(configuredInsetsHandling) ||
128
+ INSETS_HANDLING_DISABLE.equals(configuredInsetsHandling) ||
129
+ INSETS_HANDLING_NATIVE.equals(configuredInsetsHandling)
130
+ ) {
101
131
  insetsHandling = configuredInsetsHandling;
102
132
  } else {
103
133
  Logger.warn(
104
134
  "SystemBars",
105
- "Unknown insetsHandling value '" + configuredInsetsHandling + "'. Falling back to '" + INSETS_HANDLING_CSS + "'."
135
+ "Unknown insetsHandling value '" + configuredInsetsHandling + "'. Falling back to '" + INSETS_HANDLING_NATIVE + "'."
106
136
  );
107
- insetsHandling = INSETS_HANDLING_CSS;
137
+ insetsHandling = INSETS_HANDLING_NATIVE;
108
138
  }
109
139
 
140
+ warnAboutUnsupportedConfigurationValues();
141
+
110
142
  initWindowInsetsListener();
111
- initSafeAreaCSSVariables();
112
143
 
113
144
  getBridge().executeOnMainThread(() -> {
114
145
  setStyle(style, "");
@@ -152,51 +183,14 @@ public class SystemBars extends Plugin {
152
183
  call.resolve();
153
184
  }
154
185
 
155
- @JavascriptInterface
156
- public void onDOMReady() {
157
- if (INSETS_HANDLING_CSS.equals(insetsHandling)) {
158
- getActivity().runOnUiThread(() -> {
159
- this.bridge.getWebView().evaluateJavascript(viewportMetaJSFunction, (res) -> {
160
- hasViewportCover = res.equals("true");
161
-
162
- getBridge().getWebView().requestApplyInsets();
163
- });
164
- });
165
- }
166
- }
167
-
168
- private Insets calcSafeAreaInsets(WindowInsetsCompat insets) {
169
- Insets safeArea = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
170
- if (insets.isVisible(WindowInsetsCompat.Type.ime())) {
171
- return Insets.of(safeArea.left, safeArea.top, safeArea.right, 0);
172
- }
173
- return Insets.of(safeArea.left, safeArea.top, safeArea.right, safeArea.bottom);
174
- }
175
-
176
- private void initSafeAreaCSSVariables() {
177
- if (INSETS_HANDLING_CSS.equals(insetsHandling)) {
178
- WindowInsetsCompat insets;
179
-
180
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
181
- View v = (View) this.getBridge().getWebView().getParent();
182
- insets = ViewCompat.getRootWindowInsets(v);
183
- } else {
184
- insets = WindowInsetsCompat.CONSUMED;
185
- }
186
-
187
- if (insets != null) {
188
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
189
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
190
- }
191
- }
192
- }
193
-
194
186
  private void initWindowInsetsListener() {
195
187
  if (INSETS_HANDLING_DISABLE.equals(insetsHandling)) {
196
188
  return;
197
189
  }
198
190
 
199
- ViewCompat.setOnApplyWindowInsetsListener((View) getBridge().getWebView().getParent(), (v, insets) -> {
191
+ View view = getActivity().getWindow().getDecorView();
192
+
193
+ ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> {
200
194
  boolean shouldPassthroughInsets = getWebViewMajorVersion() >= WEBVIEW_VERSION_WITH_SAFE_AREA_FIX && hasViewportCover;
201
195
 
202
196
  Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
@@ -207,10 +201,7 @@ public class SystemBars extends Plugin {
207
201
  // We need to correct for a possible shown IME
208
202
  v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
209
203
 
210
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
211
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
212
-
213
- return new WindowInsetsCompat.Builder(insets)
204
+ WindowInsetsCompat newInsets = new WindowInsetsCompat.Builder(insets)
214
205
  .setInsets(
215
206
  WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(),
216
207
  Insets.of(
@@ -221,18 +212,20 @@ public class SystemBars extends Plugin {
221
212
  )
222
213
  )
223
214
  .build();
224
- }
225
215
 
226
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
227
- // We need to correct for a possible shown IME
228
- v.setPadding(
229
- systemBarsInsets.left,
230
- systemBarsInsets.top,
231
- systemBarsInsets.right,
232
- keyboardVisible ? imeInsets.bottom : systemBarsInsets.bottom
233
- );
216
+ injectSafeAreaCSS(newInsets);
217
+
218
+ return newInsets;
234
219
  }
235
220
 
221
+ // We need to correct for a possible shown IME
222
+ v.setPadding(
223
+ systemBarsInsets.left,
224
+ systemBarsInsets.top,
225
+ systemBarsInsets.right,
226
+ keyboardVisible ? imeInsets.bottom : systemBarsInsets.bottom
227
+ );
228
+
236
229
  // Returning `WindowInsetsCompat.CONSUMED` breaks recalculation of safe area insets
237
230
  // So we have to explicitly set insets to `0`
238
231
  // See: https://issues.chromium.org/issues/461332423
@@ -240,20 +233,28 @@ public class SystemBars extends Plugin {
240
233
  .setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), Insets.of(0, 0, 0, 0))
241
234
  .build();
242
235
 
243
- Insets safeAreaInsets = calcSafeAreaInsets(newInsets);
244
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
236
+ injectSafeAreaCSS(newInsets);
245
237
 
246
238
  return newInsets;
247
239
  });
248
240
  }
249
241
 
250
- private void injectSafeAreaCSS(int top, int right, int bottom, int left) {
242
+ private void injectSafeAreaCSS(WindowInsetsCompat insets) {
243
+ if (!INSETS_HANDLING_CSS.equals(insetsHandling)) {
244
+ return;
245
+ }
246
+
247
+ Insets systemBarsInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
248
+ boolean keyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
249
+
251
250
  // Convert pixels to density-independent pixels
252
251
  float density = getActivity().getResources().getDisplayMetrics().density;
253
- float topPx = top / density;
254
- float rightPx = right / density;
255
- float bottomPx = bottom / density;
256
- float leftPx = left / density;
252
+ float topPx = systemBarsInsets.top / density;
253
+ float rightPx = systemBarsInsets.right / density;
254
+ // For native insets the value gets automatically corrected when the IME is visible (in newer WebView versions),
255
+ // but for these injected values we have to handle that manually (for all WebView versions).
256
+ float bottomPx = (keyboardVisible ? 0 : systemBarsInsets.bottom) / density;
257
+ float leftPx = systemBarsInsets.left / density;
257
258
 
258
259
  // Execute JavaScript to inject the CSS
259
260
  getBridge().executeOnMainThread(() -> {
@@ -1,6 +1,6 @@
1
1
  ext {
2
2
  androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
3
- cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '14.0.1'
3
+ cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '15.0.0'
4
4
  }
5
5
 
6
6
  buildscript {
@@ -3,6 +3,7 @@ package com.getcapacitor.cordova;
3
3
  import android.content.Intent;
4
4
  import android.os.Bundle;
5
5
  import android.webkit.WebView;
6
+ import com.getcapacitor.CordovaBridgeConfig;
6
7
  import com.getcapacitor.Logger;
7
8
  import com.getcapacitor.Plugin;
8
9
  import com.getcapacitor.annotation.CapacitorPlugin;
@@ -16,7 +17,7 @@ import org.apache.cordova.PluginManager;
16
17
  import org.json.JSONException;
17
18
 
18
19
  @CapacitorPlugin(name = "__CordovaPlugin")
19
- public class CordovaPlugin extends Plugin {
20
+ public class CordovaPlugin extends Plugin implements CordovaBridgeConfig {
20
21
 
21
22
  private MockCordovaInterfaceImpl cordovaInterface;
22
23
  private CordovaWebView webView;
@@ -83,16 +84,13 @@ public class CordovaPlugin extends Plugin {
83
84
  }
84
85
 
85
86
  @Override
86
- public boolean hasPermission(String permission) {
87
- if (permission.equals("DisableDeploy")) {
88
- return preferences.getBoolean(permission, false);
89
- }
90
-
91
- if (permission.equals("KeepRunning")) {
92
- return preferences.getBoolean(permission, true);
93
- }
87
+ public boolean shouldKeepRunning() {
88
+ return preferences.getBoolean("KeepRunning", true);
89
+ }
94
90
 
95
- return false;
91
+ @Override
92
+ public boolean isDeployDisabled() {
93
+ return preferences.getBoolean("DisableDeploy", false);
96
94
  }
97
95
 
98
96
  @Override
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor/android",
3
- "version": "9.0.0-alpha.6",
3
+ "version": "9.0.0-alpha.8",
4
4
  "description": "Capacitor: Cross-platform apps with JavaScript and the web",
5
5
  "homepage": "https://capacitorjs.com",
6
6
  "author": "Ionic Team <hi@ionic.io> (https://ionic.io)",
@@ -26,7 +26,7 @@
26
26
  "verify": "./gradlew :capacitor-android:clean :capacitor-android:lint :capacitor-android:build :capacitor-android:test"
27
27
  },
28
28
  "peerDependencies": {
29
- "@capacitor/core": "^9.0.0-alpha.6"
29
+ "@capacitor/core": "^9.0.0-alpha.8"
30
30
  },
31
31
  "publishConfig": {
32
32
  "access": "public"
@@ -1,37 +0,0 @@
1
- package com.getcapacitor;
2
-
3
- import com.getcapacitor.annotation.CapacitorPlugin;
4
- import java.lang.annotation.Retention;
5
- import java.lang.annotation.RetentionPolicy;
6
-
7
- /**
8
- * Base annotation for all Plugins
9
- * @deprecated
10
- * <p> Use {@link CapacitorPlugin} instead
11
- */
12
- @Retention(RetentionPolicy.RUNTIME)
13
- @Deprecated
14
- public @interface NativePlugin {
15
- /**
16
- * Request codes this plugin uses and responds to, in order to tie
17
- * Android events back the plugin to handle
18
- */
19
- int[] requestCodes() default {};
20
-
21
- /**
22
- * Permissions this plugin needs, in order to make permission requests
23
- * easy if the plugin only needs basic permission prompting
24
- */
25
- String[] permissions() default {};
26
-
27
- /**
28
- * The request code to use when automatically requesting permissions
29
- */
30
- int permissionRequestCode() default 9000;
31
-
32
- /**
33
- * A custom name for the plugin, otherwise uses the
34
- * simple class name.
35
- */
36
- String name() default "";
37
- }