Skip to content

Commit 7b4acb5

Browse files
Move Termux Properties to com.termux.app.settings.properties package
The termux properties handling was mixed in with termux preferences. They are now moved out of into a separate sub package, the following classes are added: - `SharedProperties` class which is an implementation similar to android's `SharedPreferences` interface for reading from ".properties" files which also maintains an in-memory cache for the key/value pairs. Two types of in-memory cache maps are maintained, one for the literal `String` values found in the file for the keys and an additional one that stores (near) primitive `Object` values for internal use by the caller. Write support is currently not implemented, but may be added if we provide users a GUI to modify the properties. We cannot just overwrite the ".properties" files, since comments also exits, so in-place editing would be required. - `SharedPropertiesParser` interface that the caller of `SharedProperties` must implement. It is currently only used to map `String` values to internal `Object` values. - `TermuxPropertyConstants` class that defines shared constants of the properties used by Termux app and its plugins. This class should be imported by other termux plugin apps instead of copying and defining their own constants. - `TermuxSharedProperties` class that acts as manager for handling termux properties. It implements the `SharedPropertiesParser` interface and acts as the wrapper for the `SharedProperties` class.
1 parent dbf8477 commit 7b4acb5

File tree

8 files changed

+1173
-210
lines changed

8 files changed

+1173
-210
lines changed

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ android {
1111
implementation "androidx.viewpager:viewpager:1.0.0"
1212
implementation "androidx.drawerlayout:drawerlayout:1.1.1"
1313
implementation 'androidx.core:core:1.5.0-beta02'
14+
implementation 'com.google.guava:guava:24.1-jre'
1415
implementation project(":terminal-view")
1516
}
1617

app/src/main/java/com/termux/app/TermuxActivity.java

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
import com.termux.app.input.BellHandler;
5252
import com.termux.app.input.extrakeys.ExtraKeysView;
5353
import com.termux.app.input.FullScreenWorkAround;
54+
import com.termux.app.settings.properties.TermuxPropertyConstants;
55+
import com.termux.app.settings.properties.TermuxSharedProperties;
5456
import com.termux.terminal.EmulatorDebug;
5557
import com.termux.terminal.TerminalColors;
5658
import com.termux.terminal.TerminalSession;
@@ -110,6 +112,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection
110112
ExtraKeysView mExtraKeysView;
111113

112114
TermuxPreferences mSettings;
115+
TermuxSharedProperties mProperties;
113116

