Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,61 +1,41 @@
/*
* ============================================================================
* Name : DashboardManager.java
* Author : IIAB Project
* Copyright : Copyright (c) 2026 IIAB Project
* Description : Initial dasboard status helper
* Author : AppDevForAll
* Copyright : Copyright (c) 2026 AppDevForAll
* Description : Home dashboard status helper: binds the Wi-Fi and Hotspot tiles
* and reflects their OS connectivity state on the LEDs. The legacy
* "tunnel"/ESPW toggle was removed with the dead SOCKS-proxy
* mechanism (ADFA-4553); content is served from the native local
* server, so there is no tunnel state to display.
* ============================================================================
*/
package org.iiab.controller;

import android.app.Activity;
import android.content.Intent;
import android.provider.Settings;
import android.transition.AutoTransition;
import android.transition.TransitionManager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

public class DashboardManager {

private final Activity activity;
private final LinearLayout dashboardContainer;

private final View dashWifi, dashHotspot, dashTunnel;
private final View ledWifi, ledHotspot, ledTunnel;
private final View standaloneEspwButton;
private final View standaloneEspwDescription;
private final View dashWifi, dashHotspot;
private final View ledWifi, ledHotspot;

// Memory variables to avoid freezing the screen
private boolean lastTunnelState = false;
private boolean lastDegradedState = false;
private boolean isFirstRun = true;

public interface DashboardActionCallback {
void onToggleEspwRequested();
}

public DashboardManager(Activity activity, View rootView, DashboardActionCallback callback) {
public DashboardManager(Activity activity, View rootView) {
this.activity = activity;

// Bind all the views
dashboardContainer = (LinearLayout) rootView.findViewById(R.id.dashboard_container);
dashWifi = rootView.findViewById(R.id.dash_wifi);
dashHotspot = rootView.findViewById(R.id.dash_hotspot);
dashTunnel = rootView.findViewById(R.id.dash_tunnel);

ledWifi = rootView.findViewById(R.id.led_wifi);
ledHotspot = rootView.findViewById(R.id.led_hotspot);
ledTunnel = rootView.findViewById(R.id.led_tunnel);

standaloneEspwButton = rootView.findViewById(R.id.control);
standaloneEspwDescription = rootView.findViewById(R.id.control_description);

setupListeners(callback);
setupListeners();
}

private void setupListeners(DashboardActionCallback callback) {
private void setupListeners() {
// Single tap opens Settings directly
dashWifi.setOnClickListener(v -> activity.startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)));

Expand All @@ -68,54 +48,11 @@ private void setupListeners(DashboardActionCallback callback) {
activity.startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
}
});

// The Tunnel/ESPW toggle logic
View.OnClickListener toggleEspw = v -> callback.onToggleEspwRequested();
standaloneEspwButton.setOnClickListener(toggleEspw);
dashTunnel.setOnClickListener(toggleEspw);
}

// Updates the LED graphics based on actual OS connectivity states
public void updateConnectivityLeds(boolean isWifiOn, boolean isHotspotOn) {
ledWifi.setBackgroundResource(isWifiOn ? R.drawable.led_on_green : R.drawable.led_off);
ledHotspot.setBackgroundResource(isHotspotOn ? R.drawable.led_on_green : R.drawable.led_off);
}

