html2apk 0.3.0 → 0.4.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 +27 -22
- package/examples/minimal/dist/MeuApp-1.0.0-debug.apk +0 -0
- package/package.json +1 -1
- package/src/cordova/project.js +19 -1
- package/src/core/build-apk.js +257 -30
- package/src/desktop/main.js +132 -1
- package/src/desktop/preload.js +13 -0
- package/src/desktop/renderer/index.html +3 -2
- package/src/desktop/renderer/renderer.js +908 -35
- package/src/desktop/renderer/styles.css +60 -2
- package/src/templates/cordova-plugin-html2apk-bridge/src/android/Html2ApkBridge.java +312 -32
- package/src/templates/cordova-plugin-html2apk-bridge/www/html2apk-bridge.js +31 -2
- package/src/templates/html2apk-onesignal.js +1 -1
- package/src/utils/command-runner.js +3 -0
|
@@ -889,7 +889,12 @@ h2 {
|
|
|
889
889
|
gap: 10px;
|
|
890
890
|
}
|
|
891
891
|
|
|
892
|
-
.code-card
|
|
892
|
+
.code-card-top {
|
|
893
|
+
display: grid;
|
|
894
|
+
gap: 8px;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
.code-card-top code {
|
|
893
898
|
overflow-wrap: anywhere;
|
|
894
899
|
color: #d6e4f7;
|
|
895
900
|
background: #0c1117;
|
|
@@ -897,7 +902,7 @@ h2 {
|
|
|
897
902
|
padding: 10px;
|
|
898
903
|
}
|
|
899
904
|
|
|
900
|
-
.code-card span {
|
|
905
|
+
.code-card-top span {
|
|
901
906
|
color: var(--blue);
|
|
902
907
|
font-weight: 800;
|
|
903
908
|
}
|
|
@@ -923,6 +928,59 @@ h2 {
|
|
|
923
928
|
padding-top: 10px;
|
|
924
929
|
}
|
|
925
930
|
|
|
931
|
+
.copy-example {
|
|
932
|
+
border-top: 1px solid var(--line);
|
|
933
|
+
padding-top: 12px;
|
|
934
|
+
display: grid;
|
|
935
|
+
gap: 8px;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
.copy-example-header {
|
|
939
|
+
display: flex;
|
|
940
|
+
align-items: center;
|
|
941
|
+
justify-content: space-between;
|
|
942
|
+
gap: 10px;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
.copy-example-header strong {
|
|
946
|
+
font-size: .88rem;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.copy-code-button {
|
|
950
|
+
min-height: 34px;
|
|
951
|
+
border: 1px solid var(--line);
|
|
952
|
+
border-radius: 8px;
|
|
953
|
+
padding: 0 12px;
|
|
954
|
+
background: var(--bg);
|
|
955
|
+
color: var(--blue);
|
|
956
|
+
font-weight: 800;
|
|
957
|
+
cursor: pointer;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
.copy-code-button.copied {
|
|
961
|
+
color: var(--green);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
.copy-code-button.copy-error {
|
|
965
|
+
color: var(--red);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
.copy-example pre {
|
|
969
|
+
margin: 0;
|
|
970
|
+
max-height: 260px;
|
|
971
|
+
overflow: auto;
|
|
972
|
+
border-radius: 8px;
|
|
973
|
+
background: #0c1117;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
.copy-example pre code {
|
|
977
|
+
display: block;
|
|
978
|
+
padding: 12px;
|
|
979
|
+
color: #d6e4f7;
|
|
980
|
+
font: 12px/1.55 Consolas, "Courier New", monospace;
|
|
981
|
+
white-space: pre;
|
|
982
|
+
}
|
|
983
|
+
|
|
926
984
|
.success-view {
|
|
927
985
|
min-height: 100%;
|
|
928
986
|
display: none;
|
|
@@ -14,6 +14,7 @@ import android.content.ClipboardManager;
|
|
|
14
14
|
import android.content.Context;
|
|
15
15
|
import android.content.Intent;
|
|
16
16
|
import android.content.IntentFilter;
|
|
17
|
+
import android.content.SharedPreferences;
|
|
17
18
|
import android.content.pm.ApplicationInfo;
|
|
18
19
|
import android.content.pm.PackageManager;
|
|
19
20
|
import android.database.Cursor;
|
|
@@ -70,17 +71,25 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
70
71
|
private static final int REQUEST_PICK_FILE = 7411;
|
|
71
72
|
private static final int REQUEST_SAVE_FILE = 7412;
|
|
72
73
|
private static final int REQUEST_PICK_FOLDER = 7413;
|
|
74
|
+
private static final String PREFS_NAME = "html2apk_bridge";
|
|
75
|
+
private static final String PREF_PERMISSION_PREFIX = "permission_requested_";
|
|
73
76
|
|
|
74
77
|
private CallbackContext notificationPermissionCallback;
|
|
75
78
|
private CallbackContext cameraPermissionCallback;
|
|
79
|
+
private CallbackContext pendingNotificationCallback;
|
|
80
|
+
private CallbackContext pendingFlashlightCallback;
|
|
76
81
|
private CallbackContext microphonePermissionCallback;
|
|
77
82
|
private CallbackContext pendingMicStartCallback;
|
|
78
83
|
private CallbackContext filePickerCallback;
|
|
79
84
|
private CallbackContext saveFileCallback;
|
|
80
85
|
private CallbackContext folderPickerCallback;
|
|
81
86
|
private JSONObject pendingSaveFile;
|
|
87
|
+
private JSONObject pendingNotificationOptions;
|
|
82
88
|
private JSONObject initialNotification;
|
|
83
89
|
private JSONObject initialLink;
|
|
90
|
+
private Boolean pendingFlashlightEnabled;
|
|
91
|
+
private boolean pendingNotificationSchedule;
|
|
92
|
+
private boolean pendingFlashlightToggle;
|
|
84
93
|
private boolean overlaySettingsOpened;
|
|
85
94
|
private boolean torchEnabled;
|
|
86
95
|
private MediaRecorder micRecorder;
|
|
@@ -130,6 +139,9 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
130
139
|
try {
|
|
131
140
|
if ("notify".equals(action)) {
|
|
132
141
|
JSONObject options = args.optJSONObject(0);
|
|
142
|
+
if (requestNotificationPermissionForAction(options == null ? new JSONObject() : options, false, callbackContext)) {
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
133
145
|
showNotification(options == null ? new JSONObject() : options);
|
|
134
146
|
callbackContext.success();
|
|
135
147
|
return true;
|
|
@@ -137,6 +149,9 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
137
149
|
|
|
138
150
|
if ("scheduleNotification".equals(action)) {
|
|
139
151
|
JSONObject options = args.optJSONObject(0);
|
|
152
|
+
if (requestNotificationPermissionForAction(options == null ? new JSONObject() : options, true, callbackContext)) {
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
140
155
|
callbackContext.success(scheduleNotification(options == null ? new JSONObject() : options));
|
|
141
156
|
return true;
|
|
142
157
|
}
|
|
@@ -183,14 +198,12 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
183
198
|
}
|
|
184
199
|
|
|
185
200
|
if ("flashlight".equals(action)) {
|
|
186
|
-
|
|
187
|
-
callbackContext.success(flashlightStatus());
|
|
201
|
+
setFlashlightWithPermission(args.optBoolean(0, true), false, callbackContext);
|
|
188
202
|
return true;
|
|
189
203
|
}
|
|
190
204
|
|
|
191
205
|
if ("toggleFlashlight".equals(action)) {
|
|
192
|
-
|
|
193
|
-
callbackContext.success(flashlightStatus());
|
|
206
|
+
setFlashlightWithPermission(false, true, callbackContext);
|
|
194
207
|
return true;
|
|
195
208
|
}
|
|
196
209
|
|
|
@@ -343,7 +356,14 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
343
356
|
|
|
344
357
|
if ("openExactAlarmSettings".equals(action)) {
|
|
345
358
|
openExactAlarmSettings();
|
|
346
|
-
|
|
359
|
+
JSONObject result = new JSONObject();
|
|
360
|
+
result.put("permission", "android.permission.SCHEDULE_EXACT_ALARM");
|
|
361
|
+
result.put("required", Build.VERSION.SDK_INT >= Build.VERSION_CODES.S);
|
|
362
|
+
result.put("granted", canScheduleExactAlarms());
|
|
363
|
+
result.put("permissionGranted", canScheduleExactAlarms());
|
|
364
|
+
result.put("requiresSettings", Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !canScheduleExactAlarms());
|
|
365
|
+
result.put("settingsOpened", Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !canScheduleExactAlarms());
|
|
366
|
+
callbackContext.success(result);
|
|
347
367
|
return true;
|
|
348
368
|
}
|
|
349
369
|
|
|
@@ -354,11 +374,22 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
354
374
|
|
|
355
375
|
if ("requestOverlayPermission".equals(action) || "openOverlaySettings".equals(action)) {
|
|
356
376
|
openOverlaySettings();
|
|
357
|
-
|
|
377
|
+
JSONObject result = overlayPermissionStatus();
|
|
378
|
+
result.put("requested", true);
|
|
379
|
+
result.put("settingsOpened", result.optBoolean("requiresSettings"));
|
|
380
|
+
callbackContext.success(result);
|
|
358
381
|
return true;
|
|
359
382
|
}
|
|
360
383
|
|
|
361
384
|
if ("startFloatingIcon".equals(action)) {
|
|
385
|
+
if (!canDrawOverlays()) {
|
|
386
|
+
openOverlaySettings();
|
|
387
|
+
JSONObject result = overlayPermissionStatus();
|
|
388
|
+
result.put("requested", true);
|
|
389
|
+
result.put("requiresSettings", true);
|
|
390
|
+
callbackContext.success(result);
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
362
393
|
startFloatingIcon();
|
|
363
394
|
callbackContext.success(overlayPermissionStatus());
|
|
364
395
|
return true;
|
|
@@ -391,14 +422,50 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
391
422
|
|
|
392
423
|
@Override
|
|
393
424
|
public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
|
|
394
|
-
if (requestCode == REQUEST_CAMERA
|
|
425
|
+
if (requestCode == REQUEST_CAMERA) {
|
|
395
426
|
boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
|
|
427
|
+
if (pendingFlashlightCallback != null) {
|
|
428
|
+
CallbackContext callback = pendingFlashlightCallback;
|
|
429
|
+
Boolean enabled = pendingFlashlightEnabled;
|
|
430
|
+
boolean toggle = pendingFlashlightToggle;
|
|
431
|
+
pendingFlashlightCallback = null;
|
|
432
|
+
pendingFlashlightEnabled = null;
|
|
433
|
+
pendingFlashlightToggle = false;
|
|
434
|
+
|
|
435
|
+
try {
|
|
436
|
+
if (!granted) {
|
|
437
|
+
JSONObject result = shouldOpenSettingsForRuntimePermission(Manifest.permission.CAMERA)
|
|
438
|
+
? openSettingsForRuntimePermission(Manifest.permission.CAMERA, true, true)
|
|
439
|
+
: flashlightStatus();
|
|
440
|
+
result.put("requested", true);
|
|
441
|
+
result.put("granted", false);
|
|
442
|
+
callback.success(result);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
setFlashlight(toggle ? !torchEnabled : Boolean.TRUE.equals(enabled));
|
|
447
|
+
JSONObject result = flashlightStatus();
|
|
448
|
+
result.put("requested", true);
|
|
449
|
+
result.put("granted", true);
|
|
450
|
+
callback.success(result);
|
|
451
|
+
} catch (Exception error) {
|
|
452
|
+
callback.error(error.getMessage());
|
|
453
|
+
}
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (cameraPermissionCallback == null) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
396
461
|
try {
|
|
397
|
-
JSONObject result =
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
462
|
+
JSONObject result = granted
|
|
463
|
+
? runtimePermissionResult(Manifest.permission.CAMERA, true, true, true)
|
|
464
|
+
: (
|
|
465
|
+
shouldOpenSettingsForRuntimePermission(Manifest.permission.CAMERA)
|
|
466
|
+
? openSettingsForRuntimePermission(Manifest.permission.CAMERA, true, true)
|
|
467
|
+
: runtimePermissionResult(Manifest.permission.CAMERA, true, true, false)
|
|
468
|
+
);
|
|
402
469
|
cameraPermissionCallback.success(result);
|
|
403
470
|
} catch (Exception error) {
|
|
404
471
|
cameraPermissionCallback.error(error.getMessage());
|
|
@@ -423,7 +490,13 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
423
490
|
if (shouldStartRecording && granted) {
|
|
424
491
|
startMicRecorder(callback);
|
|
425
492
|
} else {
|
|
426
|
-
JSONObject result =
|
|
493
|
+
JSONObject result = granted
|
|
494
|
+
? microphoneStatus()
|
|
495
|
+
: (
|
|
496
|
+
shouldOpenSettingsForRuntimePermission(Manifest.permission.RECORD_AUDIO)
|
|
497
|
+
? openSettingsForRuntimePermission(Manifest.permission.RECORD_AUDIO, true, true)
|
|
498
|
+
: microphoneStatus()
|
|
499
|
+
);
|
|
427
500
|
result.put("requested", true);
|
|
428
501
|
result.put("granted", granted);
|
|
429
502
|
callback.success(result);
|
|
@@ -434,13 +507,57 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
434
507
|
return;
|
|
435
508
|
}
|
|
436
509
|
|
|
437
|
-
if (requestCode != REQUEST_POST_NOTIFICATIONS
|
|
510
|
+
if (requestCode != REQUEST_POST_NOTIFICATIONS) {
|
|
438
511
|
return;
|
|
439
512
|
}
|
|
440
513
|
|
|
441
514
|
boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
|
|
515
|
+
if (pendingNotificationCallback != null) {
|
|
516
|
+
CallbackContext callback = pendingNotificationCallback;
|
|
517
|
+
JSONObject options = pendingNotificationOptions == null ? new JSONObject() : pendingNotificationOptions;
|
|
518
|
+
boolean schedule = pendingNotificationSchedule;
|
|
519
|
+
pendingNotificationCallback = null;
|
|
520
|
+
pendingNotificationOptions = null;
|
|
521
|
+
pendingNotificationSchedule = false;
|
|
522
|
+
|
|
523
|
+
try {
|
|
524
|
+
if (!granted) {
|
|
525
|
+
JSONObject result = shouldOpenSettingsForRuntimePermission(Manifest.permission.POST_NOTIFICATIONS)
|
|
526
|
+
? openSettingsForRuntimePermission(Manifest.permission.POST_NOTIFICATIONS, true, true)
|
|
527
|
+
: notificationPermissionStatus();
|
|
528
|
+
result.put("requested", true);
|
|
529
|
+
result.put("granted", false);
|
|
530
|
+
callback.success(result);
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (schedule) {
|
|
535
|
+
JSONObject result = scheduleNotification(options);
|
|
536
|
+
result.put("requested", true);
|
|
537
|
+
result.put("granted", true);
|
|
538
|
+
callback.success(result);
|
|
539
|
+
} else {
|
|
540
|
+
showNotification(options);
|
|
541
|
+
callback.success();
|
|
542
|
+
}
|
|
543
|
+
} catch (Exception error) {
|
|
544
|
+
callback.error(error.getMessage());
|
|
545
|
+
}
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (notificationPermissionCallback == null) {
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
|
|
442
553
|
try {
|
|
443
|
-
JSONObject result =
|
|
554
|
+
JSONObject result = granted
|
|
555
|
+
? notificationPermissionStatus()
|
|
556
|
+
: (
|
|
557
|
+
shouldOpenSettingsForRuntimePermission(Manifest.permission.POST_NOTIFICATIONS)
|
|
558
|
+
? openSettingsForRuntimePermission(Manifest.permission.POST_NOTIFICATIONS, true, true)
|
|
559
|
+
: notificationPermissionStatus()
|
|
560
|
+
);
|
|
444
561
|
result.put("requested", true);
|
|
445
562
|
result.put("granted", granted);
|
|
446
563
|
notificationPermissionCallback.success(result);
|
|
@@ -472,6 +589,78 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
472
589
|
return this.cordova.getActivity().getApplicationContext();
|
|
473
590
|
}
|
|
474
591
|
|
|
592
|
+
private SharedPreferences preferencesStore() {
|
|
593
|
+
return context().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
private boolean wasRuntimePermissionRequested(String permission) {
|
|
597
|
+
return preferencesStore().getBoolean(PREF_PERMISSION_PREFIX + permission, false);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
private void rememberRuntimePermissionRequest(String permission) {
|
|
601
|
+
preferencesStore().edit().putBoolean(PREF_PERMISSION_PREFIX + permission, true).apply();
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
private boolean shouldOpenSettingsForRuntimePermission(String permission) {
|
|
605
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || !wasRuntimePermissionRequested(permission)) {
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
return !cordova.getActivity().shouldShowRequestPermissionRationale(permission);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
private JSONObject runtimePermissionResult(String permission, boolean required, boolean requested, boolean granted) throws Exception {
|
|
613
|
+
JSONObject result = new JSONObject();
|
|
614
|
+
result.put("permission", permission);
|
|
615
|
+
result.put("required", required);
|
|
616
|
+
result.put("requested", requested);
|
|
617
|
+
result.put("granted", granted);
|
|
618
|
+
result.put("permissionGranted", granted);
|
|
619
|
+
result.put("requiresSettings", required && !granted && shouldOpenSettingsForRuntimePermission(permission));
|
|
620
|
+
result.put("settingsOpened", false);
|
|
621
|
+
return result;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private JSONObject openSettingsForRuntimePermission(String permission, boolean required, boolean requested) throws Exception {
|
|
625
|
+
JSONObject result = runtimePermissionResult(permission, required, requested, false);
|
|
626
|
+
openPermissionSettings(permission);
|
|
627
|
+
result.put("requiresSettings", true);
|
|
628
|
+
result.put("settingsOpened", true);
|
|
629
|
+
result.put("settingsScreen", Manifest.permission.POST_NOTIFICATIONS.equals(permission) ? "notifications" : "app");
|
|
630
|
+
result.put("telaConfiguracao", result.optString("settingsScreen"));
|
|
631
|
+
return result;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
private void openPermissionSettings(String permission) {
|
|
635
|
+
if (Manifest.permission.POST_NOTIFICATIONS.equals(permission)) {
|
|
636
|
+
openNotificationSettings();
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
openAppSettings();
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
private void openAppSettings() {
|
|
644
|
+
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
|
645
|
+
intent.setData(Uri.parse("package:" + context().getPackageName()));
|
|
646
|
+
cordova.getActivity().startActivity(intent);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
private void openNotificationSettings() {
|
|
650
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
|
651
|
+
openAppSettings();
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
|
|
656
|
+
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context().getPackageName());
|
|
657
|
+
try {
|
|
658
|
+
cordova.getActivity().startActivity(intent);
|
|
659
|
+
} catch (ActivityNotFoundException error) {
|
|
660
|
+
openAppSettings();
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
475
664
|
private boolean isFloatingMode() {
|
|
476
665
|
return "floating".equals(preferences.getString("Html2ApkMode", ""));
|
|
477
666
|
}
|
|
@@ -507,17 +696,24 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
507
696
|
result.put("required", Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
|
|
508
697
|
result.put("granted", canDrawOverlays());
|
|
509
698
|
result.put("permission", "android.permission.SYSTEM_ALERT_WINDOW");
|
|
699
|
+
result.put("permissionGranted", canDrawOverlays());
|
|
700
|
+
result.put("requiresSettings", Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !canDrawOverlays());
|
|
701
|
+
result.put("settingsOpened", false);
|
|
510
702
|
return result;
|
|
511
703
|
}
|
|
512
704
|
|
|
513
705
|
private void openOverlaySettings() {
|
|
514
|
-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
|
706
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || canDrawOverlays()) {
|
|
515
707
|
return;
|
|
516
708
|
}
|
|
517
709
|
|
|
518
710
|
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
|
|
519
711
|
intent.setData(Uri.parse("package:" + context().getPackageName()));
|
|
520
|
-
|
|
712
|
+
try {
|
|
713
|
+
cordova.getActivity().startActivity(intent);
|
|
714
|
+
} catch (ActivityNotFoundException error) {
|
|
715
|
+
openAppSettings();
|
|
716
|
+
}
|
|
521
717
|
}
|
|
522
718
|
|
|
523
719
|
private void startFloatingIcon() throws Exception {
|
|
@@ -561,21 +757,42 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
561
757
|
return;
|
|
562
758
|
}
|
|
563
759
|
|
|
760
|
+
if (shouldOpenSettingsForRuntimePermission(Manifest.permission.POST_NOTIFICATIONS)) {
|
|
761
|
+
callbackContext.success(openSettingsForRuntimePermission(Manifest.permission.POST_NOTIFICATIONS, true, false));
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
|
|
564
765
|
notificationPermissionCallback = callbackContext;
|
|
766
|
+
rememberRuntimePermissionRequest(Manifest.permission.POST_NOTIFICATIONS);
|
|
565
767
|
cordova.requestPermission(this, REQUEST_POST_NOTIFICATIONS, Manifest.permission.POST_NOTIFICATIONS);
|
|
566
768
|
}
|
|
567
769
|
|
|
568
770
|
private JSONObject notificationPermissionStatus() throws Exception {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
771
|
+
boolean required = Build.VERSION.SDK_INT >= 33;
|
|
772
|
+
return runtimePermissionResult(Manifest.permission.POST_NOTIFICATIONS, required, false, hasNotificationPermission());
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
private boolean requestNotificationPermissionForAction(JSONObject options, boolean schedule, CallbackContext callbackContext) throws Exception {
|
|
776
|
+
if (hasNotificationPermission()) {
|
|
777
|
+
return false;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
if (shouldOpenSettingsForRuntimePermission(Manifest.permission.POST_NOTIFICATIONS)) {
|
|
781
|
+
callbackContext.success(openSettingsForRuntimePermission(Manifest.permission.POST_NOTIFICATIONS, true, false));
|
|
782
|
+
return true;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
pendingNotificationOptions = options;
|
|
786
|
+
pendingNotificationSchedule = schedule;
|
|
787
|
+
pendingNotificationCallback = callbackContext;
|
|
788
|
+
rememberRuntimePermissionRequest(Manifest.permission.POST_NOTIFICATIONS);
|
|
789
|
+
cordova.requestPermission(this, REQUEST_POST_NOTIFICATIONS, Manifest.permission.POST_NOTIFICATIONS);
|
|
790
|
+
return true;
|
|
574
791
|
}
|
|
575
792
|
|
|
576
793
|
private void showNotification(JSONObject options) throws Exception {
|
|
577
794
|
if (!hasNotificationPermission()) {
|
|
578
|
-
throw new Exception("POST_NOTIFICATIONS permission is not granted.
|
|
795
|
+
throw new Exception("POST_NOTIFICATIONS permission is not granted.");
|
|
579
796
|
}
|
|
580
797
|
|
|
581
798
|
ensureNotificationChannel(context());
|
|
@@ -607,8 +824,15 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
607
824
|
options.put("id", id);
|
|
608
825
|
options.put("quando", when);
|
|
609
826
|
options.put("when", when);
|
|
827
|
+
boolean exactRequested = wantsExactAlarm(options);
|
|
828
|
+
boolean exactAllowed = canScheduleExactAlarms();
|
|
829
|
+
boolean settingsOpened = false;
|
|
830
|
+
if (exactRequested && !exactAllowed) {
|
|
831
|
+
openExactAlarmSettings();
|
|
832
|
+
settingsOpened = true;
|
|
833
|
+
}
|
|
610
834
|
NotificationStore.save(context(), id, when, options);
|
|
611
|
-
NotificationReceiver.schedule(context(), id, when, options,
|
|
835
|
+
NotificationReceiver.schedule(context(), id, when, options, exactAllowed);
|
|
612
836
|
|
|
613
837
|
JSONObject result = new JSONObject();
|
|
614
838
|
result.put("id", id);
|
|
@@ -616,9 +840,24 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
616
840
|
result.put("quando", when);
|
|
617
841
|
result.put("repeating", repeatInterval(options) > 0);
|
|
618
842
|
result.put("loop", loopNotifications(options).length() > 0);
|
|
843
|
+
result.put("exactRequested", exactRequested);
|
|
844
|
+
result.put("exatoSolicitado", exactRequested);
|
|
845
|
+
result.put("exactAllowed", exactAllowed);
|
|
846
|
+
result.put("exatoPermitido", exactAllowed);
|
|
847
|
+
result.put("requiresSettings", exactRequested && !exactAllowed);
|
|
848
|
+
result.put("settingsOpened", settingsOpened);
|
|
619
849
|
return result;
|
|
620
850
|
}
|
|
621
851
|
|
|
852
|
+
private boolean wantsExactAlarm(JSONObject options) {
|
|
853
|
+
return options.optBoolean("exato",
|
|
854
|
+
options.optBoolean("exact",
|
|
855
|
+
options.optBoolean("alarmeExato",
|
|
856
|
+
options.optBoolean("exactAlarm",
|
|
857
|
+
options.optBoolean("preciso",
|
|
858
|
+
options.optBoolean("precise", false))))));
|
|
859
|
+
}
|
|
860
|
+
|
|
622
861
|
private void cancelNotification(Object input) throws Exception {
|
|
623
862
|
int id = notificationIdFromObject(input);
|
|
624
863
|
if (id == 0) {
|
|
@@ -635,14 +874,18 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
635
874
|
}
|
|
636
875
|
|
|
637
876
|
private void openExactAlarmSettings() {
|
|
638
|
-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
|
877
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || canScheduleExactAlarms()) {
|
|
639
878
|
return;
|
|
640
879
|
}
|
|
641
880
|
|
|
642
881
|
Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
|
|
643
882
|
intent.setData(Uri.parse("package:" + context().getPackageName()));
|
|
644
883
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
645
|
-
|
|
884
|
+
try {
|
|
885
|
+
context().startActivity(intent);
|
|
886
|
+
} catch (ActivityNotFoundException error) {
|
|
887
|
+
openAppSettings();
|
|
888
|
+
}
|
|
646
889
|
}
|
|
647
890
|
|
|
648
891
|
private void vibrate(long ms) {
|
|
@@ -822,15 +1065,17 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
822
1065
|
|
|
823
1066
|
private void requestCameraPermission(CallbackContext callbackContext) throws Exception {
|
|
824
1067
|
if (hasCameraPermission()) {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
1068
|
+
callbackContext.success(runtimePermissionResult(Manifest.permission.CAMERA, true, false, true));
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
if (shouldOpenSettingsForRuntimePermission(Manifest.permission.CAMERA)) {
|
|
1073
|
+
callbackContext.success(openSettingsForRuntimePermission(Manifest.permission.CAMERA, true, false));
|
|
830
1074
|
return;
|
|
831
1075
|
}
|
|
832
1076
|
|
|
833
1077
|
cameraPermissionCallback = callbackContext;
|
|
1078
|
+
rememberRuntimePermissionRequest(Manifest.permission.CAMERA);
|
|
834
1079
|
cordova.requestPermission(this, REQUEST_CAMERA, Manifest.permission.CAMERA);
|
|
835
1080
|
}
|
|
836
1081
|
|
|
@@ -847,7 +1092,13 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
847
1092
|
return;
|
|
848
1093
|
}
|
|
849
1094
|
|
|
1095
|
+
if (shouldOpenSettingsForRuntimePermission(Manifest.permission.RECORD_AUDIO)) {
|
|
1096
|
+
callbackContext.success(openSettingsForRuntimePermission(Manifest.permission.RECORD_AUDIO, true, false));
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
850
1100
|
microphonePermissionCallback = callbackContext;
|
|
1101
|
+
rememberRuntimePermissionRequest(Manifest.permission.RECORD_AUDIO);
|
|
851
1102
|
cordova.requestPermission(this, REQUEST_RECORD_AUDIO, Manifest.permission.RECORD_AUDIO);
|
|
852
1103
|
}
|
|
853
1104
|
|
|
@@ -857,6 +1108,8 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
857
1108
|
result.put("required", true);
|
|
858
1109
|
result.put("granted", hasMicrophonePermission());
|
|
859
1110
|
result.put("permissionGranted", hasMicrophonePermission());
|
|
1111
|
+
result.put("requiresSettings", !hasMicrophonePermission() && shouldOpenSettingsForRuntimePermission(Manifest.permission.RECORD_AUDIO));
|
|
1112
|
+
result.put("settingsOpened", false);
|
|
860
1113
|
result.put("recording", micRecorder != null);
|
|
861
1114
|
result.put("gravando", micRecorder != null);
|
|
862
1115
|
if (micRecorder != null) {
|
|
@@ -878,7 +1131,13 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
878
1131
|
}
|
|
879
1132
|
|
|
880
1133
|
if (!hasMicrophonePermission()) {
|
|
1134
|
+
if (shouldOpenSettingsForRuntimePermission(Manifest.permission.RECORD_AUDIO)) {
|
|
1135
|
+
callbackContext.success(openSettingsForRuntimePermission(Manifest.permission.RECORD_AUDIO, true, false));
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
881
1139
|
pendingMicStartCallback = callbackContext;
|
|
1140
|
+
rememberRuntimePermissionRequest(Manifest.permission.RECORD_AUDIO);
|
|
882
1141
|
cordova.requestPermission(this, REQUEST_RECORD_AUDIO, Manifest.permission.RECORD_AUDIO);
|
|
883
1142
|
return;
|
|
884
1143
|
}
|
|
@@ -1046,7 +1305,7 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
1046
1305
|
|
|
1047
1306
|
private void setFlashlight(boolean enabled) throws Exception {
|
|
1048
1307
|
if (!hasCameraPermission()) {
|
|
1049
|
-
throw new Exception("CAMERA permission is not granted.
|
|
1308
|
+
throw new Exception("CAMERA permission is not granted.");
|
|
1050
1309
|
}
|
|
1051
1310
|
|
|
1052
1311
|
CameraManager manager = (CameraManager) context().getSystemService(Context.CAMERA_SERVICE);
|
|
@@ -1058,12 +1317,33 @@ public class Html2ApkBridge extends CordovaPlugin {
|
|
|
1058
1317
|
torchEnabled = enabled;
|
|
1059
1318
|
}
|
|
1060
1319
|
|
|
1320
|
+
private void setFlashlightWithPermission(boolean enabled, boolean toggle, CallbackContext callbackContext) throws Exception {
|
|
1321
|
+
if (!hasCameraPermission()) {
|
|
1322
|
+
if (shouldOpenSettingsForRuntimePermission(Manifest.permission.CAMERA)) {
|
|
1323
|
+
callbackContext.success(openSettingsForRuntimePermission(Manifest.permission.CAMERA, true, false));
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
pendingFlashlightCallback = callbackContext;
|
|
1328
|
+
pendingFlashlightEnabled = enabled;
|
|
1329
|
+
pendingFlashlightToggle = toggle;
|
|
1330
|
+
rememberRuntimePermissionRequest(Manifest.permission.CAMERA);
|
|
1331
|
+
cordova.requestPermission(this, REQUEST_CAMERA, Manifest.permission.CAMERA);
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
setFlashlight(toggle ? !torchEnabled : enabled);
|
|
1336
|
+
callbackContext.success(flashlightStatus());
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1061
1339
|
private JSONObject flashlightStatus() throws Exception {
|
|
1062
1340
|
JSONObject result = new JSONObject();
|
|
1063
1341
|
result.put("available", context().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH));
|
|
1064
1342
|
result.put("enabled", torchEnabled);
|
|
1065
1343
|
result.put("permission", "android.permission.CAMERA");
|
|
1066
1344
|
result.put("permissionGranted", hasCameraPermission());
|
|
1345
|
+
result.put("requiresSettings", !hasCameraPermission() && shouldOpenSettingsForRuntimePermission(Manifest.permission.CAMERA));
|
|
1346
|
+
result.put("settingsOpened", false);
|
|
1067
1347
|
return result;
|
|
1068
1348
|
}
|
|
1069
1349
|
|
|
@@ -7,6 +7,8 @@ var eventListeners = {};
|
|
|
7
7
|
var initialNotification = null;
|
|
8
8
|
var initialLink = null;
|
|
9
9
|
var scheduledNotificationCounter = 0;
|
|
10
|
+
var deviceReady = typeof document === "undefined";
|
|
11
|
+
var deviceReadyCallbacks = [];
|
|
10
12
|
var eventAliases = {
|
|
11
13
|
"app:ready": "app:pronto",
|
|
12
14
|
"app:paused": "app:pausado",
|
|
@@ -20,9 +22,36 @@ var eventAliases = {
|
|
|
20
22
|
"notification:clicked": "notificacao:clicada"
|
|
21
23
|
};
|
|
22
24
|
|
|
25
|
+
function markDeviceReady() {
|
|
26
|
+
if (deviceReady) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
deviceReady = true;
|
|
31
|
+
deviceReadyCallbacks.splice(0).forEach(function (callback) {
|
|
32
|
+
callback();
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function whenDeviceReady() {
|
|
37
|
+
if (deviceReady) {
|
|
38
|
+
return Promise.resolve();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return new Promise(function (resolve) {
|
|
42
|
+
deviceReadyCallbacks.push(resolve);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (typeof document !== "undefined") {
|
|
47
|
+
document.addEventListener("deviceready", markDeviceReady, false);
|
|
48
|
+
}
|
|
49
|
+
|
|
23
50
|
function call(action, args) {
|
|
24
|
-
return
|
|
25
|
-
|
|
51
|
+
return whenDeviceReady().then(function () {
|
|
52
|
+
return new Promise(function (resolve, reject) {
|
|
53
|
+
exec(resolve, reject, "Html2ApkBridge", action, args || []);
|
|
54
|
+
});
|
|
26
55
|
});
|
|
27
56
|
}
|
|
28
57
|
|