@capgo/capacitor-updater 8.48.0 → 8.49.1
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 +186 -8
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +645 -111
- package/android/src/main/java/ee/forgr/capacitor_updater/ShakeMenu.java +203 -30
- package/android/src/main/java/ee/forgr/capacitor_updater/ThreeFingerPinchDetector.java +218 -64
- package/dist/docs.json +528 -17
- package/dist/esm/definitions.d.ts +228 -10
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +7 -1
- package/dist/esm/web.js +24 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +24 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +24 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +538 -77
- package/ios/Sources/CapacitorUpdaterPlugin/ShakeMenu.swift +239 -21
- package/package.json +1 -1
|
@@ -56,6 +56,7 @@ import java.net.HttpURLConnection;
|
|
|
56
56
|
import java.net.MalformedURLException;
|
|
57
57
|
import java.net.URL;
|
|
58
58
|
import java.nio.charset.StandardCharsets;
|
|
59
|
+
import java.text.SimpleDateFormat;
|
|
59
60
|
import java.util.ArrayList;
|
|
60
61
|
import java.util.Date;
|
|
61
62
|
import java.util.HashMap;
|
|
@@ -64,6 +65,7 @@ import java.util.List;
|
|
|
64
65
|
import java.util.Map;
|
|
65
66
|
import java.util.Objects;
|
|
66
67
|
import java.util.Set;
|
|
68
|
+
import java.util.TimeZone;
|
|
67
69
|
import java.util.Timer;
|
|
68
70
|
import java.util.TimerTask;
|
|
69
71
|
import java.util.concurrent.Phaser;
|
|
@@ -109,6 +111,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
109
111
|
private static final String PREVIEW_PREVIOUS_DEFAULT_CHANNEL_WAS_SET_PREF_KEY = "CapacitorUpdater.previewPreviousDefaultChannelWasSet";
|
|
110
112
|
private static final String PREVIEW_APP_ID_PREF_KEY = "CapacitorUpdater.previewAppId";
|
|
111
113
|
private static final String PREVIEW_PAYLOAD_URL_PREF_KEY = "CapacitorUpdater.previewPayloadUrl";
|
|
114
|
+
private static final String PREVIEW_NAME_PREF_KEY = "CapacitorUpdater.previewName";
|
|
115
|
+
private static final String PREVIEW_SOURCE_PREF_KEY = "CapacitorUpdater.previewSource";
|
|
116
|
+
private static final String PREVIEW_SESSIONS_PREF_KEY = "CapacitorUpdater.previewSessions";
|
|
112
117
|
private static final String PREVIEW_SESSION_ALERT_PENDING_PREF_KEY = "CapacitorUpdater.previewSessionAlertPending";
|
|
113
118
|
private static final String[] BREAKING_EVENT_NAMES = { "breakingAvailable", "majorAvailable" };
|
|
114
119
|
private static final String LAST_FAILED_BUNDLE_PREF_KEY = "CapacitorUpdater.lastFailedBundle";
|
|
@@ -132,11 +137,12 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
132
137
|
static final int APPLICATION_EXIT_REASON_USER_REQUESTED = 10;
|
|
133
138
|
static final int APPLICATION_EXIT_REASON_DEPENDENCY_DIED = 12;
|
|
134
139
|
|
|
135
|
-
private final String pluginVersion = "8.
|
|
140
|
+
private final String pluginVersion = "8.49.1";
|
|
136
141
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
137
142
|
|
|
138
143
|
private SharedPreferences.Editor editor;
|
|
139
144
|
private SharedPreferences prefs;
|
|
145
|
+
private final Object previewSessionsLock = new Object();
|
|
140
146
|
protected CapgoUpdater implementation;
|
|
141
147
|
private Boolean persistCustomId = false;
|
|
142
148
|
private Boolean persistModifyUrl = false;
|
|
@@ -338,6 +344,296 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
338
344
|
}
|
|
339
345
|
}
|
|
340
346
|
|
|
347
|
+
private String nowIsoString() {
|
|
348
|
+
final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", java.util.Locale.US);
|
|
349
|
+
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
|
|
350
|
+
return formatter.format(new Date());
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private String normalizedPreviewMetadataValue(final String rawValue) {
|
|
354
|
+
if (rawValue == null) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
final String value = rawValue.trim();
|
|
359
|
+
if (value.isEmpty()) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
final String lowercased = value.toLowerCase(java.util.Locale.ROOT);
|
|
364
|
+
if ("undefined".equals(lowercased) || "null".equals(lowercased)) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return value;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
private JSONObject previewSessionsJson() {
|
|
372
|
+
final String raw = this.prefs == null ? null : this.prefs.getString(PREVIEW_SESSIONS_PREF_KEY, null);
|
|
373
|
+
if (raw == null || raw.trim().isEmpty()) {
|
|
374
|
+
return new JSONObject();
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
return new JSONObject(raw);
|
|
378
|
+
} catch (final JSONException e) {
|
|
379
|
+
logger.warn("Could not parse preview sessions, clearing them: " + e.getMessage());
|
|
380
|
+
this.editor.remove(PREVIEW_SESSIONS_PREF_KEY).apply();
|
|
381
|
+
return new JSONObject();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
private void savePreviewSessionsJson(final JSONObject sessions) {
|
|
386
|
+
this.editor.putString(PREVIEW_SESSIONS_PREF_KEY, sessions.toString()).apply();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private boolean hasSavedPreviewSessions() {
|
|
390
|
+
synchronized (this.previewSessionsLock) {
|
|
391
|
+
return this.previewSessionsJson().length() > 0;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private String metadataString(final JSONObject metadata, final String key) {
|
|
396
|
+
return this.normalizedPreviewMetadataValue(metadata.optString(key, null));
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
private String currentPreviewMetadataValue(final String key) {
|
|
400
|
+
return this.normalizedPreviewMetadataValue(this.prefs.getString(key, null));
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
private Set<String> availableBundleIds() {
|
|
404
|
+
final Set<String> ids = new HashSet<>();
|
|
405
|
+
for (final BundleInfo bundle : this.implementation.list(false)) {
|
|
406
|
+
ids.add(bundle.getId());
|
|
407
|
+
}
|
|
408
|
+
return ids;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
private JSObject previewInfo(
|
|
412
|
+
final String id,
|
|
413
|
+
final JSONObject metadata,
|
|
414
|
+
final Set<String> availableBundleIds,
|
|
415
|
+
final String currentBundleId
|
|
416
|
+
) throws JSONException {
|
|
417
|
+
final BundleInfo bundle = this.implementation.getBundleInfo(id);
|
|
418
|
+
if (!bundle.isBuiltin() && !availableBundleIds.contains(id)) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
if (bundle.isDeleted() || bundle.isErrorStatus()) {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
final String now = this.nowIsoString();
|
|
426
|
+
final JSObject info = new JSObject();
|
|
427
|
+
info.put("id", id);
|
|
428
|
+
info.put("bundle", InternalUtils.mapToJSObject(bundle.toJSONMap()));
|
|
429
|
+
info.put("createdAt", Objects.requireNonNullElse(this.metadataString(metadata, "createdAt"), now));
|
|
430
|
+
info.put("updatedAt", Objects.requireNonNullElse(this.metadataString(metadata, "updatedAt"), now));
|
|
431
|
+
info.put("lastUsedAt", Objects.requireNonNullElse(this.metadataString(metadata, "lastUsedAt"), now));
|
|
432
|
+
info.put("isActive", Boolean.TRUE.equals(this.previewSessionEnabled) && id.equals(currentBundleId));
|
|
433
|
+
|
|
434
|
+
for (final String key : new String[] { "name", "source", "appId", "payloadUrl" }) {
|
|
435
|
+
final String value = this.metadataString(metadata, key);
|
|
436
|
+
if (value != null) {
|
|
437
|
+
info.put(key, value);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return info;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
private JSArray listPreviewInfos(final boolean cleanup) {
|
|
445
|
+
synchronized (this.previewSessionsLock) {
|
|
446
|
+
final JSONObject sessions = this.previewSessionsJson();
|
|
447
|
+
final Set<String> availableBundleIds = this.availableBundleIds();
|
|
448
|
+
final String currentBundleId = this.implementation.getCurrentBundle().getId();
|
|
449
|
+
final JSArray previews = new JSArray();
|
|
450
|
+
final List<String> staleIds = new ArrayList<>();
|
|
451
|
+
|
|
452
|
+
final JSONArray names = sessions.names();
|
|
453
|
+
if (names == null) {
|
|
454
|
+
return previews;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
final List<JSObject> sortedPreviews = new ArrayList<>();
|
|
458
|
+
for (int i = 0; i < names.length(); i++) {
|
|
459
|
+
final String id = names.optString(i, "");
|
|
460
|
+
if (id.isEmpty()) {
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
final JSONObject metadata = sessions.optJSONObject(id);
|
|
464
|
+
if (metadata == null) {
|
|
465
|
+
staleIds.add(id);
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
try {
|
|
469
|
+
final JSObject info = this.previewInfo(id, metadata, availableBundleIds, currentBundleId);
|
|
470
|
+
if (info == null) {
|
|
471
|
+
staleIds.add(id);
|
|
472
|
+
} else {
|
|
473
|
+
sortedPreviews.add(info);
|
|
474
|
+
}
|
|
475
|
+
} catch (final JSONException e) {
|
|
476
|
+
logger.warn("Could not read preview metadata for " + id + ": " + e.getMessage());
|
|
477
|
+
staleIds.add(id);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
sortedPreviews.sort((first, second) -> second.optString("lastUsedAt", "").compareTo(first.optString("lastUsedAt", "")));
|
|
482
|
+
for (final JSObject preview : sortedPreviews) {
|
|
483
|
+
previews.put(preview);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (cleanup && !staleIds.isEmpty()) {
|
|
487
|
+
for (final String id : staleIds) {
|
|
488
|
+
sessions.remove(id);
|
|
489
|
+
}
|
|
490
|
+
this.savePreviewSessionsJson(sessions);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return previews;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
private JSObject storedPreviewInfo(final String id) {
|
|
498
|
+
synchronized (this.previewSessionsLock) {
|
|
499
|
+
final JSONObject metadata = this.previewSessionsJson().optJSONObject(id);
|
|
500
|
+
if (metadata == null) {
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
try {
|
|
504
|
+
return this.previewInfo(id, metadata, this.availableBundleIds(), this.implementation.getCurrentBundle().getId());
|
|
505
|
+
} catch (final JSONException e) {
|
|
506
|
+
logger.warn("Could not read preview metadata for " + id + ": " + e.getMessage());
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
private JSObject recordPreviewBundle(final BundleInfo bundle) {
|
|
513
|
+
return this.recordPreviewBundle(bundle, null);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
private JSObject recordPreviewBundle(final BundleInfo bundle, final String oldId) {
|
|
517
|
+
final String now = this.nowIsoString();
|
|
518
|
+
final String id = bundle.getId();
|
|
519
|
+
synchronized (this.previewSessionsLock) {
|
|
520
|
+
final JSONObject sessions = this.previewSessionsJson();
|
|
521
|
+
JSONObject metadata = sessions.optJSONObject(id);
|
|
522
|
+
final boolean replacingPreview = oldId != null && !oldId.equals(id);
|
|
523
|
+
|
|
524
|
+
try {
|
|
525
|
+
if (metadata == null && replacingPreview) {
|
|
526
|
+
final JSONObject oldMetadata = sessions.optJSONObject(oldId);
|
|
527
|
+
if (oldMetadata != null) {
|
|
528
|
+
metadata = new JSONObject(oldMetadata.toString());
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (metadata == null) {
|
|
532
|
+
metadata = new JSONObject();
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (!metadata.has("createdAt")) {
|
|
536
|
+
metadata.put("createdAt", now);
|
|
537
|
+
}
|
|
538
|
+
metadata.put("updatedAt", now);
|
|
539
|
+
if (metadata.isNull("lastUsedAt") || this.implementation.getCurrentBundle().getId().equals(id)) {
|
|
540
|
+
metadata.put("lastUsedAt", now);
|
|
541
|
+
}
|
|
542
|
+
metadata.put("version", bundle.getVersionName());
|
|
543
|
+
|
|
544
|
+
if (!replacingPreview) {
|
|
545
|
+
final String appId = this.currentPreviewMetadataValue(PREVIEW_APP_ID_PREF_KEY);
|
|
546
|
+
if (appId == null) {
|
|
547
|
+
metadata.remove("appId");
|
|
548
|
+
} else {
|
|
549
|
+
metadata.put("appId", appId);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
final String payloadUrl = this.currentPreviewMetadataValue(PREVIEW_PAYLOAD_URL_PREF_KEY);
|
|
553
|
+
if (payloadUrl == null) {
|
|
554
|
+
metadata.remove("payloadUrl");
|
|
555
|
+
} else {
|
|
556
|
+
metadata.put("payloadUrl", payloadUrl);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (!replacingPreview) {
|
|
561
|
+
final String name = this.currentPreviewMetadataValue(PREVIEW_NAME_PREF_KEY);
|
|
562
|
+
if (name == null) {
|
|
563
|
+
metadata.remove("name");
|
|
564
|
+
} else {
|
|
565
|
+
metadata.put("name", name);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
final String source = this.currentPreviewMetadataValue(PREVIEW_SOURCE_PREF_KEY);
|
|
569
|
+
if (source == null) {
|
|
570
|
+
metadata.remove("source");
|
|
571
|
+
} else {
|
|
572
|
+
metadata.put("source", source);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (this.metadataString(metadata, "name") == null) {
|
|
576
|
+
metadata.put("name", bundle.getVersionName());
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
if (oldId != null && !oldId.equals(id)) {
|
|
580
|
+
sessions.remove(oldId);
|
|
581
|
+
}
|
|
582
|
+
sessions.put(id, metadata);
|
|
583
|
+
this.savePreviewSessionsJson(sessions);
|
|
584
|
+
|
|
585
|
+
return this.previewInfo(id, metadata, this.availableBundleIds(), this.implementation.getCurrentBundle().getId());
|
|
586
|
+
} catch (final JSONException e) {
|
|
587
|
+
logger.warn("Could not store preview metadata: " + e.getMessage());
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
final JSObject fallback = new JSObject();
|
|
592
|
+
fallback.put("id", id);
|
|
593
|
+
fallback.put("bundle", InternalUtils.mapToJSObject(bundle.toJSONMap()));
|
|
594
|
+
fallback.put("createdAt", now);
|
|
595
|
+
fallback.put("updatedAt", now);
|
|
596
|
+
fallback.put("lastUsedAt", now);
|
|
597
|
+
fallback.put(
|
|
598
|
+
"isActive",
|
|
599
|
+
Boolean.TRUE.equals(this.previewSessionEnabled) && this.implementation.getCurrentBundle().getId().equals(id)
|
|
600
|
+
);
|
|
601
|
+
return fallback;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
private void updateCurrentPreviewSessionMetadataFrom(final JSObject preview) {
|
|
605
|
+
final String appId = this.normalizedPreviewMetadataValue(preview.optString("appId", null));
|
|
606
|
+
if (appId == null) {
|
|
607
|
+
this.restorePreviewPreviousAppId();
|
|
608
|
+
this.editor.remove(PREVIEW_APP_ID_PREF_KEY);
|
|
609
|
+
} else {
|
|
610
|
+
this.setActiveAppId(appId);
|
|
611
|
+
this.editor.putString(PREVIEW_APP_ID_PREF_KEY, appId);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
final String payloadUrl = this.normalizedPreviewMetadataValue(preview.optString("payloadUrl", null));
|
|
615
|
+
if (payloadUrl == null) {
|
|
616
|
+
this.editor.remove(PREVIEW_PAYLOAD_URL_PREF_KEY);
|
|
617
|
+
} else {
|
|
618
|
+
this.editor.putString(PREVIEW_PAYLOAD_URL_PREF_KEY, payloadUrl);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
final String name = this.normalizedPreviewMetadataValue(preview.optString("name", null));
|
|
622
|
+
if (name == null) {
|
|
623
|
+
this.editor.remove(PREVIEW_NAME_PREF_KEY);
|
|
624
|
+
} else {
|
|
625
|
+
this.editor.putString(PREVIEW_NAME_PREF_KEY, name);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
final String source = this.normalizedPreviewMetadataValue(preview.optString("source", null));
|
|
629
|
+
if (source == null) {
|
|
630
|
+
this.editor.remove(PREVIEW_SOURCE_PREF_KEY);
|
|
631
|
+
} else {
|
|
632
|
+
this.editor.putString(PREVIEW_SOURCE_PREF_KEY, source);
|
|
633
|
+
}
|
|
634
|
+
this.editor.apply();
|
|
635
|
+
}
|
|
636
|
+
|
|
341
637
|
public Thread startNewThread(final Runnable function, Number waitTime) {
|
|
342
638
|
Thread bgTask = new Thread(() -> {
|
|
343
639
|
try {
|
|
@@ -576,6 +872,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
576
872
|
|
|
577
873
|
this.checkForUpdateAfterDelay();
|
|
578
874
|
this.showPreviewSessionNoticeIfNeeded();
|
|
875
|
+
this.syncShakeMenuLifecycle();
|
|
579
876
|
|
|
580
877
|
// On Android 14+ (API 34+), topActivity in RecentTaskInfo returns null due to
|
|
581
878
|
// security restrictions (StrandHogg task hijacking mitigations). Use ProcessLifecycleOwner
|
|
@@ -2430,8 +2727,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2430
2727
|
call.reject("Update failed, id " + id + " does not exist.");
|
|
2431
2728
|
} else if (Boolean.TRUE.equals(this.previewSessionEnabled)) {
|
|
2432
2729
|
logger.info("Preview session set active bundle " + id + " without waiting for preview app readiness");
|
|
2730
|
+
final BundleInfo bundle = this.implementation.getBundleInfo(id);
|
|
2731
|
+
this.recordPreviewBundle(bundle);
|
|
2433
2732
|
this.reloadWithoutWaitingForAppReady();
|
|
2434
|
-
this.notifyBundleSet(
|
|
2733
|
+
this.notifyBundleSet(bundle);
|
|
2435
2734
|
this.showPreviewSessionNoticeIfNeeded();
|
|
2436
2735
|
call.resolve();
|
|
2437
2736
|
} else if (!this._reload()) {
|
|
@@ -2450,6 +2749,51 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2450
2749
|
});
|
|
2451
2750
|
}
|
|
2452
2751
|
|
|
2752
|
+
private boolean preparePreviewFallbackIfNeeded() {
|
|
2753
|
+
if (Boolean.TRUE.equals(this.previewSessionEnabled)) {
|
|
2754
|
+
return true;
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2757
|
+
final BundleInfo current = this.implementation.getCurrentBundle();
|
|
2758
|
+
if (!this.implementation.setPreviewFallbackBundle(current.getId())) {
|
|
2759
|
+
logger.error("Could not save current bundle as preview fallback");
|
|
2760
|
+
return false;
|
|
2761
|
+
}
|
|
2762
|
+
|
|
2763
|
+
final BundleInfo previousNext = this.implementation.getNextBundle();
|
|
2764
|
+
if (previousNext == null || previousNext.isDeleted() || previousNext.isErrorStatus()) {
|
|
2765
|
+
this.editor.remove(PREVIEW_PREVIOUS_NEXT_BUNDLE_PREF_KEY);
|
|
2766
|
+
} else {
|
|
2767
|
+
this.editor.putString(PREVIEW_PREVIOUS_NEXT_BUNDLE_PREF_KEY, previousNext.getId());
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
this.editor.putString(PREVIEW_PREVIOUS_APP_ID_PREF_KEY, this.implementation.appId);
|
|
2771
|
+
if (this.prefs.contains(DEFAULT_CHANNEL_PREF_KEY)) {
|
|
2772
|
+
this.editor.putString(PREVIEW_PREVIOUS_DEFAULT_CHANNEL_PREF_KEY, this.prefs.getString(DEFAULT_CHANNEL_PREF_KEY, ""));
|
|
2773
|
+
this.editor.putBoolean(PREVIEW_PREVIOUS_DEFAULT_CHANNEL_WAS_SET_PREF_KEY, true);
|
|
2774
|
+
} else {
|
|
2775
|
+
this.editor.remove(PREVIEW_PREVIOUS_DEFAULT_CHANNEL_PREF_KEY);
|
|
2776
|
+
this.editor.putBoolean(PREVIEW_PREVIOUS_DEFAULT_CHANNEL_WAS_SET_PREF_KEY, false);
|
|
2777
|
+
}
|
|
2778
|
+
this.editor.putBoolean(PREVIEW_PREVIOUS_SHAKE_MENU_PREF_KEY, Boolean.TRUE.equals(this.shakeMenuEnabled));
|
|
2779
|
+
this.editor.putBoolean(PREVIEW_PREVIOUS_SHAKE_CHANNEL_SELECTOR_PREF_KEY, Boolean.TRUE.equals(this.shakeChannelSelectorEnabled));
|
|
2780
|
+
logger.info("Preview session started with fallback bundle: " + current);
|
|
2781
|
+
return true;
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
private void activatePreviewSessionState() {
|
|
2785
|
+
this.clearIncomingPreviewTransition();
|
|
2786
|
+
this.hidePreviewTransitionLoader("preview-session-started");
|
|
2787
|
+
this.previewSessionEnabled = true;
|
|
2788
|
+
this.previewSessionAlertPending = true;
|
|
2789
|
+
this.implementation.previewSession = true;
|
|
2790
|
+
this.shakeMenuEnabled = true;
|
|
2791
|
+
this.editor.putBoolean(PREVIEW_SESSION_PREF_KEY, true);
|
|
2792
|
+
this.editor.putBoolean(PREVIEW_SESSION_ALERT_PENDING_PREF_KEY, true);
|
|
2793
|
+
this.editor.apply();
|
|
2794
|
+
this.syncShakeMenuLifecycle();
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2453
2797
|
@PluginMethod
|
|
2454
2798
|
public void startPreviewSession(final PluginCall call) {
|
|
2455
2799
|
if (!Boolean.TRUE.equals(this.allowPreview)) {
|
|
@@ -2469,39 +2813,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2469
2813
|
}
|
|
2470
2814
|
startNewThread(() -> {
|
|
2471
2815
|
try {
|
|
2472
|
-
if (!
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
logger.error("Could not save current bundle as preview fallback");
|
|
2477
|
-
call.reject("Could not save current bundle as preview fallback");
|
|
2478
|
-
return;
|
|
2479
|
-
}
|
|
2480
|
-
|
|
2481
|
-
final BundleInfo previousNext = this.implementation.getNextBundle();
|
|
2482
|
-
if (previousNext == null || previousNext.isDeleted() || previousNext.isErrorStatus()) {
|
|
2483
|
-
this.editor.remove(PREVIEW_PREVIOUS_NEXT_BUNDLE_PREF_KEY);
|
|
2484
|
-
} else {
|
|
2485
|
-
this.editor.putString(PREVIEW_PREVIOUS_NEXT_BUNDLE_PREF_KEY, previousNext.getId());
|
|
2486
|
-
}
|
|
2487
|
-
|
|
2488
|
-
this.editor.putString(PREVIEW_PREVIOUS_APP_ID_PREF_KEY, this.implementation.appId);
|
|
2489
|
-
if (this.prefs.contains(DEFAULT_CHANNEL_PREF_KEY)) {
|
|
2490
|
-
this.editor.putString(
|
|
2491
|
-
PREVIEW_PREVIOUS_DEFAULT_CHANNEL_PREF_KEY,
|
|
2492
|
-
this.prefs.getString(DEFAULT_CHANNEL_PREF_KEY, "")
|
|
2493
|
-
);
|
|
2494
|
-
this.editor.putBoolean(PREVIEW_PREVIOUS_DEFAULT_CHANNEL_WAS_SET_PREF_KEY, true);
|
|
2495
|
-
} else {
|
|
2496
|
-
this.editor.remove(PREVIEW_PREVIOUS_DEFAULT_CHANNEL_PREF_KEY);
|
|
2497
|
-
this.editor.putBoolean(PREVIEW_PREVIOUS_DEFAULT_CHANNEL_WAS_SET_PREF_KEY, false);
|
|
2498
|
-
}
|
|
2499
|
-
this.editor.putBoolean(PREVIEW_PREVIOUS_SHAKE_MENU_PREF_KEY, Boolean.TRUE.equals(this.shakeMenuEnabled));
|
|
2500
|
-
this.editor.putBoolean(
|
|
2501
|
-
PREVIEW_PREVIOUS_SHAKE_CHANNEL_SELECTOR_PREF_KEY,
|
|
2502
|
-
Boolean.TRUE.equals(this.shakeChannelSelectorEnabled)
|
|
2503
|
-
);
|
|
2504
|
-
logger.info("Preview session started with fallback bundle: " + current);
|
|
2816
|
+
if (!this.preparePreviewFallbackIfNeeded()) {
|
|
2817
|
+
this.hidePreviewTransitionLoader("preview-session-fallback-failed");
|
|
2818
|
+
call.reject("Could not save current bundle as preview fallback");
|
|
2819
|
+
return;
|
|
2505
2820
|
}
|
|
2506
2821
|
|
|
2507
2822
|
if (previewAppId != null) {
|
|
@@ -2517,15 +2832,21 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2517
2832
|
this.editor.remove(PREVIEW_PAYLOAD_URL_PREF_KEY);
|
|
2518
2833
|
}
|
|
2519
2834
|
|
|
2520
|
-
this.
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
this.
|
|
2528
|
-
|
|
2835
|
+
final String previewName = this.normalizedPreviewMetadataValue(call.getString("name"));
|
|
2836
|
+
if (previewName == null) {
|
|
2837
|
+
this.editor.remove(PREVIEW_NAME_PREF_KEY);
|
|
2838
|
+
} else {
|
|
2839
|
+
this.editor.putString(PREVIEW_NAME_PREF_KEY, previewName);
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
final String previewSource = this.normalizedPreviewMetadataValue(call.getString("source"));
|
|
2843
|
+
if (previewSource == null) {
|
|
2844
|
+
this.editor.remove(PREVIEW_SOURCE_PREF_KEY);
|
|
2845
|
+
} else {
|
|
2846
|
+
this.editor.putString(PREVIEW_SOURCE_PREF_KEY, previewSource);
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
this.activatePreviewSessionState();
|
|
2529
2850
|
call.resolve();
|
|
2530
2851
|
} catch (final Exception e) {
|
|
2531
2852
|
this.hidePreviewTransitionLoader("preview-session-failed");
|
|
@@ -2535,9 +2856,260 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2535
2856
|
});
|
|
2536
2857
|
}
|
|
2537
2858
|
|
|
2538
|
-
|
|
2539
|
-
|
|
2859
|
+
@PluginMethod
|
|
2860
|
+
public void listPreviews(final PluginCall call) {
|
|
2861
|
+
if (!Boolean.TRUE.equals(this.allowPreview)) {
|
|
2862
|
+
call.reject("listPreviews not allowed");
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2865
|
+
|
|
2866
|
+
final JSArray previews = this.listPreviewInfos(true);
|
|
2867
|
+
final JSObject ret = new JSObject();
|
|
2868
|
+
ret.put("previews", previews);
|
|
2869
|
+
ret.put("currentBundle", InternalUtils.mapToJSObject(this.implementation.getCurrentBundle().toJSONMap()));
|
|
2870
|
+
|
|
2871
|
+
for (int i = 0; i < previews.length(); i++) {
|
|
2872
|
+
final JSONObject preview = previews.optJSONObject(i);
|
|
2873
|
+
if (preview != null && preview.optBoolean("isActive", false)) {
|
|
2874
|
+
ret.put("current", preview);
|
|
2875
|
+
break;
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
final BundleInfo liveBundle = this.implementation.getPreviewFallbackBundle();
|
|
2880
|
+
if (liveBundle != null) {
|
|
2881
|
+
ret.put("liveBundle", InternalUtils.mapToJSObject(liveBundle.toJSONMap()));
|
|
2882
|
+
}
|
|
2883
|
+
|
|
2884
|
+
call.resolve(ret);
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2887
|
+
@PluginMethod
|
|
2888
|
+
public void setPreview(final PluginCall call) {
|
|
2889
|
+
if (!Boolean.TRUE.equals(this.allowPreview)) {
|
|
2890
|
+
call.reject("setPreview not allowed");
|
|
2891
|
+
return;
|
|
2892
|
+
}
|
|
2893
|
+
final String id = call.getString("id");
|
|
2894
|
+
if (id == null || id.isEmpty()) {
|
|
2895
|
+
call.reject("setPreview called without id");
|
|
2896
|
+
return;
|
|
2897
|
+
}
|
|
2898
|
+
final JSObject preview = this.storedPreviewInfo(id);
|
|
2899
|
+
if (preview == null) {
|
|
2900
|
+
call.reject("Preview " + id + " is not available locally");
|
|
2901
|
+
return;
|
|
2902
|
+
}
|
|
2903
|
+
|
|
2904
|
+
this.showPreviewTransitionLoader("set-preview");
|
|
2905
|
+
startNewThread(() -> {
|
|
2906
|
+
if (!this.preparePreviewFallbackIfNeeded()) {
|
|
2907
|
+
this.hidePreviewTransitionLoader("set-preview-fallback-failed");
|
|
2908
|
+
call.reject("Could not save current bundle as preview fallback");
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
if (!this.implementation.set(id)) {
|
|
2913
|
+
this.hidePreviewTransitionLoader("set-preview-failed");
|
|
2914
|
+
call.reject("Preview " + id + " cannot be applied");
|
|
2915
|
+
return;
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
final BundleInfo bundle = this.implementation.getBundleInfo(id);
|
|
2919
|
+
this.updateCurrentPreviewSessionMetadataFrom(preview);
|
|
2920
|
+
this.activatePreviewSessionState();
|
|
2921
|
+
this.recordPreviewBundle(bundle);
|
|
2922
|
+
if (!this.reloadWithoutWaitingForAppReady()) {
|
|
2923
|
+
this.hidePreviewTransitionLoader("set-preview-reload-failed");
|
|
2924
|
+
call.reject("Reload failed after setting preview " + id);
|
|
2925
|
+
return;
|
|
2926
|
+
}
|
|
2927
|
+
|
|
2928
|
+
this.notifyBundleSet(bundle);
|
|
2929
|
+
this.showPreviewSessionNoticeIfNeeded();
|
|
2930
|
+
call.resolve();
|
|
2931
|
+
});
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2934
|
+
public JSArray previewMenuPreviews() {
|
|
2935
|
+
return this.listPreviewInfos(true);
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2938
|
+
public boolean setPreviewFromShakeMenu(final String id) {
|
|
2939
|
+
final JSObject preview = this.storedPreviewInfo(id);
|
|
2940
|
+
if (!Boolean.TRUE.equals(this.allowPreview) || preview == null) {
|
|
2941
|
+
return false;
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2944
|
+
this.showPreviewTransitionLoader("set-preview-menu");
|
|
2945
|
+
if (!this.preparePreviewFallbackIfNeeded()) {
|
|
2946
|
+
this.hidePreviewTransitionLoader("set-preview-menu-fallback-failed");
|
|
2947
|
+
return false;
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
if (!this.implementation.set(id)) {
|
|
2951
|
+
this.hidePreviewTransitionLoader("set-preview-menu-failed");
|
|
2952
|
+
return false;
|
|
2953
|
+
}
|
|
2954
|
+
|
|
2955
|
+
final BundleInfo bundle = this.implementation.getBundleInfo(id);
|
|
2956
|
+
this.updateCurrentPreviewSessionMetadataFrom(preview);
|
|
2957
|
+
this.activatePreviewSessionState();
|
|
2958
|
+
this.recordPreviewBundle(bundle);
|
|
2959
|
+
if (!this.reloadWithoutWaitingForAppReady()) {
|
|
2960
|
+
this.hidePreviewTransitionLoader("set-preview-menu-reload-failed");
|
|
2961
|
+
return false;
|
|
2962
|
+
}
|
|
2963
|
+
|
|
2964
|
+
this.notifyBundleSet(bundle);
|
|
2965
|
+
this.showPreviewSessionNoticeIfNeeded();
|
|
2966
|
+
return true;
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
@PluginMethod
|
|
2970
|
+
public void resetPreview(final PluginCall call) {
|
|
2971
|
+
if (!Boolean.TRUE.equals(this.previewSessionEnabled)) {
|
|
2972
|
+
call.resolve();
|
|
2973
|
+
return;
|
|
2974
|
+
}
|
|
2975
|
+
startNewThread(() -> {
|
|
2976
|
+
if (this.leavePreviewSessionFromShakeMenu()) {
|
|
2977
|
+
call.resolve();
|
|
2978
|
+
} else {
|
|
2979
|
+
call.reject("Could not leave preview session");
|
|
2980
|
+
}
|
|
2981
|
+
});
|
|
2982
|
+
}
|
|
2540
2983
|
|
|
2984
|
+
@PluginMethod
|
|
2985
|
+
public void deletePreview(final PluginCall call) {
|
|
2986
|
+
if (!Boolean.TRUE.equals(this.allowPreview)) {
|
|
2987
|
+
call.reject("deletePreview not allowed");
|
|
2988
|
+
return;
|
|
2989
|
+
}
|
|
2990
|
+
final String id = call.getString("id");
|
|
2991
|
+
if (id == null || id.isEmpty()) {
|
|
2992
|
+
call.reject("deletePreview called without id");
|
|
2993
|
+
return;
|
|
2994
|
+
}
|
|
2995
|
+
if (Boolean.TRUE.equals(this.previewSessionEnabled) && this.implementation.getCurrentBundle().getId().equals(id)) {
|
|
2996
|
+
call.reject("Cannot delete the active preview");
|
|
2997
|
+
return;
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
final boolean removed;
|
|
3001
|
+
synchronized (this.previewSessionsLock) {
|
|
3002
|
+
final JSONObject sessions = this.previewSessionsJson();
|
|
3003
|
+
removed = sessions.has(id);
|
|
3004
|
+
sessions.remove(id);
|
|
3005
|
+
this.savePreviewSessionsJson(sessions);
|
|
3006
|
+
}
|
|
3007
|
+
|
|
3008
|
+
boolean deleted = false;
|
|
3009
|
+
final BundleInfo fallback = this.implementation.getPreviewFallbackBundle();
|
|
3010
|
+
final BundleInfo next = this.implementation.getNextBundle();
|
|
3011
|
+
if (
|
|
3012
|
+
removed &&
|
|
3013
|
+
!BundleInfo.ID_BUILTIN.equals(id) &&
|
|
3014
|
+
(fallback == null || !id.equals(fallback.getId())) &&
|
|
3015
|
+
(next == null || !id.equals(next.getId()))
|
|
3016
|
+
) {
|
|
3017
|
+
try {
|
|
3018
|
+
deleted = this.implementation.delete(id, false);
|
|
3019
|
+
} catch (final Exception err) {
|
|
3020
|
+
logger.warn("Could not delete preview bundle " + id + ": " + err.getMessage());
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
|
|
3024
|
+
final JSObject ret = new JSObject();
|
|
3025
|
+
ret.put("removed", removed);
|
|
3026
|
+
ret.put("deleted", deleted);
|
|
3027
|
+
call.resolve(ret);
|
|
3028
|
+
}
|
|
3029
|
+
|
|
3030
|
+
@PluginMethod
|
|
3031
|
+
public void checkPreviewUpdate(final PluginCall call) {
|
|
3032
|
+
this.handlePreviewUpdate(call, false);
|
|
3033
|
+
}
|
|
3034
|
+
|
|
3035
|
+
@PluginMethod
|
|
3036
|
+
public void updatePreview(final PluginCall call) {
|
|
3037
|
+
this.handlePreviewUpdate(call, true);
|
|
3038
|
+
}
|
|
3039
|
+
|
|
3040
|
+
private void handlePreviewUpdate(final PluginCall call, final boolean shouldDownload) {
|
|
3041
|
+
if (!Boolean.TRUE.equals(this.allowPreview)) {
|
|
3042
|
+
call.reject("Preview updates not allowed");
|
|
3043
|
+
return;
|
|
3044
|
+
}
|
|
3045
|
+
final String id = call.getString("id");
|
|
3046
|
+
if (id == null || id.isEmpty()) {
|
|
3047
|
+
call.reject("Preview update called without id");
|
|
3048
|
+
return;
|
|
3049
|
+
}
|
|
3050
|
+
final JSObject preview = this.storedPreviewInfo(id);
|
|
3051
|
+
final String payloadUrl = preview == null ? null : this.normalizePreviewPayloadUrl(preview.optString("payloadUrl", null));
|
|
3052
|
+
if (payloadUrl == null) {
|
|
3053
|
+
call.reject("Preview " + id + " has no payloadUrl to update from");
|
|
3054
|
+
return;
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
startNewThread(() -> {
|
|
3058
|
+
try {
|
|
3059
|
+
final JSONObject payload = this.fetchPreviewPayload(payloadUrl);
|
|
3060
|
+
final String version = payload.optString("version", "").trim();
|
|
3061
|
+
if (version.isEmpty()) {
|
|
3062
|
+
throw new IOException("Preview payload is missing a version");
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
final BundleInfo currentPreviewBundle = this.implementation.getBundleInfo(id);
|
|
3066
|
+
final boolean upToDate = version.equals(currentPreviewBundle.getVersionName());
|
|
3067
|
+
if (upToDate || !shouldDownload) {
|
|
3068
|
+
final JSObject ret = new JSObject();
|
|
3069
|
+
ret.put("preview", preview);
|
|
3070
|
+
ret.put("latestVersion", version);
|
|
3071
|
+
ret.put("upToDate", upToDate);
|
|
3072
|
+
ret.put("updated", false);
|
|
3073
|
+
ret.put("bundle", InternalUtils.mapToJSObject(currentPreviewBundle.toJSONMap()));
|
|
3074
|
+
call.resolve(ret);
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
final BundleInfo next = this.downloadPreviewPayloadBundle(payload);
|
|
3079
|
+
if (next.isErrorStatus()) {
|
|
3080
|
+
throw new IOException("Download failed: " + next.getStatus());
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
final boolean wasActive =
|
|
3084
|
+
Boolean.TRUE.equals(this.previewSessionEnabled) && this.implementation.getCurrentBundle().getId().equals(id);
|
|
3085
|
+
if (wasActive && !this.implementation.set(next.getId())) {
|
|
3086
|
+
throw new IOException("Downloaded preview bundle cannot be applied");
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
final JSObject savedPreview = this.recordPreviewBundle(next, id);
|
|
3090
|
+
if (wasActive) {
|
|
3091
|
+
if (!this.reloadWithoutWaitingForAppReady()) {
|
|
3092
|
+
throw new IOException("Reload failed after updating preview");
|
|
3093
|
+
}
|
|
3094
|
+
this.notifyBundleSet(next);
|
|
3095
|
+
this.showPreviewSessionNoticeIfNeeded();
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3098
|
+
final JSObject ret = new JSObject();
|
|
3099
|
+
ret.put("preview", savedPreview);
|
|
3100
|
+
ret.put("latestVersion", version);
|
|
3101
|
+
ret.put("upToDate", false);
|
|
3102
|
+
ret.put("updated", true);
|
|
3103
|
+
ret.put("bundle", InternalUtils.mapToJSObject(next.toJSONMap()));
|
|
3104
|
+
call.resolve(ret);
|
|
3105
|
+
} catch (final Exception err) {
|
|
3106
|
+
logger.error("Could not update preview: " + err.getMessage());
|
|
3107
|
+
call.reject("Could not update preview: " + err.getMessage());
|
|
3108
|
+
}
|
|
3109
|
+
});
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3112
|
+
public boolean leavePreviewSessionFromShakeMenu() {
|
|
2541
3113
|
this.showPreviewTransitionLoader("leave-preview-session");
|
|
2542
3114
|
final boolean didReset = this.resetToPreviewFallbackBundle();
|
|
2543
3115
|
if (!didReset) {
|
|
@@ -2545,16 +3117,12 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2545
3117
|
return false;
|
|
2546
3118
|
}
|
|
2547
3119
|
|
|
2548
|
-
final BundleInfo previewFallbackBundle = this.implementation.getPreviewFallbackBundle();
|
|
2549
3120
|
this.endPreviewSession(true);
|
|
2550
|
-
final BundleInfo restoredNextBundle = this.implementation.getNextBundle();
|
|
2551
|
-
this.deletePreviewBundleIfUnused(previewBundle, previewFallbackBundle, restoredNextBundle);
|
|
2552
3121
|
return true;
|
|
2553
3122
|
}
|
|
2554
3123
|
|
|
2555
3124
|
private boolean leavePreviewSessionForIncomingPreviewLink() {
|
|
2556
3125
|
this.showPreviewTransitionLoader("incoming-preview-deeplink");
|
|
2557
|
-
final BundleInfo previewBundle = this.implementation.getCurrentBundle();
|
|
2558
3126
|
final BundleInfo previewFallbackBundle = this.resolvePreviewFallbackBundle("incoming preview deeplink");
|
|
2559
3127
|
boolean didReload = false;
|
|
2560
3128
|
|
|
@@ -2577,8 +3145,6 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2577
3145
|
didReload = true;
|
|
2578
3146
|
|
|
2579
3147
|
this.endPreviewSession(true);
|
|
2580
|
-
final BundleInfo restoredNextBundle = this.implementation.getNextBundle();
|
|
2581
|
-
this.deletePreviewBundleIfUnused(previewBundle, previewFallbackBundle, restoredNextBundle);
|
|
2582
3148
|
return true;
|
|
2583
3149
|
} finally {
|
|
2584
3150
|
this.clearIncomingPreviewTransition();
|
|
@@ -2616,7 +3182,6 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2616
3182
|
}
|
|
2617
3183
|
|
|
2618
3184
|
private boolean leavePreviewSessionWithoutReload(final boolean keepPreviewGuard) {
|
|
2619
|
-
final BundleInfo previewBundle = this.implementation.getCurrentBundle();
|
|
2620
3185
|
final BundleInfo previewFallbackBundle = this.resolvePreviewFallbackBundle("preview deeplink launch");
|
|
2621
3186
|
if (previewFallbackBundle == null) {
|
|
2622
3187
|
return false;
|
|
@@ -2627,29 +3192,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2627
3192
|
}
|
|
2628
3193
|
|
|
2629
3194
|
this.endPreviewSession(keepPreviewGuard);
|
|
2630
|
-
final BundleInfo restoredNextBundle = this.implementation.getNextBundle();
|
|
2631
|
-
this.deletePreviewBundleIfUnused(previewBundle, previewFallbackBundle, restoredNextBundle);
|
|
2632
3195
|
return true;
|
|
2633
3196
|
}
|
|
2634
3197
|
|
|
2635
|
-
private void deletePreviewBundleIfUnused(
|
|
2636
|
-
final BundleInfo previewBundle,
|
|
2637
|
-
final BundleInfo previewFallbackBundle,
|
|
2638
|
-
final BundleInfo restoredNextBundle
|
|
2639
|
-
) {
|
|
2640
|
-
if (
|
|
2641
|
-
!previewBundle.isBuiltin() &&
|
|
2642
|
-
(previewFallbackBundle == null || !previewBundle.getId().equals(previewFallbackBundle.getId())) &&
|
|
2643
|
-
(restoredNextBundle == null || !previewBundle.getId().equals(restoredNextBundle.getId()))
|
|
2644
|
-
) {
|
|
2645
|
-
try {
|
|
2646
|
-
this.implementation.delete(previewBundle.getId(), false);
|
|
2647
|
-
} catch (final Exception err) {
|
|
2648
|
-
logger.warn("Cannot delete preview bundle " + previewBundle.getId() + ": " + err.getMessage());
|
|
2649
|
-
}
|
|
2650
|
-
}
|
|
2651
|
-
}
|
|
2652
|
-
|
|
2653
3198
|
public boolean reloadPreviewSessionFromShakeMenu() {
|
|
2654
3199
|
this.showPreviewTransitionLoader("reload-preview-session");
|
|
2655
3200
|
final boolean didReload;
|
|
@@ -2781,6 +3326,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2781
3326
|
this.editor.remove(PREVIEW_PREVIOUS_DEFAULT_CHANNEL_WAS_SET_PREF_KEY);
|
|
2782
3327
|
this.editor.remove(PREVIEW_APP_ID_PREF_KEY);
|
|
2783
3328
|
this.editor.remove(PREVIEW_PAYLOAD_URL_PREF_KEY);
|
|
3329
|
+
this.editor.remove(PREVIEW_NAME_PREF_KEY);
|
|
3330
|
+
this.editor.remove(PREVIEW_SOURCE_PREF_KEY);
|
|
2784
3331
|
this.editor.remove(PREVIEW_SESSION_ALERT_PENDING_PREF_KEY);
|
|
2785
3332
|
this.editor.apply();
|
|
2786
3333
|
}
|
|
@@ -2955,7 +3502,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2955
3502
|
throw new IOException("Preview payload is missing a version");
|
|
2956
3503
|
}
|
|
2957
3504
|
|
|
2958
|
-
|
|
3505
|
+
final BundleInfo current = this.implementation.getCurrentBundle();
|
|
3506
|
+
if (version.equals(current.getVersionName())) {
|
|
2959
3507
|
logger.info("Preview payload unchanged, reloading current bundle");
|
|
2960
3508
|
return this.reloadWithoutWaitingForAppReady();
|
|
2961
3509
|
}
|
|
@@ -2968,6 +3516,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2968
3516
|
throw new IOException("Downloaded preview bundle cannot be applied");
|
|
2969
3517
|
}
|
|
2970
3518
|
|
|
3519
|
+
this.recordPreviewBundle(next, current.getId());
|
|
2971
3520
|
this.notifyBundleSet(next);
|
|
2972
3521
|
return this.reloadWithoutWaitingForAppReady();
|
|
2973
3522
|
} catch (final Exception err) {
|
|
@@ -2977,7 +3526,11 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2977
3526
|
}
|
|
2978
3527
|
|
|
2979
3528
|
private void clearPreviewSessionForNativeBuildChange() {
|
|
2980
|
-
if (
|
|
3529
|
+
if (
|
|
3530
|
+
!Boolean.TRUE.equals(this.previewSessionEnabled) &&
|
|
3531
|
+
this.implementation.getPreviewFallbackBundle() == null &&
|
|
3532
|
+
!this.hasSavedPreviewSessions()
|
|
3533
|
+
) {
|
|
2981
3534
|
return;
|
|
2982
3535
|
}
|
|
2983
3536
|
logger.info("Native build changed; clearing preview session state");
|
|
@@ -2994,6 +3547,10 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
2994
3547
|
this.implementation.setPreviewFallbackBundle(null);
|
|
2995
3548
|
this.implementation.setNextBundle(null);
|
|
2996
3549
|
this.clearPreviewSessionPreferences();
|
|
3550
|
+
synchronized (this.previewSessionsLock) {
|
|
3551
|
+
this.editor.remove(PREVIEW_SESSIONS_PREF_KEY);
|
|
3552
|
+
this.editor.apply();
|
|
3553
|
+
}
|
|
2997
3554
|
}
|
|
2998
3555
|
|
|
2999
3556
|
private void restorePreviewPreviousNextBundle() {
|
|
@@ -3009,26 +3566,25 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
3009
3566
|
}
|
|
3010
3567
|
|
|
3011
3568
|
private void ensureShakeMenuStarted() {
|
|
3012
|
-
if (
|
|
3569
|
+
if (shakeMenu != null && !shakeMenu.usesGesture(this.shakeMenuGesture)) {
|
|
3013
3570
|
try {
|
|
3014
|
-
shakeMenu
|
|
3015
|
-
|
|
3571
|
+
shakeMenu.stop();
|
|
3572
|
+
shakeMenu = null;
|
|
3573
|
+
logger.info("Shake menu restarted for " + this.shakeMenuGesture + " gesture");
|
|
3016
3574
|
} catch (Exception e) {
|
|
3017
|
-
logger.error("Failed to
|
|
3575
|
+
logger.error("Failed to restart shake menu: " + e.getMessage());
|
|
3576
|
+
return;
|
|
3018
3577
|
}
|
|
3019
3578
|
}
|
|
3020
|
-
}
|
|
3021
3579
|
|
|
3022
|
-
|
|
3023
|
-
if (shakeMenu != null) {
|
|
3580
|
+
if (getActivity() instanceof com.getcapacitor.BridgeActivity && shakeMenu == null) {
|
|
3024
3581
|
try {
|
|
3025
|
-
shakeMenu.
|
|
3582
|
+
shakeMenu = new ShakeMenu(this, (com.getcapacitor.BridgeActivity) getActivity(), logger, this.shakeMenuGesture);
|
|
3583
|
+
logger.info("Shake menu initialized with " + this.shakeMenuGesture + " gesture");
|
|
3026
3584
|
} catch (Exception e) {
|
|
3027
|
-
logger.error("Failed to
|
|
3585
|
+
logger.error("Failed to initialize shake menu: " + e.getMessage());
|
|
3028
3586
|
}
|
|
3029
|
-
shakeMenu = null;
|
|
3030
3587
|
}
|
|
3031
|
-
this.syncShakeMenuLifecycle();
|
|
3032
3588
|
}
|
|
3033
3589
|
|
|
3034
3590
|
private void syncShakeMenuLifecycle() {
|
|
@@ -4406,10 +4962,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
4406
4962
|
isPreviousMainActivity = true;
|
|
4407
4963
|
}
|
|
4408
4964
|
|
|
4409
|
-
|
|
4410
|
-
if (this.shouldListenForShake()) {
|
|
4411
|
-
this.ensureShakeMenuStarted();
|
|
4412
|
-
}
|
|
4965
|
+
this.syncShakeMenuLifecycle();
|
|
4413
4966
|
} catch (Exception e) {
|
|
4414
4967
|
logger.error("Failed to run handleOnStart: " + e.getMessage());
|
|
4415
4968
|
}
|
|
@@ -4441,6 +4994,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
4441
4994
|
backgroundTask.interrupt();
|
|
4442
4995
|
}
|
|
4443
4996
|
this.implementation.activity = getActivity();
|
|
4997
|
+
this.syncShakeMenuLifecycle();
|
|
4444
4998
|
} catch (Exception e) {
|
|
4445
4999
|
logger.error("Failed to run handleOnResume: " + e.getMessage());
|
|
4446
5000
|
}
|
|
@@ -4464,29 +5018,9 @@ public class CapacitorUpdaterPlugin extends Plugin {
|
|
|
4464
5018
|
return;
|
|
4465
5019
|
}
|
|
4466
5020
|
|
|
4467
|
-
final String gesture = call.getString("gesture", null);
|
|
4468
|
-
final boolean gestureChanged;
|
|
4469
|
-
if (gesture != null) {
|
|
4470
|
-
if (!isSupportedShakeMenuGesture(gesture)) {
|
|
4471
|
-
logger.error("Unsupported shake menu gesture: " + gesture);
|
|
4472
|
-
call.reject("Unsupported shake menu gesture. Use \"shake\" or \"threeFingerPinch\".");
|
|
4473
|
-
return;
|
|
4474
|
-
}
|
|
4475
|
-
final String normalizedGesture = normalizedShakeMenuGesture(gesture);
|
|
4476
|
-
gestureChanged = !normalizedGesture.equals(this.shakeMenuGesture);
|
|
4477
|
-
this.shakeMenuGesture = normalizedGesture;
|
|
4478
|
-
} else {
|
|
4479
|
-
gestureChanged = false;
|
|
4480
|
-
}
|
|
4481
|
-
|
|
4482
5021
|
this.shakeMenuEnabled = enabled;
|
|
4483
5022
|
logger.info("Shake menu " + (enabled ? "enabled" : "disabled") + " with " + this.shakeMenuGesture + " gesture");
|
|
4484
|
-
|
|
4485
|
-
if (gestureChanged) {
|
|
4486
|
-
this.restartShakeMenuListener();
|
|
4487
|
-
} else {
|
|
4488
|
-
this.syncShakeMenuLifecycle();
|
|
4489
|
-
}
|
|
5023
|
+
this.syncShakeMenuLifecycle();
|
|
4490
5024
|
|
|
4491
5025
|
call.resolve();
|
|
4492
5026
|
}
|