mirror of
git://f0xx.org/android_cast
synced 2026-07-29 08:19:00 +03:00
footer changes, remote access changes
This commit is contained in:
@@ -62,6 +62,9 @@ public final class AppPreferences {
|
||||
private static final String KEY_DEV_DIAG_PING_RESPONSE_MODE = "dev_diag_ping_response_mode";
|
||||
private static final String KEY_DEV_BACKEND_NTP_SYNC = "dev_backend_ntp_sync";
|
||||
private static final String KEY_DEV_REMOTE_ACCESS_MODE = "dev_remote_access_mode";
|
||||
private static final String KEY_DEV_REMOTE_ACCESS_RANDOM = "dev_remote_access_random";
|
||||
private static final String KEY_DEV_REMOTE_ACCESS_SESSION_ID = "dev_remote_access_session_id";
|
||||
private static final String KEY_DEV_REMOTE_ACCESS_EXPIRES_AT = "dev_remote_access_expires_at";
|
||||
|
||||
/** Minimum interval between automatic OTA checks on app launch. */
|
||||
public static final long OTA_CHECK_INTERVAL_MS = 12 * 60 * 60 * 1000L;
|
||||
@@ -441,6 +444,32 @@ public final class AppPreferences {
|
||||
prefs(context).edit().putString(KEY_DEV_REMOTE_ACCESS_MODE, mode.name()).apply();
|
||||
}
|
||||
|
||||
public static String getDevRemoteAccessRandom(Context context) {
|
||||
return prefs(context).getString(KEY_DEV_REMOTE_ACCESS_RANDOM, "");
|
||||
}
|
||||
|
||||
public static void setDevRemoteAccessRandom(Context context, String random) {
|
||||
prefs(context).edit().putString(KEY_DEV_REMOTE_ACCESS_RANDOM, random != null ? random : "").apply();
|
||||
}
|
||||
|
||||
public static void setDevRemoteAccessSession(Context context, String sessionId, long expiresAtEpochSec) {
|
||||
prefs(context).edit()
|
||||
.putString(KEY_DEV_REMOTE_ACCESS_SESSION_ID, sessionId != null ? sessionId : "")
|
||||
.putLong(KEY_DEV_REMOTE_ACCESS_EXPIRES_AT, expiresAtEpochSec)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static void clearDevRemoteAccessSession(Context context) {
|
||||
prefs(context).edit()
|
||||
.remove(KEY_DEV_REMOTE_ACCESS_SESSION_ID)
|
||||
.remove(KEY_DEV_REMOTE_ACCESS_EXPIRES_AT)
|
||||
.apply();
|
||||
}
|
||||
|
||||
public static long getDevRemoteAccessExpiresAt(Context context) {
|
||||
return prefs(context).getLong(KEY_DEV_REMOTE_ACCESS_EXPIRES_AT, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset user-facing settings shown in Android Cast settings.
|
||||
* Developer-only settings are intentionally preserved.
|
||||
|
||||
@@ -15,9 +15,10 @@ public final class RemoteAccessCoordinator {
|
||||
Context app = context.getApplicationContext();
|
||||
if (mode == null || mode == RemoteAccessMode.DISABLED) {
|
||||
Log.i(TAG, "disabling remote access");
|
||||
RemoteAccessService.sendDisableOnce(app);
|
||||
RemoteAccessService.stop(app);
|
||||
RemoteAccessVpnService.stop(app);
|
||||
RemoteAccessService.sendDisableOnce(app);
|
||||
AppPreferences.clearDevRemoteAccessSession(app);
|
||||
return;
|
||||
}
|
||||
if (mode == RemoteAccessMode.WIREGUARD) {
|
||||
|
||||
@@ -45,7 +45,27 @@ public final class RemoteAccessService extends Service {
|
||||
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
private final Random random = new Random();
|
||||
private String sessionRandom = UUID.randomUUID().toString();
|
||||
private String sessionRandom = "";
|
||||
|
||||
private String loadOrCreateSessionRandom() {
|
||||
String stored = AppPreferences.getDevRemoteAccessRandom(this);
|
||||
if (stored != null && !stored.isEmpty()) {
|
||||
sessionRandom = stored;
|
||||
return sessionRandom;
|
||||
}
|
||||
sessionRandom = UUID.randomUUID().toString();
|
||||
AppPreferences.setDevRemoteAccessRandom(this, sessionRandom);
|
||||
return sessionRandom;
|
||||
}
|
||||
|
||||
private void checkSessionExpiry() {
|
||||
long exp = AppPreferences.getDevRemoteAccessExpiresAt(this);
|
||||
if (exp > 0 && exp < System.currentTimeMillis() / 1000L) {
|
||||
Log.i(TAG, "session expired — tearing down tunnel");
|
||||
WireGuardTunnelBridge.tearDown(this);
|
||||
AppPreferences.clearDevRemoteAccessSession(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static void start(Context context, RemoteAccessMode mode) {
|
||||
Intent i = new Intent(context, RemoteAccessService.class);
|
||||
@@ -94,6 +114,8 @@ public final class RemoteAccessService extends Service {
|
||||
}
|
||||
ensureChannel();
|
||||
startForeground(NOTIF_ID, buildNotification(mode));
|
||||
loadOrCreateSessionRandom();
|
||||
checkSessionExpiry();
|
||||
final RemoteAccessMode pollMode = mode;
|
||||
if (ACTION_START.equals(action) || ACTION_POLL.equals(action)) {
|
||||
executor.execute(() -> runPoll(pollMode));
|
||||
@@ -103,12 +125,13 @@ public final class RemoteAccessService extends Service {
|
||||
}
|
||||
|
||||
private void runPoll(RemoteAccessMode mode) {
|
||||
checkSessionExpiry();
|
||||
try {
|
||||
JSONObject hb = new JSONObject();
|
||||
hb.put("type", "ra");
|
||||
hb.put("status", "enable");
|
||||
hb.put("device_id", DeviceInfo.getDeviceUuid(this));
|
||||
hb.put("random", sessionRandom);
|
||||
hb.put("random", loadOrCreateSessionRandom());
|
||||
hb.put("app_version", com.foxx.androidcast.BuildConfig.VERSION_NAME);
|
||||
hb.put("tunnel_mode", mode.toApiValue());
|
||||
JSONArray caps = new JSONArray();
|
||||
@@ -134,11 +157,12 @@ public final class RemoteAccessService extends Service {
|
||||
private void postDisableHeartbeat() {
|
||||
try {
|
||||
WireGuardTunnelBridge.tearDown(this);
|
||||
AppPreferences.clearDevRemoteAccessSession(this);
|
||||
JSONObject hb = new JSONObject();
|
||||
hb.put("type", "ra");
|
||||
hb.put("status", "disable");
|
||||
hb.put("device_id", DeviceInfo.getDeviceUuid(this));
|
||||
hb.put("random", sessionRandom);
|
||||
hb.put("random", loadOrCreateSessionRandom());
|
||||
RemoteAccessHeartbeatClient.postRa(this, hb);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "disable notify failed: " + e.getMessage());
|
||||
@@ -150,12 +174,35 @@ public final class RemoteAccessService extends Service {
|
||||
Log.w(TAG, "unsupported tunnel in connect");
|
||||
return;
|
||||
}
|
||||
String sessionId = resp.optString("session_id", "");
|
||||
long expiresAt = resp.optLong("expires_at", 0L);
|
||||
if (!sessionId.isEmpty()) {
|
||||
AppPreferences.setDevRemoteAccessSession(this, sessionId, expiresAt);
|
||||
}
|
||||
JSONObject creds = resp.optJSONObject("credentials");
|
||||
String wgConfig = WireGuardConfigBuilder.fromConnectCredentials(creds);
|
||||
if (wgConfig.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
WireGuardTunnelBridge.applyConfig(this, wgConfig);
|
||||
if (WireGuardTunnelBridge.applyConfig(this, wgConfig)) {
|
||||
updateNotificationConnected(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateNotificationConnected(String sessionId) {
|
||||
NotificationManager nm = getSystemService(NotificationManager.class);
|
||||
if (nm == null) {
|
||||
return;
|
||||
}
|
||||
String text = sessionId.isEmpty()
|
||||
? getString(R.string.dev_remote_access_notification_connected)
|
||||
: getString(R.string.dev_remote_access_notification_session, sessionId);
|
||||
nm.notify(NOTIF_ID, new NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setContentTitle(getString(R.string.dev_remote_access_notification_title))
|
||||
.setContentText(text)
|
||||
.setOngoing(true)
|
||||
.build());
|
||||
}
|
||||
|
||||
private void scheduleNextPoll() {
|
||||
|
||||
@@ -272,6 +272,8 @@
|
||||
<string name="dev_remote_access_notification_channel">Remote access</string>
|
||||
<string name="dev_remote_access_notification_title">Remote debug active</string>
|
||||
<string name="dev_remote_access_notification_poll">Polling BE (%1$s)</string>
|
||||
<string name="dev_remote_access_notification_connected">WireGuard tunnel connected</string>
|
||||
<string name="dev_remote_access_notification_session">Connected · session %1$s</string>
|
||||
<string name="dev_tab_network_self_test">Network self-test</string>
|
||||
<string name="dev_network_selftest_unlocked">Network self-test tab unlocked</string>
|
||||
<string name="dev_network_selftest_intro">Hidden diagnostics tab. Long-press the tabs row to unlock. Runs quick network checks: connectivity, captive portal, CIDR/DNS/MTU, peer reachability, backend RTT/throughput, NAT and NTP correction.</string>
|
||||
|
||||
Reference in New Issue
Block a user