termux-app

Форк
0
198 строк · 10.2 Кб
1
package com.termux.shared.view;
2

3
import android.app.Activity;
4
import android.content.Context;
5
import android.content.res.Configuration;
6
import android.inputmethodservice.InputMethodService;
7
import android.os.Build;
8
import android.view.View;
9
import android.view.WindowInsets;
10
import android.view.WindowManager;
11
import android.view.inputmethod.InputMethodManager;
12

13
import androidx.annotation.NonNull;
14
import androidx.annotation.RequiresApi;
15
import androidx.core.view.WindowInsetsCompat;
16

17
import com.termux.shared.logger.Logger;
18

19
public class KeyboardUtils {
20

21
    private static final String LOG_TAG = "KeyboardUtils";
22

23
    public static void setSoftKeyboardVisibility(@NonNull final Runnable showSoftKeyboardRunnable, final Activity activity, final View view, final boolean visible) {
24
        if (visible) {
25
            // A Runnable with a delay is used, otherwise soft keyboard may not automatically open
26
            // on some devices, but still may fail
27
            view.postDelayed(showSoftKeyboardRunnable, 500);
28
        } else {
29
            view.removeCallbacks(showSoftKeyboardRunnable);
30
            hideSoftKeyboard(activity, view);
31
        }
32
    }
33

34
    /**
35
     * Toggle the soft keyboard. The {@link InputMethodManager#SHOW_FORCED} is passed as
36
     * {@code showFlags} so that keyboard is forcefully shown if it needs to be enabled.
37
     *
38
     * This is also important for soft keyboard to be shown when a hardware keyboard is connected, and
39
     * user has disabled the {@code Show on-screen keyboard while hardware keyboard is connected} toggle
40
     * in Android "Language and Input" settings but the current soft keyboard app overrides the
41
     * default implementation of {@link InputMethodService#onEvaluateInputViewShown()} and returns
42
     * {@code true}.
43
     */
44
    public static void toggleSoftKeyboard(final Context context) {
45
        if (context == null) return;
46
        InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
47
        if (inputMethodManager != null)
48
            inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
49
    }
50

51
    /**
52
     * Show the soft keyboard. The {@code 0} value is passed as {@code flags} so that keyboard is
53
     * forcefully shown.
54
     *
55
     * This is also important for soft keyboard to be shown on app startup when a hardware keyboard
56
     * is connected, and user has disabled the {@code Show on-screen keyboard while hardware keyboard
57
     * is connected} toggle in Android "Language and Input" settings but the current soft keyboard app
58
     * overrides the default implementation of {@link InputMethodService#onEvaluateInputViewShown()}
59
     * and returns {@code true}.
60
     * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:frameworks/base/core/java/android/inputmethodservice/InputMethodService.java;l=1751
61
     *
62
     * Also check {@link InputMethodService#onShowInputRequested(int, boolean)} which must return
63
     * {@code true}, which can be done by failing its {@code ((flags&InputMethod.SHOW_EXPLICIT) == 0)}
64
     * check by passing {@code 0} as {@code flags}.
65
     * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:frameworks/base/core/java/android/inputmethodservice/InputMethodService.java;l=2022
66
     */
67
    public static void showSoftKeyboard(final Context context, final View view) {
68
        if (context == null || view == null) return;
69
        InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
70
        if (inputMethodManager != null)
71
            inputMethodManager.showSoftInput(view, 0);
72
    }
73

74
    public static void hideSoftKeyboard(final Context context, final View view) {
75
        if (context == null || view == null) return;
76
        InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
77
        if (inputMethodManager != null)
78
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
79
    }
80

81
    public static void disableSoftKeyboard(final Activity activity, final View view) {
82
        if (activity == null || view == null) return;
83
        hideSoftKeyboard(activity, view);
84
        setDisableSoftKeyboardFlags(activity);
85
    }
86

87
    public static void setDisableSoftKeyboardFlags(final Activity activity) {
88
        if (activity != null && activity.getWindow() != null)
89
            activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
90
    }
91

92
    public static void clearDisableSoftKeyboardFlags(final Activity activity) {
93
        if (activity != null && activity.getWindow() != null)
94
            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
95
    }
96

97
    public static boolean areDisableSoftKeyboardFlagsSet(final Activity activity) {
98
        if (activity == null ||  activity.getWindow() == null) return false;
99
        return (activity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
100
    }
101

102
    public static void setSoftKeyboardAlwaysHiddenFlags(final Activity activity) {
103
        if (activity != null && activity.getWindow() != null)
104
            activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
105
    }
106

107
    public static void setSoftInputModeAdjustResize(final Activity activity) {
108
        // TODO: The flag is deprecated for API 30 and WindowInset API should be used
109
        // https://developer.android.com/reference/android/view/WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE
110
        // https://medium.com/androiddevelopers/animating-your-keyboard-fb776a8fb66d
111
        // https://stackoverflow.com/a/65194077/14686958
112
        if (activity != null && activity.getWindow() != null)
113
            activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
114
    }
115

116
    /**
117
     * Check if soft keyboard is visible.
118
     * Does not work on android 7 but does on android 11 avd.
119
     *
120
     * @param activity The Activity of the root view for which the visibility should be checked.
121
     * @return Returns {@code true} if soft keyboard is visible, otherwise {@code false}.
122
     */
123
    @RequiresApi(api = Build.VERSION_CODES.M)
124
    public static boolean isSoftKeyboardVisible(final Activity activity) {
125
        if (activity != null && activity.getWindow() != null) {
126
            WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets();
127
            if (insets != null) {
128
                WindowInsetsCompat insetsCompat = WindowInsetsCompat.toWindowInsetsCompat(insets);
129
                if (insetsCompat.isVisible(WindowInsetsCompat.Type.ime())) {
130
                    Logger.logVerbose(LOG_TAG, "Soft keyboard visible");
131
                    return true;
132
                }
133
            }
134
        }
135

136
        Logger.logVerbose(LOG_TAG, "Soft keyboard not visible");
137
        return false;
138
    }
139

140
    /**
141
     * Check if hardware keyboard is connected.
142
     * Based on default implementation of {@link InputMethodService#onEvaluateInputViewShown()}.
143
     *
144
     * https://developer.android.com/guide/topics/resources/providing-resources#ImeQualifier
145
     *
146
     * @param context The Context for operations.
147
     * @return Returns {@code true} if device has hardware keys for text input or an external hardware
148
     * keyboard is connected, otherwise {@code false}.
149
     */
150
    public static boolean isHardKeyboardConnected(final Context context) {
151
        if (context == null) return false;
152

153
        Configuration config = context.getResources().getConfiguration();
154
        return config.keyboard != Configuration.KEYBOARD_NOKEYS
155
            || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
156
    }
157

158
    /**
159
     * Check if soft keyboard should be disabled based on user configuration.
160
     *
161
     * @param context The Context for operations.
162
     * @return Returns {@code true} if device has soft keyboard should be disabled, otherwise {@code false}.
163
     */
164
    public static boolean shouldSoftKeyboardBeDisabled(final Context context, final boolean isSoftKeyboardEnabled, final boolean isSoftKeyboardEnabledOnlyIfNoHardware) {
165
        // If soft keyboard is disabled by user regardless of hardware keyboard
166
        if (!isSoftKeyboardEnabled) {
167
            return true;
168
        } else {
169
            /*
170
             * Currently, for this case, soft keyboard will be disabled on Termux app startup and
171
             * when switching back from another app. Soft keyboard can be temporarily enabled in
172
             * show/hide soft keyboard toggle behaviour with keyboard toggle buttons and will continue
173
             * to work when tapping on terminal view for opening and back button for closing, until
174
             * Termux app is switched to another app. After returning back, keyboard will be disabled
175
             * until toggle is pressed again.
176
             * This may also be helpful for the Lineage OS bug where if "Show soft keyboard" toggle
177
             * in "Language and Input" is disabled and Termux is started without a hardware keyboard
178
             * in landscape mode, and then the keyboard is connected and phone is rotated to portrait
179
             * mode and then keyboard is toggled with Termux keyboard toggle buttons, then a blank
180
             * space is shown in-place of the soft keyboard. Its likely related to
181
             * WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE which pushes up the view when
182
             * keyboard is opened instead of the keyboard opening on top of the view (hiding stuff).
183
             * If the "Show soft keyboard" toggle was disabled, then this resizing shouldn't happen.
184
             * But it seems resizing does happen, but keyboard is never opened since its not supposed to.
185
             * https://github.com/termux/termux-app/issues/1995#issuecomment-837080079
186
             */
187
            // If soft keyboard is disabled by user only if hardware keyboard is connected
188
            if(isSoftKeyboardEnabledOnlyIfNoHardware) {
189
                boolean isHardKeyboardConnected = KeyboardUtils.isHardKeyboardConnected(context);
190
                Logger.logVerbose(LOG_TAG, "Hardware keyboard connected=" + isHardKeyboardConnected);
191
                return isHardKeyboardConnected;
192
            } else {
193
                return false;
194
            }
195
        }
196
    }
197

198
}
199

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.