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
This commit is contained in:
@@ -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) {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user