Package com.aurelienpierre.sioul
Class Texts
java.lang.Object
com.aurelienpierre.sioul.Texts
Texts read on the phone for your computers (docs/texts.md; Rust's side:
crates/sioul-app/src/texts.rs), without Sioul being the phone's SMS app:
the SMS app stays the record. With READ_SMS, Android shows another app its
inbox and its sent box only (the provider's restricted views): never the
drafts, the failed or queued texts, nor a multimedia message still to
download. Java reads, and hands Rust plain JSON; Rust keys the numbers,
seals the lines, and decides what travels. Java never writes a shared file.
Asked through
StepService.call(android.content.Context, java.lang.String, java.lang.String) ("texts-…", from either process): the
permissions and the SIMs, Android's question for the permissions
(TextsAsk), the rows Rust's reader asks for by their ids (the whole
history, every column, multimedia messages and their parts), a part's
content, every row there is with its date, the texts Sioul sent lately
(to find one after a crash),
and a text to send (TextSend), whether the phone's texts changed since the
last look and whether it charges (`changes`). Heard: a new text, which
brings a step soon. The background service watches Android's provider of
texts (`watch`): the import asks Android only when they changed, and a
message received (a multimedia one too, once downloaded) brings a step
soon, as a new text does.-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classA new text, after the phone's SMS app had it (SMS_RECEIVED, sent by the system alone: its permission): a step soon, in which Rust reads it and shares it.(package private) static interfaceAn inbox's newest id asked in an order (`NEWEST`); a refusal throws.(package private) static interfaceA row of a cursor, or of a check's stand-in: its values by column. -
Field Summary
FieldsModifier and TypeFieldDescription(package private) static final StringJava's own file, in the private texts folder: how Android answered the last question (TextsAsk).(package private) static final longHow quickly Android must answer the question, giving nothing, for no question to have been shown: a person reads one longer (ms).private static final AtomicBooleanThe phone's texts changed since Rust last asked with "clear" (`changes`): set at first, so that the first step looks.(package private) static final StringSioul's private texts folder in its state (Rust's `texts::private_folder`): Java's own files there.(package private) static final StringColumns never kept: where the provider keeps a part's file on this phone.private static Runnableprivate static final longHow long after the provider's last word the watch looks for a message received: a burst of changes, one look.private static HandlerWhere that look runs (the process's main thread, which the service leaves free), and the look itself; null: not watched.(package private) static final String[]How the newest row is asked for: the limit in the sort, since Android's own SMS and MMS providers pass no ContentResolver.QUERY_ARG_LIMIT on and would give every id each time; then, from a provider that refuses a limit there, the plain sort, its ids in that order and only the first read.private static longprivate static longThe newest message received, by the provider's id, of each table (SMS, MMS), as the watch last saw it; -1: not read yet.(package private) static final intAndroid's provider: a text sent; received.(package private) static final Stringprivate static ContentObserverAndroid's provider of texts watched in this process (the background service's, or the window's); null: not watched here. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescription(package private) static boolean(package private) static booleanWhether a message was received since the watch last looked: the newest id of either inbox grew (`grew`); the newest ones kept.(package private) static voidAndroid's question for the texts' permissions: an activity never seen (TextsAsk), from Sioul's window.(package private) static JSONObjectHow Android answered the texts' last question (`remember`); null when none was asked here.(package private) static booleanaskedAtOnce(Context context) Whether the last question was answered at once, nothing given (`atOnce`); false when none was asked.(package private) static booleanatOnce(int given, long took) Whether Android answered the texts' question at once, giving none of the three: it showed none (Android 15's restricted settings after the first time, or "Don't allow" chosen twice before).(package private) static Stringcall(Context context, String verb, JSONObject asked) Rust's question (StepService.call(android.content.Context, java.lang.String, java.lang.String)): its answer in JSON, or null.(package private) static booleanchangedSince(boolean watched, AtomicBoolean mark, boolean clear) Whether the texts changed since the last look: always when not watched here (READ_SMS not given yet); else as marked, the mark cleared when `clear`.(package private) static JSONObjectRust's "texts-changes": {changed (`changedSince`), plugged (the phone on its charger)}.private static List<JSONObject> copies(ContentResolver resolver, Uri uri, String selection, String[] arguments) Every row of a query, every column copied (the cursor closed after).(package private) static JSONObjectA row's every column, as the provider gives it (a part's file's place on the phone aside).(package private) static JSONObjectfind(ContentResolver resolver, String own, long since) The texts Sioul sent since `since` (ms), as Android filed them in the sent box with Sioul as their creator: after a crash between a claim and Android's word, Rust looks for the one it claimed.(package private) static JSONObjectfindMms(ContentResolver resolver, String own, String key) Sioul's multimedia message by its key: the rows Android filed with that transaction id (the message Rust built carries it) and Sioul as their creator, each its id, its date (seconds) and its box (2: sent).(package private) static booleangrew(long before, long now) Whether an inbox's newest id grew: read before (not -1), larger now (a box that could not be read now says -1: no).(package private) static JSONObjectids(ContentResolver resolver, boolean measure) Every row there is now, each id with its own date ("sms" with "sms_at", "mms" with "mms_at": the plain texts' table gives a deleted newest text's id to the next one, and the date tells the two apart; Rust's `texts::Row`) and, when `measure`, how much media the multimedia messages hold: the rows to read, the texts deleted on the phone, and the sizes the settings say.(package private) static booleanAndroid's App info for Sioul, where ⋮ ▸ Allow restricted settings and the permissions are.(package private) static JSONObjectWhat each SIM's carrier lets Sioul send (Android's carrier configuration,SmsManager.getCarrierConfigValues, which asks no permission): that SIM's alone (only; -1 the phone's default), else each active SIM's (READ_PHONE_STATE lists them), else the default's.(package private) static JSONObjectlimitsLine(int sub, int max, int width, int height, int recipients, boolean group, boolean mms) One SIM's carrier values as Rust reads them (texts::Limits): none below zero (a carrier's "no limit" said as the largest count).private static voidlisted(ContentResolver resolver, Uri table, String name, JSONObject out) A table's ids and dates (`ids`), put in `out` under `name` and `name_at` only when listed whole.(package private) static booleanWhether a part's content travels as a file: anything but words and the SMIL that lays them out.(package private) static JSONObjectmms(JSONObject row, List<JSONObject> addresses, List<JSONObject> parts) A multimedia message, as Rust reads it: every column of its row, of its addresses and of its parts (each part's size from Android, its file's place on the phone left out), so that a later restore loses nothing.private static longThe newest id in an inbox, 0 when it is empty, -1 when it cannot be read (`newestBy`).(package private) static longnewestBy(Texts.Look look) The newest id as `look` gives it, asked in each order of NEWEST until one is taken; -1 when none is (the inbox cannot be read).private static Texts.RowA cursor's current row.(package private) static JSONObjectpart(ContentResolver resolver, long part, String target) A part's content copied to `target` (Sioul's own folder), for Rust to seal and share: {copied: bytes}, or -1.(package private) static booleanThe phone on its charger, by Android's last word on the battery (a sticky broadcast: no receiver kept).(package private) static JSONObjectread(ContentResolver resolver, long smsMark, long mmsMark, int limit, JSONArray smsIds, JSONArray mmsIds) The rows `smsIds` and `mmsIds` name (else those after the marks `sms`, `mms`: `rows`); `limit` at most, the plain texts first, by id, every column, the date among them (Rust tells a row by its id and its date); each conversation's people; and the new marks.(package private) static voidHow Android answered the question (TextsAsk), kept in Java's own file for `state`: how many of how many, how fast.(package private) static StringWhich rows a read takes: given `ids` (the rows Rust's reader asks for: those its log lacks, by their ids), those rows only; else those after the mark (no reader asks so since its version 4, 16 October 2026).(package private) static longsize(ContentResolver resolver, long part) A part's size in bytes, as Android opens it; -1 when it does not open (not downloaded).(package private) static JSONObjectsms(JSONObject row) A text of the SMS provider, as Rust reads it (crates/sioul-app/src/texts.rs, `Raw`): every column.(package private) static JSONObjectWhat Android allows Sioul: each permission, the phone's SMS app, its SIMs (with READ_PHONE_STATE: their names).(package private) static JSONObjectthreads(ContentResolver resolver) Each conversation's people, by its thread: Android's own list of each thread's recipients (the person themselves never among them), so that a group reads as a group.(package private) static voidtouched()A new text heard (Heard): changed, whatever the provider said yet.(package private) static voidNo longer watched (the service ending).(package private) static voidAndroid's provider of texts watched in this process (the background service's), once READ_SMS is given: a text received, sent, deleted or read marks them changed, read at the next step; a message received (its newest id grown, a multimedia one once downloaded) brings a step soon, as SMS_RECEIVED does (`Heard`), so that it reaches your computers within the minute.(package private) static voidThe same, `steps` saying whether a message received brings a step (the background service's process); in the window's, which exchanges each minute by itself, the watch only marks the texts changed, so that its exchanges ask Android for every row only after a change (the review of 16 October 2026, LOW 3: unwatched, it listed every row once a minute while on screen).
-
Field Details
-
TAG
- See Also:
-
FOLDER
Sioul's private texts folder in its state (Rust's `texts::private_folder`): Java's own files there.- See Also:
-
SENT_BOX
Android's provider: a text sent; received.- See Also:
-
changed
The phone's texts changed since Rust last asked with "clear" (`changes`): set at first, so that the first step looks. -
watching
Android's provider of texts watched in this process (the background service's, or the window's); null: not watched here. -
newestSms
The newest message received, by the provider's id, of each table (SMS, MMS), as the watch last saw it; -1: not read yet. -
newestMms
-
LOOK_MS
How long after the provider's last word the watch looks for a message received: a burst of changes, one look.- See Also:
-
looks
Where that look runs (the process's main thread, which the service leaves free), and the look itself; null: not watched. -
look
-
NEWEST
How the newest row is asked for: the limit in the sort, since Android's own SMS and MMS providers pass no ContentResolver.QUERY_ARG_LIMIT on and would give every id each time; then, from a provider that refuses a limit there, the plain sort, its ids in that order and only the first read. -
AT_ONCE_MS
How quickly Android must answer the question, giving nothing, for no question to have been shown: a person reads one longer (ms).- See Also:
-
ASKED
Java's own file, in the private texts folder: how Android answered the last question (TextsAsk).- See Also:
-
LOCAL_PATH
Columns never kept: where the provider keeps a part's file on this phone.- See Also:
-
-
Constructor Details
-
Texts
private Texts()
-
-
Method Details
-
watch
Android's provider of texts watched in this process (the background service's), once READ_SMS is given: a text received, sent, deleted or read marks them changed, read at the next step; a message received (its newest id grown, a multimedia one once downloaded) brings a step soon, as SMS_RECEIVED does (`Heard`), so that it reaches your computers within the minute. The look for it comes a second after the provider's last word: one message tells it several times (its text, its row, its conversation), one look. Asked again at each step until it holds. -
watch
The same, `steps` saying whether a message received brings a step (the background service's process); in the window's, which exchanges each minute by itself, the watch only marks the texts changed, so that its exchanges ask Android for every row only after a change (the review of 16 October 2026, LOW 3: unwatched, it listed every row once a minute while on screen). -
arrived
Whether a message was received since the watch last looked: the newest id of either inbox grew (`grew`); the newest ones kept. Nothing of them is read but their ids. -
grew
Whether an inbox's newest id grew: read before (not -1), larger now (a box that could not be read now says -1: no). Pure: android/jvm-checks/StepsCheck.java. -
newest
The newest id in an inbox, 0 when it is empty, -1 when it cannot be read (`newestBy`). -
newestBy
The newest id as `look` gives it, asked in each order of NEWEST until one is taken; -1 when none is (the inbox cannot be read). Pure: android/jvm-checks/StepsCheck.java. -
unwatch
No longer watched (the service ending). -
touched
A new text heard (Heard): changed, whatever the provider said yet. -
changedSince
Whether the texts changed since the last look: always when not watched here (READ_SMS not given yet); else as marked, the mark cleared when `clear`. Pure: android/jvm-checks/StepsCheck.java. -
changes
Rust's "texts-changes": {changed (`changedSince`), plugged (the phone on its charger)}.- Throws:
JSONException
-
plugged
The phone on its charger, by Android's last word on the battery (a sticky broadcast: no receiver kept). -
of
A cursor's current row. -
call
Rust's question (StepService.call(android.content.Context, java.lang.String, java.lang.String)): its answer in JSON, or null.- Throws:
JSONException
-
allowed
-
state
What Android allows Sioul: each permission, the phone's SMS app, its SIMs (with READ_PHONE_STATE: their names).- Throws:
JSONException
-
atOnce
Whether Android answered the texts' question at once, giving none of the three: it showed none (Android 15's restricted settings after the first time, or "Don't allow" chosen twice before). `took` is -1 when not measured. Pure: android/jvm-checks/TextsCheck.java. -
remember
How Android answered the question (TextsAsk), kept in Java's own file for `state`: how many of how many, how fast. -
asked
How Android answered the texts' last question (`remember`); null when none was asked here. -
askedAtOnce
Whether the last question was answered at once, nothing given (`atOnce`); false when none was asked. -
info
Android's App info for Sioul, where ⋮ ▸ Allow restricted settings and the permissions are. -
ask
Android's question for the texts' permissions: an activity never seen (TextsAsk), from Sioul's window. -
copy
A row's every column, as the provider gives it (a part's file's place on the phone aside).- Throws:
JSONException
-
sms
A text of the SMS provider, as Rust reads it (crates/sioul-app/src/texts.rs, `Raw`): every column.- Throws:
JSONException
-
mms
static JSONObject mms(JSONObject row, List<JSONObject> addresses, List<JSONObject> parts) throws JSONException A multimedia message, as Rust reads it: every column of its row, of its addresses and of its parts (each part's size from Android, its file's place on the phone left out), so that a later restore loses nothing.- Throws:
JSONException
-
media
Whether a part's content travels as a file: anything but words and the SMIL that lays them out. -
size
A part's size in bytes, as Android opens it; -1 when it does not open (not downloaded). -
threads
Each conversation's people, by its thread: Android's own list of each thread's recipients (the person themselves never among them), so that a group reads as a group.- Throws:
JSONException
-
rows
Which rows a read takes: given `ids` (the rows Rust's reader asks for: those its log lacks, by their ids), those rows only; else those after the mark (no reader asks so since its version 4, 16 October 2026). -
read
static JSONObject read(ContentResolver resolver, long smsMark, long mmsMark, int limit, JSONArray smsIds, JSONArray mmsIds) throws JSONException The rows `smsIds` and `mmsIds` name (else those after the marks `sms`, `mms`: `rows`); `limit` at most, the plain texts first, by id, every column, the date among them (Rust tells a row by its id and its date); each conversation's people; and the new marks.- Throws:
JSONException
-
copies
private static List<JSONObject> copies(ContentResolver resolver, Uri uri, String selection, String[] arguments) Every row of a query, every column copied (the cursor closed after). -
ids
Every row there is now, each id with its own date ("sms" with "sms_at", "mms" with "mms_at": the plain texts' table gives a deleted newest text's id to the next one, and the date tells the two apart; Rust's `texts::Row`) and, when `measure`, how much media the multimedia messages hold: the rows to read, the texts deleted on the phone, and the sizes the settings say. A table that could not be listed whole is left out: Rust then reads nothing and marks nothing deleted, never taking "not known" for "none there".- Throws:
JSONException
-
listed
private static void listed(ContentResolver resolver, Uri table, String name, JSONObject out) throws JSONException A table's ids and dates (`ids`), put in `out` under `name` and `name_at` only when listed whole.- Throws:
JSONException
-
part
A part's content copied to `target` (Sioul's own folder), for Rust to seal and share: {copied: bytes}, or -1.- Throws:
JSONException
-
find
The texts Sioul sent since `since` (ms), as Android filed them in the sent box with Sioul as their creator: after a crash between a claim and Android's word, Rust looks for the one it claimed.- Throws:
JSONException
-
limits
What each SIM's carrier lets Sioul send (Android's carrier configuration,SmsManager.getCarrierConfigValues, which asks no permission): that SIM's alone (only; -1 the phone's default), else each active SIM's (READ_PHONE_STATE lists them), else the default's. Numbers only, never the carrier's name.- Throws:
JSONException
-
limitsLine
static JSONObject limitsLine(int sub, int max, int width, int height, int recipients, boolean group, boolean mms) throws JSONException One SIM's carrier values as Rust reads them (texts::Limits): none below zero (a carrier's "no limit" said as the largest count). Pure: android/jvm-checks/TextsCheck.java.- Throws:
JSONException
-
findMms
Sioul's multimedia message by its key: the rows Android filed with that transaction id (the message Rust built carries it) and Sioul as their creator, each its id, its date (seconds) and its box (2: sent).- Throws:
JSONException
-