114117
/**
115118
* The connection to the {@link TermuxService}. Requested in {@link #onCreate(Bundle)} with a call to
@@ -144,16 +147,19 @@ public final class TermuxActivity extends Activity implements ServiceConnection
144147
public void onReceive(Context context, Intent intent) {
145148
if (mIsVisible) {
146149
String whatToReload = intent.getStringExtra(TERMUX_ACTIVITY.EXTRA_RELOAD_STYLE);
150+
Log.d("termux", "Reloading termux style for: " + whatToReload);
147151
if ("storage".equals(whatToReload)) {
148152
if (ensureStoragePermissionGranted())
149153
TermuxInstaller.setupStorageSymlinks(TermuxActivity.this);
150154
return;
151155
}
156+
152157
checkForFontAndColors();
153-
mSettings.reloadFromProperties(TermuxActivity.this);
158+
159+
mProperties.loadTermuxPropertiesFromDisk();
154160

155161
if (mExtraKeysView != null) {
156-
mExtraKeysView.reload(mSettings.mExtraKeys);
162+
mExtraKeysView.reload(mProperties.getExtraKeysInfo());
157163
}
158164
}
159165
}
@@ -205,7 +211,9 @@ public boolean ensureStoragePermissionGranted() {
205211
@Override
206212
public void onCreate(Bundle bundle) {
207213
mSettings = new TermuxPreferences(this);
208-
mIsUsingBlackUI = mSettings.isUsingBlackUI();
214+
mProperties = new TermuxSharedProperties(this);
215+
216+
mIsUsingBlackUI = mProperties.isUsingBlackUI();
209217
if (mIsUsingBlackUI) {
210218
this.setTheme(R.style.Theme_Termux_Black);
211219
} else {
@@ -223,7 +231,7 @@ public void onCreate(Bundle bundle) {
223231
return insets;
224232
});
225233

226-
if (mSettings.isUsingFullScreen()) {
234+
if (mProperties.isUsingFullScreen()) {
227235
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
228236
}
229237

@@ -245,7 +253,7 @@ public void onCreate(Bundle bundle) {
245253

246254

247255
ViewGroup.LayoutParams layoutParams = viewPager.getLayoutParams();
248-
layoutParams.height = layoutParams.height * (mSettings.mExtraKeys == null ? 0 : mSettings.mExtraKeys.getMatrix().length);
256+
layoutParams.height = layoutParams.height * (mProperties.getExtraKeysInfo() == null ? 0 : mProperties.getExtraKeysInfo().getMatrix().length);
249257
viewPager.setLayoutParams(layoutParams);
250258

251259
viewPager.setAdapter(new PagerAdapter() {
@@ -266,10 +274,10 @@ public Object instantiateItem(@NonNull ViewGroup collection, int position) {
266274
View layout;
267275
if (position == 0) {
268276
layout = mExtraKeysView = (ExtraKeysView) inflater.inflate(R.layout.extra_keys_main, collection, false);
269-
mExtraKeysView.reload(mSettings.mExtraKeys);
277+
mExtraKeysView.reload(mProperties.getExtraKeysInfo());
270278

271279
// apply extra keys fix if enabled in prefs
272-
if (mSettings.isUsingFullScreen() && mSettings.isUsingFullScreenWorkAround()) {
280+
if (mProperties.isUsingFullScreen() && mProperties.isUsingFullScreenWorkAround()) {
273281
FullScreenWorkAround.apply(TermuxActivity.this);
274282
}
275283

@@ -451,14 +459,14 @@ public void onClipboardText(TerminalSession session, String text) {
451459
public void onBell(TerminalSession session) {
452460
if (!mIsVisible) return;
453461

454-
switch (mSettings.mBellBehaviour) {
455-
case TermuxPreferences.BELL_BEEP:
456-
mBellSoundPool.play(mBellSoundId, 1.f, 1.f, 1, 0, 1.f);
457-
break;
458-
case TermuxPreferences.BELL_VIBRATE:
462+
switch (mProperties.getBellBehaviour()) {
463+
case TermuxPropertyConstants.IVALUE_BELL_BEHAVIOUR_VIBRATE:
459464
BellHandler.getInstance(TermuxActivity.this).doBell();
460465
break;
461-
case TermuxPreferences.BELL_IGNORE:
466+
case TermuxPropertyConstants.IVALUE_BELL_BEHAVIOUR_BEEP:
467+
mBellSoundPool.play(mBellSoundId, 1.f, 1.f, 1, 0, 1.f);
468+
break;
469+
case TermuxPropertyConstants.IVALUE_BELL_BEHAVIOUR_IGNORE:
462470
// Ignore the bell character.
463471
break;
464472
}
@@ -665,7 +673,7 @@ void addNewSession(boolean failSafe, String sessionName) {
665673

666674
String workingDirectory;
667675
if (currentSession == null) {
668-
workingDirectory = mSettings.mDefaultWorkingDir;
676+
workingDirectory = mProperties.getDefaultWorkingDirectory();
669677
} else {
670678
workingDirectory = currentSession.getCwd();
671679
}

app/src/main/java/com/termux/app/TermuxPreferences.java

Lines changed: 6 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,13 @@
22

33
import android.content.Context;
44
import android.content.SharedPreferences;
5-
import android.content.res.Configuration;
65
import android.preference.PreferenceManager;
7-
import android.util.Log;
86
import android.util.TypedValue;
9-
import android.widget.Toast;
10-
import com.termux.terminal.TerminalSession;
11-
import org.json.JSONArray;
12-
import org.json.JSONException;
13-
import org.json.JSONObject;
14-
15-
import java.io.File;
16-
import java.io.FileInputStream;
17-
import java.io.IOException;
18-
import java.io.InputStreamReader;
19-
import java.lang.annotation.Retention;
20-
import java.lang.annotation.RetentionPolicy;
21-
import java.nio.charset.StandardCharsets;
22-
import java.util.ArrayList;
23-
import java.util.HashMap;
24-
import java.util.Iterator;
25-
import java.util.List;
26-
import java.util.Map;
27-
import java.util.Properties;
287

29-
import androidx.annotation.IntDef;
30-
31-
import static com.termux.terminal.EmulatorDebug.LOG_TAG;
8+
import com.termux.terminal.TerminalSession;
329

3310
final class TermuxPreferences {
3411

35-
@IntDef({BELL_VIBRATE, BELL_BEEP, BELL_IGNORE})
36-
@Retention(RetentionPolicy.SOURCE)
37-
@interface AsciiBellBehaviour {
38-
}
39-
40-
final static class KeyboardShortcut {
41-
42-
KeyboardShortcut(int codePoint, int shortcutAction) {
43-
this.codePoint = codePoint;
44-
this.shortcutAction = shortcutAction;
45-
}
46-
47-
final int codePoint;
48-
final int shortcutAction;
49-
}
50-
51-
static final int SHORTCUT_ACTION_CREATE_SESSION = 1;
52-
static final int SHORTCUT_ACTION_NEXT_SESSION = 2;
53-
static final int SHORTCUT_ACTION_PREVIOUS_SESSION = 3;
54-
static final int SHORTCUT_ACTION_RENAME_SESSION = 4;
55-
56-
static final int BELL_VIBRATE = 1;
57-
static final int BELL_BEEP = 2;
58-
static final int BELL_IGNORE = 3;
59-
6012
private final int MIN_FONTSIZE;
6113
private static final int MAX_FONTSIZE = 256;
6214

@@ -65,34 +17,11 @@ final static class KeyboardShortcut {
6517
private static final String CURRENT_SESSION_KEY = "current_session";
6618
private static final String SCREEN_ALWAYS_ON_KEY = "screen_always_on";
6719

68-
private boolean mUseDarkUI;
6920
private boolean mScreenAlwaysOn;
7021
private int mFontSize;
71-
72-
private boolean mUseFullScreen;
73-
private boolean mUseFullScreenWorkAround;
74-
75-
@AsciiBellBehaviour
76-
int mBellBehaviour = BELL_VIBRATE;
77-
78-
boolean mBackIsEscape;
79-
boolean mDisableVolumeVirtualKeys;
8022
boolean mShowExtraKeys;
81-
String mDefaultWorkingDir;
82-
83-
ExtraKeysInfos mExtraKeys;
84-
85-
final List<KeyboardShortcut> shortcuts = new ArrayList<>();
86-
87-
/**
88-
* If value is not in the range [min, max], set it to either min or max.
89-
*/
90-
static int clamp(int value, int min, int max) {
91-
return Math.min(Math.max(value, min), max);
92-
}
9323

