feat(ao-vivo): camera sempre visivel, lista estilo iOS e dados do aparelho

- palco fixo no topo: camera grande com o rosto num quadrinho no canto
  (toque troca os dois); botao "Ligar camera" direto no palco
- controles em lista agrupada estilo Ajustes do iPhone (Grupo, Linha,
  Interruptor): camera e rastreamento, gestos, aparencia, personalidade
- cartao do celular com modelo, Android, versao do app, bateria, Wi-Fi,
  IP e estado do rosto
- APK 0.8.1 informa ip/modelo/android/app/wifi (ACCESS_WIFI_STATE, so o
  nivel do sinal); servidor usa o IP informado pelo app em vez do
  endereco da conexao

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
julio
2026-10-05 23:07:52 -03:00
co-authored by Claude Opus 5.5
parent 3e51266644
commit a058c6f453
13 changed files with 705 additions and 192 deletions
@@ -1021,8 +1021,52 @@ public class MainActivity extends Activity {
return String.format(java.util.Locale.US, "%.3f", v);
}
private String aparelhoJson = "null";
private long aparelhoEm = 0;
/** IP, modelo, Android, versão do app e sinal do Wi-Fi; recalculado a cada 10 s. */
private String infoAparelho() {
long agora = System.currentTimeMillis();
if (agora - aparelhoEm < 10000) return aparelhoJson;
aparelhoEm = agora;
try {
JSONObject a = new JSONObject();
a.put("ip", ipLocal());
a.put("modelo", (Build.MANUFACTURER + " " + Build.MODEL).trim());
a.put("android", Build.VERSION.RELEASE);
try { a.put("app", getPackageManager().getPackageInfo(getPackageName(), 0).versionName); }
catch (Exception e) { a.put("app", JSONObject.NULL); }
try {
android.net.wifi.WifiManager wifi = (android.net.wifi.WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
android.net.wifi.WifiInfo info = wifi == null ? null : wifi.getConnectionInfo();
if (info != null && info.getNetworkId() != -1) {
a.put("wifi", android.net.wifi.WifiManager.calculateSignalLevel(info.getRssi(), 5));
a.put("rssi", info.getRssi());
}
} catch (Exception e) { /* sem permissão ou sem Wi-Fi */ }
aparelhoJson = a.toString();
} catch (Exception e) {
aparelhoJson = "null";
}
return aparelhoJson;
}
/** Primeiro IPv4 privado da rede (Wi-Fi), sem precisar de permissão extra. */
private static String ipLocal() {
try {
for (java.net.NetworkInterface n : java.util.Collections.list(java.net.NetworkInterface.getNetworkInterfaces())) {
if (!n.isUp() || n.isLoopback()) continue;
for (java.net.InetAddress e : java.util.Collections.list(n.getInetAddresses())) {
if (e instanceof java.net.Inet4Address && e.isSiteLocalAddress()) return e.getHostAddress();
}
}
} catch (Exception e) { /* sem rede */ }
return null;
}
private void atualizarBrilho() {
if (naCamera) return;
web.evaluateJavascript("window.carinhaAparelho=" + infoAparelho(), null);
Intent bateria = registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
if (bateria != null) {
int level = bateria.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);