Skip to content

Commit 22e87c9

Browse files
authored
Add Android 7 to 11 network mode controllers
- Added a dedicated legacy network mode backend. - Added transactional mode writes and cellular modem restart. - Added airplane mode radio-list preservation and restoration. - Added clean up traps and post operation verification.
1 parent 49bc165 commit 22e87c9

1 file changed

Lines changed: 181 additions & 0 deletions

File tree

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package com.dhangofa.networktoggle.telephony;
2+
3+
import android.content.Context;
4+
import android.provider.Settings;
5+
import android.telephony.TelephonyManager;
6+
7+
import com.dhangofa.networktoggle.command.CommandExecutor;
8+
import com.dhangofa.networktoggle.command.CommandExecutorFactory;
9+
import com.dhangofa.networktoggle.model.CommandResult;
10+
import com.dhangofa.networktoggle.model.ExecutionMode;
11+
import com.dhangofa.networktoggle.model.NetworkMode;
12+
13+
final class LegacyNetworkModeController {
14+
private static final int MODEM_RESTART_DELAY_SECONDS = 2;
15+
16+
private final Context context;
17+
private final SimResolver simResolver;
18+
19+
LegacyNetworkModeController(Context context, SimResolver simResolver) {
20+
this.context = context.getApplicationContext();
21+
this.simResolver = simResolver;
22+
}
23+
24+
CommandResult apply(NetworkMode networkMode, ExecutionMode executionMode) {
25+
if (networkMode == null || networkMode == NetworkMode.UNKNOWN
26+
|| networkMode.getLegacyMode() < 0) {
27+
return CommandResult.failed("", "Invalid legacy network mode selected.");
28+
}
29+
30+
if (isAirplaneModeEnabled()) {
31+
return CommandResult.failed("",
32+
"Disable Airplane mode before changing the network mode.");
33+
}
34+
35+
SimResolver.SimInfo simInfo = simResolver.resolveTargetSimInfo(executionMode);
36+
if (simInfo == null || !simResolver.isValidSlotIndex(simInfo.slotIndex)
37+
|| !simResolver.isValidSubId(simInfo.subId)) {
38+
return CommandResult.failed("", "Unable to resolve the target SIM.");
39+
}
40+
41+
Integer[] currentModes = readCombinedModes();
42+
int requiredEntries = getRequiredCombinedEntries(simInfo.slotIndex);
43+
if (currentModes.length < requiredEntries) {
44+
return CommandResult.failed("",
45+
"Unable to preserve the current mode of every SIM slot.");
46+
}
47+
48+
for (int i = 0; i < requiredEntries; i++) {
49+
if (currentModes[i] == null) {
50+
return CommandResult.failed("",
51+
"Unable to read the current mode for SIM slot " + (i + 1) + ".");
52+
}
53+
}
54+
55+
currentModes[simInfo.slotIndex] = networkMode.getLegacyMode();
56+
String combinedModes = buildCombinedModes(currentModes, requiredEntries);
57+
String originalRadios = readAirplaneModeRadios();
58+
String restoreRadios = originalRadios == null
59+
? "settings delete global airplane_mode_radios"
60+
: "settings put global airplane_mode_radios " + shellEscape(originalRadios);
61+
62+
String command = buildTransactionCommand(
63+
simInfo.subId,
64+
networkMode.getLegacyMode(),
65+
combinedModes,
66+
restoreRadios
67+
);
68+
69+
CommandExecutor executor = CommandExecutorFactory.forMode(executionMode);
70+
if (executor == null) {
71+
return CommandResult.failed(command, "No execution mode selected.");
72+
}
73+
74+
CommandResult result = executor.execute(command);
75+
if (!result.isSuccess()) return result;
76+
77+
return verifyResult(command, simInfo, networkMode.getLegacyMode(),
78+
originalRadios, requiredEntries);
79+
}
80+
81+
private Integer[] readCombinedModes() {
82+
String value = Settings.Global.getString(
83+
context.getContentResolver(), "preferred_network_mode");
84+
if (value == null || value.trim().isEmpty()
85+
|| value.trim().equalsIgnoreCase("null")) {
86+
return new Integer[0];
87+
}
88+
89+
String[] parts = value.trim().split(",", -1);
90+
Integer[] modes = new Integer[parts.length];
91+
for (int i = 0; i < parts.length; i++) {
92+
modes[i] = ShellValueParser.extractFirstInt(parts[i]);
93+
}
94+
return modes;
95+
}
96+
97+
private int getRequiredCombinedEntries(int targetSlot) {
98+
TelephonyManager manager = (TelephonyManager)
99+
context.getSystemService(Context.TELEPHONY_SERVICE);
100+
int phoneCount = manager == null ? 1 : manager.getPhoneCount();
101+
return Math.max(targetSlot + 1, Math.min(phoneCount, 2));
102+
}
103+
104+
private String buildCombinedModes(Integer[] modes, int count) {
105+
StringBuilder value = new StringBuilder();
106+
for (int i = 0; i < count; i++) {
107+
if (i > 0) value.append(',');
108+
value.append(modes[i]);
109+
}
110+
return value.toString();
111+
}
112+
113+
private boolean isAirplaneModeEnabled() {
114+
return Settings.Global.getInt(
115+
context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
116+
}
117+
118+
private String readAirplaneModeRadios() {
119+
return Settings.Global.getString(
120+
context.getContentResolver(), Settings.Global.AIRPLANE_MODE_RADIOS);
121+
}
122+
123+
private String buildTransactionCommand(int subId, int requestedMode,
124+
String combinedModes, String restoreRadios) {
125+
return "cleanup() { "
126+
+ "cmd connectivity airplane-mode disable >/dev/null 2>&1; "
127+
+ restoreRadios + " >/dev/null 2>&1; "
128+
+ "}; "
129+
+ "trap cleanup EXIT INT TERM; "
130+
+ "settings put global airplane_mode_radios cell || exit 20; "
131+
+ "settings put global preferred_network_mode" + subId + " "
132+
+ requestedMode + " || exit 21; "
133+
+ "settings put global preferred_network_mode " + combinedModes
134+
+ " || exit 22; "
135+
+ "cmd connectivity airplane-mode enable || exit 23; "
136+
+ "sleep " + MODEM_RESTART_DELAY_SECONDS + "; "
137+
+ "cmd connectivity airplane-mode disable || exit 24; "
138+
+ "sleep " + MODEM_RESTART_DELAY_SECONDS + "; "
139+
+ restoreRadios + " || exit 25; "
140+
+ "trap - EXIT INT TERM; "
141+
+ "exit 0";
142+
}
143+
144+
private CommandResult verifyResult(String command, SimResolver.SimInfo simInfo,
145+
int requestedMode, String originalRadios,
146+
int requiredEntries) {
147+
String subValue = Settings.Global.getString(
148+
context.getContentResolver(),
149+
"preferred_network_mode" + simInfo.subId);
150+
Integer finalSubMode = ShellValueParser.extractFirstInt(subValue);
151+
Integer[] finalCombinedModes = readCombinedModes();
152+
String finalRadios = readAirplaneModeRadios();
153+
154+
if (isAirplaneModeEnabled()) {
155+
return CommandResult.failed(command,
156+
"Legacy mode was written, but Airplane mode is still enabled.");
157+
}
158+
if (finalSubMode == null || finalSubMode != requestedMode) {
159+
return CommandResult.failed(command,
160+
"Legacy per-subscription mode verification failed.");
161+
}
162+
if (finalCombinedModes.length < requiredEntries
163+
|| finalCombinedModes[simInfo.slotIndex] == null
164+
|| finalCombinedModes[simInfo.slotIndex] != requestedMode) {
165+
return CommandResult.failed(command,
166+
"Legacy combined mode verification failed.");
167+
}
168+
if (originalRadios == null ? finalRadios != null
169+
: !originalRadios.equals(finalRadios)) {
170+
return CommandResult.failed(command,
171+
"Original Airplane mode radio configuration was not restored.");
172+
}
173+
174+
return CommandResult.completed(command, 0,
175+
"Legacy network mode applied and verified.", "");
176+
}
177+
178+
private String shellEscape(String value) {
179+
return "'" + value.replace("'", "'\\''") + "'";
180+
}
181+
}

0 commit comments

Comments
 (0)