testsAndMisc/phone_focus_mode/daemon_location.sh
Krzysztof kuhy Rudnicki 094c4765f3
Some checks are pending
Pre-commit checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
focus_daemon: split 543 -> 206 + 165 + 140 + 94, with 110 tests
Location/curfew goes to daemon_location.sh, the derived state files to
daemon_state.sh, the app layer to daemon_apps.sh. All 23 functions moved
verbatim -- nothing restructured, which matters more here than anywhere
else in this session.

focus_daemon.sh has five `while IFS= read -r pkg; do ... done <file` loops
and EVERY body calls pm. Piping any of them in lets pm inherit and drain
the loop's stdin, so it would process one package instead of all of them --
measured elsewhere in this repo as 1 of 54. That audit ran BEFORE the
extraction, not after coverage came back short, and all five moved
untouched with a note above them saying why.

CURRENT_MODE and _CURFEW_TICK_CACHED are each written in both the entry
script and a library, so both stay declared with main, same call as
NET_BUILT in the curfew split.

110 assertions and 33 mutations, all killed. Two survived the first run and
both were defects in my own tests: the whitelist and sysprotect exactness
checks used a SUPERSTRING of a listed entry, which fails under grep -qF and
grep -qxF alike and so proved nothing about which was in use.

Two subjects are NOT at 100%, and the numbers are reported as measured:

  daemon_state.sh     67/67 = 100.00%
  daemon_location.sh  26/40 =  65.00%
  daemon_apps.sh      71/76 =  93.42%

Both shortfalls are kcov attribution failures, shown to be artifacts rather
than gaps. daemon_location.sh's missing lines are all inside the embedded
awk Haversine; mutating the Earth radius and dropping the longitude term
both fail the suite, and an isolated probe shows a one-line awk measuring
100% where the identical multi-line one measures 0%. Collapsing the formula
to satisfy the tool would cost the readability of the only real mathematics
in the repo, so it stays.

daemon_apps.sh's five are the trailing `done <file` of the very loops
described above. That is the same artifact piping fixed in curfew_net.sh,
and it is exactly what must NOT be done here. Redirecting two of them from
/dev/null fails the suite, so the lines run; all three are pinned in the
mutation spec instead.

Over-cap count 19 -> 18.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
2026-08-17 16:54:04 +02:00

95 lines
3.3 KiB
Bash
Executable File

#!/system/bin/sh
# shellcheck shell=ash
# daemon_location.sh — where-and-when for focus_daemon.sh: reading the phone's
# GPS fix, the great-circle distance from home, and whether the night curfew
# window is currently open.
#
# A flat sibling, not lib/: deploy.sh pushes phone scripts into one directory.
#
# Sourced by focus_daemon.sh, which owns log() and the config.sh globals these
# read ($NIGHT_CURFEW_*, $CURFEW_FORCE_FILE, $CURFEW_OVERRIDE_FILE). It also
# owns $_CURFEW_TICK_CACHED: curfew_active memoises per tick and main clears
# the memo each loop, so both files write it and it stays with main.
# ---- Location ----
get_location() {
dumpsys location 2>/dev/null |
grep -oE '[-]?[0-9]{1,3}\.[0-9]{4,},[-]?[0-9]{1,3}\.[0-9]{4,}' |
head -1
}
# ---- Distance Calculation (Haversine via awk) ----
calc_distance() {
echo "$1 $2 $3 $4" | awk '{
PI = 3.14159265358979323846
R = 6371000.0
lat1 = $1 * PI / 180.0
lon1 = $2 * PI / 180.0
lat2 = $3 * PI / 180.0
lon2 = $4 * PI / 180.0
dlat = lat2 - lat1
dlon = lon2 - lon1
sdlat = sin(dlat / 2.0)
sdlon = sin(dlon / 2.0)
a = sdlat * sdlat + cos(lat1) * cos(lat2) * sdlon * sdlon
c = 2.0 * atan2(sqrt(a), sqrt(1.0 - a))
printf "%d\n", R * c
}'
}
# ---- Night curfew time check ----
# Returns 0 (true) when the local clock is inside the curfew window.
# Fails OPEN (return 1 = not curfew) on a malformed clock so a broken `date`
# can never strand you behind the strict list — essentials stay reachable
# either way, but the day list is the less-surprising default.
_dec() {
# Strip leading zeros so a zero-padded HHMM ("0500", "0830") is not parsed
# as (sometimes invalid) octal by the shell's arithmetic. Portable across
# ash/mksh; keeps at least one digit so "0000" -> "0".
local n="$1"
while [ "${n#0}" != "$n" ] && [ "${#n}" -gt 1 ]; do n="${n#0}"; done
printf '%s' "$n"
}
is_curfew_now() {
local now start end
now="$(date +%H%M 2>/dev/null)"
case "$now" in
'' | *[!0-9]*) return 1 ;;
esac
now="$(_dec "$now")"
start="$(_dec "$NIGHT_CURFEW_START")"
end="$(_dec "$NIGHT_CURFEW_END")"
if [ "$start" -le "$end" ]; then
[ "$now" -ge "$start" ] && [ "$now" -lt "$end" ]
else
# Window wraps past midnight (e.g. 2300 -> 0500).
[ "$now" -ge "$start" ] || [ "$now" -lt "$end" ]
fi
}
# Curfew is ACTIVE when enabled, not manually overridden, and either forced on
# (test hook) or inside the time window. The is_allowed() switch below consults
# this; because is_allowed() only runs during the focus-mode sweep/reconcile,
# curfew automatically takes effect only at home and is a no-op when away.
#
# Memoized once per main-loop tick (reset at the top of main()'s while loop):
# is_allowed() calls this once per enabled package in the sweep, and
# is_curfew_now forks `date` - on-device this meant up to ~N extra forks per
# 10s tick for N enabled apps, all recomputing a value that cannot change
# within a single tick. Result is cached in _CURFEW_TICK_RESULT.
curfew_active() {
if [ -n "$_CURFEW_TICK_CACHED" ]; then
[ "$_CURFEW_TICK_RESULT" = "1" ]
return
fi
_CURFEW_TICK_CACHED=1
_CURFEW_TICK_RESULT=0
if [ "${NIGHT_CURFEW_ENABLED:-0}" = "1" ] && [ ! -e "$CURFEW_OVERRIDE_FILE" ]; then
if [ -e "$CURFEW_FORCE_FILE" ] || is_curfew_now; then
_CURFEW_TICK_RESULT=1
fi
fi
[ "$_CURFEW_TICK_RESULT" = "1" ]
}