- Implement DeviceRegistry for remote device management - Add dashboard for device tracking and blocking - Remote device blocking capability with admin control - Support for device aliasing and notes - Enhanced device management interface - Dashboard with real-time device status - Configurable registry URL in build config 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
156 lines
5.3 KiB
Java
156 lines
5.3 KiB
Java
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));
|
|
}
|
|
}
|