html2apk 0.9.0 → 0.11.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.
@@ -414,6 +414,8 @@ function nativeFunctionLabHtml() {
414
414
  --green: #18864b;
415
415
  --red: #c33b3b;
416
416
  --code: #0c1117;
417
+ --soft-green: #e8f7ef;
418
+ --soft-amber: #fff6dd;
417
419
  }
418
420
  * { box-sizing: border-box; }
419
421
  body {
@@ -421,6 +423,7 @@ function nativeFunctionLabHtml() {
421
423
  font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
422
424
  background: var(--bg);
423
425
  color: var(--text);
426
+ line-height: 1.45;
424
427
  }
425
428
  header {
426
429
  position: sticky;
@@ -434,6 +437,7 @@ function nativeFunctionLabHtml() {
434
437
  h1 { margin: 0; font-size: 1.2rem; }
435
438
  header p { margin: 6px 0 0; color: var(--muted); line-height: 1.35; }
436
439
  main { display: grid; gap: 14px; padding: 14px; }
440
+ #groups { display: grid; gap: 14px; }
437
441
  section {
438
442
  border: 1px solid var(--line);
439
443
  border-radius: 8px;
@@ -446,6 +450,52 @@ function nativeFunctionLabHtml() {
446
450
  font-size: .98rem;
447
451
  border-bottom: 1px solid var(--line);
448
452
  }
453
+ h2.with-action {
454
+ display: flex;
455
+ align-items: center;
456
+ justify-content: space-between;
457
+ gap: 10px;
458
+ }
459
+ h2.with-action button {
460
+ min-height: 32px;
461
+ width: auto;
462
+ padding: 6px 9px;
463
+ font-size: .78rem;
464
+ text-align: center;
465
+ white-space: nowrap;
466
+ }
467
+ .toolbar {
468
+ display: grid;
469
+ grid-template-columns: repeat(4, minmax(0, 1fr));
470
+ gap: 8px;
471
+ margin-top: 12px;
472
+ }
473
+ .toolbar input {
474
+ grid-column: 1 / -1;
475
+ min-height: 42px;
476
+ width: 100%;
477
+ border: 1px solid var(--line);
478
+ border-radius: 8px;
479
+ background: var(--panel);
480
+ color: var(--text);
481
+ padding: 9px 11px;
482
+ font: inherit;
483
+ }
484
+ .stats {
485
+ display: flex;
486
+ flex-wrap: wrap;
487
+ gap: 8px;
488
+ margin-top: 10px;
489
+ }
490
+ .chip {
491
+ border: 1px solid var(--line);
492
+ border-radius: 999px;
493
+ color: var(--muted);
494
+ background: var(--panel);
495
+ padding: 4px 9px;
496
+ font-size: .78rem;
497
+ font-weight: 800;
498
+ }
449
499
  .grid {
450
500
  display: grid;
451
501
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
@@ -462,7 +512,15 @@ function nativeFunctionLabHtml() {
462
512
  font-weight: 800;
463
513
  text-align: left;
464
514
  }
515
+ button[disabled] { opacity: .68; }
465
516
  button:active { transform: translateY(1px); }
517
+ button.primary { background: var(--blue); border-color: var(--blue); color: #fff; }
518
+ button.safe { background: var(--soft-green); color: var(--green); }
519
+ button.listener { background: var(--soft-amber); color: #8a5f00; }
520
+ button.external { background: #f2edff; color: #6b46c1; }
521
+ button.running { outline: 2px solid var(--blue); }
522
+ button.ok { border-color: var(--green); }
523
+ button.fail { border-color: var(--red); }
466
524
  button small { display: block; margin-top: 4px; color: var(--muted); font-weight: 600; line-height: 1.3; }
467
525
  .danger { background: #fff0f0; color: var(--red); }
468
526
  .notice {
@@ -473,6 +531,57 @@ function nativeFunctionLabHtml() {
473
531
  color: #745400;
474
532
  line-height: 1.42;
475
533
  }
534
+ .output-head {
535
+ display: flex;
536
+ align-items: center;
537
+ justify-content: space-between;
538
+ gap: 10px;
539
+ padding: 12px;
540
+ border-bottom: 1px solid var(--line);
541
+ }
542
+ .output-head h2 { padding: 0; border: 0; }
543
+ .output-feed {
544
+ display: grid;
545
+ gap: 8px;
546
+ max-height: 360px;
547
+ overflow: auto;
548
+ padding: 12px;
549
+ }
550
+ .log-entry {
551
+ border: 1px solid var(--line);
552
+ border-left: 4px solid var(--blue);
553
+ border-radius: 8px;
554
+ padding: 9px;
555
+ background: color-mix(in srgb, var(--panel) 96%, var(--blue));
556
+ }
557
+ .log-entry.ok { border-left-color: var(--green); }
558
+ .log-entry.error { border-left-color: var(--red); }
559
+ .log-entry strong { display: block; font-size: .9rem; }
560
+ .log-entry time { display: block; margin-top: 2px; color: var(--muted); font-size: .74rem; }
561
+ .log-entry pre {
562
+ margin: 8px 0 0;
563
+ white-space: pre-wrap;
564
+ word-break: break-word;
565
+ color: #dfe9f8;
566
+ background: var(--code);
567
+ border-radius: 7px;
568
+ padding: 8px;
569
+ font: .78rem/1.45 ui-monospace, SFMono-Regular, Consolas, monospace;
570
+ }
571
+ .guide {
572
+ display: grid;
573
+ grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
574
+ gap: 10px;
575
+ padding: 12px;
576
+ }
577
+ .guide article {
578
+ border: 1px solid var(--line);
579
+ border-radius: 8px;
580
+ padding: 10px;
581
+ background: color-mix(in srgb, var(--panel) 96%, var(--blue));
582
+ }
583
+ .guide strong { display: block; margin-bottom: 4px; }
584
+ .guide p { margin: 0; color: var(--muted); font-size: .88rem; }
476
585
  @media (prefers-color-scheme: dark) {
477
586
  :root {
478
587
  --bg: #10141b;
@@ -480,19 +589,51 @@ function nativeFunctionLabHtml() {
480
589
  --text: #e6edf7;
481
590
  --muted: #9aa8ba;
482
591
  --line: #283243;
592
+ --soft-green: #122d22;
593
+ --soft-amber: #332a12;
483
594
  }
484
595
  button { background: #172642; }
485
596
  .danger { background: #351c20; }
486
597
  .notice { background: #2d2816; color: #f2cc60; }
487
598
  }
599
+ @media (max-width: 720px) {
600
+ .toolbar { grid-template-columns: 1fr 1fr; }
601
+ h2.with-action { align-items: flex-start; flex-direction: column; }
602
+ }
488
603
  </style>
489
604
  </head>
490
605
  <body>
491
606
  <header>
492
607
  <h1>Teste de funcoes html2apk</h1>
493
- <p>Toque nos botoes para chamar as funcoes interpretadas do APK. Algumas abrem permissoes, camera, seletor de arquivo ou outro app Android.</p>
608
+ <p>Use botoes manuais, lotes seguros e eventos passivos para testar as funcoes interpretadas do APK. Os resultados aparecem aqui e tambem no console runtime.</p>
609
+ <div class="toolbar" aria-label="Controles do laboratorio">
610
+ <button id="runSafeButton" class="primary" type="button">Rodar testes seguros</button>
611
+ <button id="runPrepareButton" type="button">Preparar dados</button>
612
+ <button id="registerEventsButton" type="button">Registrar eventos</button>
613
+ <button id="clearLogButton" type="button">Limpar resultados</button>
614
+ <input id="filterInput" type="search" placeholder="Filtrar funcao, evento ou categoria">
615
+ </div>
616
+ <div id="stats" class="stats" aria-live="polite"></div>
494
617
  </header>
495
- <main id="groups"></main>
618
+ <main>
619
+ <section aria-label="Resultado ao vivo">
620
+ <div class="output-head">
621
+ <h2>Resultado ao vivo</h2>
622
+ <span class="chip">Novos no topo</span>
623
+ </div>
624
+ <div id="outputFeed" class="output-feed" aria-live="polite"></div>
625
+ </section>
626
+ <section aria-label="Como testar eventos passivos">
627
+ <h2>Eventos que nao dependem de botao</h2>
628
+ <div class="guide">
629
+ <article><strong>USB, fone e volume</strong><p>Conecte/desconecte cabo, fone ou mude o volume fisico. O evento aparece no resultado ao vivo.</p></article>
630
+ <article><strong>Teclado</strong><p>Toque no campo de filtro para abrir o teclado; feche o teclado para testar o evento inverso.</p></article>
631
+ <article><strong>Sensores</strong><p>Sacuda o aparelho, vire a tela para baixo ou aproxime a mao do sensor de proximidade.</p></article>
632
+ <article><strong>Notificacao e share</strong><p>Use os botoes de notificacao/compartilhamento e observe os callbacks registrados automaticamente.</p></article>
633
+ </div>
634
+ </section>
635
+ <div id="groups"></div>
636
+ </main>
496
637
  <script>
497
638
  (function () {
498
639
  var state = {
@@ -503,7 +644,10 @@ function nativeFunctionLabHtml() {
503
644
  lastImage: null,
504
645
  lastPhoto: null,
505
646
  micRecording: false,
506
- eventsReady: false
647
+ eventsReady: false,
648
+ eventStops: [],
649
+ outputCount: 0,
650
+ sequenceRunning: false
507
651
  };
508
652
  var sampleImageBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAAASUVORK5CYII=";
509
653
 
@@ -514,11 +658,78 @@ function nativeFunctionLabHtml() {
514
658
  return window[name];
515
659
  }
516
660
 
661
+ function delay(ms) {
662
+ return new Promise(function (resolve) {
663
+ setTimeout(resolve, ms);
664
+ });
665
+ }
666
+
667
+ function safeValue(value) {
668
+ if (value instanceof Error) {
669
+ return {
670
+ name: value.name,
671
+ message: value.message,
672
+ stack: value.stack
673
+ };
674
+ }
675
+ if (typeof value === "undefined") {
676
+ return undefined;
677
+ }
678
+ try {
679
+ return JSON.parse(JSON.stringify(value));
680
+ } catch (error) {
681
+ return String(value);
682
+ }
683
+ }
684
+
685
+ function valueToText(value) {
686
+ var normalized = safeValue(value);
687
+ if (typeof normalized === "undefined") {
688
+ return "";
689
+ }
690
+ if (typeof normalized === "string") {
691
+ return normalized;
692
+ }
693
+ return JSON.stringify(normalized, null, 2);
694
+ }
695
+
696
+ function appendOutput(title, value, kind) {
697
+ var feed = document.getElementById("outputFeed");
698
+ var entry;
699
+ var pre;
700
+ var textValue;
701
+
702
+ if (!feed) {
703
+ return;
704
+ }
705
+
706
+ state.outputCount += 1;
707
+ entry = document.createElement("article");
708
+ entry.className = "log-entry " + (kind === "error" ? "error" : (kind === "ok" ? "ok" : "info"));
709
+ entry.innerHTML = "<strong></strong><time></time>";
710
+ entry.querySelector("strong").textContent = title;
711
+ entry.querySelector("time").textContent = new Date().toLocaleTimeString();
712
+
713
+ textValue = valueToText(value);
714
+ if (textValue) {
715
+ pre = document.createElement("pre");
716
+ pre.textContent = textValue;
717
+ entry.appendChild(pre);
718
+ }
719
+
720
+ feed.prepend(entry);
721
+ while (feed.children.length > 80) {
722
+ feed.lastElementChild.remove();
723
+ }
724
+ updateStats();
725
+ }
726
+
517
727
  function log(title, value, kind) {
518
728
  var consoleKind = kind === "err" ? "error" : (kind === "ok" ? "ok" : "info");
519
729
  var hasValue = value !== "" && typeof value !== "undefined";
730
+ appendOutput(title, hasValue ? value : undefined, consoleKind);
520
731
  if (window.Html2ApkRuntimeConsole && typeof window.Html2ApkRuntimeConsole.log === "function") {
521
- window.Html2ApkRuntimeConsole.log(consoleKind, title, hasValue ? value : undefined);
732
+ window.Html2ApkRuntimeConsole.log(consoleKind, title, hasValue ? safeValue(value) : undefined);
522
733
  return;
523
734
  }
524
735
  if (consoleKind === "error") {
@@ -532,54 +743,181 @@ function nativeFunctionLabHtml() {
532
743
 
533
744
  async function run(id) {
534
745
  var test = actions[id];
746
+ var button = document.querySelector("[data-action='" + id + "']");
747
+ var result;
535
748
  if (!test) {
536
749
  return;
537
750
  }
751
+ if (button) {
752
+ button.classList.remove("ok", "fail");
753
+ button.classList.add("running");
754
+ button.disabled = true;
755
+ }
538
756
  log("Executando " + test.title, "", "");
539
757
  try {
540
- var result = await test.run();
758
+ result = await test.run();
541
759
  log("OK: " + test.title, result, "ok");
760
+ if (button) {
761
+ button.classList.add("ok");
762
+ }
763
+ return { ok: true, result: result };
542
764
  } catch (error) {
543
765
  log("ERRO: " + test.title, error, "err");
766
+ if (button) {
767
+ button.classList.add("fail");
768
+ }
769
+ return { ok: false, error: error };
770
+ } finally {
771
+ if (button) {
772
+ button.classList.remove("running");
773
+ button.disabled = false;
774
+ }
775
+ }
776
+ }
777
+
778
+ async function runSequence(ids, label) {
779
+ var index;
780
+ if (state.sequenceRunning) {
781
+ log("Lote ignorado", { motivo: "Ja existe um lote em execucao." }, "info");
782
+ return;
783
+ }
784
+ state.sequenceRunning = true;
785
+ log("Inicio do lote: " + label, { total: ids.length }, "info");
786
+ try {
787
+ for (index = 0; index < ids.length; index += 1) {
788
+ await run(ids[index]);
789
+ await delay(160);
790
+ }
791
+ log("Fim do lote: " + label, { total: ids.length }, "ok");
792
+ } finally {
793
+ state.sequenceRunning = false;
544
794
  }
545
795
  }
546
796
 
547
797
  function registerEvents() {
798
+ var registered = [];
799
+ var missing = [];
800
+ var failed = [];
801
+
802
+ function remember(stop) {
803
+ if (typeof stop === "function") {
804
+ state.eventStops.push(stop);
805
+ }
806
+ }
807
+
808
+ function listen(name, title) {
809
+ if (typeof window[name] !== "function") {
810
+ missing.push(name);
811
+ return;
812
+ }
813
+ try {
814
+ remember(window[name](function (event) {
815
+ log(title, event, "ok");
816
+ }));
817
+ registered.push(name);
818
+ } catch (error) {
819
+ failed.push({ name: name, message: error.message });
820
+ log("Falha ao registrar " + name, error, "err");
821
+ }
822
+ }
823
+
824
+ function event(type, title) {
825
+ if (typeof window.aoEvento !== "function") {
826
+ missing.push("aoEvento:" + type);
827
+ return;
828
+ }
829
+ try {
830
+ remember(window.aoEvento(type, function (detail) {
831
+ log(title, detail, "ok");
832
+ }));
833
+ registered.push("aoEvento:" + type);
834
+ } catch (error) {
835
+ failed.push({ name: "aoEvento:" + type, message: error.message });
836
+ log("Falha ao registrar evento " + type, error, "err");
837
+ }
838
+ }
839
+
548
840
  if (state.eventsReady) {
549
841
  return { registered: true, already: true };
550
842
  }
551
843
  state.eventsReady = true;
552
- fn("aoEvento")("app:background", function (event) { log("evento app:background", event, "ok"); });
553
- fn("aoEvento")("app:voltou", function (event) { log("evento app:voltou", event, "ok"); });
554
- fn("aoEvento")("botao:voltar", function (event) { log("evento botao:voltar", event, "ok"); });
555
- fn("aoEvento")("rede:mudou", function (event) { log("evento rede:mudou", event, "ok"); });
556
- fn("aoEvento")("bateria:mudou", function (event) { log("evento bateria:mudou", event, "ok"); });
557
- fn("aoClicarNotificacao")(function (event) { log("notificacao clicada", event, "ok"); });
558
- return { registered: true };
844
+ event("app:background", "evento app:background");
845
+ event("app:voltou", "evento app:voltou");
846
+ event("botao:voltar", "evento botao:voltar");
847
+ event("rede:mudou", "evento rede:mudou");
848
+ event("bateria:mudou", "evento bateria:mudou");
849
+ [
850
+ ["aoMinimizar", "app minimizado"],
851
+ ["aoVoltarParaApp", "app voltou"],
852
+ ["aoAbrirLink", "link recebido"],
853
+ ["aoReceberCompartilhamento", "compartilhamento recebido"],
854
+ ["aoMudarRede", "rede mudou"],
855
+ ["aoMudarBateria", "bateria mudou"],
856
+ ["aoConectarUSB", "usb conectado"],
857
+ ["aoDesconectarUSB", "usb desconectado"],
858
+ ["aoConectarFone", "fone conectado"],
859
+ ["aoDesconectarFone", "fone desconectado"],
860
+ ["aoMudarVolume", "volume mudou"],
861
+ ["aoAbrirTeclado", "teclado abriu"],
862
+ ["aoFecharTeclado", "teclado fechou"],
863
+ ["aoMudarOrientacao", "orientacao mudou"],
864
+ ["aoSacudirCelular", "celular sacudido"],
865
+ ["aoVirarCelularParaBaixo", "tela para baixo"],
866
+ ["aoAproximarObjeto", "objeto proximo"],
867
+ ["aoTirarPrint", "print detectado"],
868
+ ["aoNFC", "nfc recebido"],
869
+ ["aoReceberNotificacao", "notificacao recebida"],
870
+ ["aoClicarNotificacao", "notificacao clicada"],
871
+ ["aoConectarBT", "bluetooth conectado"],
872
+ ["aoReceberDadosBT", "dados bluetooth"],
873
+ ["aoDarErroBT", "erro bluetooth"],
874
+ ["aoConectarWiFi", "wifi conectado"],
875
+ ["aoReceberDadosWiFi", "dados wifi"],
876
+ ["aoDarErroWiFi", "erro wifi"]
877
+ ].forEach(function (item) {
878
+ listen(item[0], item[1]);
879
+ });
880
+ return { registered: registered.length, missing: missing, failed: failed };
559
881
  }
560
882
 
561
883
  var actions = {
562
884
  toast: { title: "toast()", run: function () { return fn("toast")("Mensagem do app de teste"); } },
563
885
  vibrar: { title: "vibrar()", run: function () { return fn("vibrar")(250); } },
886
+ aguardar: { title: "aguardar(1000)", run: function () { return fn("aguardar")(1000); } },
564
887
  copiarTexto: { title: "copiarTexto()", run: function () { return fn("copiarTexto")("Texto copiado pelo html2apk"); } },
565
888
  lerTextoCopiado: { title: "lerTextoCopiado()", run: function () { return fn("lerTextoCopiado")(); } },
566
889
  compartilharTexto: { title: "compartilharTexto()", run: function () { return fn("compartilharTexto")("Compartilhado pelo app de teste html2apk"); } },
567
890
  compartilhar: { title: "compartilhar()", run: function () { return fn("compartilhar")({ texto: "Teste html2apk", url: "https://example.com" }); } },
891
+ compartilharApp: { title: "share_me()", run: function () { return fn("share_me")({ titulo: "Compartilhar app de teste" }); } },
892
+ receberCompartilhamento: { title: "aoReceberCompartilhamento()", run: function () { if (state.stopShareEvent) { state.stopShareEvent(); } state.stopShareEvent = fn("aoReceberCompartilhamento")(function (event) { log("compartilhamento recebido", event, "ok"); }); return { listening: true }; } },
893
+ compartilhamentoInicial: { title: "obterCompartilhamentoInicial()", run: function () { return fn("obterCompartilhamentoInicial")(); } },
894
+ iniciarBt: { title: "aoConectarBT()", run: function () { if (state.stopBtConnect) { state.stopBtConnect(); } state.stopBtConnect = fn("aoConectarBT")(function (event) { state.bluetoothConnected = true; log("bluetooth conectado", event, "ok"); }); if (state.stopBtData) { state.stopBtData(); } state.stopBtData = fn("aoReceberDadosBT")(function (data) { log("dados bluetooth", data, "ok"); }); if (state.stopBtError) { state.stopBtError(); } state.stopBtError = fn("aoDarErroBT")(function (error) { log("erro bluetooth", error, "err"); }); return { listening: true }; } },
895
+ procurarBt: { title: "procurarBT()", run: async function () { var devices = await fn("procurarBT")({ timeoutMs: 10000 }); state.bluetoothDevices = devices || []; state.bluetoothDeviceId = state.bluetoothDevices[0] && state.bluetoothDevices[0].id; return devices; } },
896
+ conectarBt: { title: "conectarBT()", run: async function () { if (!state.bluetoothDeviceId) { var devices = await fn("procurarBT")({ timeoutMs: 10000 }); state.bluetoothDevices = devices || []; state.bluetoothDeviceId = state.bluetoothDevices[0] && state.bluetoothDevices[0].id; } if (!state.bluetoothDeviceId) { return { connected: false, message: "Nenhum dispositivo encontrado." }; } return fn("conectarBT")(state.bluetoothDeviceId); } },
897
+ enviarBt: { title: "enviarBT()", run: function () { return fn("enviarBT")({ origem: "laboratorio-html2apk", mensagem: "Ola via Bluetooth", quando: Date.now() }); } },
898
+ iniciarWifi: { title: "aoConectarWiFi()", run: function () { if (state.stopWifiConnect) { state.stopWifiConnect(); } state.stopWifiConnect = fn("aoConectarWiFi")(function (event) { state.wifiConnected = true; log("wifi conectado", event, "ok"); }); if (state.stopWifiData) { state.stopWifiData(); } state.stopWifiData = fn("aoReceberDadosWiFi")(function (data) { log("dados wifi", data, "ok"); }); if (state.stopWifiError) { state.stopWifiError(); } state.stopWifiError = fn("aoDarErroWiFi")(function (error) { log("erro wifi", error, "err"); }); return { listening: true }; } },
899
+ procurarWifi: { title: "procurarWiFi()", run: async function () { var devices = await fn("procurarWiFi")({ timeoutMs: 10000 }); state.wifiDevices = devices || []; state.wifiDeviceId = state.wifiDevices[0] && state.wifiDevices[0].id; return devices; } },
900
+ conectarWifi: { title: "conectarWiFi()", run: async function () { if (!state.wifiDeviceId) { var devices = await fn("procurarWiFi")({ timeoutMs: 10000 }); state.wifiDevices = devices || []; state.wifiDeviceId = state.wifiDevices[0] && state.wifiDevices[0].id; } if (!state.wifiDeviceId) { return { connected: false, message: "Nenhum dispositivo Wi-Fi encontrado." }; } return fn("conectarWiFi")(state.wifiDeviceId); } },
901
+ enviarWifi: { title: "enviarWiFi()", run: function () { return fn("enviarWiFi")({ origem: "laboratorio-html2apk", mensagem: "Ola via Wi-Fi", quando: Date.now() }); } },
568
902
 
569
903
  notificar: { title: "notificar()", run: function () { return fn("notificar")({ titulo: "html2apk", texto: "Notificacao imediata", aoClicar: { funcao: "toast", argumentos: ["Notificacao clicada"] } }); } },
570
904
  agendarNotificacao: { title: "agendarNotificacao()", run: async function () { var result = await fn("agendarNotificacao")({ titulo: "html2apk", texto: "Agendada para 10 segundos", quando: Date.now() + 10000 }); state.scheduledId = result && result.id; return result; } },
905
+ agendarNotificacoes: { title: "agendarNotificacoes()", run: function () { return fn("agendarNotificacoes")([{ titulo: "Lista 1", texto: "Primeira notificacao", quando: Date.now() + 12000 }, { titulo: "Lista 2", texto: "Segunda notificacao", quando: Date.now() + 18000 }]); } },
571
906
  cancelarNotificacao: { title: "cancelarNotificacao()", run: function () { return fn("cancelarNotificacao")(state.scheduledId || 0); } },
572
907
  agendarLoopNotificacoes: { title: "agendarLoopNotificacoes()", run: async function () { var result = await fn("agendarLoopNotificacoes")({ aCada: "30s", notificacoes: [{ titulo: "Loop 1", texto: "Primeiro item" }, { titulo: "Loop 2", texto: "Segundo item" }] }); state.loopId = result && result.id; return result; } },
573
908
  cancelarLoopNotificacoes: { title: "cancelarLoopNotificacoes()", run: function () { return fn("cancelarLoopNotificacoes")(state.loopId || 0); } },
574
909
  pushInfo: { title: "Push OneSignal", run: function () { if (typeof window.solicitarPermissaoPush !== "function") { return { available: false, message: "Configure OneSignal App ID no app real para testar push remoto." }; } return window.solicitarPermissaoPush(); } },
575
910
 
576
- statusPermissoes: { title: "statusPermissoes()", run: function () { return fn("statusPermissoes")(["CAMERA", "RECORD_AUDIO", "ACCESS_FINE_LOCATION", "POST_NOTIFICATIONS", "SET_WALLPAPER"]); } },
911
+ statusPermissoes: { title: "statusPermissoes()", run: function () { return fn("statusPermissoes")(["CAMERA", "RECORD_AUDIO", "ACCESS_FINE_LOCATION", "ACCESS_COARSE_LOCATION", "POST_NOTIFICATIONS", "SET_WALLPAPER", "BLUETOOTH_SCAN", "BLUETOOTH_CONNECT", "NFC", "SYSTEM_ALERT_WINDOW"]); } },
577
912
  permissaoNotificacao: { title: "solicitarPermissaoNotificacoes()", run: function () { return fn("solicitarPermissaoNotificacoes")(); } },
913
+ statusPermissaoNotificacoes: { title: "statusPermissaoNotificacoes()", run: function () { return fn("statusPermissaoNotificacoes")(); } },
578
914
  permissaoCamera: { title: "solicitarPermissaoCamera()", run: function () { return fn("solicitarPermissaoCamera")(); } },
579
915
  permissaoMicrofone: { title: "solicitarPermissaoMicrofone()", run: function () { return fn("solicitarPermissaoMicrofone")(); } },
916
+ statusMicrofone: { title: "statusMicrofone()", run: function () { return fn("statusMicrofone")(); } },
580
917
  alarmeExato: { title: "podeAgendarNotificacaoExata()", run: function () { return fn("podeAgendarNotificacaoExata")(); } },
581
918
  abrirAlarmeExato: { title: "abrirConfiguracaoAlarmeExato()", run: function () { return fn("abrirConfiguracaoAlarmeExato")(); } },
582
919
  statusSobreposicao: { title: "statusPermissaoSobreposicao()", run: function () { return fn("statusPermissaoSobreposicao")(); } },
920
+ solicitarSobreposicao: { title: "solicitarPermissaoSobreposicao()", run: function () { return fn("solicitarPermissaoSobreposicao")(); } },
583
921
  abrirSobreposicao: { title: "abrirConfiguracaoSobreposicao()", run: function () { return fn("abrirConfiguracaoSobreposicao")(); } },
584
922
 
585
923
  fullscreenOn: { title: "fullscreen(true)", run: function () { return fn("fullscreen")(true); } },
@@ -588,19 +926,36 @@ function nativeFunctionLabHtml() {
588
926
  telaAcordadaOff: { title: "manterTelaAcordada(false)", run: function () { return fn("manterTelaAcordada")(false); } },
589
927
  brilhoTela: { title: "brilhoTela()", run: function () { return fn("brilhoTela")(0.72); } },
590
928
  corTema: { title: "definirCorTema()", run: function () { return fn("definirCorTema")({ statusBarColor: "#126fff", navigationBarColor: "#10141b", darkIcons: false }); } },
929
+ corBarrasSistema: { title: "definirCorBarrasSistema()", run: function () { return fn("definirCorBarrasSistema")({ statusBarColor: "#18864b", navigationBarColor: "#10141b", darkIcons: false }); } },
930
+ lanternaOn: { title: "lanterna(true)", run: function () { return fn("lanterna")(true); } },
931
+ lanternaOff: { title: "lanterna(false)", run: function () { return fn("lanterna")(false); } },
591
932
  lanterna: { title: "alternarLanterna()", run: function () { return fn("alternarLanterna")(); } },
592
933
  statusLanterna: { title: "statusLanterna()", run: function () { return fn("statusLanterna")(); } },
593
- iniciarIconeFlutuante: { title: "iniciarIconeFlutuante()", run: function () { return fn("iniciarIconeFlutuante")(); } },
934
+ capturarTela: { title: "capturarTela()", run: function () { return fn("capturarTela")({ formato: "png" }); } },
935
+ tirarPrint: { title: "tirarPrint()", run: function () { return fn("tirarPrint")({ formato: "png" }); } },
936
+ volumeAtual: { title: "volumeAtual()", run: function () { return fn("volumeAtual")(); } },
937
+ definirVolume: { title: "definirVolume('midia', 0.5)", run: function () { return fn("definirVolume")("midia", 0.5, { mostrarUI: true }); } },
938
+ aumentarVolume: { title: "aumentarVolume()", run: function () { return fn("aumentarVolume")("midia", 1, { mostrarUI: true }); } },
939
+ diminuirVolume: { title: "diminuirVolume()", run: function () { return fn("diminuirVolume")("midia", 1, { mostrarUI: true }); } },
940
+ iniciarIconeFlutuante: { title: "iniciarIconeFlutuante()", run: function () { return fn("iniciarIconeFlutuante")({ opacidade: 0.85 }); } },
941
+ configurarIconeFlutuante: { title: "configurarIconeFlutuante()", run: function () { return fn("configurarIconeFlutuante")({ opacidade: 0.65, tamanho: 58 }); } },
942
+ definirOpacidadeIconeFlutuante: { title: "definirOpacidadeIconeFlutuante()", run: function () { return fn("definirOpacidadeIconeFlutuante")(0.55); } },
594
943
  pararIconeFlutuante: { title: "pararIconeFlutuante()", run: function () { return fn("pararIconeFlutuante")(); } },
944
+ minimizarApp: { title: "minimizarApp()", run: function () { return fn("minimizarApp")(); } },
945
+ fecharApp: { title: "fecharApp()", run: function () { return fn("fecharApp")(); } },
595
946
 
596
947
  tirarFoto: { title: "tirarFoto()", run: async function () { var result = await fn("tirarFoto")({ base64: true }); state.lastPhoto = result; return result; } },
597
948
  capturarVideo: { title: "capturarVideo()", run: function () { return fn("capturarVideo")({ duracaoSegundos: 5 }); } },
598
949
  escanearQRCode: { title: "escanearQRCode()", run: function () { return fn("escanearQRCode")(); } },
599
950
  ouvirMic: { title: "ouvirMic()", run: async function () { state.micRecording = true; return fn("ouvirMic")(); } },
600
951
  pararMic: { title: "pararMic()", run: async function () { state.micRecording = false; return fn("pararMic")(); } },
952
+ falar: { title: "falar()", run: function () { return fn("falar")("Ola, eu sou o html2apk", { idioma: "pt-BR", velocidade: 1 }); } },
953
+ pararFala: { title: "pararFala()", run: function () { return fn("pararFala")(); } },
954
+ ouvir: { title: "ouvir()", run: function () { return fn("ouvir")({ idioma: "pt-BR", prompt: "Fale uma frase para testar" }); } },
955
+ ocr: { title: "ocr(imagem)", run: async function () { if (!state.lastImage) { state.lastImage = await fn("escolherImagem")(); } if (!state.lastImage || !state.lastImage.uri) { return { canceled: true }; } return fn("ocr")(state.lastImage); } },
601
956
 
602
957
  escolherImagem: { title: "escolherImagem()", run: async function () { var result = await fn("escolherImagem")(); state.lastImage = result; return result; } },
603
- escolherImagens: { title: "escolherImagens()", run: function () { return fn("escolherImagens")({ multiplo: true }); } },
958
+ escolherImagens: { title: "escolherImagens()", run: function () { return fn("escolherImagens")({ multiplas: true }); } },
604
959
  escolherArquivo: { title: "escolherArquivo()", run: function () { return fn("escolherArquivo")({ tipos: ["text/*", "application/json", "image/*"] }); } },
605
960
  escolherArquivos: { title: "escolherArquivos()", run: function () { return fn("escolherArquivos")({ multiplo: true }); } },
606
961
  escolherVideo: { title: "escolherVideo()", run: function () { return fn("escolherVideo")(); } },
@@ -622,6 +977,7 @@ function nativeFunctionLabHtml() {
622
977
  abrirNoApp: { title: "abrirNoApp()", run: function () { return fn("abrirNoApp")("#teste-funcoes"); } },
623
978
  abrirForaDoApp: { title: "abrirForaDoApp()", run: function () { return fn("abrirForaDoApp")("https://example.com"); } },
624
979
  abrirUrl: { title: "abrirUrl()", run: function () { return fn("abrirUrl")("https://example.com"); } },
980
+ abrirUrlExterno: { title: "abrirUrlExterno()", run: function () { return fn("abrirUrlExterno")("https://example.com"); } },
625
981
  discar: { title: "discar()", run: function () { return fn("discar")("11999999999"); } },
626
982
  abrirMapa: { title: "abrirMapa()", run: function () { return fn("abrirMapa")("Sao Paulo"); } },
627
983
  abrirWhatsapp: { title: "abrirWhatsapp()", run: function () { return fn("abrirWhatsapp")("5511999999999", "Teste html2apk"); } },
@@ -633,6 +989,7 @@ function nativeFunctionLabHtml() {
633
989
  infoArmazenamento: { title: "infoArmazenamento()", run: function () { return fn("infoArmazenamento")(); } },
634
990
  infoDesempenho: { title: "infoDesempenho()", run: function () { return fn("infoDesempenho")(); } },
635
991
  appsAbertos: { title: "appsAbertos()", run: function () { return fn("appsAbertos")(); } },
992
+ infoAppsAbertos: { title: "infoAppsAbertos()", run: function () { return fn("infoAppsAbertos")(); } },
636
993
 
637
994
  obterLocalizacao: { title: "obterLocalizacao()", run: function () { return fn("obterLocalizacao")({ altaPrecisao: true, timeoutMs: 10000 }); } },
638
995
  acompanharLocalizacao: { title: "acompanharLocalizacao()", run: async function () { var result = await fn("acompanharLocalizacao")({ intervaloMs: 5000 }); state.watchId = result && result.watchId; return result; } },
@@ -657,38 +1014,199 @@ function nativeFunctionLabHtml() {
657
1014
  };
658
1015
 
659
1016
  var groups = [
660
- { title: "Feedback e compartilhamento", ids: ["toast", "vibrar", "copiarTexto", "lerTextoCopiado", "compartilharTexto", "compartilhar"] },
661
- { title: "Notificacoes", ids: ["notificar", "agendarNotificacao", "cancelarNotificacao", "agendarLoopNotificacoes", "cancelarLoopNotificacoes", "pushInfo"] },
662
- { title: "Permissoes e configuracoes", ids: ["statusPermissoes", "permissaoNotificacao", "permissaoCamera", "permissaoMicrofone", "alarmeExato", "abrirAlarmeExato", "statusSobreposicao", "abrirSobreposicao"] },
663
- { title: "Tela e hardware", ids: ["fullscreenOn", "fullscreenOff", "telaAcordadaOn", "telaAcordadaOff", "brilhoTela", "corTema", "lanterna", "statusLanterna", "iniciarIconeFlutuante", "pararIconeFlutuante"] },
1017
+ { title: "Feedback e compartilhamento", ids: ["toast", "vibrar", "aguardar", "copiarTexto", "lerTextoCopiado", "compartilharTexto", "compartilhar", "compartilharApp", "receberCompartilhamento", "compartilhamentoInicial"] },
1018
+ { title: "Bluetooth", ids: ["iniciarBt", "procurarBt", "conectarBt", "enviarBt"] },
1019
+ { title: "Wi-Fi local", ids: ["iniciarWifi", "procurarWifi", "conectarWifi", "enviarWifi"] },
1020
+ { title: "Notificacoes", ids: ["notificar", "agendarNotificacao", "agendarNotificacoes", "cancelarNotificacao", "agendarLoopNotificacoes", "cancelarLoopNotificacoes", "pushInfo"] },
1021
+ { title: "Permissoes e configuracoes", ids: ["statusPermissoes", "permissaoNotificacao", "statusPermissaoNotificacoes", "permissaoCamera", "permissaoMicrofone", "statusMicrofone", "alarmeExato", "abrirAlarmeExato", "statusSobreposicao", "solicitarSobreposicao", "abrirSobreposicao"] },
1022
+ { title: "Tela e hardware", ids: ["fullscreenOn", "fullscreenOff", "telaAcordadaOn", "telaAcordadaOff", "brilhoTela", "corTema", "corBarrasSistema", "lanternaOn", "lanternaOff", "lanterna", "statusLanterna", "capturarTela", "tirarPrint", "volumeAtual", "definirVolume", "aumentarVolume", "diminuirVolume", "iniciarIconeFlutuante", "configurarIconeFlutuante", "definirOpacidadeIconeFlutuante", "pararIconeFlutuante", "minimizarApp", "fecharApp"] },
664
1023
  { title: "Camera, QR Code e microfone", ids: ["tirarFoto", "capturarVideo", "escanearQRCode", "ouvirMic", "pararMic"] },
1024
+ { title: "Texto e voz", ids: ["ocr", "falar", "pararFala", "ouvir"] },
665
1025
  { title: "Arquivos e midia", ids: ["escolherImagem", "escolherImagens", "escolherArquivo", "escolherArquivos", "escolherVideo", "escolherPasta", "salvarArquivoPicker", "salvarArquivoCrud", "lerArquivo", "lerArquivoCompleto", "listarArquivos", "infoArquivo", "arquivoExiste", "abrirArquivo", "compartilharArquivo", "baixarArquivo", "baixarBase64", "baixarArquivoLocal", "excluirArquivo"] },
666
- { title: "Abrir apps externos", ids: ["abrirNoApp", "abrirForaDoApp", "abrirUrl", "discar", "abrirMapa", "abrirWhatsapp"] },
667
- { title: "Diagnostico", ids: ["infoDispositivo", "infoRede", "infoBateria", "infoMemoria", "infoArmazenamento", "infoDesempenho", "appsAbertos"] },
1026
+ { title: "Abrir apps externos", ids: ["abrirNoApp", "abrirForaDoApp", "abrirUrl", "abrirUrlExterno", "discar", "abrirMapa", "abrirWhatsapp"] },
1027
+ { title: "Diagnostico", ids: ["infoDispositivo", "infoRede", "infoBateria", "infoMemoria", "infoArmazenamento", "infoDesempenho", "appsAbertos", "infoAppsAbertos"] },
668
1028
  { title: "Localizacao e seguranca", ids: ["obterLocalizacao", "acompanharLocalizacao", "pararLocalizacao", "aoMudarLocalizacao", "autenticarBiometria", "salvarSeguro", "lerSeguro", "lerSeguroCompleto", "listarSeguro", "removerSeguro", "limparSeguro"] },
669
1029
  { title: "Papel de parede", ids: ["infoPapelParede", "definirPapelParede", "abrirConfigPapel", "definirImagemEscolhida"] },
670
1030
  { title: "Eventos", ids: ["registrarEventos", "obterNotificacaoInicial", "obterLinkInicial"] }
671
1031
  ];
672
1032
 
1033
+ var safeActionIds = [
1034
+ "registrarEventos", "statusPermissoes", "statusPermissaoNotificacoes", "statusMicrofone",
1035
+ "alarmeExato", "statusSobreposicao", "statusLanterna", "volumeAtual",
1036
+ "infoDispositivo", "infoRede", "infoBateria", "infoMemoria", "infoArmazenamento",
1037
+ "infoDesempenho", "appsAbertos", "infoAppsAbertos", "listarArquivos", "arquivoExiste",
1038
+ "compartilhamentoInicial", "obterNotificacaoInicial", "obterLinkInicial", "infoPapelParede",
1039
+ "aguardar", "lerTextoCopiado"
1040
+ ];
1041
+ var setupActionIds = [
1042
+ "salvarArquivoCrud", "lerArquivo", "lerArquivoCompleto", "infoArquivo", "salvarSeguro",
1043
+ "lerSeguro", "lerSeguroCompleto", "listarSeguro", "baixarBase64"
1044
+ ];
1045
+ var listenerActionIds = [
1046
+ "registrarEventos", "receberCompartilhamento", "iniciarBt", "iniciarWifi", "aoMudarLocalizacao"
1047
+ ];
1048
+ var externalActionIds = [
1049
+ "compartilharTexto", "compartilhar", "compartilharApp", "abrirForaDoApp", "abrirUrl",
1050
+ "abrirUrlExterno", "discar", "abrirMapa", "abrirWhatsapp", "abrirAlarmeExato",
1051
+ "abrirSobreposicao", "abrirConfigPapel", "escolherImagem", "escolherImagens",
1052
+ "escolherArquivo", "escolherArquivos", "escolherVideo", "escolherPasta",
1053
+ "salvarArquivoPicker", "baixarArquivoLocal", "tirarFoto", "capturarVideo",
1054
+ "escanearQRCode", "ouvir", "autenticarBiometria"
1055
+ ];
1056
+ var dangerActionIds = ["fecharApp", "minimizarApp", "limparSeguro", "excluirArquivo", "pararIconeFlutuante"];
1057
+ var initialSmokeIds = ["registrarEventos", "statusPermissoes", "infoDispositivo", "infoRede", "infoBateria", "volumeAtual"];
1058
+
1059
+ function toSet(ids) {
1060
+ return ids.reduce(function (map, id) {
1061
+ map[id] = true;
1062
+ return map;
1063
+ }, {});
1064
+ }
1065
+
1066
+ var safeActionSet = toSet(safeActionIds);
1067
+ var setupActionSet = toSet(setupActionIds);
1068
+ var listenerActionSet = toSet(listenerActionIds);
1069
+ var externalActionSet = toSet(externalActionIds);
1070
+ var dangerActionSet = toSet(dangerActionIds);
1071
+
1072
+ function actionMode(id) {
1073
+ if (listenerActionSet[id]) {
1074
+ return "listener";
1075
+ }
1076
+ if (safeActionSet[id]) {
1077
+ return "safe";
1078
+ }
1079
+ if (setupActionSet[id]) {
1080
+ return "setup";
1081
+ }
1082
+ if (externalActionSet[id]) {
1083
+ return "external";
1084
+ }
1085
+ return "manual";
1086
+ }
1087
+
1088
+ function actionHint(id) {
1089
+ var mode = actionMode(id);
1090
+ if (mode === "listener") {
1091
+ return "Registra e fica escutando";
1092
+ }
1093
+ if (mode === "safe") {
1094
+ return "Pode rodar no lote seguro";
1095
+ }
1096
+ if (mode === "setup") {
1097
+ return "Prepara ou consulta dados de teste";
1098
+ }
1099
+ if (mode === "external") {
1100
+ return "Abre permissao, seletor ou app externo";
1101
+ }
1102
+ if (dangerActionSet[id]) {
1103
+ return "Afeta estado do app";
1104
+ }
1105
+ return "Toque para executar";
1106
+ }
1107
+
1108
+ function groupRunnableIds(group) {
1109
+ return group.ids.filter(function (id) {
1110
+ return safeActionSet[id] || setupActionSet[id];
1111
+ });
1112
+ }
1113
+
1114
+ function updateStats() {
1115
+ var stats = document.getElementById("stats");
1116
+ var total = Object.keys(actions).length;
1117
+ if (!stats) {
1118
+ return;
1119
+ }
1120
+ stats.innerHTML = [
1121
+ "<span class='chip'>" + total + " testes no laboratorio</span>",
1122
+ "<span class='chip'>" + safeActionIds.length + " seguros em lote</span>",
1123
+ "<span class='chip'>" + listenerActionIds.length + " grupos de escuta</span>",
1124
+ "<span class='chip'>" + state.outputCount + " resultados</span>"
1125
+ ].join("");
1126
+ }
1127
+
1128
+ function applyFilter() {
1129
+ var filter = document.getElementById("filterInput");
1130
+ var term = filter ? filter.value.trim().toLowerCase() : "";
1131
+ document.querySelectorAll("#groups section").forEach(function (section) {
1132
+ var visible = 0;
1133
+ var groupTitle = section.querySelector("h2").textContent.toLowerCase();
1134
+ section.querySelectorAll("[data-action]").forEach(function (button) {
1135
+ var text = button.textContent.toLowerCase();
1136
+ var match = !term || text.indexOf(term) !== -1 || groupTitle.indexOf(term) !== -1;
1137
+ button.hidden = !match;
1138
+ if (match) {
1139
+ visible += 1;
1140
+ }
1141
+ });
1142
+ section.hidden = visible === 0;
1143
+ });
1144
+ }
1145
+
673
1146
  function render() {
674
1147
  var root = document.getElementById("groups");
1148
+ var notice = "<p class='notice'>Os lotes seguros evitam camera, seletores, apps externos e acoes que fecham/minimizam. Para eventos passivos, deixe o app aberto e provoque o evento fisico no aparelho.</p>";
675
1149
  root.innerHTML = groups.map(function (group) {
676
- return "<section><h2>" + group.title + "</h2><div class='grid'>" + group.ids.map(function (id) {
1150
+ var runnable = groupRunnableIds(group);
1151
+ var runButton = runnable.length
1152
+ ? "<button type='button' data-run-group='" + runnable.join(",") + "'>Rodar seguros (" + runnable.length + ")</button>"
1153
+ : "";
1154
+ return "<section><h2 class='with-action'><span>" + group.title + "</span>" + runButton + "</h2><div class='grid'>" + group.ids.map(function (id) {
677
1155
  var item = actions[id];
678
- return "<button type='button' data-action='" + id + "'>" + item.title + "<small>Toque para executar</small></button>";
1156
+ var mode = actionMode(id);
1157
+ var classes = [mode];
1158
+ if (dangerActionSet[id]) {
1159
+ classes.push("danger");
1160
+ }
1161
+ return "<button type='button' class='" + classes.join(" ") + "' data-action='" + id + "'><span>" + item.title + "</span><small>" + actionHint(id) + "</small></button>";
679
1162
  }).join("") + "</div></section>";
680
- }).join("") + "<p class='notice'>Video wallpaper, push remoto e fundo de chamadas dependem de configuracao do sistema, OneSignal ou fabricante. O app mostra o retorno real quando a funcao nao puder agir direto.</p>";
1163
+ }).join("") + notice;
1164
+ updateStats();
1165
+ applyFilter();
681
1166
  }
682
1167
 
683
1168
  document.addEventListener("click", function (event) {
1169
+ var groupButton = event.target.closest("[data-run-group]");
684
1170
  var button = event.target.closest("[data-action]");
1171
+ if (groupButton) {
1172
+ runSequence(groupButton.getAttribute("data-run-group").split(","), "grupo");
1173
+ return;
1174
+ }
685
1175
  if (button) {
686
1176
  run(button.getAttribute("data-action"));
687
1177
  }
688
1178
  });
689
1179
 
1180
+ document.addEventListener("input", function (event) {
1181
+ if (event.target && event.target.id === "filterInput") {
1182
+ applyFilter();
1183
+ }
1184
+ });
1185
+
1186
+ document.getElementById("runSafeButton").addEventListener("click", function () {
1187
+ runSequence(safeActionIds, "testes seguros");
1188
+ });
1189
+
1190
+ document.getElementById("runPrepareButton").addEventListener("click", function () {
1191
+ runSequence(setupActionIds, "preparar dados");
1192
+ });
1193
+
1194
+ document.getElementById("registerEventsButton").addEventListener("click", function () {
1195
+ run("registrarEventos");
1196
+ });
1197
+
1198
+ document.getElementById("clearLogButton").addEventListener("click", function () {
1199
+ var feed = document.getElementById("outputFeed");
1200
+ if (feed) {
1201
+ feed.innerHTML = "";
1202
+ }
1203
+ state.outputCount = 0;
1204
+ updateStats();
1205
+ });
1206
+
690
1207
  document.addEventListener("deviceready", function () {
691
1208
  log("deviceready", { ready: true }, "ok");
1209
+ runSequence(initialSmokeIds, "diagnostico inicial");
692
1210
  }, false);
693
1211
 
694
1212
  render();
@@ -719,7 +1237,15 @@ async function createNativeFunctionLabProject() {
719
1237
  "RECORD_AUDIO",
720
1238
  "ACCESS_FINE_LOCATION",
721
1239
  "ACCESS_COARSE_LOCATION",
722
- "SET_WALLPAPER"
1240
+ "SET_WALLPAPER",
1241
+ "BLUETOOTH_SCAN",
1242
+ "BLUETOOTH_CONNECT",
1243
+ "NFC",
1244
+ "MODIFY_AUDIO_SETTINGS",
1245
+ "SYSTEM_ALERT_WINDOW",
1246
+ "ACCESS_NETWORK_STATE",
1247
+ "ACCESS_WIFI_STATE",
1248
+ "CHANGE_WIFI_MULTICAST_STATE"
723
1249
  ]
724
1250
  };
725
1251