-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathservice.sh
More file actions
524 lines (440 loc) · 16.4 KB
/
Copy pathservice.sh
File metadata and controls
524 lines (440 loc) · 16.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
#!/system/bin/sh
MODDIR=${0%/*}
LOGFILE=/data/adb/modules/caros-switcher/log.txt
CONFFILE=/sdcard/CarOS/config.env
STATEFILE=/data/adb/modules/caros-switcher/state.json
# Source the centralized configuration
. "$MODDIR/caros_config.sh"
# Rotate logs if > 1MB
if [ -f "$LOGFILE" ] && [ "$(stat -c%s "$LOGFILE" 2>/dev/null || echo 0)" -gt 1048576 ]; then
mv "$LOGFILE" "${LOGFILE}.old" 2>/dev/null
fi
log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $@" >> "$LOGFILE"; }
error_log() { echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $@" >> "$LOGFILE"; }
# Create configuration if it doesn't exist
if [ ! -f "$CONFFILE" ]; then
mkdir -p "$(dirname "$CONFFILE")"
log "Creating config file: $CONFFILE"
generate_user_config > "$CONFFILE"
chmod 644 "$CONFFILE"
log "Config file created successfully"
fi
[ -f "$CONFFILE" ] && . "$CONFFILE"
# Apply default values
apply_defaults
vlog(){ [ "$VERBOSE" = "1" ] && log "[DBG]" "$@"; }
wifi_on(){
cmd wifi set-wifi-enabled enabled 2>/dev/null || svc wifi enable 2>/dev/null || {
settings put global wifi_on 1 2>/dev/null || error_log "Failed to enable WiFi"
}
}
wifi_off(){
cmd wifi set-wifi-enabled disabled 2>/dev/null || svc wifi disable 2>/dev/null || {
settings put global wifi_on 0 2>/dev/null || error_log "Failed to disable WiFi"
}
}
data_on(){
log "Enabling mobile data..."
# Method 1: Modern Android (11+)
cmd telephony data enable 2>/dev/null || {
# Method 2: Settings + svc fallback
settings put global mobile_data 1 2>/dev/null
svc data enable 2>/dev/null
}
# Ensure mobile radio is on
settings put global airplane_mode_on 0 2>/dev/null
# Force data connection reestablishment
cmd phone data connection-state true 2>/dev/null
# Wait briefly for radio to initialize
sleep 1
# Trigger data connection through telephony service
service call phone 27 i32 1 2>/dev/null || {
service call phone 34 i32 1 2>/dev/null
}
# Verify data is enabled
DATA_STATE=$(settings get global mobile_data 2>/dev/null)
if [ "$DATA_STATE" != "1" ]; then
error_log "Failed to enable mobile data - state: $DATA_STATE"
return 1
fi
vlog "Mobile data enabled successfully"
return 0
}
data_off(){
log "Disabling mobile data..."
# Method 1: Modern Android (11+)
cmd telephony data disable 2>/dev/null || {
# Method 2: Settings + svc fallback
settings put global mobile_data 0 2>/dev/null
svc data disable 2>/dev/null
}
# Verify data is disabled
DATA_STATE=$(settings get global mobile_data 2>/dev/null)
if [ "$DATA_STATE" != "0" ]; then
error_log "Failed to disable mobile data - state: $DATA_STATE"
fi
vlog "Mobile data disabled"
}
check_data_connection(){
[ "$VERBOSE" != "1" ] && return 0
# Check mobile data state
DATA_ENABLED=$(settings get global mobile_data 2>/dev/null)
vlog "Mobile data setting: $DATA_ENABLED"
# Check if SIM is present and active
SIM_STATE=$(getprop gsm.sim.state 2>/dev/null)
vlog "SIM state: $SIM_STATE"
# Check data connection state
DATA_CONN=$(dumpsys telephony.registry 2>/dev/null | grep "mDataConnectionState" | head -1)
vlog "Data connection: $DATA_CONN"
# Check APN settings
APN_INFO=$(dumpsys telephony.registry 2>/dev/null | grep -i "apn" | head -3)
vlog "APN info: $APN_INFO"
# Check if we have an IP address
IP_INFO=$(ip addr show rmnet_data0 2>/dev/null || ip addr show rmnet0 2>/dev/null)
if [ -n "$IP_INFO" ]; then
vlog "Data interface has IP address"
else
vlog "WARNING: No IP address on data interface"
fi
}
bt_on(){
cmd bluetooth enable >/dev/null 2>&1 || settings put global bluetooth_on 1 >/dev/null 2>&1 || {
service call bluetooth_manager 6 >/dev/null 2>&1 || error_log "Failed to enable Bluetooth"
}
}
bt_off(){
cmd bluetooth disable >/dev/null 2>&1 || settings put global bluetooth_on 0 >/dev/null 2>&1 || {
service call bluetooth_manager 8 >/dev/null 2>&1 || error_log "Failed to disable Bluetooth"
}
}
battery_saver_on(){ settings put global low_power 1 || error_log "Failed to enable battery saver"; }
battery_saver_off(){ settings put global low_power 0 || error_log "Failed to disable battery saver"; }
set_cpu_max(){
MAX="$1"
if [ -n "$MAX" ]; then
SUCCESS=0
for cpu in /sys/devices/system/cpu/cpu[0-9]*; do
if [ -e "$cpu/cpufreq/scaling_max_freq" ] && [ -w "$cpu/cpufreq/scaling_max_freq" ]; then
echo "$MAX" > "$cpu/cpufreq/scaling_max_freq" 2>/dev/null && SUCCESS=1
fi
done
[ "$SUCCESS" = "0" ] && error_log "Failed to set CPU max frequency to $MAX"
fi
}
reset_cpu_max(){
SUCCESS=0
for cpu in /sys/devices/system/cpu/cpu[0-9]*; do
if [ -e "$cpu/cpufreq/scaling_max_freq" ] && [ -e "$cpu/cpufreq/cpuinfo_max_freq" ] && [ -w "$cpu/cpufreq/scaling_max_freq" ]; then
cat "$cpu/cpufreq/cpuinfo_max_freq" > "$cpu/cpufreq/scaling_max_freq" 2>/dev/null && SUCCESS=1
fi
done
[ "$SUCCESS" = "0" ] && error_log "Failed to reset CPU max frequency"
}
screen_off(){ input keyevent 26 >/dev/null 2>&1; }
screen_on(){ input keyevent 224 >/dev/null 2>&1 || input keyevent 82 >/dev/null 2>&1; }
charge_limit_on(){
SUCCESS=0
for n in \
/sys/class/power_supply/battery/charging_enabled \
/sys/class/power_supply/battery/charge_enabled \
/sys/class/power_supply/battery/charge_disable \
/sys/class/power_supply/battery/input_suspend \
/sys/class/power_supply/usb/input_current_limit \
/sys/class/power_supply/battery/constant_charge_current_max \
; do
if [ -e "$n" ] && [ -w "$n" ]; then
case "$n" in
*/input_current_limit|*/constant_charge_current_max)
echo 500000 > "$n" 2>/dev/null && SUCCESS=1 ;;
*charging_enabled|*charge_enabled)
echo 0 > "$n" 2>/dev/null && SUCCESS=1 ;;
*charge_disable|*input_suspend)
echo 1 > "$n" 2>/dev/null && SUCCESS=1 ;;
esac
fi
done
[ "$SUCCESS" = "0" ] && vlog "No writable charge control found"
return $((1-SUCCESS))
}
charge_limit_off(){
SUCCESS=0
for n in \
/sys/class/power_supply/battery/charging_enabled \
/sys/class/power_supply/battery/charge_enabled \
/sys/class/power_supply/battery/charge_disable \
/sys/class/power_supply/battery/input_suspend \
/sys/class/power_supply/usb/input_current_limit \
/sys/class/power_supply/battery/constant_charge_current_max \
; do
if [ -e "$n" ] && [ -w "$n" ]; then
case "$n" in
*/input_current_limit|*/constant_charge_current_max)
echo 3000000 > "$n" 2>/dev/null && SUCCESS=1 ;;
*charging_enabled|*charge_enabled)
echo 1 > "$n" 2>/dev/null && SUCCESS=1 ;;
*charge_disable|*input_suspend)
echo 0 > "$n" 2>/dev/null && SUCCESS=1 ;;
esac
fi
done
[ "$SUCCESS" = "0" ] && vlog "No writable charge control found"
return 0
}
set_nova_default(){
[ "$SET_NOVA_DEFAULT" = "1" ] || return 0
# Vérifier si Nova Launcher est installé
if ! pm list packages | grep -q "com.teslacoilsw.launcher"; then
vlog "Nova Launcher not installed, skipping default launcher setup"
return 1
fi
# Définir Nova Launcher comme launcher par défaut
if cmd package set-home-activity com.teslacoilsw.launcher/com.android.launcher3.Launcher >/dev/null 2>&1; then
vlog "Nova Launcher set as default launcher"
return 0
elif pm set-home-activity com.teslacoilsw.launcher/com.android.launcher3.Launcher >/dev/null 2>&1; then
vlog "Nova Launcher set as default launcher (fallback method)"
return 0
else
# Méthode alternative avec settings
settings put secure default_input_method com.teslacoilsw.launcher >/dev/null 2>&1
vlog "Nova Launcher setup attempted via settings"
return 0
fi
}
# Enable Bluetooth audio sink mode (A2DP sink)
enable_bt_audio_sink(){
[ "$ENABLE_BT_AUDIO_SINK" = "1" ] || return 0
vlog "Enabling Bluetooth audio sink mode"
# Ensure Bluetooth is on
bt_on
sleep 1
# Make device discoverable for pairing
# Timeout 0 means stay discoverable indefinitely while in car
settings put global bluetooth_discoverable_timeout 0 2>/dev/null
# Enable Bluetooth discoverability via dumpsys
cmd bluetooth_manager enable 2>/dev/null
cmd bluetooth_manager set-discoverability on 2>/dev/null || {
# Fallback method
settings put global bluetooth_on 1 2>/dev/null
}
# Try to enable A2DP sink mode via system properties
setprop persist.bluetooth.a2dp_sink.enabled true 2>/dev/null
setprop bluetooth.a2dp.sink.enabled true 2>/dev/null
# Try to set Bluetooth class to audio sink
setprop bluetooth.device.class 0x240404 2>/dev/null
# Enable audio routing to main speaker for Bluetooth audio
# This ensures incoming Bluetooth audio plays through system audio
settings put system bluetooth_audio_output 0 2>/dev/null
vlog "Bluetooth audio sink mode enabled - device should be discoverable"
log "BT Audio Sink: Device is now discoverable for audio streaming"
}
# Disable Bluetooth audio sink mode
disable_bt_audio_sink(){
[ "$ENABLE_BT_AUDIO_SINK" = "1" ] || return 0
vlog "Disabling Bluetooth audio sink mode"
# Disable discoverability to save battery when not in car
settings put global bluetooth_discoverable_timeout 120 2>/dev/null
cmd bluetooth_manager set-discoverability off 2>/dev/null
# Disable A2DP sink mode
setprop persist.bluetooth.a2dp_sink.enabled false 2>/dev/null
setprop bluetooth.a2dp.sink.enabled false 2>/dev/null
# Reset Bluetooth class to default (phone)
setprop bluetooth.device.class 0x5A020C 2>/dev/null
vlog "Bluetooth audio sink mode disabled"
}
# Enable WiFi hotspot for audio streaming
enable_wifi_audio_hotspot(){
[ "$ENABLE_WIFI_AUDIO_HOTSPOT" = "1" ] || return 0
vlog "Enabling WiFi hotspot for audio streaming"
# Ensure WiFi is on
wifi_on
sleep 1
# Stop any existing hotspot
cmd wifi stop-softap 2>/dev/null
sleep 1
# Start WiFi hotspot with configured SSID and password
# Method 1: Using cmd wifi (Android 11+)
cmd wifi start-softap "$WIFI_AUDIO_HOTSPOT_SSID" wpa2-psk "$WIFI_AUDIO_HOTSPOT_PASSWORD" 2>/dev/null || {
# Method 2: Using settings (fallback)
settings put global wifi_ap_ssid "$WIFI_AUDIO_HOTSPOT_SSID" 2>/dev/null
settings put global wifi_ap_passwd "$WIFI_AUDIO_HOTSPOT_PASSWORD" 2>/dev/null
svc wifi enable 2>/dev/null
}
vlog "WiFi hotspot enabled - SSID: $WIFI_AUDIO_HOTSPOT_SSID"
log "WiFi Audio Hotspot: Enabled for audio streaming (SSID: $WIFI_AUDIO_HOTSPOT_SSID)"
}
# Disable WiFi hotspot for audio streaming
disable_wifi_audio_hotspot(){
[ "$ENABLE_WIFI_AUDIO_HOTSPOT" = "1" ] || return 0
vlog "Disabling WiFi hotspot for audio streaming"
# Stop WiFi hotspot
cmd wifi stop-softap 2>/dev/null || {
settings put global wifi_ap_ssid "" 2>/dev/null
}
vlog "WiFi hotspot disabled"
}
usb_connected(){
if [ -f /sys/class/power_supply/usb/online ] && [ "$(cat /sys/class/power_supply/usb/online 2>/dev/null)" = "1" ]; then
return 0
fi
dumpsys usb 2>/dev/null | grep -q "mConnected=true" && return 0
return 1
}
aa_process_active(){
# Cache to avoid repeated calls
if [ -n "$AA_CACHE" ] && [ $(($(date +%s) - AA_CACHE_TIME)) -lt 2 ]; then
[ "$AA_CACHE" = "1" ] && return 0 || return 1
fi
AA_CACHE_TIME=$(date +%s)
if pidof com.google.android.projection.gearhead >/dev/null 2>&1; then
AA_CACHE=1
return 0
fi
if dumpsys activity services 2>/dev/null | grep -qi com.google.android.projection.gearhead; then
AA_CACHE=1
return 0
fi
AA_CACHE=0
return 1
}
bt_connected_to_audi(){
# Quick check with cache
if [ -n "$BT_CACHE" ] && [ $(($(date +%s) - BT_CACHE_TIME)) -lt 5 ]; then
[ "$BT_CACHE" = "1" ] && return 0 || return 1
fi
BT_CACHE_TIME=$(date +%s)
# Escape special characters in AUDI_BT_NAMES
ESCAPED_NAMES="$(echo "$AUDI_BT_NAMES" | sed 's/[].[^$\\/*]/\\&/g')"
# Quick attempt with dumpsys
if DUMP="$(dumpsys bluetooth_manager 2>/dev/null | head -100)"; then
# Check by MAC if specified
if [ -n "$AUDI_BT_MAC" ]; then
if echo "$DUMP" | grep -i "$AUDI_BT_MAC" | grep -qi "Connected.*true\|State.*Connected"; then
BT_CACHE=1
return 0
fi
fi
# Check by name
if echo "$DUMP" | grep -Eiq "Name:.*($ESCAPED_NAMES)" && echo "$DUMP" | grep -qi "Connected.*true\|State.*Connected"; then
BT_CACHE=1
return 0
fi
# Fallback: broader search
if echo "$DUMP" | grep -Eiq "($ESCAPED_NAMES)" && echo "$DUMP" | grep -qi "Connected"; then
BT_CACHE=1
return 0
fi
else
vlog "Bluetooth dumpsys failed, assuming disconnected"
fi
BT_CACHE=0
return 1
}
apply_wired_profile(){
if [ "$KEEP_DATA_IN_CAR" = "1" ]; then
data_on
sleep 2 # Give data time to connect
check_data_connection
else
data_off
fi
if [ "$ALLOW_BT_IN_WIRED" = "1" ]; then bt_on; else bt_off; fi
if [ "$KEEP_WIFI_IN_WIRED" = "1" ]; then wifi_on; else wifi_off; fi
battery_saver_off
reset_cpu_max
[ "$LIMIT_QUICK_CHARGE_WIRED" = "1" ] && charge_limit_on
set_nova_default
# Enable audio streaming (Bluetooth or WiFi hotspot based on config)
enable_bt_audio_sink
enable_wifi_audio_hotspot
screen_off
}
apply_wireless_profile(){
bt_on
wifi_on
if [ "$KEEP_DATA_IN_CAR" = "1" ]; then
data_on
sleep 2 # Give data time to connect
check_data_connection
else
data_off
fi
battery_saver_off
reset_cpu_max
charge_limit_off
set_nova_default
# Note: BT audio sink NOT enabled in wireless mode because Bluetooth is already
# being used to connect to the car. WiFi may also be used by wireless AA.
# Audio streaming features disabled in wireless mode.
screen_off
}
apply_idle_profile(){
if [ "$KEEP_WIFI_IN_IDLE" = "1" ]; then wifi_on; else wifi_off; fi
if [ "$KEEP_DATA_IN_CAR" = "1" ]; then
data_on
sleep 2 # Give data time to connect
check_data_connection
else
data_off
fi
battery_saver_on
set_cpu_max "$IDLE_MAX_CPU_FREQ"
charge_limit_off
disable_bt_audio_sink
disable_wifi_audio_hotspot
}
STATE=""
LOOP_COUNT=0
AA_CACHE=""
AA_CACHE_TIME=0
BT_CACHE=""
BT_CACHE_TIME=0
log "CarOS Profile Switcher service v0.2.3 started"
# Grant permissions on service start (async)
"$MODDIR/grant_permissions.sh" &
while true; do
LOOP_COUNT=$((LOOP_COUNT + 1))
# Periodic log to prove the service is working
[ $((LOOP_COUNT % 100)) -eq 0 ] && log "Service alive, loop #$LOOP_COUNT"
# Re-grant permissions periodically (every ~30 minutes = 600 loops)
if [ $((LOOP_COUNT % 600)) -eq 0 ]; then
"$MODDIR/grant_permissions.sh" &
fi
WIRED=0
WIRELESS=0
# Check with error handling
if usb_connected && aa_process_active; then
WIRED=1
vlog "Detected WIRED mode"
elif bt_connected_to_audi && aa_process_active; then
WIRELESS=1
vlog "Detected WIRELESS mode"
fi
NEWSTATE="IDLE"
if [ "$WIRED" = "1" ]; then
NEWSTATE="WIRED"
elif [ "$WIRELESS" = "1" ]; then
NEWSTATE="WIRELESS"
fi
if [ "$NEWSTATE" != "$STATE" ]; then
log "State change: $STATE -> $NEWSTATE"
case "$NEWSTATE" in
WIRED)
apply_wired_profile
log "Applied WIRED profile"
;;
WIRELESS)
apply_wireless_profile
log "Applied WIRELESS profile"
;;
IDLE)
apply_idle_profile
log "Applied IDLE profile"
;;
esac
STATE="$NEWSTATE"
# Save state
echo "{\"state\":\"$STATE\",\"timestamp\":\"$(date)\"}" > "$STATEFILE" 2>/dev/null
fi
sleep 3
done