Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf68d52c authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

SoftInput flag requires focused View to show IME

Historically SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE
have not required focused editor View [1] to work.  This is easy to
use, but also easy to tell IMEs to connect to InputConnection, which
is often recognized as a bug by users because often nothing happens
when the user taps the software keyboard.

This would become more obvious when we start allowing nothing to have
focus (Bug 68841055) in Android P.

Although how we should deal with "dummy InputConnection" is still an
open question, ignoring these SoftInput flags for apps that target P+
when there is no focused editor view is probably better than the
current behavior, where non-functional software keyboard is likely to
be shown.  The user is still able to show the IME by explicitly tap
the edit field.

As an implementation note, this CL trusts the targetSdkVersion
reported from the target application process, which is in general
unsafe.  That said, for this particular purpose it is acceptable.

 [1]: focused View that returns true from View#onCheckIsTextEditor().

Bug: 69256929
Test: atest CtsInputMethodTestCases
Test: atest FrameworksCoreTests:com.android.internal.inputmethod.InputMethodUtilsTest
Change-Id: I56682c7dee71d461687b9e80ab746d382fd55e0c
parent b0fbfcea
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -1672,12 +1672,20 @@ public interface WindowManager extends ViewManager {
         * Visibility state for {@link #softInputMode}: please show the soft
         * input area when normally appropriate (when the user is navigating
         * forward to your window).
         *
         * <p>Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag
         * is ignored unless there is a focused view that returns {@code true} from
         * {@link View#isInEditMode()} when the window is focused.</p>
         */
        public static final int SOFT_INPUT_STATE_VISIBLE = 4;

        /**
         * Visibility state for {@link #softInputMode}: please always make the
         * soft input area visible when this window receives input focus.
         *
         * <p>Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag
         * is ignored unless there is a focused view that returns {@code true} from
         * {@link View#isInEditMode()} when the window is focused.</p>
         */
        public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;

+4 −2
Original line number Diff line number Diff line
@@ -1333,7 +1333,8 @@ public final class InputMethodManager {
                        + Integer.toHexString(controlFlags));
                final InputBindResult res = mService.startInputOrWindowGainedFocus(
                        startInputReason, mClient, windowGainingFocus, controlFlags, softInputMode,
                        windowFlags, tba, servedContext, missingMethodFlags);
                        windowFlags, tba, servedContext, missingMethodFlags,
                        view.getContext().getApplicationInfo().targetSdkVersion);
                if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res);
                if (res != null) {
                    if (res.id != null) {
@@ -1588,7 +1589,8 @@ public final class InputMethodManager {
                mService.startInputOrWindowGainedFocus(
                        InputMethodClient.START_INPUT_REASON_WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
                        rootView.getWindowToken(), controlFlags, softInputMode, windowFlags, null,
                        null, 0 /* missingMethodFlags */);
                        null, 0 /* missingMethodFlags */,
                        rootView.getContext().getApplicationInfo().targetSdkVersion);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
+21 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.internal.inputmethod;

import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR;
import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -26,6 +29,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
import android.os.RemoteException;
import android.provider.Settings;
@@ -33,6 +37,7 @@ import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.Printer;
import android.util.Slog;
@@ -1510,4 +1515,20 @@ public class InputMethodUtils {
        }
        return locales;
    }

    public static boolean isSoftInputModeStateVisibleAllowed(
            int targetSdkVersion, int controlFlags) {
        if (targetSdkVersion < Build.VERSION_CODES.P) {
            // for compatibility.
            return true;
        }
        if ((controlFlags & CONTROL_WINDOW_VIEW_HAS_FOCUS) == 0) {
            return false;
        }
        if ((controlFlags & CONTROL_WINDOW_IS_TEXT_EDITOR) == 0) {
            return false;
        }
        return true;
    }

}
+2 −1
Original line number Diff line number Diff line
@@ -61,7 +61,8 @@ interface IInputMethodManager {
            in IInputMethodClient client, in IBinder windowToken, int controlFlags,
            /* @android.view.WindowManager.LayoutParams.SoftInputModeFlags */ int softInputMode,
            int windowFlags, in EditorInfo attribute, IInputContext inputContext,
            /* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags);
            /* @InputConnectionInspector.MissingMethodFlags */ int missingMethodFlags,
            int unverifiedTargetSdkVersion);

    void showInputMethodPickerFromClient(in IInputMethodClient client,
            int auxiliarySubtypeMode);
+29 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.internal.inputmethod;

import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_IS_TEXT_EDITOR;
import static android.view.inputmethod.InputMethodManager.CONTROL_WINDOW_VIEW_HAS_FOCUS;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.in;
import static org.hamcrest.Matchers.not;
@@ -31,6 +34,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
import android.os.Parcel;
import android.support.test.InstrumentationRegistry;
@@ -1410,4 +1414,29 @@ public class InputMethodUtilsTest {
        assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c"));
        assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US"));
    }

    @Test
    public void testIsSoftInputModeStateVisibleAllowed() {
        // On pre-P devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are always
        // allowed, regardless of the focused view state.
        assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
                Build.VERSION_CODES.O_MR1, 0));
        assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
                Build.VERSION_CODES.O_MR1, CONTROL_WINDOW_VIEW_HAS_FOCUS));
        assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
                Build.VERSION_CODES.O_MR1,
                CONTROL_WINDOW_VIEW_HAS_FOCUS | CONTROL_WINDOW_IS_TEXT_EDITOR));

        // On P+ devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are allowed only
        // when there is a focused View and its View#onCheckIsTextEditor() returns true.
        assertFalse(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
                Build.VERSION_CODES.P, 0));
        assertFalse(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
                Build.VERSION_CODES.P, CONTROL_WINDOW_VIEW_HAS_FOCUS));
        assertTrue(InputMethodUtils.isSoftInputModeStateVisibleAllowed(
                Build.VERSION_CODES.P,
                CONTROL_WINDOW_VIEW_HAS_FOCUS | CONTROL_WINDOW_IS_TEXT_EDITOR));

    }

}
Loading