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

Commit ef1965bd authored by lumark's avatar lumark
Browse files

Show IME in default display for some use cases.

- Since IME is a kind of system decoration, for some use cases
  that has not set FLAG_CAN_SHOW_SYSTEM_DECORATIONS flag,
  it means there is no system decorations in display & need to show IME
  in default display.
- For VR 2D display case, we show IME in default display
  when detected VR IME started.
- Add unit tests for verifying above logics in InputMethodManagerServiceTests:
  - testComputeImeDisplayId_defaultDisplayId
  - testComputeImeDisplayId_InvalidDisplayId
  - testComputeImeDisplayId_VrIme
  - testComputeImeDisplayId_noSystemDecorationSupportDisplay
  - testComputeImeDisplayId_withSystemDecorationSupportDisplay

Bug: 114350902
Test: atest FrameworksServicesTests:InputMethodManagerServiceTests
Change-Id: Iedd71e4ddf4983f90b02dd72e471e7fa8e838fbf
parent 6ea57e1b
Loading
Loading
Loading
Loading
+51 −2
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@

package com.android.server.inputmethod;

import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -65,6 +66,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManagerInternal;
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Binder;
@@ -102,6 +104,8 @@ import android.util.Printer;
import android.util.Slog;
import android.util.Xml;
import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.LayoutInflater;
@@ -392,6 +396,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    };

    private void restoreNonVrImeFromSettingsNoCheck() {
        mIsVrImeStarted = false;
        // switch back to non-VR InputMethod from settings.
        synchronized (mMethodMap) {
            final String lastInputId = mSettings.getSelectedInputMethod();
@@ -594,6 +599,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
     */
    int mCurTokenDisplayId = INVALID_DISPLAY;

    final ImeDisplayValidator mImeDisplayValidator;

    /** True if VR IME started by {@link #startVrInputMethodNoCheck}. */
    boolean mIsVrImeStarted;

    /**
     * If non-null, this is the input method service we are currently connected
     * to.
@@ -992,6 +1002,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                    // set this is as current inputMethod without updating settings.
                    setInputMethodEnabledLocked(info.getId(), true);
                    setInputMethodLocked(info.getId(), NOT_A_SUBTYPE_ID);
                    mIsVrImeStarted = true;
                    break;
                }
            }
@@ -1388,6 +1399,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        mIWindowManager = IWindowManager.Stub.asInterface(
                ServiceManager.getService(Context.WINDOW_SERVICE));
        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
        final DisplayManagerInternal displayManagerInternal = LocalServices.getService(
                DisplayManagerInternal.class);
        mImeDisplayValidator = (displayId) -> {
            final DisplayInfo displayInfo = displayManagerInternal.getDisplayInfo(displayId);
            return displayInfo != null
                    && (displayInfo.flags & Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0;
        };
        mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
            @Override
            public void executeMessage(Message msg) {
@@ -1913,8 +1931,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            // Wait, the client no longer has access to the display.
            return InputBindResult.INVALID_DISPLAY_ID;
        }
        // Now that the display ID is validated, we trust cs.selfReportedDisplayId for this session.
        final int displayIdToShowIme = cs.selfReportedDisplayId;
        // Compute the final shown display ID with validated cs.selfReportedDisplayId for this
        // session & other conditions.
        final int displayIdToShowIme = computeImeDisplayIdForTarget(
                cs.selfReportedDisplayId, mIsVrImeStarted, mImeDisplayValidator);

        if (mCurClient != cs) {
            // Was the keyguard locked when switching over to the new client?
@@ -2014,6 +2034,35 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
        return InputBindResult.IME_NOT_CONNECTED;
    }

    @FunctionalInterface
    interface ImeDisplayValidator {
        boolean displayCanShowIme(int displayId);
    }

    /**
     * Find the display where the IME should be shown.
     *
     * @param displayId the ID of the display where the IME client target is.
     * @param isVrImeStarted {@code true} if VR IME started, {@code false} otherwise.
     * @param checker instance of {@link ImeDisplayValidator} which is used for
     *                checking display config to adjust the final target display.
     * @return The ID of the display where the IME should be shown.
     */
    static int computeImeDisplayIdForTarget(int displayId, boolean isVrImeStarted,
            @NonNull ImeDisplayValidator checker) {
        // For VR IME, we always show in default display.
        if (isVrImeStarted) {
            return DEFAULT_DISPLAY;
        }
        if (displayId == DEFAULT_DISPLAY || displayId == INVALID_DISPLAY) {
            // We always assume that the default display id suitable to show the IME window.
            return DEFAULT_DISPLAY;
        }
        // Show IME in default display when the display with IME target doesn't support system
        // decorations.
        return checker.displayCanShowIme(displayId) ? displayId : DEFAULT_DISPLAY;
    }

    @Override
    public void finishInput(IInputMethodClient client) {
    }
+102 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.server.inputmethod;

import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class InputMethodManagerServiceTests {
    static final int SYSTEM_DECORATION_SUPPORT_DISPLAY_ID = 2;
    static final int NO_SYSTEM_DECORATION_SUPPORT_DISPLAY_ID = 3;

    static InputMethodManagerService.ImeDisplayValidator sChecker =
            (displayId) -> {
                switch (displayId) {
                    case SYSTEM_DECORATION_SUPPORT_DISPLAY_ID:
                        return true;
                    case NO_SYSTEM_DECORATION_SUPPORT_DISPLAY_ID:
                        return false;
                    default:
                        throw new IllegalArgumentException("Unknown displayId=" + displayId);
                }
            };

    static InputMethodManagerService.ImeDisplayValidator sMustNotBeCalledChecker =
            (displayId) -> {
                fail("Should not pass to display config check for this test case.");
                return false;
            };

    @Test
    public void testComputeImeDisplayId_defaultDisplayId() {
        // Make sure that there is a short-circuit for DEFAULT_DISPLAY.
        assertEquals(DEFAULT_DISPLAY,
                InputMethodManagerService.computeImeDisplayIdForTarget(
                        DEFAULT_DISPLAY, false /* isVrImeStarted */,
                        sMustNotBeCalledChecker));
    }

    @Test
    public void testComputeImeDisplayId_InvalidDisplayId() {
        // Make sure that there is a short-circuit for INVALID_DISPLAY.
        assertEquals(DEFAULT_DISPLAY,
                InputMethodManagerService.computeImeDisplayIdForTarget(
                        INVALID_DISPLAY, false /* isVrImeStarted */,
                        sMustNotBeCalledChecker));
    }

    @Test
    public void testComputeImeDisplayId_VrIme() {
        // Make sure that there is a short-circuit for VR IME.
        assertEquals(DEFAULT_DISPLAY,
                InputMethodManagerService.computeImeDisplayIdForTarget(
                        SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, true /* isVrImeStarted */,
                        sMustNotBeCalledChecker));
    }

    @Test
    public void testComputeImeDisplayId_noSystemDecorationSupportDisplay() {
        // Presume display didn't support system decoration.
        // Make sure IME displayId is DEFAULT_DISPLAY.
        assertEquals(DEFAULT_DISPLAY,
                InputMethodManagerService.computeImeDisplayIdForTarget(
                        NO_SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, false /* isVrImeStarted */,
                        sChecker));
    }

    @Test
    public void testComputeImeDisplayId_withSystemDecorationSupportDisplay() {
        // Presume display support system decoration.
        // Make sure IME displayId is the same display.
        assertEquals(SYSTEM_DECORATION_SUPPORT_DISPLAY_ID,
                InputMethodManagerService.computeImeDisplayIdForTarget(
                        SYSTEM_DECORATION_SUPPORT_DISPLAY_ID, false /* isVrImeStarted */,
                        sChecker));
    }
}