From 6a69c629ff486f7b0a9a51ce01e6a4edc7e2e10e Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:27:48 +0530 Subject: [PATCH 01/33] Added ShellValueParser for reusable shell-output parsing --- .../telephony/ShellValueParser.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 app/src/main/java/com/dhangofa/networktoggle/telephony/ShellValueParser.java diff --git a/app/src/main/java/com/dhangofa/networktoggle/telephony/ShellValueParser.java b/app/src/main/java/com/dhangofa/networktoggle/telephony/ShellValueParser.java new file mode 100644 index 0000000..078f5af --- /dev/null +++ b/app/src/main/java/com/dhangofa/networktoggle/telephony/ShellValueParser.java @@ -0,0 +1,26 @@ +package com.dhangofa.networktoggle.telephony; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +final class ShellValueParser { + private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+"); + + private ShellValueParser() { + } + + static Integer extractFirstInt(String text) { + try { + if (text == null + || text.trim().isEmpty() + || text.trim().equalsIgnoreCase("null")) { + return null; + } + + Matcher matcher = NUMBER_PATTERN.matcher(text); + return matcher.find() ? Integer.parseInt(matcher.group()) : null; + } catch (Exception ignored) { + return null; + } + } +} From 5b4995fcaaccf0a56df9a7334e5ab8ac7700d892 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:28:53 +0530 Subject: [PATCH 02/33] Added SimResolver for subscription ID and physical-slot resolution --- .../networktoggle/telephony/SimResolver.java | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 app/src/main/java/com/dhangofa/networktoggle/telephony/SimResolver.java diff --git a/app/src/main/java/com/dhangofa/networktoggle/telephony/SimResolver.java b/app/src/main/java/com/dhangofa/networktoggle/telephony/SimResolver.java new file mode 100644 index 0000000..3f961ba --- /dev/null +++ b/app/src/main/java/com/dhangofa/networktoggle/telephony/SimResolver.java @@ -0,0 +1,134 @@ +package com.dhangofa.networktoggle.telephony; + +import android.os.Build; +import android.telephony.SubscriptionManager; + +import com.dhangofa.networktoggle.command.CommandExecutor; +import com.dhangofa.networktoggle.command.CommandExecutorFactory; +import com.dhangofa.networktoggle.config.AppPreferences; +import com.dhangofa.networktoggle.model.CommandResult; +import com.dhangofa.networktoggle.model.ExecutionMode; +import com.dhangofa.networktoggle.model.TargetSim; + +public final class SimResolver { + public static final int INVALID_SLOT_INDEX = -1; + public static final int INVALID_SUB_ID = -1; + + private final AppPreferences appPreferences; + + public SimResolver(AppPreferences appPreferences) { + this.appPreferences = appPreferences; + } + + public int resolveTargetSlotIndex(ExecutionMode executionMode) { + TargetSim targetSim = appPreferences.getTargetSim(); + + if (!targetSim.isAuto()) { + appPreferences.setAutoSimError(false); + return targetSim.getManualSlotIndex(); + } + + return resolveAutoSlotIndex(executionMode); + } + + public int resolveTargetSubId(ExecutionMode executionMode) { + TargetSim targetSim = appPreferences.getTargetSim(); + + if (targetSim == TargetSim.AUTO) { + int subId = SubscriptionManager.getDefaultDataSubscriptionId(); + return isValidSubId(subId) ? subId : INVALID_SUB_ID; + } + + return resolveSubIdFromDumpsys( + executionMode, + targetSim.getManualSlotIndex() + ); + } + + public boolean isValidSlotIndex(int slotIndex) { + return slotIndex == 0 || slotIndex == 1; + } + + public boolean isValidSubId(int subId) { + return subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID + && subId != INVALID_SUB_ID; + } + + private int resolveAutoSlotIndex(ExecutionMode executionMode) { + int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); + + if (!isValidSubId(dataSubId)) { + appPreferences.setAutoSimError(true); + return INVALID_SLOT_INDEX; + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + try { + int slotIndex = SubscriptionManager.getSlotIndex(dataSubId); + if (isValidSlotIndex(slotIndex)) { + appPreferences.setAutoSimError(false); + return slotIndex; + } + } catch (Exception ignored) { + } + } + + int slotIndex = resolveSlotIndexFromDumpsys(executionMode, dataSubId); + if (isValidSlotIndex(slotIndex)) { + appPreferences.setAutoSimError(false); + return slotIndex; + } + + appPreferences.setAutoSimError(true); + return INVALID_SLOT_INDEX; + } + + private int resolveSlotIndexFromDumpsys( + ExecutionMode executionMode, + int dataSubId + ) { + String command = "dumpsys isub | grep -E \"\\{id=" + dataSubId + + "([^0-9]| )\" | head -n 1 " + + "| grep -o -E \"simSlotIndex=[0-9]+\" " + + "| cut -d '=' -f 2"; + + CommandResult result = execute(executionMode, command); + Integer slotIndex = result.isSuccess() + ? ShellValueParser.extractFirstInt(result.getStdout()) + : null; + + return slotIndex != null && isValidSlotIndex(slotIndex) + ? slotIndex + : INVALID_SLOT_INDEX; + } + + private int resolveSubIdFromDumpsys( + ExecutionMode executionMode, + int slotIndex + ) { + String command = "dumpsys isub | grep -E \"simSlotIndex=" + slotIndex + + "([^0-9]| )\" | head -n 1 " + + "| grep -o -E \"\\{id=[0-9]+\" " + + "| cut -d '=' -f 2"; + + CommandResult result = execute(executionMode, command); + Integer subId = result.isSuccess() + ? ShellValueParser.extractFirstInt(result.getStdout()) + : null; + + return subId != null && subId > 0 + ? subId + : INVALID_SUB_ID; + } + + private CommandResult execute( + ExecutionMode executionMode, + String command + ) { + CommandExecutor executor = CommandExecutorFactory.forMode(executionMode); + if (executor == null) { + return CommandResult.failed(command, "No execution mode selected."); + } + return executor.execute(command); + } +} From 8341a08d3ea31bdf58d9f292f77fa68724749c9d Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:30:55 +0530 Subject: [PATCH 03/33] Added NetworkModeReader for preferred network mode readback --- .../telephony/NetworkModeReader.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 app/src/main/java/com/dhangofa/networktoggle/telephony/NetworkModeReader.java diff --git a/app/src/main/java/com/dhangofa/networktoggle/telephony/NetworkModeReader.java b/app/src/main/java/com/dhangofa/networktoggle/telephony/NetworkModeReader.java new file mode 100644 index 0000000..68dc0f4 --- /dev/null +++ b/app/src/main/java/com/dhangofa/networktoggle/telephony/NetworkModeReader.java @@ -0,0 +1,67 @@ +package com.dhangofa.networktoggle.telephony; + +import com.dhangofa.networktoggle.command.CommandExecutor; +import com.dhangofa.networktoggle.command.CommandExecutorFactory; +import com.dhangofa.networktoggle.config.AppPreferences; +import com.dhangofa.networktoggle.model.CommandResult; +import com.dhangofa.networktoggle.model.ExecutionMode; +import com.dhangofa.networktoggle.model.NetworkMode; +import com.dhangofa.networktoggle.model.TargetSim; + +public final class NetworkModeReader { + private final AppPreferences appPreferences; + private final SimResolver simResolver; + + public NetworkModeReader( + AppPreferences appPreferences, + SimResolver simResolver + ) { + this.appPreferences = appPreferences; + this.simResolver = simResolver; + } + + public NetworkMode readCurrentMode() { + ExecutionMode executionMode = appPreferences.getExecutionMode(); + if (executionMode == ExecutionMode.NONE) { + return NetworkMode.UNKNOWN; + } + + TargetSim targetSim = appPreferences.getTargetSim(); + int targetSubId = simResolver.resolveTargetSubId(executionMode); + + String command; + if (simResolver.isValidSubId(targetSubId)) { + command = "value=$(settings get global preferred_network_mode" + + targetSubId + + "); if [ -n \"$value\" ] " + + "&& [ \"$value\" != \"null\" ]; then " + + "echo \"$value\"; else exit 1; fi"; + } else if (targetSim == TargetSim.AUTO) { + command = "data_sim=$(settings get global multi_sim_data_call); " + + "[ \"$data_sim\" -gt 0 ] 2>/dev/null || exit 1; " + + "settings get global preferred_network_mode${data_sim}"; + } else { + return NetworkMode.UNKNOWN; + } + + CommandResult result = execute(executionMode, command); + if (!result.isSuccess()) { + return NetworkMode.UNKNOWN; + } + + return NetworkMode.fromLegacyMode( + ShellValueParser.extractFirstInt(result.getStdout()) + ); + } + + private CommandResult execute( + ExecutionMode executionMode, + String command + ) { + CommandExecutor executor = CommandExecutorFactory.forMode(executionMode); + if (executor == null) { + return CommandResult.failed(command, "No execution mode selected."); + } + return executor.execute(command); + } +} From 1f28e25fde26239860c52b218818158d180e010a Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:32:59 +0530 Subject: [PATCH 04/33] Added NetworkModeController for applying selected network modes --- .../telephony/NetworkModeController.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 app/src/main/java/com/dhangofa/networktoggle/telephony/NetworkModeController.java diff --git a/app/src/main/java/com/dhangofa/networktoggle/telephony/NetworkModeController.java b/app/src/main/java/com/dhangofa/networktoggle/telephony/NetworkModeController.java new file mode 100644 index 0000000..752b678 --- /dev/null +++ b/app/src/main/java/com/dhangofa/networktoggle/telephony/NetworkModeController.java @@ -0,0 +1,46 @@ +package com.dhangofa.networktoggle.telephony; + +import com.dhangofa.networktoggle.command.CommandExecutor; +import com.dhangofa.networktoggle.command.CommandExecutorFactory; +import com.dhangofa.networktoggle.model.CommandResult; +import com.dhangofa.networktoggle.model.ExecutionMode; +import com.dhangofa.networktoggle.model.NetworkMode; + +public final class NetworkModeController { + private final SimResolver simResolver; + + public NetworkModeController(SimResolver simResolver) { + this.simResolver = simResolver; + } + + public CommandResult apply( + NetworkMode networkMode, + ExecutionMode executionMode + ) { + if (networkMode == null + || networkMode == NetworkMode.UNKNOWN + || networkMode.getBinaryMask() == null) { + return CommandResult.failed("", "Invalid network mode selected."); + } + + int slotIndex = simResolver.resolveTargetSlotIndex(executionMode); + if (!simResolver.isValidSlotIndex(slotIndex)) { + return CommandResult.failed( + "", + "Unable to resolve the target physical SIM slot." + ); + } + + String command = "cmd phone set-allowed-network-types-for-users -s " + + slotIndex + + " " + + networkMode.getBinaryMask(); + + CommandExecutor executor = CommandExecutorFactory.forMode(executionMode); + if (executor == null) { + return CommandResult.failed(command, "No execution mode selected."); + } + + return executor.execute(command); + } +} From 2a7d448d847fd74b0c4f70ae531032b1549de27b Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:35:39 +0530 Subject: [PATCH 05/33] Removed SIM resolution and telephony shell-command construction from NetworkTileService - Removed SIM resolution and telephony shell-command construction from NetworkTileService. - Updated NetworkTileService to coordinate the modular telephony components. - Preserved existing Target SIM, readback, switching, cache, label, icon, and Auto SIM error behavior. --- .../networktoggle/NetworkTileService.java | 223 ++++++------------ 1 file changed, 73 insertions(+), 150 deletions(-) diff --git a/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java b/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java index 6ee741a..2149cbf 100644 --- a/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java +++ b/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java @@ -6,34 +6,29 @@ import android.graphics.Paint; import android.graphics.Typeface; import android.graphics.drawable.Icon; -import android.os.Build; import android.os.Handler; import android.os.Looper; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; -import android.telephony.SubscriptionManager; import android.widget.Toast; -import com.dhangofa.networktoggle.command.CommandExecutor; -import com.dhangofa.networktoggle.command.CommandExecutorFactory; import com.dhangofa.networktoggle.config.AppPreferences; import com.dhangofa.networktoggle.model.CommandResult; import com.dhangofa.networktoggle.model.ExecutionMode; import com.dhangofa.networktoggle.model.NetworkMode; -import com.dhangofa.networktoggle.model.TargetSim; +import com.dhangofa.networktoggle.telephony.NetworkModeController; +import com.dhangofa.networktoggle.telephony.NetworkModeReader; +import com.dhangofa.networktoggle.telephony.SimResolver; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class NetworkTileService extends TileService { - private static final int INVALID_SLOT_INDEX = -1; - private static final int INVALID_SUB_ID = -1; - private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor(); - private static final AtomicBoolean IS_SWITCHING = new AtomicBoolean(false); - private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+"); + private static final ExecutorService EXECUTOR = + Executors.newSingleThreadExecutor(); + private static final AtomicBoolean IS_SWITCHING = + new AtomicBoolean(false); private static Icon icon4g; private static Icon icon5g; @@ -42,25 +37,36 @@ public class NetworkTileService extends TileService { private static Icon iconUnknown; private final Handler mainHandler = new Handler(Looper.getMainLooper()); + private AppPreferences appPreferences; + private NetworkModeReader networkModeReader; + private NetworkModeController networkModeController; @Override public void onCreate() { super.onCreate(); + appPreferences = new AppPreferences(this); + SimResolver simResolver = new SimResolver(appPreferences); + networkModeReader = new NetworkModeReader(appPreferences, simResolver); + networkModeController = new NetworkModeController(simResolver); } @Override public void onStartListening() { super.onStartListening(); + NetworkMode cachedMode = appPreferences.getCachedNetworkMode(); updateTileUI(cachedMode); if (appPreferences.getExecutionMode() == ExecutionMode.NONE - || cachedMode != NetworkMode.UNKNOWN) return; + || cachedMode != NetworkMode.UNKNOWN) { + return; + } EXECUTOR.execute(() -> { - NetworkMode realMode = readCurrentNetworkMode(); + NetworkMode realMode = networkModeReader.readCurrentMode(); + mainHandler.post(() -> { if (realMode != NetworkMode.UNKNOWN) { appPreferences.setCachedNetworkMode(realMode); @@ -75,6 +81,7 @@ public void onStartListening() { @Override public void onClick() { super.onClick(); + if (!IS_SWITCHING.compareAndSet(false, true)) { updateTileSwitchingUI(); return; @@ -92,16 +99,22 @@ public void onClick() { updateTileSwitchingUI(); EXECUTOR.execute(() -> { - boolean success = applyNetworkMode(nextMode, executionMode); + CommandResult result = networkModeController.apply( + nextMode, + executionMode + ); + mainHandler.post(() -> { try { - if (success) { + if (result.isSuccess()) { appPreferences.setCachedNetworkMode(nextMode); appPreferences.setAutoSimError(false); updateTileUI(nextMode); } else { updateTileUI(currentMode); - if (appPreferences.hasAutoSimError()) showAutoSimErrorToast(); + if (appPreferences.hasAutoSimError()) { + showAutoSimErrorToast(); + } } } finally { IS_SWITCHING.set(false); @@ -112,35 +125,60 @@ public void onClick() { private Icon createTextOnlyIcon(String text) { int size = 256; - Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); + Bitmap bitmap = Bitmap.createBitmap( + size, + size, + Bitmap.Config.ARGB_8888 + ); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.WHITE); - paint.setTypeface(Typeface.create("sans-serif-condensed", Typeface.BOLD)); + paint.setTypeface(Typeface.create( + "sans-serif-condensed", + Typeface.BOLD + )); paint.setTextAlign(Paint.Align.CENTER); paint.setTextSize(190f); + float width = paint.measureText(text); - if (width > 240f) paint.setTextScaleX(240f / width); - Paint.FontMetrics fm = paint.getFontMetrics(); - float y = (size / 2f) - (fm.descent + fm.ascent) / 2f; + if (width > 240f) { + paint.setTextScaleX(240f / width); + } + + Paint.FontMetrics metrics = paint.getFontMetrics(); + float y = (size / 2f) - (metrics.descent + metrics.ascent) / 2f; canvas.drawText(text, size / 2f, y, paint); + return Icon.createWithBitmap(bitmap); } private Icon getCachedIcon(String text) { switch (text) { - case "4G": if (icon4g == null) icon4g = createTextOnlyIcon("4G"); return icon4g; - case "5G": if (icon5g == null) icon5g = createTextOnlyIcon("5G"); return icon5g; - case "P5G": if (iconP5g == null) iconP5g = createTextOnlyIcon("P5G"); return iconP5g; - case "P4G": if (iconP4g == null) iconP4g = createTextOnlyIcon("P4G"); return iconP4g; - default: if (iconUnknown == null) iconUnknown = createTextOnlyIcon("?"); return iconUnknown; + case "4G": + if (icon4g == null) icon4g = createTextOnlyIcon("4G"); + return icon4g; + case "5G": + if (icon5g == null) icon5g = createTextOnlyIcon("5G"); + return icon5g; + case "P5G": + if (iconP5g == null) iconP5g = createTextOnlyIcon("P5G"); + return iconP5g; + case "P4G": + if (iconP4g == null) iconP4g = createTextOnlyIcon("P4G"); + return iconP4g; + default: + if (iconUnknown == null) { + iconUnknown = createTextOnlyIcon("?"); + } + return iconUnknown; } } private void updateTileSwitchingUI() { Tile tile = getQsTile(); if (tile == null) return; + tile.setState(Tile.STATE_INACTIVE); tile.setLabel("Switching..."); tile.setIcon(getCachedIcon("?")); @@ -150,6 +188,7 @@ private void updateTileSwitchingUI() { private void updateTileUI(NetworkMode mode) { Tile tile = getQsTile(); if (tile == null) return; + if (mode == NetworkMode.UNKNOWN) { if (appPreferences.getExecutionMode() == ExecutionMode.NONE) { tile.setState(Tile.STATE_UNAVAILABLE); @@ -164,132 +203,16 @@ private void updateTileUI(NetworkMode mode) { tile.setLabel(mode.getTileLabel()); tile.setIcon(getCachedIcon(mode.getIconText())); } - tile.updateTile(); - } - - private NetworkMode readCurrentNetworkMode() { - ExecutionMode executionMode = appPreferences.getExecutionMode(); - if (executionMode == ExecutionMode.NONE) return NetworkMode.UNKNOWN; - - TargetSim targetSim = appPreferences.getTargetSim(); - int targetSubId = INVALID_SUB_ID; - if (targetSim == TargetSim.AUTO) { - targetSubId = SubscriptionManager.getDefaultDataSubscriptionId(); - } else { - targetSubId = resolveSubIdFromDumpsys(executionMode, targetSim.getManualSlotIndex()); - } - - String command; - if (targetSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID - && targetSubId != INVALID_SUB_ID) { - command = "value=$(settings get global preferred_network_mode" + targetSubId + "); " - + "if [ -n \"$value\" ] && [ \"$value\" != \"null\" ]; then " - + "echo \"$value\"; else exit 1; fi"; - } else if (targetSim == TargetSim.AUTO) { - command = "data_sim=$(settings get global multi_sim_data_call); " - + "[ \"$data_sim\" -gt 0 ] 2>/dev/null || exit 1; " - + "settings get global preferred_network_mode${data_sim}"; - } else { - return NetworkMode.UNKNOWN; - } - CommandResult result = runCommandForResult(executionMode, command); - if (result.getExitCode() != 0) return NetworkMode.UNKNOWN; - return NetworkMode.fromLegacyMode(extractFirstInt(result.getStdout())); - } - - private CommandResult runCommandForResult(ExecutionMode mode, String command) { - CommandExecutor executor = CommandExecutorFactory.forMode(mode); - if (executor == null) { - return CommandResult.failed(command, "No execution mode selected."); - } - return executor.execute(command); - } - - private Integer extractFirstInt(String text) { - try { - if (text == null || text.trim().isEmpty() || text.trim().equalsIgnoreCase("null")) return null; - Matcher matcher = NUMBER_PATTERN.matcher(text); - return matcher.find() ? Integer.parseInt(matcher.group()) : null; - } catch (Exception e) { - return null; - } - } - - private boolean isValidSlotIndex(int slotIndex) { - return slotIndex == 0 || slotIndex == 1; - } - - private void setAutoSimError(boolean value) { - appPreferences.setAutoSimError(value); + tile.updateTile(); } private void showAutoSimErrorToast() { - Toast.makeText(this, - "Unable to detect active data SIM automatically. Please choose SIM from the app.", - Toast.LENGTH_LONG).show(); - } - - private int resolveTargetSlotIndex(ExecutionMode executionMode) { - TargetSim targetSim = appPreferences.getTargetSim(); - if (!targetSim.isAuto()) { - setAutoSimError(false); - return targetSim.getManualSlotIndex(); - } - return resolveAutoSlotIndex(executionMode); + Toast.makeText( + this, + "Unable to detect active data SIM automatically. " + + "Please choose SIM from the app.", + Toast.LENGTH_LONG + ).show(); } - - private int resolveAutoSlotIndex(ExecutionMode executionMode) { - int dataSubId = SubscriptionManager.getDefaultDataSubscriptionId(); - if (dataSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - setAutoSimError(true); - return INVALID_SLOT_INDEX; - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - try { - int slot = SubscriptionManager.getSlotIndex(dataSubId); - if (isValidSlotIndex(slot)) { - setAutoSimError(false); - return slot; - } - } catch (Exception ignored) { - } - } - int slot = resolveSlotIndexFromDumpsys(executionMode, dataSubId); - if (isValidSlotIndex(slot)) { - setAutoSimError(false); - return slot; - } - setAutoSimError(true); - return INVALID_SLOT_INDEX; - } - - private int resolveSlotIndexFromDumpsys(ExecutionMode executionMode, int dataSubId) { - String command = "dumpsys isub | grep -E \"\\{id=" + dataSubId - + "([^0-9]| )\" | head -n 1 | grep -o -E \"simSlotIndex=[0-9]+\" " - + "| cut -d '=' -f 2"; - CommandResult result = runCommandForResult(executionMode, command); - Integer slot = result.getExitCode() == 0 ? extractFirstInt(result.getStdout()) : null; - return slot != null && isValidSlotIndex(slot) ? slot : INVALID_SLOT_INDEX; - } - - private int resolveSubIdFromDumpsys(ExecutionMode executionMode, int slotIndex) { - String command = "dumpsys isub | grep -E \"simSlotIndex=" + slotIndex - + "([^0-9]| )\" | head -n 1 | grep -o -E \"\\{id=[0-9]+\" " - + "| cut -d '=' -f 2"; - CommandResult result = runCommandForResult(executionMode, command); - Integer subId = result.getExitCode() == 0 ? extractFirstInt(result.getStdout()) : null; - return subId != null && subId > 0 ? subId : INVALID_SUB_ID; - } - - private boolean applyNetworkMode(NetworkMode mode, ExecutionMode executionMode) { - int slotIndex = resolveTargetSlotIndex(executionMode); - if (!isValidSlotIndex(slotIndex) || mode.getBinaryMask() == null) return false; - - String command = "cmd phone set-allowed-network-types-for-users -s " - + slotIndex + " " + mode.getBinaryMask(); - CommandResult result = runCommandForResult(executionMode, command); - return result.isSuccess(); - } - } From 0bc41937cf2f01e9998c506f663ecee717df4c27 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:39:43 +0530 Subject: [PATCH 06/33] Added ordered cycle persistence to AppPreferences --- .../networktoggle/config/AppPreferences.java | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/dhangofa/networktoggle/config/AppPreferences.java b/app/src/main/java/com/dhangofa/networktoggle/config/AppPreferences.java index 4b824fe..de5ac8f 100644 --- a/app/src/main/java/com/dhangofa/networktoggle/config/AppPreferences.java +++ b/app/src/main/java/com/dhangofa/networktoggle/config/AppPreferences.java @@ -7,12 +7,16 @@ import com.dhangofa.networktoggle.model.NetworkMode; import com.dhangofa.networktoggle.model.TargetSim; +import java.util.ArrayList; +import java.util.List; + public final class AppPreferences { private static final String PREFS_NAME = "NetTogglePrefs"; private static final String KEY_EXEC_MODE = "exec_mode"; private static final String KEY_TARGET_SIM = "target_sim"; private static final String KEY_NETWORK_STATE = "net_state"; private static final String KEY_AUTO_SIM_ERROR = "auto_sim_error"; + private static final String KEY_TILE_CYCLE_MODES = "tile_cycle_modes"; private final SharedPreferences preferences; @@ -26,19 +30,11 @@ public ExecutionMode getExecutionMode() { preferences.getInt(KEY_EXEC_MODE, ExecutionMode.NONE.getValue())); } - public void setExecutionMode(ExecutionMode mode) { - preferences.edit().putInt(KEY_EXEC_MODE, mode.getValue()).apply(); - } - public TargetSim getTargetSim() { return TargetSim.fromValue( preferences.getInt(KEY_TARGET_SIM, TargetSim.AUTO.getValue())); } - public void setTargetSim(TargetSim targetSim) { - preferences.edit().putInt(KEY_TARGET_SIM, targetSim.getValue()).apply(); - } - public NetworkMode getCachedNetworkMode() { return NetworkMode.fromStateValue( preferences.getInt(KEY_NETWORK_STATE, NetworkMode.UNKNOWN.getStateValue())); @@ -48,6 +44,10 @@ public void setCachedNetworkMode(NetworkMode mode) { preferences.edit().putInt(KEY_NETWORK_STATE, mode.getStateValue()).apply(); } + public void clearCachedNetworkMode() { + setCachedNetworkMode(NetworkMode.UNKNOWN); + } + public boolean hasAutoSimError() { return preferences.getBoolean(KEY_AUTO_SIM_ERROR, false); } @@ -72,6 +72,31 @@ public void onTargetSimChanged(TargetSim targetSim) { .apply(); } + public List getTileCycleModes() { + String saved = preferences.getString(KEY_TILE_CYCLE_MODES, ""); + List modes = new ArrayList<>(); + if (saved == null || saved.trim().isEmpty()) return modes; + + String[] ids = saved.split(","); + for (String id : ids) { + try { + NetworkMode mode = NetworkMode.valueOf(id.trim()); + if (mode != NetworkMode.UNKNOWN && !modes.contains(mode)) modes.add(mode); + } catch (IllegalArgumentException ignored) { + } + } + return modes; + } + + public void setTileCycleModes(List modes) { + StringBuilder value = new StringBuilder(); + for (NetworkMode mode : modes) { + if (value.length() > 0) value.append(','); + value.append(mode.name()); + } + preferences.edit().putString(KEY_TILE_CYCLE_MODES, value.toString()).apply(); + } + public void clearTransientState() { preferences.edit() .putInt(KEY_NETWORK_STATE, NetworkMode.UNKNOWN.getStateValue()) From c349fd09a29bf30573a7e391f15f9ade44b0f6aa Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:42:30 +0530 Subject: [PATCH 07/33] Added TileCycleManager for validating and navigating ordered tile cycles --- .../networktoggle/cycle/TileCycleManager.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 app/src/main/java/com/dhangofa/networktoggle/cycle/TileCycleManager.java diff --git a/app/src/main/java/com/dhangofa/networktoggle/cycle/TileCycleManager.java b/app/src/main/java/com/dhangofa/networktoggle/cycle/TileCycleManager.java new file mode 100644 index 0000000..95155b1 --- /dev/null +++ b/app/src/main/java/com/dhangofa/networktoggle/cycle/TileCycleManager.java @@ -0,0 +1,92 @@ +package com.dhangofa.networktoggle.cycle; + +import com.dhangofa.networktoggle.config.AppPreferences; +import com.dhangofa.networktoggle.model.NetworkMode; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public final class TileCycleManager { + public static final int MIN_MODES = 2; + public static final int MAX_MODES = 3; + + private static final List DEFAULT_CYCLE = + Collections.unmodifiableList(Arrays.asList( + NetworkMode.FIVE_G_ONLY, + NetworkMode.FOUR_G_ONLY, + NetworkMode.PREFERRED_5G + )); + + public enum ChangeResult { + CHANGED, + MINIMUM_REACHED, + MAXIMUM_REACHED, + INVALID_MODE, + NO_CHANGE + } + + private final AppPreferences appPreferences; + + public TileCycleManager(AppPreferences appPreferences) { + this.appPreferences = appPreferences; + } + + public List getCycle() { + List saved = appPreferences.getTileCycleModes(); + if (!isValid(saved)) { + appPreferences.setTileCycleModes(DEFAULT_CYCLE); + return new ArrayList<>(DEFAULT_CYCLE); + } + return new ArrayList<>(saved); + } + + public NetworkMode getFirstMode() { + return getCycle().get(0); + } + + public NetworkMode getNextMode(NetworkMode currentMode) { + List cycle = getCycle(); + int currentIndex = cycle.indexOf(currentMode); + if (currentIndex < 0) return cycle.get(0); + return cycle.get((currentIndex + 1) % cycle.size()); + } + + public ChangeResult setSelected(NetworkMode mode, boolean selected) { + if (mode == null || mode == NetworkMode.UNKNOWN) { + return ChangeResult.INVALID_MODE; + } + + List cycle = getCycle(); + boolean alreadySelected = cycle.contains(mode); + if (selected == alreadySelected) return ChangeResult.NO_CHANGE; + + if (selected) { + if (cycle.size() >= MAX_MODES) return ChangeResult.MAXIMUM_REACHED; + cycle.add(mode); + } else { + if (cycle.size() <= MIN_MODES) return ChangeResult.MINIMUM_REACHED; + cycle.remove(mode); + } + + appPreferences.setTileCycleModes(cycle); + appPreferences.clearCachedNetworkMode(); + return ChangeResult.CHANGED; + } + + public boolean isValid(List cycle) { + if (cycle == null || cycle.size() < MIN_MODES || cycle.size() > MAX_MODES) { + return false; + } + + List unique = new ArrayList<>(); + for (NetworkMode mode : cycle) { + if (mode == null || mode == NetworkMode.UNKNOWN || unique.contains(mode)) { + return false; + } + unique.add(mode); + } + return true; + } +} From 841c1b4633890de1c71d01aebfc9f84ea23f1dab Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:49:53 +0530 Subject: [PATCH 08/33] Add Quick Tile Cycle configuration card - Added a dedicated Quick Tile Cycle card. - Added mode selectors for 5G Only, 4G Only, Preferred 5G, and Preferred 4G. - Added selected-mode count display. - Added a live preview of the configured cycle order. - Reused the existing card, control, border, text, and brand styling. - Kept the cycle card in a separate reusable layout resource. --- .../ui/TileCycleUiController.java | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 app/src/main/java/com/dhangofa/networktoggle/ui/TileCycleUiController.java diff --git a/app/src/main/java/com/dhangofa/networktoggle/ui/TileCycleUiController.java b/app/src/main/java/com/dhangofa/networktoggle/ui/TileCycleUiController.java new file mode 100644 index 0000000..5f91afc --- /dev/null +++ b/app/src/main/java/com/dhangofa/networktoggle/ui/TileCycleUiController.java @@ -0,0 +1,84 @@ +package com.dhangofa.networktoggle.ui; + +import android.app.Activity; +import android.widget.CheckBox; +import android.widget.TextView; +import android.widget.Toast; + +import com.dhangofa.networktoggle.R; +import com.dhangofa.networktoggle.cycle.TileCycleManager; +import com.dhangofa.networktoggle.model.NetworkMode; + +import java.util.List; + +public final class TileCycleUiController { + private final Activity activity; + private final TileCycleManager cycleManager; + private final CheckBox mode5gOnly; + private final CheckBox mode4gOnly; + private final CheckBox modePref5g; + private final CheckBox modePref4g; + private final TextView selectedCount; + private final TextView cycleOrder; + private boolean updatingUi; + + public TileCycleUiController(Activity activity, TileCycleManager cycleManager) { + this.activity = activity; + this.cycleManager = cycleManager; + mode5gOnly = activity.findViewById(R.id.cycle5gOnly); + mode4gOnly = activity.findViewById(R.id.cycle4gOnly); + modePref5g = activity.findViewById(R.id.cyclePreferred5g); + modePref4g = activity.findViewById(R.id.cyclePreferred4g); + selectedCount = activity.findViewById(R.id.cycleSelectedCount); + cycleOrder = activity.findViewById(R.id.cycleOrderText); + } + + public void initialize() { + refresh(); + mode5gOnly.setOnCheckedChangeListener((button, selected) -> + handleSelection(NetworkMode.FIVE_G_ONLY, selected)); + mode4gOnly.setOnCheckedChangeListener((button, selected) -> + handleSelection(NetworkMode.FOUR_G_ONLY, selected)); + modePref5g.setOnCheckedChangeListener((button, selected) -> + handleSelection(NetworkMode.PREFERRED_5G, selected)); + modePref4g.setOnCheckedChangeListener((button, selected) -> + handleSelection(NetworkMode.PREFERRED_4G, selected)); + } + + private void handleSelection(NetworkMode mode, boolean selected) { + if (updatingUi) return; + + TileCycleManager.ChangeResult result = cycleManager.setSelected(mode, selected); + if (result == TileCycleManager.ChangeResult.MINIMUM_REACHED) { + showToast("Select at least 2 tile modes."); + } else if (result == TileCycleManager.ChangeResult.MAXIMUM_REACHED) { + showToast("You can select up to 3 tile modes."); + } + refresh(); + } + + private void refresh() { + updatingUi = true; + List cycle = cycleManager.getCycle(); + mode5gOnly.setChecked(cycle.contains(NetworkMode.FIVE_G_ONLY)); + mode4gOnly.setChecked(cycle.contains(NetworkMode.FOUR_G_ONLY)); + modePref5g.setChecked(cycle.contains(NetworkMode.PREFERRED_5G)); + modePref4g.setChecked(cycle.contains(NetworkMode.PREFERRED_4G)); + selectedCount.setText("Selected: " + cycle.size() + "/3"); + cycleOrder.setText(buildOrderText(cycle)); + updatingUi = false; + } + + private String buildOrderText(List cycle) { + StringBuilder text = new StringBuilder("Cycle: "); + for (int i = 0; i < cycle.size(); i++) { + if (i > 0) text.append(" → "); + text.append(cycle.get(i).getDisplayName()); + } + return text.toString(); + } + + private void showToast(String message) { + Toast.makeText(activity, message, Toast.LENGTH_SHORT).show(); + } +} From 032f5bb68dc49e8afd5e4977997afb0299c405d5 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:54:29 +0530 Subject: [PATCH 09/33] Add Quick Tile Cycle configuration card - Added a dedicated Quick Tile Cycle card. - Added mode selectors for 5G Only, 4G Only, Preferred 5G, and Preferred 4G. - Added selected-mode count display. - Added a live preview of the configured cycle order. - Reused the existing card, control, border, text, and brand styling. - Kept the cycle card in a separate reusable layout resource. --- .../main/res/layout/view_tile_cycle_card.xml | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 app/src/main/res/layout/view_tile_cycle_card.xml diff --git a/app/src/main/res/layout/view_tile_cycle_card.xml b/app/src/main/res/layout/view_tile_cycle_card.xml new file mode 100644 index 0000000..92047c4 --- /dev/null +++ b/app/src/main/res/layout/view_tile_cycle_card.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 450e9d6f06a63faa474e13fc6231991ea4b7e0d6 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:55:21 +0530 Subject: [PATCH 10/33] Add tile cycle UI controller - Added TileCycleUiController to keep cycle-selection logic out of MainActivity. - Connected each cycle selector to its corresponding NetworkMode. - Refreshed selector states from the saved ordered cycle. - Blocked selections above the three-mode maximum. - Blocked removals below the two-mode minimum. - Restored the previous checkbox state after an invalid selection attempt. - Added user feedback for minimum and maximum selection limits. - Updated the selected count and cycle-order preview after each valid change. --- .../com/dhangofa/networktoggle/ui/TileCycleUiController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/dhangofa/networktoggle/ui/TileCycleUiController.java b/app/src/main/java/com/dhangofa/networktoggle/ui/TileCycleUiController.java index 5f91afc..7b06b9e 100644 --- a/app/src/main/java/com/dhangofa/networktoggle/ui/TileCycleUiController.java +++ b/app/src/main/java/com/dhangofa/networktoggle/ui/TileCycleUiController.java @@ -82,3 +82,4 @@ private void showToast(String message) { Toast.makeText(activity, message, Toast.LENGTH_SHORT).show(); } } + From 0cbbcee218f537efcffc5c6dc7607ab8986d83ed Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:02:36 +0530 Subject: [PATCH 11/33] Integrate tile cycle controls into MainActivity - Initialized TileCycleManager from the shared AppPreferences instance. - Initialized TileCycleUiController after the activity layout and views were ready. - Kept cycle configuration logic outside MainActivity. - Preserved existing Root, Shizuku, Target SIM, warning, link, and lifecycle behavior. --- .../java/com/dhangofa/networktoggle/MainActivity.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java b/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java index b66c6f6..7e1d008 100644 --- a/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java +++ b/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java @@ -38,10 +38,14 @@ import com.dhangofa.networktoggle.config.AppPreferences; import com.dhangofa.networktoggle.model.ExecutionMode; import com.dhangofa.networktoggle.model.TargetSim; +import com.dhangofa.networktoggle.cycle.TileCycleManager; +import com.dhangofa.networktoggle.ui.TileCycleUiController; + import rikka.shizuku.Shizuku; -public class MainActivity extends Activity { +public class MainActivity extends Activity { + private RadioGroup radioGroup; private RadioButton radioRoot; private RadioButton radioShizuku; @@ -56,6 +60,7 @@ public class MainActivity extends Activity { private TextView autoSimWarningText; private AppPreferences appPreferences; + private TileCycleUiController tileCycleUiController; private volatile boolean activityDestroyed; private Thread rootCheckThread; private Process rootCheckProcess; @@ -99,6 +104,9 @@ protected void onCreate(Bundle savedInstanceState) { appPreferences = new AppPreferences(this); bindViews(); bindLinks(); + TileCycleManager tileCycleManager = new TileCycleManager(appPreferences); + tileCycleUiController = new TileCycleUiController(this, tileCycleManager); + tileCycleUiController.initialize(); registerShizukuListeners(); loadSavedExecutionMode(); loadSavedTargetSimMode(); From a491a5c88f4806a28b8e515e3a0456366aae6cb1 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:09:12 +0530 Subject: [PATCH 12/33] Use configured cycle in NetworkTileService - Initialized TileCycleManager inside NetworkTileService. - Replaced the fixed four-mode cycle with the saved user-configured cycle. - Used the first configured mode when the current state is not part of the selected cycle. - Updated the unknown-state tile label to show the first configured target mode. - Preserved command execution, SIM resolution, readback, caching, icons, and switching-state behavior. --- .../dhangofa/networktoggle/NetworkTileService.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java b/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java index 2149cbf..4c18b3d 100644 --- a/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java +++ b/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java @@ -19,6 +19,7 @@ import com.dhangofa.networktoggle.telephony.NetworkModeController; import com.dhangofa.networktoggle.telephony.NetworkModeReader; import com.dhangofa.networktoggle.telephony.SimResolver; +import com.dhangofa.networktoggle.cycle.TileCycleManager; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -41,12 +42,14 @@ public class NetworkTileService extends TileService { private AppPreferences appPreferences; private NetworkModeReader networkModeReader; private NetworkModeController networkModeController; + private TileCycleManager tileCycleManager; @Override public void onCreate() { super.onCreate(); appPreferences = new AppPreferences(this); + tileCycleManager = new TileCycleManager(appPreferences); SimResolver simResolver = new SimResolver(appPreferences); networkModeReader = new NetworkModeReader(appPreferences, simResolver); networkModeController = new NetworkModeController(simResolver); @@ -95,7 +98,7 @@ public void onClick() { } NetworkMode currentMode = appPreferences.getCachedNetworkMode(); - NetworkMode nextMode = NetworkMode.nextInDefaultCycle(currentMode); + NetworkMode nextMode = tileCycleManager.getNextMode(currentMode); updateTileSwitchingUI(); EXECUTOR.execute(() -> { @@ -195,12 +198,14 @@ private void updateTileUI(NetworkMode mode) { tile.setLabel("Setup Required"); } else { tile.setState(Tile.STATE_INACTIVE); - tile.setLabel(mode.getTileLabel()); + NetworkMode firstMode = tileCycleManager.getFirstMode(); + tile.setLabel("Tap to Set " + firstMode.getTileLabel()); } tile.setIcon(getCachedIcon("?")); } else { tile.setState(Tile.STATE_ACTIVE); - tile.setLabel(mode.getTileLabel()); + NetworkMode firstMode = tileCycleManager.getFirstMode(); + tile.setLabel("Tap to Set " + firstMode.getTileLabel()); tile.setIcon(getCachedIcon(mode.getIconText())); } From b5e0b36a1d3274dcb5392eaf7c909bba550c3d16 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:14:54 +0530 Subject: [PATCH 13/33] Add Quick Tile Cycle card to main layout - Added the reusable Quick Tile Cycle card to the main app layout. - Positioned the cycle configuration below the Execution Mode and Target SIM controls. - Kept the Developer card below the new cycle section. - Reused the existing spacing and card styling. --- app/src/main/res/layout/activity_main.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ae81eb5..fd46ccd 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -326,6 +326,8 @@ + + Date: Tue, 11 Aug 2026 17:41:06 +0530 Subject: [PATCH 14/33] Prevent stale readback from overriding tile state - Added a current-state check before applying asynchronous network mode readback. - Ignored stale readback callbacks after a successful tile operation. - Removed the redundant unknown-state UI update from failed readback. - Prevented the configured first-mode prompt from overriding the active tile label. - Preserved normal readback behavior when the cached state is still unknown. --- .../networktoggle/NetworkTileService.java | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java b/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java index 4c18b3d..2488cfe 100644 --- a/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java +++ b/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java @@ -67,19 +67,26 @@ public void onStartListening() { return; } - EXECUTOR.execute(() -> { - NetworkMode realMode = networkModeReader.readCurrentMode(); - - mainHandler.post(() -> { - if (realMode != NetworkMode.UNKNOWN) { - appPreferences.setCachedNetworkMode(realMode); - updateTileUI(realMode); - } else { - updateTileUI(cachedMode); - } - }); - }); - } + EXECUTOR.execute(() -> { + NetworkMode realMode = networkModeReader.readCurrentMode(); + + mainHandler.post(() -> { + /* + * A tile click or another operation may have updated the state + * while this asynchronous readback was running. + */ + if (appPreferences.getCachedNetworkMode() + != NetworkMode.UNKNOWN) { + return; + } + + if (realMode != NetworkMode.UNKNOWN) { + appPreferences.setCachedNetworkMode(realMode); + updateTileUI(realMode); + } + }); + }); + } @Override public void onClick() { From 665b767c1f3aa612bf652ccdf88edd08a20e8bee Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:26:13 +0530 Subject: [PATCH 15/33] Activated the custom NoActionBar light and dark themes from the application manifest --- app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a11f23c..f4291a9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,7 +12,7 @@ android:label="NetToggle" android:icon="@drawable/ic_launcher" android:roundIcon="@drawable/ic_launcher" - android:theme="@android:style/Theme.DeviceDefault.DayNight" + android:theme="@style/Theme.NetToggle" android:supportsRtl="true"> Date: Tue, 11 Aug 2026 19:31:23 +0530 Subject: [PATCH 16/33] Removed framework ActionBar initialization from MainActivity - Activated the custom NoActionBar theme through the application manifest. - Removed framework ActionBar initialization from MainActivity. - Removed the ActionBar-hosted version pill and title styling. - Removed unused ActionBar-specific imports. - Retained app version lookup for a future in-layout version display. - Preserved status bar styling and all existing app behavior. --- .../dhangofa/networktoggle/MainActivity.java | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java b/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java index 7e1d008..5446677 100644 --- a/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java +++ b/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java @@ -24,11 +24,9 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; -import android.graphics.Typeface; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.view.Gravity; import android.view.View; import android.widget.ImageView; import android.widget.RadioButton; @@ -97,7 +95,6 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); activityDestroyed = false; - configureActionBar(); configureStatusBar(); setContentView(R.layout.activity_main); @@ -114,41 +111,6 @@ protected void onCreate(Bundle savedInstanceState) { bindSelectionListeners(); } - private void configureActionBar() { - if (getActionBar() == null) return; - - getActionBar().setDisplayOptions( - android.app.ActionBar.DISPLAY_SHOW_TITLE - | android.app.ActionBar.DISPLAY_SHOW_CUSTOM); - - TextView versionText = new TextView(this); - versionText.setText("v" + getAppVersionName()); - versionText.setTextSize(12); - versionText.setTypeface(null, Typeface.BOLD); - versionText.setTextColor(getColor(R.color.brand_on_primary_container)); - versionText.setBackgroundResource(R.drawable.shape_pill_badge_bg); - - float density = getResources().getDisplayMetrics().density; - versionText.setPadding((int) (10 * density), (int) (4 * density), - (int) (10 * density), (int) (4 * density)); - - android.app.ActionBar.LayoutParams params = new android.app.ActionBar.LayoutParams( - android.app.ActionBar.LayoutParams.WRAP_CONTENT, - android.app.ActionBar.LayoutParams.WRAP_CONTENT, - Gravity.END | Gravity.CENTER_VERTICAL); - params.setMarginEnd((int) (16 * density)); - - getActionBar().setCustomView(versionText, params); - getActionBar().setElevation(0); - - try { - int titleId = getResources().getIdentifier("action_bar_title", "id", "android"); - TextView titleText = findViewById(titleId); - if (titleText != null) titleText.setTypeface(null, Typeface.BOLD); - } catch (Exception ignored) { - } - } - private void configureStatusBar() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return; From 525b5bf402d41e13c25884a47a6e390ed1cbee92 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:34:38 +0530 Subject: [PATCH 17/33] Added shape_segmented_container for new buttons --- app/src/main/res/drawable/shape_segmented_container.xml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 app/src/main/res/drawable/shape_segmented_container.xml diff --git a/app/src/main/res/drawable/shape_segmented_container.xml b/app/src/main/res/drawable/shape_segmented_container.xml new file mode 100644 index 0000000..d22bb10 --- /dev/null +++ b/app/src/main/res/drawable/shape_segmented_container.xml @@ -0,0 +1,6 @@ + + + + + + From 4fe4922d6cba0195e4c2c005e27e3add97992583 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:36:11 +0530 Subject: [PATCH 18/33] Added selector_segmented_tab for new buttons --- .../main/res/drawable/selector_segmented_tab.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 app/src/main/res/drawable/selector_segmented_tab.xml diff --git a/app/src/main/res/drawable/selector_segmented_tab.xml b/app/src/main/res/drawable/selector_segmented_tab.xml new file mode 100644 index 0000000..ae444e7 --- /dev/null +++ b/app/src/main/res/drawable/selector_segmented_tab.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + From 77fb2b123e1024d7ea332bf22f091540e900e07c Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:37:25 +0530 Subject: [PATCH 19/33] Added color_segmented_text for new buttons --- app/src/main/res/drawable/color_segmented_text.xml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 app/src/main/res/drawable/color_segmented_text.xml diff --git a/app/src/main/res/drawable/color_segmented_text.xml b/app/src/main/res/drawable/color_segmented_text.xml new file mode 100644 index 0000000..aedf598 --- /dev/null +++ b/app/src/main/res/drawable/color_segmented_text.xml @@ -0,0 +1,5 @@ + + + + + From 429638e10447574d67208eb728e74d21ecb73335 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:45:47 +0530 Subject: [PATCH 20/33] Update activity_main to contain new buttons, shape, developer card - New Button added - Developer card minimize - App version added --- app/src/main/res/layout/activity_main.xml | 510 +++++++++------------- 1 file changed, 212 insertions(+), 298 deletions(-) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index fd46ccd..9b4d7aa 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,6 +1,5 @@ + android:paddingBottom="20dp"> - - - - - - - - - - - - - - + - + android:layout_marginBottom="12dp"> + - + android:layout_width="48dp" + android:layout_height="48dp" + android:background="@drawable/social_icon_bg" + android:layout_marginEnd="16dp"> + android:tint="@color/brand_primary" /> - - - + - - - + android:orientation="vertical" + android:background="@drawable/section_outline_bg" + android:padding="12dp" + android:layout_marginBottom="12dp"> + + - + android:gravity="center_vertical"> - + android:layout_marginEnd="6dp" /> - - - - - - - - - - - - - - - - + android:paddingVertical="4dp" /> + - + + + - - - - - - - - - - - - - - - - - - - + + - - - + android:paddingVertical="8dp" + android:background="@drawable/selector_segmented_tab" + android:textColor="@color/color_segmented_text" + android:textSize="12sp" + android:textStyle="bold" /> + - - - + + android:padding="12dp" + android:layout_marginBottom="12dp"> + + + + + + + + + + + + + + + + android:gravity="center" + android:textColor="@color/status_error_text" + android:background="@drawable/shape_status_badge_error" + android:paddingHorizontal="6dp" + android:paddingVertical="4dp" + android:visibility="gone" + android:layout_marginTop="8dp" /> + + + + + + + + android:layout_marginEnd="12dp" /> - + android:layout_weight="1" + android:orientation="vertical"> + + + + + + android:orientation="horizontal"> - - - - - - From 58b07e3be4b2c40d4dc7bf8302ef9dcc786b7c0c Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:48:31 +0530 Subject: [PATCH 21/33] Added new icon reference for tile cycle --- .../main/res/layout/view_tile_cycle_card.xml | 233 ++++++++++-------- 1 file changed, 128 insertions(+), 105 deletions(-) diff --git a/app/src/main/res/layout/view_tile_cycle_card.xml b/app/src/main/res/layout/view_tile_cycle_card.xml index 92047c4..4bf1606 100644 --- a/app/src/main/res/layout/view_tile_cycle_card.xml +++ b/app/src/main/res/layout/view_tile_cycle_card.xml @@ -1,146 +1,169 @@ + android:background="@drawable/section_outline_bg" + android:padding="12dp" + android:layout_marginBottom="12dp"> - - - - - + + + android:orientation="horizontal" + android:gravity="center_vertical"> + + + - - - - - + android:textSize="10sp" + android:textStyle="bold" + android:paddingHorizontal="8dp" + android:paddingVertical="4dp" /> + + - + android:orientation="vertical"> + - - + + - - + + + android:textStyle="bold" + android:textSize="12sp" + android:layout_marginStart="4dp"/> - - - - + + - - + + + android:layout_weight="1" + android:text="○ Preferred 4G" + android:padding="10dp" + android:background="@drawable/shape_segmented_container" + android:textColor="#808080" + android:textStyle="bold" + android:textSize="12sp" + android:layout_marginStart="4dp"/> - + + android:background="@drawable/shape_segmented_container" + android:padding="8dp" + android:layout_marginTop="12dp"> + + + + + + + + + + + From dc345d4ab4c66450a0d29c31a83b1ad90b31a40a Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:50:16 +0530 Subject: [PATCH 22/33] Added refresh/cycle vector icon for the tile cycle card --- app/src/main/res/drawable/ic_refresh.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 app/src/main/res/drawable/ic_refresh.xml diff --git a/app/src/main/res/drawable/ic_refresh.xml b/app/src/main/res/drawable/ic_refresh.xml new file mode 100644 index 0000000..51a6c50 --- /dev/null +++ b/app/src/main/res/drawable/ic_refresh.xml @@ -0,0 +1,14 @@ + + + + From ba0c4710b5da9c6d8dc8830247220280f4fa1e35 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:59:24 +0530 Subject: [PATCH 23/33] Fix issues - Restore all six IDs expected by TileCycleUiController. - Use CheckBox, not static TextView, for cycle options. --- .../main/res/layout/view_tile_cycle_card.xml | 221 +++++++++--------- 1 file changed, 104 insertions(+), 117 deletions(-) diff --git a/app/src/main/res/layout/view_tile_cycle_card.xml b/app/src/main/res/layout/view_tile_cycle_card.xml index 4bf1606..af35456 100644 --- a/app/src/main/res/layout/view_tile_cycle_card.xml +++ b/app/src/main/res/layout/view_tile_cycle_card.xml @@ -2,168 +2,155 @@ + android:orientation="vertical" + android:padding="12dp"> - + + android:layout_centerVertical="true" + android:gravity="center_vertical" + android:orientation="horizontal"> + + android:tint="@color/brand_primary" /> + + android:textStyle="bold" /> + android:textStyle="bold" /> - - - - - - - - - - - - - - - - - + android:layout_marginBottom="10dp" + android:text="Select 2 to 3 modes. Selection order becomes the tile cycle order." + android:textColor="@color/text_secondary" + android:textSize="11sp" /> - - - + + - - - - + + + + + - - - - + + + From 7ab025b130d9865f4348a45d8aeb71cdfdc7f637 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:04:20 +0530 Subject: [PATCH 24/33] Bind appVersionText in MainActivity --- app/src/main/java/com/dhangofa/networktoggle/MainActivity.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java b/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java index 5446677..5a4ea11 100644 --- a/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java +++ b/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java @@ -47,6 +47,7 @@ public class MainActivity extends Activity { private RadioGroup radioGroup; private RadioButton radioRoot; private RadioButton radioShizuku; + private TextView appVersionText; private TextView statusText; private ImageView githubLink; private ImageView telegramLink; @@ -100,6 +101,7 @@ protected void onCreate(Bundle savedInstanceState) { appPreferences = new AppPreferences(this); bindViews(); + appVersionText.setText("v" + getAppVersionName()); bindLinks(); TileCycleManager tileCycleManager = new TileCycleManager(appPreferences); tileCycleUiController = new TileCycleUiController(this, tileCycleManager); @@ -126,6 +128,7 @@ private void bindViews() { radioRoot = findViewById(R.id.radioRoot); radioShizuku = findViewById(R.id.radioShizuku); statusText = findViewById(R.id.shizukuStatusText); + appVersionText = findViewById(R.id.appVersionText); targetSimRadioGroup = findViewById(R.id.targetSimRadioGroup); radioSimAuto = findViewById(R.id.radioSimAuto); radioSim1 = findViewById(R.id.radioSim1); From 0f8616f4cef08cc634bc27e97498aa06161ffd20 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:06:29 +0530 Subject: [PATCH 25/33] Added Segment control colors --- app/src/main/res/values/colors.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 7ae2eaa..b71b1d3 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -24,4 +24,10 @@ #F4EFF4 + + + #F3EDF7 + #EADDFF + #21005D + #49454F From 652ed57090d6185a10749d0031585681def209cb Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:07:21 +0530 Subject: [PATCH 26/33] Added Segment control colors for night mode --- app/src/main/res/values-night/colors.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 4bf04ac..b3b7f98 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -24,4 +24,10 @@ #2B2930 + + + #1B1A20 + #36323F + #EADDFF + #938F96 From 6510f0548a286dfe6d8ed8e5dcabca6cc23117f7 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:10:16 +0530 Subject: [PATCH 27/33] Remove hardcoded colors --- app/src/main/res/drawable/shape_segmented_container.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/drawable/shape_segmented_container.xml b/app/src/main/res/drawable/shape_segmented_container.xml index d22bb10..93b7f91 100644 --- a/app/src/main/res/drawable/shape_segmented_container.xml +++ b/app/src/main/res/drawable/shape_segmented_container.xml @@ -1,6 +1,7 @@ - - - + + + From 5bd7c797af499440e4769df640bee84e2bedc925 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:11:37 +0530 Subject: [PATCH 28/33] Remove hardcoded colors --- app/src/main/res/drawable/selector_segmented_tab.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/drawable/selector_segmented_tab.xml b/app/src/main/res/drawable/selector_segmented_tab.xml index ae444e7..83e1f50 100644 --- a/app/src/main/res/drawable/selector_segmented_tab.xml +++ b/app/src/main/res/drawable/selector_segmented_tab.xml @@ -1,16 +1,17 @@ + - - - + + + - + - + From 57d462de463929baaea7e0b31b0088345655ed7a Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:15:37 +0530 Subject: [PATCH 29/33] Remove hardcoded colors and change location of color_segmented_text.xml --- app/src/main/res/color/color_segmented_text.xml | 10 ++++++++++ app/src/main/res/drawable/color_segmented_text.xml | 5 ----- 2 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 app/src/main/res/color/color_segmented_text.xml delete mode 100644 app/src/main/res/drawable/color_segmented_text.xml diff --git a/app/src/main/res/color/color_segmented_text.xml b/app/src/main/res/color/color_segmented_text.xml new file mode 100644 index 0000000..4d24810 --- /dev/null +++ b/app/src/main/res/color/color_segmented_text.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/color_segmented_text.xml b/app/src/main/res/drawable/color_segmented_text.xml deleted file mode 100644 index aedf598..0000000 --- a/app/src/main/res/drawable/color_segmented_text.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - From 3549a482dbd22a7917ca5ba29e41acb0b5208a98 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:20:55 +0530 Subject: [PATCH 30/33] Update set status to change color --- .../dhangofa/networktoggle/MainActivity.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java b/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java index 5a4ea11..61a1c22 100644 --- a/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java +++ b/app/src/main/java/com/dhangofa/networktoggle/MainActivity.java @@ -255,10 +255,24 @@ private void checkShizukuPermission(boolean requestIfNeeded) { } } - private void setStatus(String text, int color) { - statusText.setText(text); - statusText.setTextColor(color); - } + private void setStatus(String text, int color) { + statusText.setText(text); + statusText.setTextColor(color); + + if (color == 0xFF1B873F) { + statusText.setBackgroundResource( + R.drawable.shape_status_badge_success + ); + } else if (color == 0xFFFF5555) { + statusText.setBackgroundResource( + R.drawable.shape_status_badge_error + ); + } else { + statusText.setBackgroundResource( + R.drawable.shape_pill_badge_bg + ); + } + } private String getAppVersionName() { try { From 396018a6be935199cad9f39765750b84bb9357a2 Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:31:13 +0530 Subject: [PATCH 31/33] fix closing tags --- app/src/main/res/drawable/selector_segmented_tab.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/drawable/selector_segmented_tab.xml b/app/src/main/res/drawable/selector_segmented_tab.xml index 83e1f50..3377f2c 100644 --- a/app/src/main/res/drawable/selector_segmented_tab.xml +++ b/app/src/main/res/drawable/selector_segmented_tab.xml @@ -1,4 +1,3 @@ - @@ -15,3 +14,4 @@ + From 6d9e557076ee4218f1c82c6f9838e6b733b179bc Mon Sep 17 00:00:00 2001 From: DK <117024745+Dhangofa@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:10:59 +0530 Subject: [PATCH 32/33] Refine main screen spacing and version pill - Reduced excessive spacing in the header and Quick Settings hint. - Added consistent 12dp spacing between primary cards. - Reduced outer horizontal and bottom padding for a more compact layout. - Refined title, version pill, and description spacing. - Added consistent minimum heights to segmented controls. - Removed redundant Developer card top margin. - Preserved the existing responsive ScrollView layout and visual hierarchy. --- app/src/main/res/layout/activity_main.xml | 110 ++++++++++++++++++---- 1 file changed, 92 insertions(+), 18 deletions(-) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 9b4d7aa..ad77aef 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -11,28 +11,96 @@ android:layout_height="wrap_content" android:orientation="vertical" android:paddingHorizontal="16dp" - android:paddingTop="12dp" - android:paddingBottom="20dp"> + android:paddingTop="16dp" + android:paddingBottom="20dp" + android:gravity="center_horizontal"> - + + + + + + + + + + + + + + - + + android:layout_width="38dp" + android:layout_height="38dp" + android:background="@drawable/shape_pill_badge_bg" + android:layout_marginEnd="10dp"> + + android:tint="@color/brand_primary" + android:contentDescription="QS Tile" /> + + @@ -70,7 +139,7 @@ + android:layout_marginBottom="10dp"> + android:layout_marginBottom="10dp"> Date: Tue, 11 Aug 2026 21:19:11 +0530 Subject: [PATCH 33/33] Fix: Show active network mode in QS tile label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixed the active QS tile label to display the current network mode. - Limited the “Tap to Set” prompt to the unknown tile state. - Kept the first configured cycle mode as the unknown-state target. - Preserved dynamic icons, configured cycle order, caching, and asynchronous readback protection. --- .../networktoggle/NetworkTileService.java | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java b/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java index 2488cfe..2fa9c5e 100644 --- a/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java +++ b/app/src/main/java/com/dhangofa/networktoggle/NetworkTileService.java @@ -195,29 +195,33 @@ private void updateTileSwitchingUI() { tile.updateTile(); } - private void updateTileUI(NetworkMode mode) { - Tile tile = getQsTile(); - if (tile == null) return; - - if (mode == NetworkMode.UNKNOWN) { - if (appPreferences.getExecutionMode() == ExecutionMode.NONE) { - tile.setState(Tile.STATE_UNAVAILABLE); - tile.setLabel("Setup Required"); - } else { - tile.setState(Tile.STATE_INACTIVE); - NetworkMode firstMode = tileCycleManager.getFirstMode(); - tile.setLabel("Tap to Set " + firstMode.getTileLabel()); - } - tile.setIcon(getCachedIcon("?")); - } else { - tile.setState(Tile.STATE_ACTIVE); - NetworkMode firstMode = tileCycleManager.getFirstMode(); - tile.setLabel("Tap to Set " + firstMode.getTileLabel()); - tile.setIcon(getCachedIcon(mode.getIconText())); - } - - tile.updateTile(); - } + private void updateTileUI(NetworkMode mode) { + Tile tile = getQsTile(); + + if (tile == null) { + return; + } + + if (mode == NetworkMode.UNKNOWN) { + if (appPreferences.getExecutionMode() == ExecutionMode.NONE) { + tile.setState(Tile.STATE_UNAVAILABLE); + tile.setLabel("Setup Required"); + } else { + NetworkMode firstMode = tileCycleManager.getFirstMode(); + + tile.setState(Tile.STATE_INACTIVE); + tile.setLabel("Tap to Set " + firstMode.getTileLabel()); + } + + tile.setIcon(getCachedIcon("?")); + } else { + tile.setState(Tile.STATE_ACTIVE); + tile.setLabel(mode.getTileLabel()); + tile.setIcon(getCachedIcon(mode.getIconText())); + } + + tile.updateTile(); + } private void showAutoSimErrorToast() { Toast.makeText(