9424
TermuxPreferences(Context context) {
95-
reloadFromProperties(context);
9625
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
9726

9827
float dipInPixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, context.getResources().getDisplayMetrics());
@@ -139,18 +68,6 @@ boolean isScreenAlwaysOn() {
13968
return mScreenAlwaysOn;
14069
}
14170

142-
boolean isUsingBlackUI() {
143-
return mUseDarkUI;
144-
}
145-
146-
boolean isUsingFullScreen() {
147-
return mUseFullScreen;
148-
}
149-
150-
boolean isUsingFullScreenWorkAround() {
151-
return mUseFullScreenWorkAround;
152-
}
153-
15471
void setScreenAlwaysOn(Context context, boolean newValue) {
15572
mScreenAlwaysOn = newValue;
15673
PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(SCREEN_ALWAYS_ON_KEY, newValue).apply();
@@ -169,108 +86,11 @@ static TerminalSession getCurrentSession(TermuxActivity context) {
16986
return null;
17087
}
17188

172-
void reloadFromProperties(Context context) {
173-
File propsFile = new File(TermuxConstants.TERMUX_PROPERTIES_PRIMARY_PATH);
174-
if (!propsFile.exists())
175-
propsFile = new File(TermuxConstants.TERMUX_PROPERTIES_SECONDARY_PATH);
176-
177-
Properties props = new Properties();
178-
try {
179-
if (propsFile.isFile() && propsFile.canRead()) {
180-
try (FileInputStream in = new FileInputStream(propsFile)) {
181-
props.load(new InputStreamReader(in, StandardCharsets.UTF_8));
182-
}
183-
}
184-
} catch (Exception e) {
185-
Toast.makeText(context, "Could not open properties file termux.properties: " + e.getMessage(), Toast.LENGTH_LONG).show();
186-
Log.e("termux", "Error loading props", e);
187-
}
188-
189-
switch (props.getProperty("bell-character", "vibrate")) {
190-
case "beep":
191-
mBellBehaviour = BELL_BEEP;
192-
break;
193-
case "ignore":
194-
mBellBehaviour = BELL_IGNORE;
195-
break;
196-
default: // "vibrate".
197-
mBellBehaviour = BELL_VIBRATE;
198-
break;
199-
}
200-
201-
switch (props.getProperty("use-black-ui", "").toLowerCase()) {
202-
case "true":
203-
mUseDarkUI = true;
204-
break;
205-
case "false":
206-
mUseDarkUI = false;
207-
break;
208-
default:
209-
int nightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
210-
mUseDarkUI = nightMode == Configuration.UI_MODE_NIGHT_YES;
211-
}
212-
213-
mUseFullScreen = "true".equals(props.getProperty("fullscreen", "false").toLowerCase());
214-
mUseFullScreenWorkAround = "true".equals(props.getProperty("use-fullscreen-workaround", "false").toLowerCase());
215-
216-
mDefaultWorkingDir = props.getProperty("default-working-directory", TermuxConstants.HOME_PATH);
217-
File workDir = new File(mDefaultWorkingDir);
218-
if (!workDir.exists() || !workDir.isDirectory()) {
219-
// Fallback to home directory if user configured working directory is not exist
220-
// or is a regular file.
221-
mDefaultWorkingDir = TermuxConstants.HOME_PATH;
222-
}
223-
224-
String defaultExtraKeys = "[[ESC, TAB, CTRL, ALT, {key: '-', popup: '|'}, DOWN, UP]]";
225-
226-
try {
227-
String extrakeyProp = props.getProperty("extra-keys", defaultExtraKeys);
228-
String extraKeysStyle = props.getProperty("extra-keys-style", "default");
229-
mExtraKeys = new ExtraKeysInfos(extrakeyProp, extraKeysStyle);
230-
} catch (JSONException e) {
231-
Toast.makeText(context, "Could not load the extra-keys property from the config: " + e.toString(), Toast.LENGTH_LONG).show();
232-
Log.e("termux", "Error loading props", e);
233-
234-
try {
235-
mExtraKeys = new ExtraKeysInfos(defaultExtraKeys, "default");
236-
} catch (JSONException e2) {
237-
e2.printStackTrace();
238-
Toast.makeText(context, "Can't create default extra keys", Toast.LENGTH_LONG).show();
239-
mExtraKeys = null;
240-
}
241-
}
242-
243-
mBackIsEscape = "escape".equals(props.getProperty("back-key", "back"));
244-
mDisableVolumeVirtualKeys = "volume".equals(props.getProperty("volume-keys", "virtual"));
245-
246-
shortcuts.clear();
247-
parseAction("shortcut.create-session", SHORTCUT_ACTION_CREATE_SESSION, props);
248-
parseAction("shortcut.next-session", SHORTCUT_ACTION_NEXT_SESSION, props);
249-
parseAction("shortcut.previous-session", SHORTCUT_ACTION_PREVIOUS_SESSION, props);
250-
parseAction("shortcut.rename-session", SHORTCUT_ACTION_RENAME_SESSION, props);
251-
}
252-
253-
private void parseAction(String name, int shortcutAction, Properties props) {
254-
String value = props.getProperty(name);
255-
if (value == null) return;
256-
String[] parts = value.toLowerCase().trim().split("\\+");
257-
String input = parts.length == 2 ? parts[1].trim() : null;
258-
if (!(parts.length == 2 && parts[0].trim().equals("ctrl")) || input.isEmpty() || input.length() > 2) {
259-
Log.e("termux", "Keyboard shortcut '" + name + "' is not Ctrl+<something>");
260-
return;
261-
}
262-
263-
char c = input.charAt(0);
264-
int codePoint = c;
265-
if (Character.isLowSurrogate(c)) {
266-
if (input.length() != 2 || Character.isHighSurrogate(input.charAt(1))) {
267-
Log.e("termux", "Keyboard shortcut '" + name + "' is not Ctrl+<something>");
268-
return;
269-
} else {
270-
codePoint = Character.toCodePoint(input.charAt(1), c);
271-
}
272-
}
273-
shortcuts.add(new KeyboardShortcut(codePoint, shortcutAction));
89+
/**
90+
* If value is not in the range [min, max], set it to either min or max.
91+
*/
92+
static int clamp(int value, int min, int max) {
93+
return Math.min(Math.max(value, min), max);
27494
}
27595

27696
}

0 commit comments

Comments
 (0)