diff --git a/app/src/main/java/com/termux/app/fragments/settings/TerminalIOPreferencesFragment.java b/app/src/main/java/com/termux/app/fragments/settings/TerminalIOPreferencesFragment.java index ef0a56c2c8..d9500f841d 100644 --- a/app/src/main/java/com/termux/app/fragments/settings/TerminalIOPreferencesFragment.java +++ b/app/src/main/java/com/termux/app/fragments/settings/TerminalIOPreferencesFragment.java @@ -53,6 +53,9 @@ public void putBoolean(String key, boolean value) { case "soft_keyboard_enabled": mPreferences.setSoftKeyboardEnabled(value); break; + case "soft_keyboard_enabled_only_if_no_hardware": + mPreferences.setSoftKeyboardEnabledOnlyIfNoHardware(value); + break; default: break; } @@ -63,6 +66,8 @@ public boolean getBoolean(String key, boolean defValue) { switch (key) { case "soft_keyboard_enabled": return mPreferences.getSoftKeyboardEnabled(); + case "soft_keyboard_enabled_only_if_no_hardware": + return mPreferences.getSoftKeyboardEnabledOnlyIfNoHardware(); default: return false; } 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 93e387d16f..18a0d39b03 100644 --- a/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java +++ b/app/src/main/java/com/termux/app/terminal/TermuxTerminalViewClient.java @@ -80,7 +80,7 @@ public void onSingleTapUp(MotionEvent e) { if (!KeyboardUtils.areDisableSoftKeyboardFlagsSet(mActivity)) KeyboardUtils.showSoftKeyboard(mActivity, mActivity.getTerminalView()); else - Logger.logVerbose(LOG_TAG, "Not showing keyboard onSingleTapUp since its disabled"); + Logger.logVerbose(LOG_TAG, "Not showing soft keyboard onSingleTapUp since its disabled"); } @Override @@ -380,8 +380,10 @@ public void onToggleSoftKeyboardRequest() { } public void setSoftKeyboardState(boolean isStartup, boolean isReloadTermuxProperties) { - // If soft keyboard is disabled by user for Termux - if (!mActivity.getPreferences().getSoftKeyboardEnabled()) { + // If soft keyboard is disabled by user for Termux (check function docs for Termux behaviour info) + if (KeyboardUtils.shouldSoftKeyboardBeDisabled(mActivity, + mActivity.getPreferences().getSoftKeyboardEnabled(), + mActivity.getPreferences().getSoftKeyboardEnabledOnlyIfNoHardware())) { Logger.logVerbose(LOG_TAG, "Maintaining disabled soft keyboard"); KeyboardUtils.disableSoftKeyboard(mActivity, mActivity.getTerminalView()); } else { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0cebd0b560..b12521886c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -151,8 +151,13 @@ Keyboard - Soft Keyboard + Soft Keyboard Enabled Soft keyboard will be disabled. Soft keyboard will be enabled. (Default) + + Soft Keyboard If No Hardware + Soft keyboard will be enabled even if hardware keyboard is connected. (Default) + Soft keyboard will be enabled only if no hardware keyboard is connected. + diff --git a/app/src/main/res/xml/terminal_io_preferences.xml b/app/src/main/res/xml/terminal_io_preferences.xml index d20e7c58bf..6aecbf482c 100644 --- a/app/src/main/res/xml/terminal_io_preferences.xml +++ b/app/src/main/res/xml/terminal_io_preferences.xml @@ -10,6 +10,12 @@ app:summaryOn="@string/soft_keyboard_on" app:title="@string/soft_keyboard_title" /> + + diff --git a/termux-shared/src/main/java/com/termux/shared/settings/preferences/TermuxAppSharedPreferences.java b/termux-shared/src/main/java/com/termux/shared/settings/preferences/TermuxAppSharedPreferences.java index 086e50d75e..7c6656cdb3 100644 --- a/termux-shared/src/main/java/com/termux/shared/settings/preferences/TermuxAppSharedPreferences.java +++ b/termux-shared/src/main/java/com/termux/shared/settings/preferences/TermuxAppSharedPreferences.java @@ -62,6 +62,14 @@ public void setSoftKeyboardEnabled(boolean value) { SharedPreferenceUtils.setBoolean(mSharedPreferences, TERMUX_APP.KEY_SOFT_KEYBOARD_ENABLED, value, false); } + public boolean getSoftKeyboardEnabledOnlyIfNoHardware() { + return SharedPreferenceUtils.getBoolean(mSharedPreferences, TERMUX_APP.KEY_SOFT_KEYBOARD_ENABLED_ONLY_IF_NO_HARDWARE, TERMUX_APP.DEFAULT_VALUE_KEY_SOFT_KEYBOARD_ENABLED_ONLY_IF_NO_HARDWARE); + } + + public void setSoftKeyboardEnabledOnlyIfNoHardware(boolean value) { + SharedPreferenceUtils.setBoolean(mSharedPreferences, TERMUX_APP.KEY_SOFT_KEYBOARD_ENABLED_ONLY_IF_NO_HARDWARE, value, false); + } + public boolean getKeepScreenOn() { diff --git a/termux-shared/src/main/java/com/termux/shared/settings/preferences/TermuxPreferenceConstants.java b/termux-shared/src/main/java/com/termux/shared/settings/preferences/TermuxPreferenceConstants.java index 633b7c3441..efec9d9863 100644 --- a/termux-shared/src/main/java/com/termux/shared/settings/preferences/TermuxPreferenceConstants.java +++ b/termux-shared/src/main/java/com/termux/shared/settings/preferences/TermuxPreferenceConstants.java @@ -1,7 +1,7 @@ package com.termux.shared.settings.preferences; /* - * Version: v0.9.0 + * Version: v0.10.0 * * Changelog * @@ -40,6 +40,10 @@ * * - 0.9.0 (2021-04-07) * - Updated javadocs. + * + * - 0.10.0 (2021-05-12) + * - Added following to `TERMUX_APP`: + * `KEY_SOFT_KEYBOARD_ENABLED_ONLY_IF_NO_HARDWARE` and `DEFAULT_VALUE_KEY_SOFT_KEYBOARD_ENABLED_ONLY_IF_NO_HARDWARE`. */ /** @@ -70,6 +74,13 @@ public static final class TERMUX_APP { public static final String KEY_SOFT_KEYBOARD_ENABLED = "soft_keyboard_enabled"; public static final boolean DEFAULT_VALUE_KEY_SOFT_KEYBOARD_ENABLED = true; + /** + * Defines the key for whether the soft keyboard will be enabled only if no hardware keyboard + * attached, for cases where users want to use a hardware keyboard instead. + */ + public static final String KEY_SOFT_KEYBOARD_ENABLED_ONLY_IF_NO_HARDWARE = "soft_keyboard_enabled_only_if_no_hardware"; + public static final boolean DEFAULT_VALUE_KEY_SOFT_KEYBOARD_ENABLED_ONLY_IF_NO_HARDWARE = false; + /** * Defines the key for whether to always keep screen on. diff --git a/termux-shared/src/main/java/com/termux/shared/view/KeyboardUtils.java b/termux-shared/src/main/java/com/termux/shared/view/KeyboardUtils.java index 3891086dec..a54b4fa9f9 100644 --- a/termux-shared/src/main/java/com/termux/shared/view/KeyboardUtils.java +++ b/termux-shared/src/main/java/com/termux/shared/view/KeyboardUtils.java @@ -2,6 +2,7 @@ import android.app.Activity; import android.content.Context; +import android.content.res.Configuration; import android.inputmethodservice.InputMethodService; import android.view.View; import android.view.WindowInsets; @@ -32,8 +33,8 @@ public static void setSoftKeyboardVisibility(@NonNull final Runnable showSoftKey * Toggle the soft keyboard. The {@link InputMethodManager#SHOW_FORCED} is passed as * {@code showFlags} so that keyboard is forcefully shown if it needs to be enabled. * - * This is also important for soft keyboard to be shown when a hardware keyboard is attached, and - * user has disabled the {@code Show on-screen keyboard while hardware keyboard is attached} toggle + * This is also important for soft keyboard to be shown when a hardware keyboard is connected, and + * user has disabled the {@code Show on-screen keyboard while hardware keyboard is connected} toggle * in Android "Language and Input" settings but the current soft keyboard app overrides the * default implementation of {@link InputMethodService#onEvaluateInputViewShown()} and returns * {@code true}. @@ -50,8 +51,8 @@ public static void toggleSoftKeyboard(final Context context) { * forcefully shown. * * This is also important for soft keyboard to be shown on app startup when a hardware keyboard - * is attached, and user has disabled the {@code Show on-screen keyboard while hardware keyboard - * is attached} toggle in Android "Language and Input" settings but the current soft keyboard app + * is connected, and user has disabled the {@code Show on-screen keyboard while hardware keyboard + * is connected} toggle in Android "Language and Input" settings but the current soft keyboard app * overrides the default implementation of {@link InputMethodService#onEvaluateInputViewShown()} * and returns {@code true}. * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:frameworks/base/core/java/android/inputmethodservice/InputMethodService.java;l=1751 @@ -110,21 +111,85 @@ public static void setResizeTerminalViewForSoftKeyboardFlags(final Activity acti activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); } - /** Check if keyboard visible. Does not work on android 7 but does on android 11 avd. */ + /** + * Check if soft keyboard is visible. + * Does not work on android 7 but does on android 11 avd. + * + * @param activity The Activity of the root view for which the visibility should be checked. + * @return Returns {@code true} if soft keyboard is visible, otherwise {@code false}. + */ public static boolean isSoftKeyboardVisible(final Activity activity) { if (activity != null && activity.getWindow() != null) { WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets(); if (insets != null) { WindowInsetsCompat insetsCompat = WindowInsetsCompat.toWindowInsetsCompat(insets); - if (insetsCompat != null && insetsCompat.isVisible(WindowInsetsCompat.Type.ime())) { - Logger.logVerbose(LOG_TAG, "Keyboard visible"); + if (insetsCompat.isVisible(WindowInsetsCompat.Type.ime())) { + Logger.logVerbose(LOG_TAG, "Soft keyboard visible"); return true; } } } - Logger.logVerbose(LOG_TAG, "Keyboard not visible"); + Logger.logVerbose(LOG_TAG, "Soft keyboard not visible"); return false; } + /** + * Check if hardware keyboard is connected. + * Based on default implementation of {@link InputMethodService#onEvaluateInputViewShown()}. + * + * https://developer.android.com/guide/topics/resources/providing-resources#ImeQualifier + * + * @param context The Context for operations. + * @return Returns {@code true} if device has hardware keys for text input or an external hardware + * keyboard is connected, otherwise {@code false}. + */ + public static boolean isHardKeyboardConnected(final Context context) { + if (context == null) return false; + + Configuration config = context.getResources().getConfiguration(); + return config.keyboard != Configuration.KEYBOARD_NOKEYS + || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; + } + + /** + * Check if soft keyboard should be disabled based on user configuration. + * + * @param context The Context for operations. + * @return Returns {@code true} if device has soft keyboard should be disabled, otherwise {@code false}. + */ + public static boolean shouldSoftKeyboardBeDisabled(final Context context, final boolean isSoftKeyboardEnabled, final boolean isSoftKeyboardEnabledOnlyIfNoHardware) { + // If soft keyboard is disabled by user regardless of hardware keyboard + if (!isSoftKeyboardEnabled) { + return true; + } else { + /* + * Currently, for this case, soft keyboard will be disabled on Termux app startup and + * when switching back from another app. Soft keyboard can be temporarily enabled in + * show/hide soft keyboard toggle behaviour with keyboard toggle buttons and will continue + * to work when tapping on terminal view for opening and back button for closing, until + * Termux app is switched to another app. After returning back, keyboard will be disabled + * until toggle is pressed again. + * This may also be helpful for the Lineage OS bug where if "Show soft keyboard" toggle + * in "Language and Input" is disabled and Termux is started without a hardware keyboard + * in landscape mode, and then the keyboard is connected and phone is rotated to portrait + * mode and then keyboard is toggled with Termux keyboard toggle buttons, then a blank + * space is shown in-place of the soft keyboard. Its likely related to + * WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE which pushes up the view when + * keyboard is opened instead of the keyboard opening on top of the view (hiding stuff). + * If the "Show soft keyboard" toggle was disabled, then this resizing shouldn't happen. + * But it seems resizing does happen, but keyboard is never opened since its not supposed to. + * https://github.com/termux/termux-app/issues/1995#issuecomment-837080079 + */ + // If soft keyboard is disabled by user only if hardware keyboard is connected + if(isSoftKeyboardEnabledOnlyIfNoHardware) { + boolean isHardKeyboardConnected = KeyboardUtils.isHardKeyboardConnected(context); + Logger.logVerbose(LOG_TAG, "Hardware keyboard connected=" + isHardKeyboardConnected); + return isHardKeyboardConnected; + } else { + return false; + } + } + } + }