package com.streamplayer; import android.content.Context; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.util.Locale; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; /** * Informa al dashboard qué dispositivos tienen instalada la app y permite bloquearlos remotamente. */ public class DeviceRegistry { public interface Callback { void onAllowed(); void onBlocked(String reason); void onError(String message); } private static final String TAG = "DeviceRegistry"; private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private final Context appContext; private final OkHttpClient httpClient; private final ExecutorService executorService; private final Handler mainHandler = new Handler(Looper.getMainLooper()); public DeviceRegistry(Context context) { this.appContext = context.getApplicationContext(); this.httpClient = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .callTimeout(20, TimeUnit.SECONDS) .build(); this.executorService = Executors.newSingleThreadExecutor(); } public void syncDevice(Callback callback) { if (TextUtils.isEmpty(BuildConfig.DEVICE_REGISTRY_URL)) { postAllowed(callback); return; } executorService.execute(() -> { try { JSONObject payload = new JSONObject(); payload.put("deviceId", getDeviceId()); payload.put("deviceName", Build.MODEL); payload.put("model", Build.MODEL); payload.put("manufacturer", capitalize(Build.MANUFACTURER)); payload.put("osVersion", Build.VERSION.RELEASE + " (API " + Build.VERSION.SDK_INT + ")"); payload.put("appVersionName", BuildConfig.VERSION_NAME); payload.put("appVersionCode", BuildConfig.VERSION_CODE); String endpoint = sanitizeBaseUrl(BuildConfig.DEVICE_REGISTRY_URL) + "/api/devices/register"; RequestBody body = RequestBody.create(payload.toString(), JSON); Request request = new Request.Builder() .url(endpoint) .post(body) .build(); try (Response response = httpClient.newCall(request).execute()) { if (!response.isSuccessful() || response.body() == null) { throw new IOException("HTTP " + response.code()); } String responseText = response.body().string(); JSONObject json = new JSONObject(responseText); boolean blocked = json.optBoolean("blocked", false); JSONObject deviceJson = json.optJSONObject("device"); String reason = json.optString("message"); if (TextUtils.isEmpty(reason) && deviceJson != null) { reason = deviceJson.optString("notes", ""); } if (blocked) { postBlocked(callback, reason); } else { postAllowed(callback); } } } catch (IOException | JSONException e) { Log.w(TAG, "Device sync error", e); postError(callback, e.getMessage()); } }); } private String sanitizeBaseUrl(String base) { if (TextUtils.isEmpty(base)) { return ""; } if (base.endsWith("/")) { return base.substring(0, base.length() - 1); } return base; } private String getDeviceId() { String id = Settings.Secure.getString(appContext.getContentResolver(), Settings.Secure.ANDROID_ID); if (TextUtils.isEmpty(id)) { id = Build.MODEL + "-" + Build.BOARD + "-" + BuildConfig.VERSION_CODE; } return id; } private String capitalize(String value) { if (TextUtils.isEmpty(value)) { return ""; } return value.substring(0, 1).toUpperCase(Locale.getDefault()) + value.substring(1); } public void release() { executorService.shutdownNow(); } private void postAllowed(Callback callback) { if (callback == null) { return; } mainHandler.post(callback::onAllowed); } private void postBlocked(Callback callback, String reason) { if (callback == null) { return; } mainHandler.post(() -> callback.onBlocked(reason)); } private void postError(Callback callback, String message) { if (callback == null) { return; } mainHandler.post(() -> callback.onError(message)); } }