Skip to content

Commit 75771b0

Browse files
committed
session migrates to external display when available
+ immersive fullscreen when hardware keyboard is present + if hardware input & external display available, display kept on This is to support a more "desktop mode" linux when the device is docked (having both hardware keyboard and an external display).
1 parent fcc8e12 commit 75771b0

4 files changed

Lines changed: 112 additions & 5 deletions

File tree

termux-app/terminal-term/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<uses-permission android:name="android.permission.VIBRATE" />
1414
<uses-permission android:name="android.permission.WAKE_LOCK"/>
1515
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
16+
<uses-permission android:name="android.permission.BLUETOOTH" />
1617

1718
<application
1819
android:extractNativeLibs="true"

termux-app/terminal-term/src/main/java/com/termux/app/TermuxActivity.java

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.annotation.TargetApi;
66
import android.app.Activity;
77
import android.app.AlertDialog;
8+
import android.bluetooth.BluetoothDevice;
89
import android.content.ActivityNotFoundException;
910
import android.content.BroadcastReceiver;
1011
import android.content.ClipData;
@@ -16,14 +17,18 @@
1617
import android.content.IntentFilter;
1718
import android.content.ServiceConnection;
1819
import android.content.pm.PackageManager;
20+
import android.content.res.Configuration;
1921
import android.graphics.Color;
2022
import android.graphics.Paint;
2123
import android.graphics.Typeface;
24+
import android.hardware.display.DisplayManager;
25+
import android.hardware.usb.UsbManager;
2226
import android.media.AudioAttributes;
2327
import android.media.SoundPool;
2428
import android.net.Uri;
2529
import android.os.Build;
2630
import android.os.Bundle;
31+
import android.os.Handler;
2732
import android.os.IBinder;
2833
import android.os.Vibrator;
2934
import androidx.annotation.NonNull;
@@ -39,12 +44,14 @@
3944
import android.util.Log;
4045
import android.view.ContextMenu;
4146
import android.view.ContextMenu.ContextMenuInfo;
47+
import android.view.Display;
4248
import android.view.Gravity;
4349
import android.view.LayoutInflater;
4450
import android.view.Menu;
4551
import android.view.MenuItem;
4652
import android.view.View;
4753
import android.view.ViewGroup;
54+
import android.view.Window;
4855
import android.view.WindowManager;
4956
import android.view.inputmethod.InputMethodManager;
5057
import android.widget.ArrayAdapter;
@@ -199,6 +206,56 @@ public boolean ensureStoragePermissionGranted() {
199206
}
200207
}
201208

209+
public void makeFullscreen() {
210+
InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
211+
Window window = getWindow();
212+
View view = window.getDecorView();
213+
214+
// rerun the serviceIntent, since we might need to switch screens if they attached/detached
215+
if ((mListViewAdapter != null) && (mListViewAdapter.getCount() != 0)) {
216+
Intent serviceIntent = new Intent(this, TermuxService.class);
217+
serviceIntent.putExtra("username", username);
218+
serviceIntent.putExtra("hostname", hostname);
219+
serviceIntent.putExtra("port", port);
220+
serviceIntent.putExtra("sessionName", sessionName);
221+
serviceIntent.setAction(TermuxService.ACTION_EXECUTE);
222+
startService(serviceIntent);
223+
}
224+
225+
// hide/show soft input depending on the availability of hardware input devices
226+
boolean was_fullscreen = false;
227+
if (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_NOKEYS) {
228+
mgr.showSoftInput(mTerminalView, InputMethodManager.SHOW_IMPLICIT);
229+
} else {
230+
mgr.showSoftInput(mTerminalView, InputMethodManager.HIDE_IMPLICIT_ONLY);
231+
// if we are on a separate display, keep that display on and in fullscreen while we are on it
232+
if (window.getWindowManager().getDefaultDisplay().getDisplayId() != Display.DEFAULT_DISPLAY) {
233+
// FLAG_KEEP_SCREEN_ON is separate from wakelock, specific to the screen this activity is on;
234+
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
235+
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
236+
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
237+
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
238+
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
239+
| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
240+
| View.SYSTEM_UI_FLAG_IMMERSIVE);
241+
was_fullscreen = true;
242+
}
243+
}
244+
245+
if (!was_fullscreen) {
246+
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
247+
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
248+
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
249+
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
250+
}
251+
}
252+
253+
// when gaining focus, we may or may not get SystemUiVisibilityChange event
254+
@Override
255+
public void onWindowFocusChanged(boolean hasFocus) {
256+
super.onWindowFocusChanged(hasFocus);
257+
if (hasFocus) makeFullscreen();
258+
}
202259
@Override
203260
public void onCreate(Bundle bundle) {
204261
super.onCreate(bundle);
@@ -210,14 +267,41 @@ public void onCreate(Bundle bundle) {
210267
setContentView(R.layout.drawer_layout);
211268
mTerminalView = findViewById(R.id.terminal_view);
212269
mTerminalView.setOnKeyListener(new TermuxViewClient(this));
213-
214270
mTerminalView.setTextSize(mSettings.getFontSize());
271+
272+
mTerminalView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
273+
@Override public void onSystemUiVisibilityChange(int visibility) { makeFullscreen(); }
274+
});
275+
276+
final BroadcastReceiver changeReceiver = new BroadcastReceiver() {
277+
public void onReceive(Context context, Intent intent) {
278+
makeFullscreen();
279+
}
280+
};
281+
282+
// bluetooth/usb may be used to attach/detach input devices; listen to them.
283+
IntentFilter filter = new IntentFilter();
284+
filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
285+
filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
286+
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
287+
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
288+
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
289+
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
290+
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
291+
registerReceiver(changeReceiver, filter);
292+
293+
// displays may be added/removed, and we may need to move activities to/from them
294+
((DisplayManager)getSystemService(DISPLAY_SERVICE)).registerDisplayListener(new DisplayManager.DisplayListener() {
295+
@Override public void onDisplayAdded(int i) { makeFullscreen(); }
296+
@Override public void onDisplayRemoved(int i) { makeFullscreen(); }
297+
@Override public void onDisplayChanged(int i) { makeFullscreen(); }
298+
}, null);
299+
215300
mTerminalView.requestFocus();
216301

