From 4666777ae5875a7af39557fff7420c0ffec60b5d Mon Sep 17 00:00:00 2001 From: John S Peterson Date: Tue, 23 Jul 2024 22:12:42 +0000 Subject: [PATCH 1/2] new Settings API : read write settings --- app/src/main/AndroidManifest.xml | 1 + .../com/termux/api/TermuxApiReceiver.java | 4 + .../java/com/termux/api/apis/SettingsAPI.java | 197 ++++++++++++++++++ 3 files changed, 202 insertions(+) create mode 100644 app/src/main/java/com/termux/api/apis/SettingsAPI.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f9d37121..ed656f8a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,6 +34,7 @@ + diff --git a/app/src/main/java/com/termux/api/TermuxApiReceiver.java b/app/src/main/java/com/termux/api/TermuxApiReceiver.java index b752864b..3463abd3 100644 --- a/app/src/main/java/com/termux/api/TermuxApiReceiver.java +++ b/app/src/main/java/com/termux/api/TermuxApiReceiver.java @@ -31,6 +31,7 @@ import com.termux.api.apis.NotificationListAPI; import com.termux.api.apis.SAFAPI; import com.termux.api.apis.SensorAPI; +import com.termux.api.apis.SettingsAPI; import com.termux.api.apis.ShareAPI; import com.termux.api.apis.SmsInboxAPI; import com.termux.api.apis.SmsSendAPI; @@ -196,6 +197,9 @@ private void doWork(Context context, Intent intent) { case "Sensor": SensorAPI.onReceive(context, intent); break; + case "Settings": + SettingsAPI.onReceive(this, context, intent); + break; case "Share": ShareAPI.onReceive(this, context, intent); break; diff --git a/app/src/main/java/com/termux/api/apis/SettingsAPI.java b/app/src/main/java/com/termux/api/apis/SettingsAPI.java new file mode 100644 index 00000000..fdd0c53d --- /dev/null +++ b/app/src/main/java/com/termux/api/apis/SettingsAPI.java @@ -0,0 +1,197 @@ +package com.termux.api.apis; + +import android.app.ActivityManager; +import android.app.ActivityManager.MemoryInfo; +import android.app.ApplicationExitInfo; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.content.Context; +import android.content.Intent; +import android.util.JsonWriter; + +import androidx.annotation.RequiresPermission; +import androidx.appcompat.app.AppCompatActivity; + +import com.termux.api.TermuxApiReceiver; +import com.termux.api.util.ResultReturner; +import com.termux.shared.logger.Logger; + +import java.util.List; +import java.io.PrintWriter; +import java.io.StringWriter; + +import android.content.ContentResolver; +import android.provider.Settings; + +// INDENTATION NOTICE this file indentation is configured for mobile screens . small tall screen . DON'T CHANGE it if you edit from desktop computer with large screen and you think it looks wrong to you . it's intentional not a mistake . to reduce unnecessary nesting horizontally and allow set ts=2 in vim tab width 2 spaces only + +// after I wrote JSON I realized all output was only one line . so this will convert to simpler output without json +// class JsonWriter { +class myWriter { + +StringWriter sw; +public myWriter(StringWriter s) { + sw = s; +} +void setIndent(String s){} +void beginArray(){} +void endArray(){} +void value(String s) { + if (s == null) { + s = "null"; + // if (s.trim().isEmpty() + } else if (s.isEmpty()) + s = "nmempty"; + s += "\n"; + sw.append(s); +} + +} + +public class SettingsAPI { + +private static final String LOG_TAG = "SettingsAPI"; +static Context context; +static TermuxApiReceiver receiver; +static Intent intent; +static StringWriter sw; +// static JsonWriter out; +static myWriter out; + +static ContentResolver cr; +static String setting; +static String type; + +public static void onReceive(TermuxApiReceiver _receiver, final Context _context, Intent _intent) { + Logger.logDebug(LOG_TAG, "onReceive"); + context = _context; + receiver = _receiver; + intent = _intent; + sw = new StringWriter(); + // out = new JsonWriter(sw); + out = new myWriter(sw); + + // out.setIndent(" "); + out.setIndent(" "); + + cr = context.getContentResolver(); + setting = intent.getStringExtra("setting"); + type = intent.getStringExtra("type"); + + Logger.logInfo(LOG_TAG, "==*==*==*=="); + Logger.logInfo(LOG_TAG, "received " + intent.toString()); + + try { + try { + // jsonTest(); + settings(); + } catch (Exception e) { + Logger.logError(LOG_TAG, e.toString()); + out.value(e.toString()); + } + write(); + } catch (Exception e) { + Logger.logError(LOG_TAG, e.toString()); + } +} + +static void write() { + ResultReturner.returnData(context.getApplicationContext(), intent, new ResultReturner.WithInput() { + @Override public void writeResult(PrintWriter _out) throws Exception { + try { + // Logger.logInfo(LOG_TAG, "printing \n\""+sw+"\""); + // out.value("\n"); + _out.print(sw); + } catch (Exception e) { + Logger.logError(LOG_TAG, e.toString()); + } + } + }); +} + +// # [ array of values +// # { object of key value pair +/* +static void jsonTest() throws Exception { + Logger.logInfo(LOG_TAG, "JSON test"); + out.beginArray(); + out.value("123"); + + // out.beginObject(); + // out.name("on").value(0); + // out.value(name); + // out.endObject(); + + out.endArray(); +} +*/ + +static void get() throws Exception { + switch(type) { + case "string": + String get = Settings.Global.getString(cr, setting); + out.value(get); + Logger.logInfo(LOG_TAG, "received string \"" + get + "\""); + break; + case "int": + int geti = Settings.Global.getInt(cr, setting); + // out.name(geti.toString()); + out.value(geti+""); + Logger.logInfo(LOG_TAG, "received int \"" + geti + "\""); + break; + default: + out.value(type +" is invalid type did you mean string/int"); + break; + } +} + +static void set() throws Exception { + String value = intent.getStringExtra("value"); + Logger.logInfo(LOG_TAG, "received value \""+value+"\""); + boolean result = false; + switch(type) { + case "string": + // if (value == null || value.trim().isEmpty()) { + // out.value("notice setting empty value"); + if (value == null) + value = ""; + out.value("setting "+setting+" to \""+value+"\""); + result = Settings.Global.putString(cr, setting, value); + break; + case "int": + if (value == null || value.trim().isEmpty()) { + out.value("int value cannot be empty"); + return; + } + out.value("setting "+setting+" to \""+value+"\""); + result = Settings.Global.putInt(cr, setting, Integer.parseInt(value)); + break; + default: + out.value(type +" is invalid type did you mean string/int"); + // out.value("correct usage termux-api Settings -a get/set --es type string/int --es setting name"); + break; + } + out.value("boolean result: "+result); +} + +static void settings() throws Exception { + String action = intent.getAction(); + Logger.logInfo(LOG_TAG, "received action "+action); + // out.beginArray(); + // out.beginObject(); + switch(action) { + case "get": + get(); + break; + case "set": + set(); + break; + default: + out.value(action+" is invalid action. only get/set accepted"); + break; + } + // out.endObject(); + // out.endArray(); +} +} // class From d2da2c389fea5a372b3cacbd606fab9f252e422f Mon Sep 17 00:00:00 2001 From: John Peterson Date: Thu, 14 May 2026 20:00:04 -0300 Subject: [PATCH 2/2] also read write secure and system setting --- .../java/com/termux/api/apis/SettingsAPI.java | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/termux/api/apis/SettingsAPI.java b/app/src/main/java/com/termux/api/apis/SettingsAPI.java index fdd0c53d..8f8a1758 100644 --- a/app/src/main/java/com/termux/api/apis/SettingsAPI.java +++ b/app/src/main/java/com/termux/api/apis/SettingsAPI.java @@ -62,6 +62,7 @@ public class SettingsAPI { static ContentResolver cr; static String setting; static String type; +static String domain; public static void onReceive(TermuxApiReceiver _receiver, final Context _context, Intent _intent) { Logger.logDebug(LOG_TAG, "onReceive"); @@ -78,6 +79,7 @@ public static void onReceive(TermuxApiReceiver _receiver, final Context _context cr = context.getContentResolver(); setting = intent.getStringExtra("setting"); type = intent.getStringExtra("type"); + domain = intent.getStringExtra("domain"); Logger.logInfo(LOG_TAG, "==*==*==*=="); Logger.logInfo(LOG_TAG, "received " + intent.toString()); @@ -127,10 +129,37 @@ static void jsonTest() throws Exception { } */ +static String getString() throws Exception { + switch(domain) { + case "global": + return Settings.Global.getString(cr, setting); + case "secure": + return Settings.Secure.getString(cr, setting); + case "system": + return Settings.System.getString(cr, setting); + default: + return domain +" is invalid. valid global/system"; + } +} + +static boolean setString(String value) throws Exception { + switch(domain) { + case "global": + return Settings.Global.putString(cr, setting, value); + case "secure": + return Settings.Secure.putString(cr, setting, value); + case "system": + return Settings.System.putString(cr, setting, value); + default: + out.value("invalid domain "+domain +" did you mean global/system"); + return false; + } +} + static void get() throws Exception { switch(type) { case "string": - String get = Settings.Global.getString(cr, setting); + String get = getString(); out.value(get); Logger.logInfo(LOG_TAG, "received string \"" + get + "\""); break; @@ -157,7 +186,7 @@ static void set() throws Exception { if (value == null) value = ""; out.value("setting "+setting+" to \""+value+"\""); - result = Settings.Global.putString(cr, setting, value); + result = setString(value); break; case "int": if (value == null || value.trim().isEmpty()) {