From 39c69db820efec991e6bbfef9bd7ea4cc50912be Mon Sep 17 00:00:00 2001 From: agnostic-apollo Date: Sun, 9 May 2021 07:28:12 +0500 Subject: [PATCH] Fix issues where soft keyboard was not shown in some cases when hardware keyboard was attached v2 This is an update to 4d1851e6 commit. The toggle logic change previously was actually being applied to ctrl+alt+k hardware keyboard shortcut instead of the mentioned extra keys "KEYBOARD" toggle. However, now it applies to the extra keys "KEYBOARD" toggle button as well, in addition to drawer "KEYBOARD" toggle button and ctrl+alt+k hardware keyboard shortcut. They will all behave the same now. Updated onSingleTapUp() to also forcefully show keyboard. Fixed issue where "hide-soft-keyboard-on-startup" property wasn't respected anymore due to forced keyboard showing done in 4d1851e6. Removed "stateAlwaysVisible" flag from AndroidManifest since its ignored in Android 10 by default and not needed due to usage of InputMethodManager.showSoftInput(). https://developer.android.com/reference/android/view/WindowManager.LayoutParams#SOFT_INPUT_STATE_ALWAYS_VISIBLE Moved "adjustResize" from AndroidManifest into java code (which is also deprecated in API 30) to centralize keyboard logic. --- app/src/main/AndroidManifest.xml | 3 +- .../java/com/termux/app/TermuxActivity.java | 13 +-- .../terminal/TermuxTerminalViewClient.java | 94 +++++++++++++++---- .../terminal/io/TerminalToolbarViewPager.java | 1 + .../terminal/io/extrakeys/ExtraKeysView.java | 12 ++- 5 files changed, 95 insertions(+), 28 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cef9943d..ee6eae63 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,8 +57,7 @@ android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|uiMode|keyboard|keyboardHidden|navigation" android:label="@string/application_name" android:launchMode="singleTask" - android:resizeableActivity="true" - android:windowSoftInputMode="adjustResize|stateAlwaysVisible"> + android:resizeableActivity="true"> diff --git a/app/src/main/java/com/termux/app/TermuxActivity.java b/app/src/main/java/com/termux/app/TermuxActivity.java index 003dec95..1381998e 100644 --- a/app/src/main/java/com/termux/app/TermuxActivity.java +++ b/app/src/main/java/com/termux/app/TermuxActivity.java @@ -25,7 +25,6 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.autofill.AutofillManager; -import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.ListView; import android.widget.Toast; @@ -237,7 +236,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection public void onResume() { super.onResume(); - mTermuxTerminalViewClient.setSoftKeyboardState(); + mTermuxTerminalViewClient.setSoftKeyboardState(true); } /** @@ -418,7 +417,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection private void setToggleKeyboardView() { findViewById(R.id.toggle_keyboard_button).setOnClickListener(v -> { - TermuxTerminalViewClient.toggleSoftKeyboard(this); + mTermuxTerminalViewClient.onToggleSoftKeyboardRequest(); getDrawer().closeDrawers(); }); @@ -447,8 +446,6 @@ public final class TermuxActivity extends Activity implements ServiceConnection // Set {@link TerminalView#TERMINAL_VIEW_KEY_LOGGING_ENABLED} value mTerminalView.setIsTerminalViewKeyLoggingEnabled(mPreferences.getTerminalViewKeyLoggingEnabled()); - mTerminalView.requestFocus(); - mTermuxTerminalSessionClient.checkForFontAndColors(); } @@ -677,6 +674,10 @@ public final class TermuxActivity extends Activity implements ServiceConnection return mTerminalView; } + public TermuxTerminalViewClient getTermuxTerminalViewClient() { + return mTermuxTerminalViewClient; + } + public TermuxTerminalSessionClient getTermuxTerminalSessionClient() { return mTermuxTerminalSessionClient; } @@ -767,7 +768,7 @@ public final class TermuxActivity extends Activity implements ServiceConnection setTerminalToolbarHeight(); - mTermuxTerminalViewClient.setSoftKeyboardState(); + mTermuxTerminalViewClient.setSoftKeyboardState(true); // To change the activity and drawer theme, activity needs to be recreated. // But this will destroy the activity, and will call the onCreate() again. diff --git a/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java b/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java index 400db111..57cb5732 100644 --- a/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java +++ b/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java @@ -1,6 +1,7 @@ package com.termux.app.terminal; import android.annotation.SuppressLint; +import android.app.Activity; import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.ClipData; @@ -15,6 +16,7 @@ import android.view.Gravity; import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.View; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.ListView; @@ -38,7 +40,6 @@ import com.termux.shared.termux.TermuxUtils; import com.termux.terminal.KeyHandler; import com.termux.terminal.TerminalEmulator; import com.termux.terminal.TerminalSession; -import com.termux.view.TerminalView; import java.util.Arrays; import java.util.Collections; @@ -75,8 +76,7 @@ public class TermuxTerminalViewClient extends TermuxTerminalViewClientBase { @Override public void onSingleTapUp(MotionEvent e) { - InputMethodManager mgr = (InputMethodManager) mActivity.getSystemService(Context.INPUT_METHOD_SERVICE); - mgr.showSoftInput(mActivity.getTerminalView(), InputMethodManager.SHOW_IMPLICIT); + showSoftKeyboard(mActivity, mActivity.getTerminalView()); } @Override @@ -125,7 +125,7 @@ public class TermuxTerminalViewClient extends TermuxTerminalViewClientBase { } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { mActivity.getDrawer().closeDrawers(); } else if (unicodeChar == 'k'/* keyboard */) { - toggleSoftKeyboard(mActivity); + onToggleSoftKeyboardRequest(); } else if (unicodeChar == 'm'/* menu */) { mActivity.getTerminalView().showContextMenu(); } else if (unicodeChar == 'r'/* rename */) { @@ -372,23 +372,83 @@ public class TermuxTerminalViewClient extends TermuxTerminalViewClientBase { * check by passing {@code 0} as {@code flags}. * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:frameworks/base/core/java/android/inputmethodservice/InputMethodService.java;l=2022 */ - public static void showSoftKeyboard(Context context, TerminalView terminalView) { + public static void showSoftKeyboard(Context context, View view) { InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - inputMethodManager.showSoftInput(terminalView, 0); + inputMethodManager.showSoftInput(view, 0); } - public void setSoftKeyboardState() { - // If soft keyboard is to disabled - if (!mActivity.getPreferences().getSoftKeyboardEnabled()) { - mActivity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - } else { - mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - showSoftKeyboard(mActivity, mActivity.getTerminalView()); - } + public static void hideSoftKeyboard(Context context, View view) { + InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } - // If soft keyboard is to be hidden on startup - if (mActivity.getProperties().shouldSoftKeyboardBeHiddenOnStartup()) { - mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); + public static void disableSoftKeyboard(Activity activity, View view) { + hideSoftKeyboard(activity, view); + setDisableSoftKeyboardFlags(activity); + } + + public static void setDisableSoftKeyboardFlags(Activity activity) { + activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + } + + public static void clearDisableSoftKeyboardFlags(Activity activity) { + activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + } + + public void setResizeTerminalViewForSoftKeyboardFlags() { + // TODO: The flag is deprecated for API 30 and WindowInset API should be used + // https://developer.android.com/reference/android/view/WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE + // https://medium.com/androiddevelopers/animating-your-keyboard-fb776a8fb66d + // https://stackoverflow.com/a/65194077/14686958 + mActivity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + } + + /** + * Called when user requests the soft keyboard to be toggled via "KEYBOARD" toggle button in + * drawer or extra keys, or with ctrl+alt+k hardware keyboard shortcut. + */ + public void onToggleSoftKeyboardRequest() { + // If soft keyboard is disabled by user for Termux + if (!mActivity.getPreferences().getSoftKeyboardEnabled()) { + disableSoftKeyboard(mActivity, mActivity.getTerminalView()); + } else { + clearDisableSoftKeyboardFlags(mActivity); + toggleSoftKeyboard(mActivity); + } + } + + public void setSoftKeyboardState(boolean isStartup) { + // If soft keyboard is disabled by user for Termux + if (!mActivity.getPreferences().getSoftKeyboardEnabled()) { + disableSoftKeyboard(mActivity, mActivity.getTerminalView()); + } else { + // Set flag to automatically push up TerminalView when keyboard is opened instead of showing over it + setResizeTerminalViewForSoftKeyboardFlags(); + + // Clear any previous flags to disable soft keyboard in case setting updated + clearDisableSoftKeyboardFlags(mActivity); + + // If soft keyboard is to be hidden on startup + if (isStartup && mActivity.getProperties().shouldSoftKeyboardBeHiddenOnStartup()) { + hideSoftKeyboard(mActivity, mActivity.getTerminalView()); + } else { + // Force show soft keyboard + showSoftKeyboard(mActivity, mActivity.getTerminalView()); + + mActivity.getTerminalView().setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View view, boolean hasFocus) { + if (hasFocus) { + showSoftKeyboard(mActivity, mActivity.getTerminalView()); + } else { + hideSoftKeyboard(mActivity, mActivity.getTerminalView()); + } + } + }); + + // Request focus for TerminalView + mActivity.getTerminalView().requestFocus(); + } } } diff --git a/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java b/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java index 06bdfe19..5e7adfb8 100644 --- a/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java +++ b/app/src/main/java/com/termux/app/terminal/io/TerminalToolbarViewPager.java @@ -44,6 +44,7 @@ public class TerminalToolbarViewPager { if (position == 0) { layout = inflater.inflate(R.layout.view_terminal_toolbar_extra_keys, collection, false); ExtraKeysView extraKeysView = (ExtraKeysView) layout; + extraKeysView.setTermuxTerminalViewClient(mActivity.getTermuxTerminalViewClient()); mActivity.setExtraKeysView(extraKeysView); extraKeysView.reload(mActivity.getProperties().getExtraKeysInfo()); diff --git a/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeysView.java b/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeysView.java index da4cbeaf..31afa07f 100644 --- a/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeysView.java +++ b/app/src/main/java/com/termux/app/terminal/io/extrakeys/ExtraKeysView.java @@ -23,12 +23,12 @@ import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.GridLayout; import android.widget.PopupWindow; import com.termux.R; +import com.termux.app.terminal.TermuxTerminalViewClient; import com.termux.view.TerminalView; import androidx.drawerlayout.widget.DrawerLayout; @@ -44,6 +44,8 @@ public final class ExtraKeysView extends GridLayout { private static final int INTERESTING_COLOR = 0xFF80DEEA; private static final int BUTTON_PRESSED_COLOR = 0xFF7F7F7F; + TermuxTerminalViewClient mTermuxTerminalViewClient; + public ExtraKeysView(Context context, AttributeSet attrs) { super(context, attrs); } @@ -82,8 +84,8 @@ public final class ExtraKeysView extends GridLayout { private void sendKey(View view, String keyName, boolean forceCtrlDown, boolean forceLeftAltDown) { TerminalView terminalView = view.findViewById(R.id.terminal_view); if ("KEYBOARD".equals(keyName)) { - InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.toggleSoftInput(0, 0); + if(mTermuxTerminalViewClient != null) + mTermuxTerminalViewClient.onToggleSoftKeyboardRequest(); } else if ("DRAWER".equals(keyName)) { DrawerLayout drawer = view.findViewById(R.id.drawer_layout); drawer.openDrawer(Gravity.LEFT); @@ -379,4 +381,8 @@ public final class ExtraKeysView extends GridLayout { } } + public void setTermuxTerminalViewClient(TermuxTerminalViewClient termuxTerminalViewClient) { + this.mTermuxTerminalViewClient = termuxTerminalViewClient; + } + }