// The Magic Morphing Animation!
public void setTunnelState(boolean isTunnelActive, boolean isDegraded) {
// ANTI-FREEZE SHIELD!
// If the state is exactly the same as 3 seconds ago, abort to avoid blocking the UI
if (!isFirstRun && lastTunnelState == isTunnelActive && lastDegradedState == isDegraded) {
return;
}
isFirstRun = false;
lastTunnelState = isTunnelActive;
lastDegradedState = isDegraded;

// Tells Android to smoothly animate any layout changes we make next
TransitionManager.beginDelayedTransition((ViewGroup) dashboardContainer.getParent(), new AutoTransition().setDuration(300));

if (isTunnelActive) {
// Morph into 33% / 33% / 33% Dashboard mode
standaloneEspwButton.setVisibility(View.GONE);
standaloneEspwDescription.setVisibility(View.GONE);
dashTunnel.setVisibility(View.VISIBLE);
ledTunnel.setBackgroundResource(isDegraded ? R.drawable.led_on_orange : R.drawable.led_on_green);

// Force recalculate
dashboardContainer.setWeightSum(3f);
} else {
// Morph back into 50% / 50% mode
dashTunnel.setVisibility(View.GONE);
// TODO: [RESTORE] Uncomment to show ESPW button again
// standaloneEspwButton.setVisibility(View.VISIBLE);
// standaloneEspwDescription.setVisibility(View.VISIBLE);
// The LED turns off implicitly since the whole dash_tunnel hides, but we can enforce it:
ledTunnel.setBackgroundResource(R.drawable.led_off);
// Force recalculate
dashboardContainer.setWeightSum(2f);
}
// Force recalculate
dashboardContainer.requestLayout();
}
}
58 changes: 0 additions & 58 deletions controller/app/src/main/java/org/iiab/controller/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
private long serverUpSinceMs = 0L; // ADFA-4466: for server_stopped uptime bucket
public boolean isNegotiating = false;
public DashboardFragment.SystemState currentSystemState = DashboardFragment.SystemState.NONE;
public boolean isProxyDegraded = false;
public Boolean targetServerState = null;
public String serverTransitionText = "";
public UsageFragment usageFragment;
Expand Down Expand Up @@ -653,25 +652,6 @@ private boolean pingUrl(String urlStr) {
}
}

private void runNegotiationSequence() {
isNegotiating = true;
runOnUiThread(() -> {
updateUIColorsAndVisibility(); // We forced an immediate visual update
});

AppExecutors.get().io().execute(() -> {
// Native architecture: content is served locally at localhost:8085.
boolean localAlive = pingUrl("http://localhost:8085/home");

isNegotiating = false;
updateServerAlive(localAlive);
isProxyDegraded = false;
currentTargetUrl = localAlive ? "http://localhost:8085/home" : null;

runOnUiThread(this::updateUIColorsAndVisibility);
});
}

private void prepareVpn() {
BatteryUtils.checkAndPromptOptimizations(MainActivity.this, batteryOptLauncher);
}
Expand Down Expand Up @@ -760,7 +740,6 @@ else if (mode == AppCompatDelegate.MODE_NIGHT_YES)
else themeToggle.setImageResource(R.drawable.ic_theme_system);
}


