这是indexloc提供的服务,不要输入任何密码
Skip to content

Commit 90f908d

Browse files
Added/Fixed: Use ~/.termux/termux.float.properties and fix bug created in a46762a
- Fixed termux session being recreated on showing from notification. - Added exit button to notification. - Increased notification priority so its easier to show/hide/exit. - Ensure session is killed on exit like `TermuxService` does it. - Added support for `~/.termux/color.properties` and `~/.termux/font.ttf` to set colors and font. - Added support for bell. - Added support for `~/.termux/termux.float.properties` which supports the following properties: `enforce-char-based-input`, `ctrl-space-workaround`, `bell-character`, `terminal-cursor-style`, `terminal-transcript-rows`, `back-key`, `default-working-directory`, `volume-keys`.
1 parent 46a4870 commit 90f908d

File tree

9 files changed

+292
-64
lines changed

9 files changed

+292
-64
lines changed

app/build.gradle

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,14 @@ android {
5353

5454
dependencies {
5555
implementation 'androidx.annotation:annotation:1.2.0'
56-
implementation 'com.termux.termux-app:termux-shared:9f1203f049'
57-
implementation 'com.termux.termux-app:terminal-view:9f1203f049'
56+
57+
implementation 'com.termux.termux-app:termux-shared:bc779d2ffb'
58+
implementation 'com.termux.termux-app:terminal-view:bc779d2ffb'
59+
60+
// Use if below libraries are published locally by termux-app with `./gradlew publishReleasePublicationToMavenLocal` and used with `mavenLocal()`.
61+
// If updates are done, republish there and sync project with gradle files here
62+
//implementation 'com.termux:termux-shared:0.117'
63+
//implementation 'com.termux:terminal-view:0.117'
5864

5965
testImplementation 'junit:junit:4.13.2'
6066
}

app/src/main/java/com/termux/window/FloatingBubbleManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ private TermuxFloatView getTermuxFloatView() {
122122
}
123123

124124
private TerminalView getTerminalView() {
125-
return mTermuxFloatView.mTerminalView;
125+
return mTermuxFloatView.getTerminalView();
126126
}
127127

128128
private WindowManager getWindowManager() {

app/src/main/java/com/termux/window/TermuxFloatService.java

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,13 @@
2222
import com.termux.shared.shell.TermuxShellEnvironmentClient;
2323
import com.termux.shared.termux.TermuxConstants;
2424
import com.termux.shared.termux.TermuxConstants.TERMUX_FLOAT_APP.TERMUX_FLOAT_SERVICE;
25-
import com.termux.terminal.TerminalSession;
26-
import com.termux.terminal.TerminalSessionClient;
2725

2826
public class TermuxFloatService extends Service {
2927

30-
/**
31-
* The {@link TerminalSessionClient} interface implementation to allow for communication between
32-
* {@link TerminalSession} and {@link TermuxFloatService}.
33-
*/
34-
TermuxFloatSessionClient mTermuxFloatSessionClient;
35-
3628
private TermuxFloatView mFloatingWindow;
3729

30+
private TermuxSession mSession;
31+
3832
private boolean mVisibleWindow = true;
3933

4034
private static final String LOG_TAG = "TermuxFloatService";
@@ -58,7 +52,7 @@ public int onStartCommand(Intent intent, int flags, int startId) {
5852
// Run again in case service is already started and onCreate() is not called
5953
runStartForeground();
6054

61-
if (!initializeFloatView())
55+
if (mFloatingWindow == null && !initializeFloatView())
6256
return Service.START_NOT_STICKY;
6357

6458
String action = intent.getAction();
@@ -67,7 +61,7 @@ public int onStartCommand(Intent intent, int flags, int startId) {
6761
switch (action) {
6862
case TERMUX_FLOAT_SERVICE.ACTION_STOP_SERVICE:
6963
Logger.logDebug(LOG_TAG, "ACTION_STOP_SERVICE intent received");
70-
requestStopService();
64+
actionStopService();
7165
break;
7266
case TERMUX_FLOAT_SERVICE.ACTION_SHOW:
7367
Logger.logDebug(LOG_TAG, "ACTION_SHOW intent received");
@@ -107,6 +101,13 @@ public void requestStopService() {
107101
stopSelf();
108102
}
109103

104+
/** Process action to stop service. */
105+
private void actionStopService() {
106+
if (mSession != null)
107+
mSession.killIfExecuting(this, false);
108+
requestStopService();
109+
}
110+
110111
/** Make service run in foreground mode. */
111112
private void runStartForeground() {
112113
setupNotificationChannel();
@@ -138,7 +139,7 @@ private Notification buildNotification() {
138139

139140
// Build the notification
140141
Notification.Builder builder = NotificationUtils.geNotificationBuilder(this,
141-
TermuxConstants.TERMUX_FLOAT_APP_NOTIFICATION_CHANNEL_ID, Notification.PRIORITY_MIN,
142+
TermuxConstants.TERMUX_FLOAT_APP_NOTIFICATION_CHANNEL_ID, Notification.PRIORITY_LOW,
142143
TermuxConstants.TERMUX_FLOAT_APP_NAME, notificationText, null,
143144
contentIntent, null, NotificationUtils.NOTIFICATION_MODE_SILENT);
144145
if (builder == null) return null;
@@ -155,29 +156,31 @@ private Notification buildNotification() {
155156
// TermuxSessions are always ongoing
156157
builder.setOngoing(true);
157158

159+
// Set Exit button action
160+
Intent exitIntent = new Intent(this, TermuxFloatService.class).setAction(TERMUX_FLOAT_SERVICE.ACTION_STOP_SERVICE);
161+
builder.addAction(android.R.drawable.ic_delete, res.getString(R.string.notification_action_exit), PendingIntent.getService(this, 0, exitIntent, 0));
162+
158163
return builder.build();
159164
}
160165

161166

162167

163168
@SuppressLint("InflateParams")
164169
private boolean initializeFloatView() {
165-
mTermuxFloatSessionClient = new TermuxFloatSessionClient(this);
166-
167170
boolean floatWindowWasNull = false;
168171
if (mFloatingWindow == null) {
169172
mFloatingWindow = (TermuxFloatView) ((LayoutInflater)
170173
getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.activity_main, null);
171174
floatWindowWasNull = true;
172175
}
173176

174-
mFloatingWindow.initFloatView();
177+
mFloatingWindow.initFloatView(this);
175178

176-
TermuxSession session = createTermuxSession(
177-
new ExecutionCommand(0, null, null, null, null, false, false), null);
178-
if (session == null)
179+
mSession = createTermuxSession(
180+
new ExecutionCommand(0, null, null, null, mFloatingWindow.getProperties().getDefaultWorkingDirectory(), false, false), null);
181+
if (mSession == null)
179182
return false;
180-
mFloatingWindow.mTerminalView.attachSession(session.getTerminalSession());
183+
mFloatingWindow.getTerminalView().attachSession(mSession.getTerminalSession());
181184

182185
try {
183186
mFloatingWindow.launchFloatingWindow();
@@ -219,24 +222,23 @@ public synchronized TermuxSession createTermuxSession(ExecutionCommand execution
219222
if (Logger.getLogLevel() >= Logger.LOG_LEVEL_VERBOSE)
220223
Logger.logVerboseExtended(LOG_TAG, executionCommand.toString());
221224

222-
// If the execution command was started for a plugin, only then will the stdout be set
223-
// Otherwise if command was manually started by the user like by adding a new terminal session,
224-
// then no need to set stdout
225+
executionCommand.terminalTranscriptRows = mFloatingWindow.getProperties().getTerminalTranscriptRows();
225226
TermuxSession newTermuxSession = TermuxSession.execute(this, executionCommand,
226-
mTermuxFloatSessionClient, null, new TermuxShellEnvironmentClient(),
227+
mFloatingWindow.getTermuxFloatSessionClient(), null, new TermuxShellEnvironmentClient(),
227228
sessionName, executionCommand.isPluginExecutionCommand);
228229
if (newTermuxSession == null) {
229230
Logger.logError(LOG_TAG, "Failed to execute new TermuxSession command for:\n" + executionCommand.getCommandIdAndLabelLogString());
230231
return null;
231232
}
232233

234+
// Emulator won't be set at this point so colors won't be set by TermuxFloatSessionClient.checkForFontAndColors()
235+
mFloatingWindow.reloadViewStyling();
236+
233237
return newTermuxSession;
234238
}
235239

236-
237-
238-
public TermuxFloatView getFloatingWindow() {
239-
return mFloatingWindow;
240+
public TermuxSession getSession() {
241+
return mSession;
240242
}
241243

242244
}

app/src/main/java/com/termux/window/TermuxFloatSessionClient.java

Lines changed: 151 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,76 @@
33
import android.content.ClipData;
44
import android.content.ClipboardManager;
55
import android.content.Context;
6-
import android.os.Vibrator;
6+
import android.graphics.Typeface;
7+
import android.media.AudioAttributes;
8+
import android.media.SoundPool;
9+
import android.text.TextUtils;
710

11+
import com.termux.shared.logger.Logger;
12+
import com.termux.shared.settings.properties.TermuxPropertyConstants;
813
import com.termux.shared.terminal.TermuxTerminalSessionClientBase;
14+
import com.termux.shared.terminal.io.BellHandler;
15+
import com.termux.shared.termux.TermuxConstants;
16+
import com.termux.terminal.TerminalColors;
917
import com.termux.terminal.TerminalSession;
18+
import com.termux.terminal.TextStyle;
19+
20+
import java.io.File;
21+
import java.io.FileInputStream;
22+
import java.io.InputStream;
23+
import java.util.Properties;
1024

1125
public class TermuxFloatSessionClient extends TermuxTerminalSessionClientBase {
1226

1327
private final TermuxFloatService mService;
28+
private final TermuxFloatView mView;
29+
30+
private SoundPool mBellSoundPool;
31+
32+
private int mBellSoundId;
1433

1534
private static final String LOG_TAG = "TermuxFloatSessionClient";
1635

17-
public TermuxFloatSessionClient(TermuxFloatService service) {
18-
this.mService = service;
36+
public TermuxFloatSessionClient(TermuxFloatService service, TermuxFloatView view) {
37+
mService = service;
38+
mView = view;
1939
}
2040

41+
/**
42+
* Should be called when TermuxFloatView.onAttachedToWindow() is called
43+
*/
44+
public void onAttachedToWindow() {
45+
// Just initialize the mBellSoundPool and load the sound, otherwise bell might not run
46+
// the first time bell key is pressed and play() is called, since sound may not be loaded
47+
// quickly enough before the call to play(). https://stackoverflow.com/questions/35435625
48+
getBellSoundPool();
49+
}
50+
51+
/**
52+
* Should be called when TermuxFloatView.onDetachedFromWindow() is called
53+
*/
54+
public void onDetachedFromWindow() {
55+
// Release mBellSoundPool resources, specially to prevent exceptions like the following to be thrown
56+
// java.util.concurrent.TimeoutException: android.media.SoundPool.finalize() timed out after 10 seconds
57+
// Bell is not played in background anyways
58+
// Related: https://stackoverflow.com/a/28708351/14686958
59+
releaseBellSoundPool();
60+
}
61+
62+
/**
63+
* Should be called when TermuxFloatView.onReload() is called
64+
*/
65+
public void onReload() {
66+
checkForFontAndColors();
67+
}
68+
69+
70+
2171
@Override
2272
public void onTextChanged(TerminalSession changedSession) {
23-
TermuxFloatView floatingWindow = mService.getFloatingWindow();
24-
if (floatingWindow != null)
25-
floatingWindow.mTerminalView.onScreenUpdated();
73+
if (!mView.isVisible()) return;
74+
75+
mView.getTerminalView().onScreenUpdated();
2676
}
2777

2878
@Override
@@ -37,8 +87,101 @@ public void onCopyTextToClipboard(TerminalSession pastingSession, String text) {
3787
}
3888

3989
@Override
40-
public void onBell(TerminalSession riningSession) {
41-
((Vibrator) mService.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
90+
public void onPasteTextFromClipboard(TerminalSession session) {
91+
if (!mView.isVisible()) return;
92+
93+
ClipboardManager clipboard = (ClipboardManager) mService.getSystemService(Context.CLIPBOARD_SERVICE);
94+
ClipData clipData = clipboard.getPrimaryClip();
95+
if (clipData != null) {
96+
CharSequence paste = clipData.getItemAt(0).coerceToText(mService);
97+
if (!TextUtils.isEmpty(paste)) mView.getTerminalView().mEmulator.paste(paste.toString());
98+
}
99+
}
100+
101+
@Override
102+
public void onBell(TerminalSession session) {
103+
if (!mView.isVisible()) return;
104+
105+
switch (mView.getProperties().getBellBehaviour()) {
106+
case TermuxPropertyConstants.IVALUE_BELL_BEHAVIOUR_VIBRATE:
107+
BellHandler.getInstance(mService).doBell();
108+
break;
109+
case TermuxPropertyConstants.IVALUE_BELL_BEHAVIOUR_BEEP:
110+
getBellSoundPool().play(mBellSoundId, 1.f, 1.f, 1, 0, 1.f);
111+
break;
112+
case TermuxPropertyConstants.IVALUE_BELL_BEHAVIOUR_IGNORE:
113+
// Ignore the bell character.
114+
break;
115+
}
116+
}
117+
118+
@Override
119+
public void onColorsChanged(TerminalSession changedSession) {
120+
updateBackgroundColor();
121+
}
122+
123+
124+
@Override
125+
public Integer getTerminalCursorStyle() {
126+
return mView.getProperties().getTerminalCursorStyle();
127+
}
128+
129+
130+
/** Initialize and get mBellSoundPool */
131+
private synchronized SoundPool getBellSoundPool() {
132+
if (mBellSoundPool == null) {
133+
mBellSoundPool = new SoundPool.Builder().setMaxStreams(1).setAudioAttributes(
134+
new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
135+
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).build()).build();
136+
137+
mBellSoundId = mBellSoundPool.load(mService, R.raw.bell, 1);
138+
}
139+
140+
return mBellSoundPool;
141+
}
142+
143+
/** Release mBellSoundPool resources */
144+
private synchronized void releaseBellSoundPool() {
145+
if (mBellSoundPool != null) {
146+
mBellSoundPool.release();
147+
mBellSoundPool = null;
148+
}
149+
}
150+
151+
152+
153+
public void checkForFontAndColors() {
154+
try {
155+
File colorsFile = TermuxConstants.TERMUX_COLOR_PROPERTIES_FILE;
156+
File fontFile = TermuxConstants.TERMUX_FONT_FILE;
157+
158+
final Properties props = new Properties();
159+
if (colorsFile.isFile()) {
160+
try (InputStream in = new FileInputStream(colorsFile)) {
161+
props.load(in);
162+
}
163+
}
164+
165+
TerminalColors.COLOR_SCHEME.updateWith(props);
166+
TerminalSession session = mService.getSession().getTerminalSession();
167+
if (session != null && session.getEmulator() != null) {
168+
session.getEmulator().mColors.reset();
169+
}
170+
updateBackgroundColor();
171+
172+
final Typeface newTypeface = (fontFile.exists() && fontFile.length() > 0) ? Typeface.createFromFile(fontFile) : Typeface.MONOSPACE;
173+
mView.getTerminalView().setTypeface(newTypeface);
174+
} catch (Exception e) {
175+
Logger.logStackTraceWithMessage(LOG_TAG, "Error in checkForFontAndColors()", e);
176+
}
177+
}
178+
179+
public void updateBackgroundColor() {
180+
//if (!mView.isVisible()) return;
181+
TerminalSession session = mService.getSession().getTerminalSession();
182+
if (session != null && session.getEmulator() != null) {
183+
mView.getTerminalView().setBackgroundColor(session.getEmulator().mColors.mCurrentColors[TextStyle.COLOR_INDEX_BACKGROUND]);
184+
}
42185
}
43186

44187
}

0 commit comments

Comments
 (0)