package br.carinha.rosto; import android.content.Context; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; import android.os.Handler; import android.os.Looper; import android.util.Log; /** * Acha a placa na rede pelo anúncio mDNS "_carinha._tcp" (avahi na Orange Pi, o mesmo do * carinha.local). Assim, se o IP da placa mudar, o app se reconecta sem ninguém digitar endereço. * Uma busca por vez; desiste depois de alguns segundos e responde no fio principal. */ final class Descoberta { interface Resposta { void achou(String endereco); } // null = não achou private static final String TAG = "CarinhaDescoberta"; private static final String TIPO = "_carinha._tcp."; private static final long LIMITE = 8000; private final NsdManager nsd; private final Handler principal = new Handler(Looper.getMainLooper()); private NsdManager.DiscoveryListener ouvinte; private Resposta resposta; Descoberta(Context c) { nsd = (NsdManager) c.getApplicationContext().getSystemService(Context.NSD_SERVICE); } boolean procurando() { return ouvinte != null; } void procurar(Resposta r) { if (nsd == null) { r.achou(null); return; } if (ouvinte != null) return; resposta = r; ouvinte = new NsdManager.DiscoveryListener() { @Override public void onDiscoveryStarted(String tipo) { } @Override public void onDiscoveryStopped(String tipo) { } @Override public void onStartDiscoveryFailed(String tipo, int erro) { terminar(null); } @Override public void onStopDiscoveryFailed(String tipo, int erro) { } @Override public void onServiceLost(NsdServiceInfo s) { } @Override public void onServiceFound(NsdServiceInfo s) { if (!s.getServiceType().startsWith("_carinha._tcp")) return; resolver(s); } }; try { nsd.discoverServices(TIPO, NsdManager.PROTOCOL_DNS_SD, ouvinte); } catch (Exception e) { Log.w(TAG, "busca falhou: " + e); ouvinte = null; r.achou(null); return; } principal.postDelayed(new Runnable() { @Override public void run() { terminar(null); } }, LIMITE); } @SuppressWarnings("deprecation") private void resolver(NsdServiceInfo s) { try { nsd.resolveService(s, new NsdManager.ResolveListener() { @Override public void onResolveFailed(NsdServiceInfo s, int erro) { Log.w(TAG, "não resolveu: " + erro); } @Override public void onServiceResolved(NsdServiceInfo s) { if (s.getHost() == null || s.getHost().isLoopbackAddress()) return; String ip = s.getHost().getHostAddress(); if (ip == null || ip.contains(":")) return; // só IPv4: o servidor ouve em 0.0.0.0 terminar("http://" + ip + ":" + s.getPort()); } }); } catch (Exception e) { Log.w(TAG, "resolver falhou: " + e); } } private void terminar(final String endereco) { principal.post(new Runnable() { @Override public void run() { if (ouvinte == null) return; // já respondeu try { nsd.stopServiceDiscovery(ouvinte); } catch (Exception e) { /* já parou */ } ouvinte = null; Resposta r = resposta; resposta = null; Log.i(TAG, endereco == null ? "placa não encontrada na rede" : "placa encontrada: " + endereco); if (r != null) r.achou(endereco); } }); } void parar() { terminar(null); } }