Package com.aurelienpierre.sioul
Class Calls
java.lang.Object
com.aurelienpierre.sioul.Calls
Calls screened (docs/android.md, "Calls"; docs/research/call-screening.md,
section 8). Android asks Sioul about each call (CallScreen, as the "Caller
ID & spam app"); the answer comes from a table Sioul's Rust side wrote
ahead (crates/sioul-app/src/calls.rs, `calls/table.json` in its state
folder), read here in milliseconds, without Sioul's library or Qt. A call
is let ring, or refused plainly: the network sends it to the operator's
voicemail, as a call declined by hand; it stays in the phone's own call
history. Every incoming call screened, declined or let ring, is written in
Sioul's list (`held.jsonl`, `held`), which Rust reads and copies into this
phone's log, for the Porch of each of your devices (docs/porch.md, "Calls
declined").
The order, a table of version 2 (research 8.3; the call screening apart,
crates/sioul-core/src/screening.rs): the floors first, which always ring (an
emergency number or the emergency services' callback number; any call for
a day after you call an emergency number; the numbers of `floors.people`,
from an older table only); then your blocked numbers, refused; then, for a
number nobody knows, what the screening keeps out whatever else (a number
never shown as a caller's, a failed verification, an automated caller);
then a second call from the same number within 15 minutes, which rings;
then the people you know (your lists, your address books, this phone's
contacts, a number you called in the last days, Always through), as the
table's frame for now says: the times, Free time, and the layers above them
(a slot of time for you, do-not-disturb from its switch or a focus
session), a number you called beyond its row only while you expect a call;
then everyone else by the call screening: Expecting a call, then what it
lets ring by itself (off, resting in your work and admin hours, its rule
for numbers nobody knows and hidden numbers), never where your contacts'
row declines (review of part 2, 19 October 2026). A table of version 1 (an older
Sioul's) is read in its own order: "Let every call through" before a
second call, then the frame's row for everyone. Nothing to decide from (no
table, a table past its frames, a row a frame does not name, anything that
fails): it rings, as Android would. The JVM checks this order against
Rust's (crates/sioul-core/src/calls.rs, `decide`) on tables as Rust writes
them (android/jvm-checks/: DecideCheck, TableCheck).
Here too: Rust's questions (
StepService.call(android.content.Context, java.lang.String, java.lang.String), verbs "calls-…"); the
press of Expecting a call (once "Let every call through") on the background
service's notification, kept in a file of this phone's (`through-here.json`)
that Rust reads and shares with your other devices; and the numbers you
called lately, by their key, a fortnight at most and only while the call
screening counts them, never shared (`called.json`), which count as your
contacts.-
Nested Class Summary
Nested ClassesModifier and TypeClassDescription(package private) static final classWhat Sioul answers, and why: for the response, the list of calls held, and the log.(package private) static final classOne stretch of time and who rings in it.(package private) static interfaceWhat the decision asks of the phone beyond the table: Android's emergency list, its contacts.(package private) static final classA press of Expecting a call (once "Let every call through"): when (ms), on or off, until (ms; 0: until turned off).(package private) static final classHow the table's country writes its numbers (phones.rs's Region).(package private) static final classThe call screening, as a table of version 2 says it (crates/sioul-core/src/screening.rs, `TablePart`): what becomes of a number nobody knows, apart from do-not-disturb and every state.(package private) static final classThe table as Rust wrote it (crates/sioul-core/src/calls.rs, `Table`). -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static Calls.Tableprivate static longprivate static long(package private) static final StringThe numbers you called lately, by their key, with when (this phone's own, never shared).private static final longA number called counts this long at most, whatever a table says (ms): screening.rs's CALLED_DAYS.private static final Stringprivate static final StringRust's state folder (android/main.cpp: XDG_STATE_HOME is files/state), and the calls' own in it.(package private) static final Stringprivate static final longCalls screened are kept this long in the list's file.private static final String(package private) static final String(package private) static final String(package private) static final Stringprivate static final longPast this size the list's file is rewritten without its old lines.private static final intThe table's shape this code reads, and the one before it; another one is not read (the calls ring). -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescription(package private) static voidA line added at the end of the list's file in `folder`; past its size, its lines older than a month dropped first.private static Stringprivate static Calls.DecisionbyFrame(Calls.Decision decision, Calls.Frame frame, String who) Who rings now, as the frame for now says; past the frames, nothing to decide from.private static Calls.DecisionbyFrame(Calls.Decision decision, Calls.Frame frame, String who, String own) As above, a person's own row (`own`, "own-0") read first when the frame has it: then "own", for the Porch's sentence (calls.rs's `decide`; review of part 6, F7).(package private) static Stringcall(Context context, String verb, JSONObject asked) Rust's question (StepService.call(android.content.Context, java.lang.String, java.lang.String), verbs "calls-…"), from Sioul's own process or the service's.(package private) static longWhen you last called this number from this phone (ms), within `keepMs` (14 days at most); 0 never, or forgotten.(package private) static longcalledKeep(Calls.Table table) How long a number called counts, as the table says (0: not at all, the call screening counting none, or no table of version 2), never more than CALLED_MAX_MS.(package private) static Calls.Decisiondecide(Context context, Call.Details details, long now) Sioul's answer about a call (CallScreen), in milliseconds.(package private) static Calls.DecisiondecideFor(Calls.Table table, String raw, boolean hidden, long now, long emergencyAt, Calls.Press local, long lastCall, Calls.Phone phone) decideFor with no verification and no number called: as a table of version 1 is decided, and the checks before version 2.(package private) static Calls.DecisiondecideFor(Calls.Table table, String raw, boolean hidden, long now, long emergencyAt, Calls.Press local, long lastCall, Calls.Phone phone, String verified, long called) The decision itself, from what the phone knows (crates/sioul-core/src/ calls.rs, `decide`, takes the same steps, and its tests the same cases): the floors; who; blocked; then, version 2, what the screening keeps out of a number nobody knows whatever else, a second call, the people you know by the frame (a number called lately beyond its row only while you expect a call), everyone else by the call screening, never where your contacts' row declines but while you expect a call; version 1, Let every call through, a second call, the frame.private static booleandigitsOnly(String text) (package private) static longemergencyAt(Context context) When you last called an emergency number (ms), as this phone saw it; 0 never.(package private) static Fileprivate static boolean(package private) static voidheld(Context context, Calls.Decision decision) An incoming call screened, declined or let ring, in the list Rust reads and copies into this phone's log for your other devices (one JSON line each; lines older than a month dropped now and then).private static JSONObjectkeptCalls(JSONObject called, long now, long keep) The numbers called within `keep` before `now`, none ahead of it.(package private) static Stringkey(String raw, Calls.Region region, Set<String> trunkZero) A number as the table keys it: phones.rs's `key` for what a caller ID holds (crates/sioul-core/src/calls.rs, `incoming_key`, does the same, and its tests check the two agree): "+33199001234"; a short code as written ("112", "3114"); a value that is not a number, as written without spaces.private static Calls.Presslater(Calls.Press local, Calls.Press shared) The later of this phone's own press and your devices' latest, by when each was pressed.(package private) static Stringline(Calls.Decision decision, Calls.Table table) A call's line (crates/sioul-core/src/calls.rs, `Held`): when, its number's key and the number as the network gave it, hidden or not, who it was by your lists, the phone's contacts' name when the table did not know it, the time of day (the table's frame then, even for a call decided before it: a second call), why, whether it rang, the network's verification, whether it counted as your contacts because you called it lately.(package private) static StringA number's key ("+33199001234") in the French plan's national form ("0199001234"), its overseas departments' included (+262, +590, +594, +596); null for any other (screening.rs, `national`).private static booleanopenBlocked(Context context) Android's own blocked numbers (calls and texts, for every app): its page, for you to add one.private static booleanAndroid's page of default apps, where "Caller ID & spam app" is chosen or set to none.(package private) static StringphoneContact(Context context, String raw) The name this phone's contacts give a number; null when none has it (or contacts are not readable).(package private) static voidExpecting a call (once "Let every call through") pressed on this phone (the notification): on for `minutes` (0: until turned off), or off.(package private) static Stringprivate static JSONObjectprivate static longrememberCall(Context context, String key, long now) The number's last call before this one (ms, 0 none); this one remembered.(package private) static voidrememberCalled(File folder, String key, long now, long keepMs) A number you called, by its key, with when (`called.json`, in `folder`, this phone's own, never shared), kept `keepMs` (14 days at most): the others pruned as it is written; with `keepMs` 0, nothing recorded and the file gone (review of part 2, F5).private static voidrememberEmergency(Context context, long now) private static Calls.Decisionsaid(Calls.Decision decision, boolean refuse, String why) private static booleanspacing(char c) private static Stringspam(Calls.Screening screening, String key, String verified) What the screening keeps out of a number nobody knows whatever else (decideFor's step 3; calls.rs's `spam`): a number never shown as a caller's, a failed verification, an automated caller, each while set to voicemail; null otherwise.private static boolean(package private) static JSONObjectWhat this phone allows: {api, available (the role exists here), held (Sioul holds it), contacts (READ_CONTACTS), table (one is written), emergency_at (ms)}.(package private) static booleansystemEmergency(Context context, String raw) An emergency number on Android's own list (the SIM's, the network's); false when it cannot say.(package private) static Calls.TableThe table, read again only when its file changed; none when there is none or it does not read.private static voidThe list's file without its lines older than a month.private static StringWithout the spaces and marks around it (phones.rs: `trim_matches` of both).private static StringwithoutWrittenTrunk(String digits, Set<String> trunkZero) "+330199…" → "+33199…": a trunk 0 written after a country code that has none.private static voidwriteWhole(File file, String text) Written beside, then renamed: never half a file.
-
Field Details
-
TAG
- See Also:
-
FOLDER
Rust's state folder (android/main.cpp: XDG_STATE_HOME is files/state), and the calls' own in it.- See Also:
-
TABLE
- See Also:
-
HELD
- See Also:
-
THROUGH
- See Also:
-
RECENT
- See Also:
-
EMERGENCY
- See Also:
-
CALLED
The numbers you called lately, by their key, with when (this phone's own, never shared).- See Also:
-
VERSION
The table's shape this code reads, and the one before it; another one is not read (the calls ring).- See Also:
-
CALLED_MAX_MS
A number called counts this long at most, whatever a table says (ms): screening.rs's CALLED_DAYS.- See Also:
-
KEPT_MS
Calls screened are kept this long in the list's file.- See Also:
-
TRIM_BYTES
Past this size the list's file is rewritten without its old lines.- See Also:
-
cached
-
cachedStamp
-
cachedSize
-
-
Constructor Details
-
Calls
private Calls()
-
-
Method Details
-
national
A number's key ("+33199001234") in the French plan's national form ("0199001234"), its overseas departments' included (+262, +590, +594, +596); null for any other (screening.rs, `national`). -
digitsOnly
-
folder
-
table
The table, read again only when its file changed; none when there is none or it does not read. -
key
A number as the table keys it: phones.rs's `key` for what a caller ID holds (crates/sioul-core/src/calls.rs, `incoming_key`, does the same, and its tests check the two agree): "+33199001234"; a short code as written ("112", "3114"); a value that is not a number, as written without spaces. -
withoutWrittenTrunk
"+330199…" → "+33199…": a trunk 0 written after a country code that has none. -
spacing
-
trimmed
Without the spaces and marks around it (phones.rs: `trim_matches` of both). -
asWritten
-
systemEmergency
An emergency number on Android's own list (the SIM's, the network's); false when it cannot say. -
phoneContact
The name this phone's contacts give a number; null when none has it (or contacts are not readable). -
decide
Sioul's answer about a call (CallScreen), in milliseconds. -
decideFor
static Calls.Decision decideFor(Calls.Table table, String raw, boolean hidden, long now, long emergencyAt, Calls.Press local, long lastCall, Calls.Phone phone) decideFor with no verification and no number called: as a table of version 1 is decided, and the checks before version 2. -
decideFor
static Calls.Decision decideFor(Calls.Table table, String raw, boolean hidden, long now, long emergencyAt, Calls.Press local, long lastCall, Calls.Phone phone, String verified, long called) The decision itself, from what the phone knows (crates/sioul-core/src/ calls.rs, `decide`, takes the same steps, and its tests the same cases): the floors; who; blocked; then, version 2, what the screening keeps out of a number nobody knows whatever else, a second call, the people you know by the frame (a number called lately beyond its row only while you expect a call), everyone else by the call screening, never where your contacts' row declines but while you expect a call; version 1, Let every call through, a second call, the frame. `verified`: the network's word ("passed", "failed", ""); `called`: when you last called this number (ms, 0 never). -
spam
What the screening keeps out of a number nobody knows whatever else (decideFor's step 3; calls.rs's `spam`): a number never shown as a caller's, a failed verification, an automated caller, each while set to voicemail; null otherwise. -
byFrame
Who rings now, as the frame for now says; past the frames, nothing to decide from. -
byFrame
private static Calls.Decision byFrame(Calls.Decision decision, Calls.Frame frame, String who, String own) As above, a person's own row (`own`, "own-0") read first when the frame has it: then "own", for the Porch's sentence (calls.rs's `decide`; review of part 6, F7). -
later
The later of this phone's own press and your devices' latest, by when each was pressed. -
said
-
hasDigit
-
press
Expecting a call (once "Let every call through") pressed on this phone (the notification): on for `minutes` (0: until turned off), or off. Kept for the screening at once; Rust shares it with your other devices at its next step. -
rememberCall
The number's last call before this one (ms, 0 none); this one remembered. Calls older than an hour forgotten. -
calledKeep
How long a number called counts, as the table says (0: not at all, the call screening counting none, or no table of version 2), never more than CALLED_MAX_MS. -
rememberCalled
A number you called, by its key, with when (`called.json`, in `folder`, this phone's own, never shared), kept `keepMs` (14 days at most): the others pruned as it is written; with `keepMs` 0, nothing recorded and the file gone (review of part 2, F5). -
calledAt
When you last called this number from this phone (ms), within `keepMs` (14 days at most); 0 never, or forgotten. The file pruned as it is read, gone when nothing is left, when it does not read, or with `keepMs` 0. -
keptCalls
The numbers called within `keep` before `now`, none ahead of it. -
rememberEmergency
-
emergencyAt
When you last called an emergency number (ms), as this phone saw it; 0 never. -
held
An incoming call screened, declined or let ring, in the list Rust reads and copies into this phone's log for your other devices (one JSON line each; lines older than a month dropped now and then). Never an outgoing call; written after Android has its answer, so the ringing never waits. -
line
A call's line (crates/sioul-core/src/calls.rs, `Held`): when, its number's key and the number as the network gave it, hidden or not, who it was by your lists, the phone's contacts' name when the table did not know it, the time of day (the table's frame then, even for a call decided before it: a second call), why, whether it rang, the network's verification, whether it counted as your contacts because you called it lately. Null when it cannot be made. -
append
A line added at the end of the list's file in `folder`; past its size, its lines older than a month dropped first. -
trim
The list's file without its lines older than a month. -
call
Rust's question (StepService.call(android.content.Context, java.lang.String, java.lang.String), verbs "calls-…"), from Sioul's own process or the service's.- Throws:
JSONException
-
state
What this phone allows: {api, available (the role exists here), held (Sioul holds it), contacts (READ_CONTACTS), table (one is written), emergency_at (ms)}.- Throws:
JSONException
-
openRoles
Android's page of default apps, where "Caller ID & spam app" is chosen or set to none. -
openBlocked
Android's own blocked numbers (calls and texts, for every app): its page, for you to add one. -
start
-
read
- Throws:
IOException
-
readJson
-
writeWhole
Written beside, then renamed: never half a file.
-