217302
final ViewPager viewPager = findViewById(R.id.viewpager);
218303
if (mSettings.isShowExtraKeys()) viewPager.setVisibility(View.VISIBLE);
219304

220-
221305
ViewGroup.LayoutParams layoutParams = viewPager.getLayoutParams();
222306
layoutParams.height = layoutParams.height * mSettings.mExtraKeys.length;
223307
viewPager.setLayoutParams(layoutParams);
@@ -796,6 +880,7 @@ public boolean onContextItemSelected(MenuItem item) {
796880
session.reset();
797881
showToast(getResources().getString(R.string.reset_toast_notification), true);
798882
}
883+
makeFullscreen();
799884
return true;
800885
}
801886
default:

termux-app/terminal-term/src/main/java/com/termux/app/TermuxService.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.termux.app;
22

33
import android.annotation.SuppressLint;
4+
import android.app.ActivityManager;
5+
import android.app.ActivityOptions;
46
import android.app.Notification;
57
import android.app.NotificationChannel;
68
import android.app.NotificationManager;
@@ -9,6 +11,8 @@
911
import android.content.Context;
1012
import android.content.Intent;
1113
import android.content.res.Resources;
14+
import android.graphics.Rect;
15+
import android.hardware.display.DisplayManager;
1216
import android.net.wifi.WifiManager;
1317
import android.os.Binder;
1418
import android.os.Build;
@@ -17,6 +21,7 @@
1721
import android.os.PowerManager;
1822
import android.system.Os;
1923
import android.util.Log;
24+
import android.view.Display;
2025
import android.widget.ArrayAdapter;
2126

2227
import com.termux.R;
@@ -137,7 +142,22 @@ public int onStartCommand(Intent intent, int flags, int startId) {
137142
Log.e(EmulatorDebug.LOG_TAG, "Currently only intents from UserLAnd are supported");
138143
} else {
139144
// Launch the main Termux app, which will now show the current session:
140-
startActivity(new Intent(this, TermuxActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
145+
Intent si = new Intent(this, TermuxActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
146+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
147+
ActivityOptions options = ActivityOptions.makeBasic();
148+
DisplayManager dm = (DisplayManager)getSystemService(DISPLAY_SERVICE);
149+
Display ds[] = dm.getDisplays();
150+
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
151+
for(Display d: ds) {
152+
if ((d.getState() > Display.STATE_OFF) && ((d.getFlags() & Display.FLAG_PRESENTATION) != 0) && ((d.getFlags() & Display.FLAG_PRIVATE) == 0)) {
153+
options.setLaunchBounds(null);
154+
options.setLaunchDisplayId(d.getDisplayId());
155+
break;
156+
}
157+
}
158+
startActivity(si, options.toBundle());
159+
} else
160+
startActivity(si);
141161
}
142162
} else if (action != null) {
143163
Log.e(EmulatorDebug.LOG_TAG, "Unknown TermuxService action: '" + action + "'");

termux-app/terminal-term/src/main/java/com/termux/app/TermuxViewClient.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package com.termux.app;
22

33
import android.content.Context;
4+
import android.content.res.Configuration;
45
import android.media.AudioManager;
56
import androidx.drawerlayout.widget.DrawerLayout;
67
import android.view.Gravity;
78
import android.view.InputDevice;
89
import android.view.KeyEvent;
910
import android.view.MotionEvent;
11+
import android.view.View;
1012
import android.view.inputmethod.InputMethodManager;
1113

1214
import com.termux.terminal.KeyHandler;
@@ -39,8 +41,7 @@ public float onScale(float scale) {
3941

4042
@Override
4143
public void onSingleTapUp(MotionEvent e) {
42-
InputMethodManager mgr = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
43-
mgr.showSoftInput(mActivity.mTerminalView, InputMethodManager.SHOW_IMPLICIT);
44+
mActivity.makeFullscreen();
4445
}
4546

4647
@Override

0 commit comments

Comments
 (0)