22
33import android .annotation .SuppressLint ;
44import android .content .Context ;
5+ import android .content .Intent ;
56import android .graphics .PixelFormat ;
67import android .graphics .Point ;
78import android .graphics .Typeface ;
1213import android .view .MotionEvent ;
1314import android .view .ScaleGestureDetector ;
1415import android .view .ScaleGestureDetector .OnScaleGestureListener ;
16+ import android .view .View ;
17+ import android .view .ViewGroup ;
1518import android .view .WindowManager ;
1619import android .view .inputmethod .InputMethodManager ;
20+ import android .widget .Button ;
1721import android .widget .LinearLayout ;
1822import android .widget .Toast ;
1923
@@ -35,6 +39,8 @@ public class TermuxFloatView extends LinearLayout {
3539 InputMethodManager imm ;
3640
3741 TerminalView mTerminalView ;
42+ ViewGroup mWindowControls ;
43+ FloatingBubbleManager mFloatingBubbleManager ;
3844
3945 private boolean withFocus = true ;
4046 int initialX ;
@@ -46,6 +52,8 @@ public class TermuxFloatView extends LinearLayout {
4652
4753 final int [] location = new int [2 ];
4854
55+ final int [] windowControlsLocation = new int [2 ];
56+
4957 final ScaleGestureDetector mScaleDetector = new ScaleGestureDetector (getContext (), new OnScaleGestureListener () {
5058 private static final int MIN_SIZE = 50 ;
5159
@@ -89,6 +97,19 @@ private static int computeLayoutFlags(boolean withFocus) {
8997 public void initializeFloatingWindow () {
9098 mTerminalView = findViewById (R .id .terminal_view );
9199 mTerminalView .setOnKeyListener (new TermuxFloatViewClient (this ));
100+ mFloatingBubbleManager = new FloatingBubbleManager (this );
101+ initWindowControls ();
102+ }
103+
104+ private void initWindowControls () {
105+ mWindowControls = findViewById (R .id .window_controls );
106+ mWindowControls .setOnClickListener (v -> changeFocus (true ));
107+
108+ Button minimizeButton = findViewById (R .id .minimize_button );
109+ minimizeButton .setOnClickListener (v -> mFloatingBubbleManager .toggleBubble ());
110+
111+ Button exitButton = findViewById (R .id .exit_button );
112+ exitButton .setOnClickListener (v -> exit ());
92113 }
93114
94115 @ Override
@@ -147,6 +168,13 @@ public boolean onInterceptTouchEvent(MotionEvent event) {
147168 int y = location [1 ];
148169 float touchX = event .getRawX ();
149170 float touchY = event .getRawY ();
171+
172+ if (didClickInsideWindowControls (touchX , touchY )) {
173+ // avoid unintended focus event if we are tapping on our window controls
174+ // so that keyboard doesn't possibly show briefly
175+ return false ;
176+ }
177+
150178 boolean clickedInside = (touchX >= x ) && (touchX <= (x + layoutParams .width )) && (touchY >= y ) && (touchY <= (y + layoutParams .height ));
151179
152180 switch (event .getAction ()) {
@@ -163,15 +191,31 @@ public boolean onInterceptTouchEvent(MotionEvent event) {
163191 return false ;
164192 }
165193
194+ private boolean didClickInsideWindowControls (float touchX , float touchY ) {
195+ if (mWindowControls .getVisibility () == View .GONE ) {
196+ return false ;
197+ }
198+ mWindowControls .getLocationOnScreen (windowControlsLocation );
199+ int controlsX = windowControlsLocation [0 ];
200+ int controlsY = windowControlsLocation [1 ];
201+
202+ return (touchX >= controlsX && touchX <= controlsX + mWindowControls .getWidth ()) &&
203+ (touchY >= controlsY && touchY <= controlsY + mWindowControls .getHeight ());
204+ }
205+
166206 void showTouchKeyboard () {
167207 mTerminalView .post (() -> imm .showSoftInput (mTerminalView , InputMethodManager .SHOW_IMPLICIT ));
168208 }
169209
210+ void hideTouchKeyboard () {
211+ mTerminalView .post (() -> imm .hideSoftInputFromWindow (mTerminalView .getWindowToken (), InputMethodManager .HIDE_IMPLICIT_ONLY ));
212+ }
213+
170214 void updateLongPressMode (boolean newValue ) {
171215 isInLongPressState = newValue ;
172- setBackgroundResource ( newValue ? R . drawable . floating_window_background_resize : R . drawable . floating_window_background );
216+ mFloatingBubbleManager . updateLongPressBackgroundResource ( isInLongPressState );
173217 setAlpha (newValue ? ALPHA_MOVING : (withFocus ? ALPHA_FOCUS : ALPHA_NOT_FOCUS ));
174- if (newValue ) {
218+ if (newValue && ! mFloatingBubbleManager . isMinimized () ) {
175219 Toast toast = Toast .makeText (getContext (), R .string .after_long_press , Toast .LENGTH_SHORT );
176220 toast .setGravity (Gravity .CENTER , 0 , 0 );
177221 toast .show ();
@@ -207,6 +251,9 @@ public boolean onTouchEvent(MotionEvent event) {
207251 * Visually indicate focus and show the soft input as needed.
208252 */
209253 void changeFocus (boolean newFocus ) {
254+ if (newFocus && mFloatingBubbleManager .isMinimized ()) {
255+ mFloatingBubbleManager .displayAsFloatingWindow ();
256+ }
210257 if (newFocus == withFocus ) {
211258 if (newFocus ) showTouchKeyboard ();
212259 return ;
@@ -219,5 +266,12 @@ void changeFocus(boolean newFocus) {
219266
220267 public void closeFloatingWindow () {
221268 mWindowManager .removeView (this );
269+ mFloatingBubbleManager .cleanup ();
270+ mFloatingBubbleManager = null ;
271+ }
272+
273+ private void exit () {
274+ Intent intent = new Intent (getContext (), TermuxFloatService .class );
275+ getContext ().stopService (intent );
222276 }
223277}
0 commit comments