@capacitor-plus/android 8.3.4 → 8.3.5

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.
@@ -48,14 +48,14 @@ var nativeBridge = (function (exports) {
48
48
  const newFormData = [];
49
49
  for (const pair of formData.entries()) {
50
50
  const [key, value] = pair;
51
- if (value instanceof File) {
51
+ if (value instanceof Blob) {
52
52
  const base64File = await readFileAsBase64(value);
53
53
  newFormData.push({
54
54
  key,
55
55
  value: base64File,
56
56
  type: 'base64File',
57
57
  contentType: value.type,
58
- fileName: value.name,
58
+ fileName: value.name || 'blob',
59
59
  });
60
60
  }
61
61
  else {
@@ -128,7 +128,7 @@ var nativeBridge = (function (exports) {
128
128
  type: 'formData',
129
129
  };
130
130
  }
131
- else if (body instanceof File) {
131
+ else if (body instanceof Blob) {
132
132
  const fileData = await readFileAsBase64(body);
133
133
  return {
134
134
  data: fileData,
@@ -1214,42 +1214,44 @@ public class Bridge {
1214
1214
  protected Map<String, PermissionState> getPermissionStates(Plugin plugin) {
1215
1215
  Map<String, PermissionState> permissionsResults = new HashMap<>();
1216
1216
  CapacitorPlugin annotation = plugin.getPluginHandle().getPluginAnnotation();
1217
- for (Permission perm : annotation.permissions()) {
1218
- // If a permission is defined with no permission constants, return GRANTED for it.
1219
- // Otherwise, get its true state.
1220
- if (perm.strings().length == 0 || (perm.strings().length == 1 && perm.strings()[0].isEmpty())) {
1221
- String key = perm.alias();
1222
- if (!key.isEmpty()) {
1223
- PermissionState existingResult = permissionsResults.get(key);
1224
-
1225
- // auto set permission state to GRANTED if the alias is empty.
1226
- if (existingResult == null) {
1227
- permissionsResults.put(key, PermissionState.GRANTED);
1228
- }
1229
- }
1230
- } else {
1231
- for (String permString : perm.strings()) {
1232
- String key = perm.alias().isEmpty() ? permString : perm.alias();
1233
- PermissionState permissionStatus;
1234
- if (ActivityCompat.checkSelfPermission(this.getContext(), permString) == PackageManager.PERMISSION_GRANTED) {
1235
- permissionStatus = PermissionState.GRANTED;
1236
- } else {
1237
- permissionStatus = PermissionState.PROMPT;
1238
-
1239
- // Check if there is a cached permission state for the "Never ask again" state
1240
- SharedPreferences prefs = getContext().getSharedPreferences(PERMISSION_PREFS_NAME, Activity.MODE_PRIVATE);
1241
- String state = prefs.getString(permString, null);
1242
-
1243
- if (state != null) {
1244
- permissionStatus = PermissionState.byState(state);
1217
+ if (annotation != null) {
1218
+ for (Permission perm : annotation.permissions()) {
1219
+ // If a permission is defined with no permission constants, return GRANTED for it.
1220
+ // Otherwise, get its true state.
1221
+ if (perm.strings().length == 0 || (perm.strings().length == 1 && perm.strings()[0].isEmpty())) {
1222
+ String key = perm.alias();
1223
+ if (!key.isEmpty()) {
1224
+ PermissionState existingResult = permissionsResults.get(key);
1225
+
1226
+ // auto set permission state to GRANTED if the alias is empty.
1227
+ if (existingResult == null) {
1228
+ permissionsResults.put(key, PermissionState.GRANTED);
1245
1229
  }
1246
1230
  }
1231
+ } else {
1232
+ for (String permString : perm.strings()) {
1233
+ String key = perm.alias().isEmpty() ? permString : perm.alias();
1234
+ PermissionState permissionStatus;
1235
+ if (ActivityCompat.checkSelfPermission(this.getContext(), permString) == PackageManager.PERMISSION_GRANTED) {
1236
+ permissionStatus = PermissionState.GRANTED;
1237
+ } else {
1238
+ permissionStatus = PermissionState.PROMPT;
1239
+
1240
+ // Check if there is a cached permission state for the "Never ask again" state
1241
+ SharedPreferences prefs = getContext().getSharedPreferences(PERMISSION_PREFS_NAME, Activity.MODE_PRIVATE);
1242
+ String state = prefs.getString(permString, null);
1243
+
1244
+ if (state != null) {
1245
+ permissionStatus = PermissionState.byState(state);
1246
+ }
1247
+ }
1247
1248
 
1248
- PermissionState existingResult = permissionsResults.get(key);
1249
+ PermissionState existingResult = permissionsResults.get(key);
1249
1250
 
1250
- // multiple permissions with the same alias must all be true, otherwise all false.
1251
- if (existingResult == null || existingResult == PermissionState.GRANTED) {
1252
- permissionsResults.put(key, permissionStatus);
1251
+ // multiple permissions with the same alias must all be true, otherwise all false.
1252
+ if (existingResult == null || existingResult == PermissionState.GRANTED) {
1253
+ permissionsResults.put(key, permissionStatus);
1254
+ }
1253
1255
  }
1254
1256
  }
1255
1257
  }
@@ -46,6 +46,17 @@ public class BridgeWebChromeClient extends WebChromeClient {
46
46
  void onActivityResult(ActivityResult result);
47
47
  }
48
48
 
49
+ // Static variables to store pending file chooser state to survive activity recreation
50
+ private static ValueCallback<Uri[]> pendingFilePathCallback;
51
+ private static Uri pendingImageFileUri;
52
+ private static FileChooserType pendingFileChooserType;
53
+
54
+ private enum FileChooserType {
55
+ IMAGE_CAPTURE,
56
+ VIDEO_CAPTURE,
57
+ FILE_PICKER
58
+ }
59
+
49
60
  private ActivityResultLauncher permissionLauncher;
50
61
  private ActivityResultLauncher activityLauncher;
51
62
  private PermissionListener permissionListener;
@@ -70,10 +81,70 @@ public class BridgeWebChromeClient extends WebChromeClient {
70
81
  activityLauncher = bridge.registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), (result) -> {
71
82
  if (activityListener != null) {
72
83
  activityListener.onActivityResult(result);
84
+ } else if (pendingFilePathCallback != null) {
85
+ // Handle case where activity was recreated and instance callback is null
86
+ // Use the static callback instead
87
+ handlePendingFileChooserResult(result);
73
88
  }
74
89
  });
75
90
  }
76
91
 
92
+ /**
93
+ * Handle file chooser result when the activity was recreated and instance callbacks were lost.
94
+ * This uses the static pending callback to deliver the result.
95
+ */
96
+ private void handlePendingFileChooserResult(ActivityResult result) {
97
+ if (pendingFilePathCallback == null) {
98
+ return;
99
+ }
100
+
101
+ try {
102
+ Uri[] uriResult = null;
103
+ if (result.getResultCode() == Activity.RESULT_OK) {
104
+ switch (pendingFileChooserType) {
105
+ case IMAGE_CAPTURE:
106
+ if (pendingImageFileUri != null) {
107
+ uriResult = new Uri[] { pendingImageFileUri };
108
+ }
109
+ break;
110
+ case VIDEO_CAPTURE:
111
+ Intent videoData = result.getData();
112
+ if (videoData != null && videoData.getData() != null) {
113
+ uriResult = new Uri[] { videoData.getData() };
114
+ }
115
+ break;
116
+ case FILE_PICKER:
117
+ Intent fileData = result.getData();
118
+ if (fileData != null) {
119
+ if (fileData.getClipData() != null) {
120
+ final int numFiles = fileData.getClipData().getItemCount();
121
+ uriResult = new Uri[numFiles];
122
+ for (int i = 0; i < numFiles; i++) {
123
+ uriResult[i] = fileData.getClipData().getItemAt(i).getUri();
124
+ }
125
+ } else {
126
+ uriResult = WebChromeClient.FileChooserParams.parseResult(result.getResultCode(), fileData);
127
+ }
128
+ }
129
+ break;
130
+ }
131
+ }
132
+ pendingFilePathCallback.onReceiveValue(uriResult);
133
+ } finally {
134
+ // Clear the static state after handling
135
+ clearPendingFileChooserState();
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Clear the static pending file chooser state.
141
+ */
142
+ private static void clearPendingFileChooserState() {
143
+ pendingFilePathCallback = null;
144
+ pendingImageFileUri = null;
145
+ pendingFileChooserType = null;
146
+ }
147
+
77
148
  /**
78
149
  * Render web content in `view`.
79
150
  *
@@ -340,12 +411,19 @@ public class BridgeWebChromeClient extends WebChromeClient {
340
411
  return false;
341
412
  }
342
413
  takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);
414
+
415
+ // Store in static variables to survive activity recreation
416
+ pendingFilePathCallback = filePathCallback;
417
+ pendingImageFileUri = imageFileUri;
418
+ pendingFileChooserType = FileChooserType.IMAGE_CAPTURE;
419
+
343
420
  activityListener = (activityResult) -> {
344
421
  Uri[] result = null;
345
422
  if (activityResult.getResultCode() == Activity.RESULT_OK) {
346
423
  result = new Uri[] { imageFileUri };
347
424
  }
348
425
  filePathCallback.onReceiveValue(result);
426
+ clearPendingFileChooserState();
349
427
  };
350
428
  activityLauncher.launch(takePictureIntent);
351
429
 
@@ -359,12 +437,18 @@ public class BridgeWebChromeClient extends WebChromeClient {
359
437
  return false;
360
438
  }
361
439
 
440
+ // Store in static variables to survive activity recreation
441
+ pendingFilePathCallback = filePathCallback;
442
+ pendingImageFileUri = null;
443
+ pendingFileChooserType = FileChooserType.VIDEO_CAPTURE;
444
+
362
445
  activityListener = (activityResult) -> {
363
446
  Uri[] result = null;
364
447
  if (activityResult.getResultCode() == Activity.RESULT_OK) {
365
448
  result = new Uri[] { activityResult.getData().getData() };
366
449
  }
367
450
  filePathCallback.onReceiveValue(result);
451
+ clearPendingFileChooserState();
368
452
  };
369
453
  activityLauncher.launch(takeVideoIntent);
370
454
 
@@ -383,6 +467,12 @@ public class BridgeWebChromeClient extends WebChromeClient {
383
467
  intent.setType(validTypes[0]);
384
468
  }
385
469
  }
470
+
471
+ // Store in static variables to survive activity recreation
472
+ pendingFilePathCallback = filePathCallback;
473
+ pendingImageFileUri = null;
474
+ pendingFileChooserType = FileChooserType.FILE_PICKER;
475
+
386
476
  try {
387
477
  activityListener = (activityResult) -> {
388
478
  Uri[] result;
@@ -397,10 +487,12 @@ public class BridgeWebChromeClient extends WebChromeClient {
397
487
  result = WebChromeClient.FileChooserParams.parseResult(activityResult.getResultCode(), resultIntent);
398
488
  }
399
489
  filePathCallback.onReceiveValue(result);
490
+ clearPendingFileChooserState();
400
491
  };
401
492
  activityLauncher.launch(intent);
402
493
  } catch (ActivityNotFoundException e) {
403
494
  filePathCallback.onReceiveValue(null);
495
+ clearPendingFileChooserState();
404
496
  }
405
497
  }
406
498
 
@@ -2,6 +2,7 @@ package com.getcapacitor;
2
2
 
3
3
  import android.content.Context;
4
4
  import android.os.Build;
5
+ import android.text.InputType;
5
6
  import android.util.AttributeSet;
6
7
  import android.util.TypedValue;
7
8
  import android.view.KeyEvent;
@@ -17,6 +18,7 @@ public class CapacitorWebView extends WebView {
17
18
 
18
19
  private BaseInputConnection capInputConnection;
19
20
  private Bridge bridge;
21
+ private boolean autosuggestionEnabled = true;
20
22
 
21
23
  public CapacitorWebView(Context context, AttributeSet attrs) {
22
24
  super(context, attrs);
@@ -26,6 +28,10 @@ public class CapacitorWebView extends WebView {
26
28
  this.bridge = bridge;
27
29
  }
28
30
 
31
+ public void setAutosuggestionEnabled(boolean enabled) {
32
+ autosuggestionEnabled = enabled;
33
+ }
34
+
29
35
  @Override
30
36
  public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
31
37
  CapConfig config;
@@ -36,13 +42,23 @@ public class CapacitorWebView extends WebView {
36
42
  }
37
43
 
38
44
  boolean captureInput = config.isInputCaptured();
45
+ InputConnection inputConnection;
39
46
  if (captureInput) {
40
47
  if (capInputConnection == null) {
41
48
  capInputConnection = new BaseInputConnection(this, false);
42
49
  }
43
- return capInputConnection;
50
+ inputConnection = capInputConnection;
51
+ } else {
52
+ inputConnection = super.onCreateInputConnection(outAttrs);
44
53
  }
45
- return super.onCreateInputConnection(outAttrs);
54
+
55
+ if (!autosuggestionEnabled) {
56
+ // See https://stackoverflow.com/a/28009054/640584
57
+ outAttrs.inputType &= ~EditorInfo.TYPE_MASK_VARIATION;
58
+ outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
59
+ }
60
+
61
+ return inputConnection;
46
62
  }
47
63
 
48
64
  @Override
@@ -164,13 +164,18 @@ public class SystemBars extends Plugin {
164
164
  }
165
165
 
166
166
  private void initSafeAreaCSSVariables() {
167
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && insetHandlingEnabled) {
167
+ WindowInsetsCompat insets;
168
+
169
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
168
170
  View v = (View) this.getBridge().getWebView().getParent();
169
- WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(v);
170
- if (insets != null) {
171
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
172
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
173
- }
171
+ insets = ViewCompat.getRootWindowInsets(v);
172
+ } else {
173
+ insets = WindowInsetsCompat.CONSUMED;
174
+ }
175
+
176
+ if (insets != null) {
177
+ Insets safeAreaInsets = calcSafeAreaInsets(insets);
178
+ injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
174
179
  }
175
180
  }
176
181
 
@@ -186,10 +191,8 @@ public class SystemBars extends Plugin {
186
191
  // We need to correct for a possible shown IME
187
192
  v.setPadding(0, 0, 0, keyboardVisible ? imeInsets.bottom : 0);
188
193
 
189
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
190
- Insets safeAreaInsets = calcSafeAreaInsets(insets);
191
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
192
- }
194
+ Insets safeAreaInsets = calcSafeAreaInsets(insets);
195
+ injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
193
196
 
194
197
  return new WindowInsetsCompat.Builder(insets)
195
198
  .setInsets(
@@ -221,10 +224,8 @@ public class SystemBars extends Plugin {
221
224
  .setInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout(), Insets.of(0, 0, 0, 0))
222
225
  .build();
223
226
 
224
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM && hasViewportCover && insetHandlingEnabled) {
225
- Insets safeAreaInsets = calcSafeAreaInsets(newInsets);
226
- injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
227
- }
227
+ Insets safeAreaInsets = calcSafeAreaInsets(newInsets);
228
+ injectSafeAreaCSS(safeAreaInsets.top, safeAreaInsets.right, safeAreaInsets.bottom, safeAreaInsets.left);
228
229
 
229
230
  return newInsets;
230
231
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor-plus/android",
3
- "version": "8.3.4",
3
+ "version": "8.3.5",
4
4
  "description": "Capacitor+: Enhanced Capacitor with automated upstream sync - Cross-platform apps with JavaScript and the web",
5
5
  "homepage": "https://capgo.app/docs/plugins/capacitor-plus/",
6
6
  "author": "Capgo Team <support@capgo.app> (https://capgo.app)",