@Override
protected void onStart() {
super.onStart();
Expand Down Expand Up @@ -800,29 +779,6 @@ public void onClick(View view) {
// Delegated
}

public void handleControlClick() {
if (!isServerAlive) {
Snackbar.make(findViewById(android.R.id.content), R.string.qr_error_no_server, Snackbar.LENGTH_LONG).show();
return;
}
if (prefs.getEnable()) {
BiometricHelper.prompt(this,
getString(R.string.auth_required_title),
getString(R.string.auth_required_subtitle),
() -> {
addToLog(getString(R.string.auth_success_disconnect));
toggleService(true);
});
} else {
if (BiometricHelper.isDeviceSecure(this)) {
addToLog(getString(R.string.user_initiated_conn));
toggleService(false);
} else {
BiometricHelper.showEnrollmentDialog(this);
}
}
}

public void handleBrowseContentClick(View v) {
if (!isServerAlive) {
Snackbar.make(v, R.string.qr_error_no_server, Snackbar.LENGTH_LONG).show();
Expand Down Expand Up @@ -986,18 +942,6 @@ public void onError(String error) {
}
}

private void toggleService(boolean stop) {
prefs.setEnable(!stop);
savePrefs();
addToLog(getString(stop ? R.string.vpn_stopping : R.string.vpn_starting));

if (!stop) {
runNegotiationSequence();
} else {
updateUIColorsAndVisibility();
}
}

public void updateUI() {
if (usageFragment != null) {
usageFragment.updateUI();
Expand All @@ -1009,7 +953,6 @@ private void checkServerStatus() {

AppExecutors.get().io().execute(() -> {
boolean localAlive = pingUrl("http://localhost:8085/home");
isProxyDegraded = false;

updateServerAlive(localAlive);

Expand Down Expand Up @@ -1977,7 +1920,6 @@ public void logStackTrace(String tag, Exception e) {
"PATH=/sbin:/system/sbin:/system/bin:/system/xbin:" + workingDirectory.getAbsolutePath() + "/usr/bin"
};


// Launch the native Android shell!
terminalSession = new com.termux.terminal.TerminalSession(
hostShell,
Expand Down
66 changes: 0 additions & 66 deletions controller/app/src/main/java/org/iiab/controller/Preferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,12 @@

public class Preferences {
public static final String PREFS_NAME = "SocksPrefs";
public static final String SOCKS_ADDR = "SocksAddr";
public static final String SOCKS_UDP_ADDR = "SocksUdpAddr";
public static final String SOCKS_PORT = "SocksPort";
public static final String SOCKS_USER = "SocksUser";
public static final String SOCKS_PASS = "SocksPass";
public static final String IPV4 = "Ipv4";
public static final String IPV6 = "Ipv6";
public static final String GLOBAL = "Global";
public static final String UDP_IN_TCP = "UdpInTcp";
public static final String REMOTE_DNS = "RemoteDNS";
public static final String APPS = "Apps";
public static final String ENABLE = "Enable";
public static final String WATCHDOG_ENABLE = "WatchdogEnable";
public static final String MAINTENANCE_MODE = "MaintenanceMode";

Expand All @@ -40,56 +34,6 @@ public Preferences(Context context) {
prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_MULTI_PROCESS);
}

public String getSocksAddress() {
return prefs.getString(SOCKS_ADDR, "127.0.0.1");
}

public void setSocksAddress(String addr) {
SharedPreferences.Editor editor = prefs.edit();
editor.putString(SOCKS_ADDR, addr);
editor.commit();
}

public String getSocksUdpAddress() {
return prefs.getString(SOCKS_UDP_ADDR, "");
}

public void setSocksUdpAddress(String addr) {
SharedPreferences.Editor editor = prefs.edit();
editor.putString(SOCKS_UDP_ADDR, addr);
editor.commit();
}

public int getSocksPort() {
return prefs.getInt(SOCKS_PORT, 1080);
}

public void setSocksPort(int port) {
SharedPreferences.Editor editor = prefs.edit();
editor.putInt(SOCKS_PORT, port);
editor.commit();
}

public String getSocksUsername() {
return prefs.getString(SOCKS_USER, "");
}

public void setSocksUsername(String user) {
SharedPreferences.Editor editor = prefs.edit();
editor.putString(SOCKS_USER, user);
editor.commit();
}

public String getSocksPassword() {
return prefs.getString(SOCKS_PASS, "");
}

public void setSocksPassword(String pass) {
SharedPreferences.Editor editor = prefs.edit();
editor.putString(SOCKS_PASS, pass);
editor.commit();
}

public String getMappedDns() {
return "198.18.0.2";
}
Expand Down Expand Up @@ -154,16 +98,6 @@ public void setApps(Set<String> apps) {
editor.commit();
}

public boolean getEnable() {
return prefs.getBoolean(ENABLE, false);
}

public void setEnable(boolean enable) {
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(ENABLE, enable);
editor.commit();
}

public boolean getWatchdogEnable() {
return prefs.getBoolean(WATCHDOG_ENABLE, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ public void onReceive(Context context, Intent intent) {
return;
}
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Preferences prefs = new Preferences(context);
if (prefs.getEnable()) {
// TODO(ADFA-3340): auto-start K2Go on boot. The previous
// VpnService/TProxyService implementation was removed (ADFA-4552,
// dead tunnel); the replacement start path will hook in here.
}
// TODO(ADFA-3340): auto-start K2Go on boot. The previous
// VpnService/TProxyService implementation was removed (ADFA-4552) and
// the "enable" pref was removed with the dead proxy (ADFA-4553); the
// replacement start path will hook in here.
}
}
}
Loading