Loading services/core/java/com/android/server/inputmethod/InputMethodDialogWindowContext.java 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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 com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; import android.content.Context; import android.view.ContextThemeWrapper; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; /** * Provides the window context for the IME switcher dialog. */ @VisibleForTesting(visibility = PACKAGE) public final class InputMethodDialogWindowContext { @Nullable private Context mDialogWindowContext; /** * Returns the window context for IME switch dialogs to receive configuration changes. * * This method initializes the window context if it was not initialized, or moves the context to * the targeted display if the current display of context is different from the display * specified by {@code displayId}. */ @NonNull @VisibleForTesting(visibility = PACKAGE) public Context get(int displayId) { if (mDialogWindowContext == null || mDialogWindowContext.getDisplayId() != displayId) { final Context systemUiContext = ActivityThread.currentActivityThread() .getSystemUiContext(displayId); final Context windowContext = systemUiContext.createWindowContext( WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, null /* options */); mDialogWindowContext = new ContextThemeWrapper( windowContext, com.android.internal.R.style.Theme_DeviceDefault_Settings); } return mDialogWindowContext; } } services/core/java/com/android/server/inputmethod/InputMethodMenuController.java +12 −34 Original line number Diff line number Diff line Loading @@ -16,22 +16,19 @@ package com.android.server.inputmethod; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.server.inputmethod.InputMethodManagerService.DEBUG; import static com.android.server.inputmethod.InputMethodUtils.NOT_A_SUBTYPE_ID; import android.app.ActivityThread; import android.annotation.Nullable; import android.app.AlertDialog; import android.app.KeyguardManager; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.IBinder; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Slog; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; Loading @@ -45,7 +42,6 @@ import android.widget.Switch; import android.widget.TextView; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; import com.android.server.wm.WindowManagerInternal; Loading @@ -53,8 +49,7 @@ import com.android.server.wm.WindowManagerInternal; import java.util.List; /** A controller to show/hide the input method menu */ @VisibleForTesting(visibility = PACKAGE) public class InputMethodMenuController { final class InputMethodMenuController { private static final String TAG = InputMethodMenuController.class.getSimpleName(); private final InputMethodManagerService mService; Loading @@ -64,17 +59,18 @@ public class InputMethodMenuController { private final KeyguardManager mKeyguardManager; private final WindowManagerInternal mWindowManagerInternal; private Context mSettingsContext; private AlertDialog.Builder mDialogBuilder; private AlertDialog mSwitchingDialog; private IBinder mSwitchingDialogToken; private View mSwitchingDialogTitleView; private InputMethodInfo[] mIms; private int[] mSubtypeIds; private boolean mShowImeWithHardKeyboard; @VisibleForTesting(visibility = PACKAGE) @GuardedBy("ImfLock.class") @Nullable private InputMethodDialogWindowContext mDialogWindowContext; public InputMethodMenuController(InputMethodManagerService service) { mService = service; mSettings = mService.mSettings; Loading Loading @@ -132,8 +128,11 @@ public class InputMethodMenuController { } } final Context settingsContext = getSettingsContext(displayId); mDialogBuilder = new AlertDialog.Builder(settingsContext); if (mDialogWindowContext == null) { mDialogWindowContext = new InputMethodDialogWindowContext(); } final Context dialogWindowContext = mDialogWindowContext.get(displayId); mDialogBuilder = new AlertDialog.Builder(dialogWindowContext); mDialogBuilder.setOnCancelListener(dialog -> hideInputMethodMenu()); final Context dialogContext = mDialogBuilder.getContext(); Loading Loading @@ -199,7 +198,7 @@ public class InputMethodMenuController { // Use an alternate token for the dialog for that window manager can group the token // with other IME windows based on type vs. grouping based on whichever token happens // to get selected by the system later on. attrs.token = mSwitchingDialogToken; attrs.token = dialogWindowContext.getWindowContextToken(); attrs.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; attrs.setTitle("Select input method"); w.setAttributes(attrs); Loading @@ -208,27 +207,6 @@ public class InputMethodMenuController { } } /** * Returns the window context for IME switch dialogs to receive configuration changes. * * This method initializes the window context if it was not initialized. This method also moves * the context to the targeted display if the current display of context is different than * the display specified by {@code displayId}. */ @VisibleForTesting public Context getSettingsContext(int displayId) { if (mSettingsContext == null || mSettingsContext.getDisplayId() != displayId) { final Context systemUiContext = ActivityThread.currentActivityThread() .getSystemUiContext(displayId); final Context windowContext = systemUiContext.createWindowContext( WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, null /* options */); mSettingsContext = new ContextThemeWrapper( windowContext, com.android.internal.R.style.Theme_DeviceDefault_Settings); mSwitchingDialogToken = mSettingsContext.getWindowContextToken(); } return mSettingsContext; } private boolean isScreenLocked() { return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure(); Loading services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java→services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java +9 −11 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; Loading @@ -48,8 +47,7 @@ import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.window.WindowTokenClient; import com.android.server.inputmethod.InputMethodManagerService; import com.android.server.inputmethod.InputMethodMenuController; import com.android.server.inputmethod.InputMethodDialogWindowContext; import org.junit.After; import org.junit.Before; Loading @@ -61,13 +59,13 @@ import org.mockito.Mockito; // scenario there. /** * Build/Install/Run: * atest WmTests:InputMethodMenuControllerTest * atest WmTests:InputMethodDialogWindowContextTest */ @Presubmit @RunWith(WindowTestRunner.class) public class InputMethodMenuControllerTest extends WindowTestsBase { public class InputMethodDialogWindowContextTest extends WindowTestsBase { private InputMethodMenuController mController; private InputMethodDialogWindowContext mWindowContext; private DualDisplayAreaGroupPolicyTest.DualDisplayContent mSecondaryDisplay; private IWindowManager mIWindowManager; Loading @@ -80,7 +78,7 @@ public class InputMethodMenuControllerTest extends WindowTestsBase { new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider(); Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider(); mController = new InputMethodMenuController(mock(InputMethodManagerService.class)); mWindowContext = new InputMethodDialogWindowContext(); mSecondaryDisplay = new DualDisplayAreaGroupPolicyTest.DualDisplayContent .Builder(mAtm, 1000, 1000).build(); mSecondaryDisplay.getDisplayInfo().state = STATE_ON; Loading Loading @@ -119,21 +117,21 @@ public class InputMethodMenuControllerTest extends WindowTestsBase { @Test public void testGetSettingsContext() { final Context contextOnDefaultDisplay = mController.getSettingsContext(DEFAULT_DISPLAY); final Context contextOnDefaultDisplay = mWindowContext.get(DEFAULT_DISPLAY); assertImeSwitchContextMetricsValidity(contextOnDefaultDisplay, mDefaultDisplay); // Obtain the context again and check if the window metrics match the IME container bounds // of the secondary display. final Context contextOnSecondaryDisplay = mController.getSettingsContext( mSecondaryDisplay.getDisplayId()); final Context contextOnSecondaryDisplay = mWindowContext.get(mSecondaryDisplay.getDisplayId()); assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mSecondaryDisplay); } @Test public void testGetSettingsContextOnDualDisplayContent() { final Context context = mController.getSettingsContext(mSecondaryDisplay.getDisplayId()); final Context context = mWindowContext.get(mSecondaryDisplay.getDisplayId()); final WindowTokenClient tokenClient = (WindowTokenClient) context.getWindowContextToken(); assertNotNull(tokenClient); spyOn(tokenClient); Loading Loading
services/core/java/com/android/server/inputmethod/InputMethodDialogWindowContext.java 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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 com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityThread; import android.content.Context; import android.view.ContextThemeWrapper; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; /** * Provides the window context for the IME switcher dialog. */ @VisibleForTesting(visibility = PACKAGE) public final class InputMethodDialogWindowContext { @Nullable private Context mDialogWindowContext; /** * Returns the window context for IME switch dialogs to receive configuration changes. * * This method initializes the window context if it was not initialized, or moves the context to * the targeted display if the current display of context is different from the display * specified by {@code displayId}. */ @NonNull @VisibleForTesting(visibility = PACKAGE) public Context get(int displayId) { if (mDialogWindowContext == null || mDialogWindowContext.getDisplayId() != displayId) { final Context systemUiContext = ActivityThread.currentActivityThread() .getSystemUiContext(displayId); final Context windowContext = systemUiContext.createWindowContext( WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, null /* options */); mDialogWindowContext = new ContextThemeWrapper( windowContext, com.android.internal.R.style.Theme_DeviceDefault_Settings); } return mDialogWindowContext; } }
services/core/java/com/android/server/inputmethod/InputMethodMenuController.java +12 −34 Original line number Diff line number Diff line Loading @@ -16,22 +16,19 @@ package com.android.server.inputmethod; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.server.inputmethod.InputMethodManagerService.DEBUG; import static com.android.server.inputmethod.InputMethodUtils.NOT_A_SUBTYPE_ID; import android.app.ActivityThread; import android.annotation.Nullable; import android.app.AlertDialog; import android.app.KeyguardManager; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.IBinder; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Slog; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; Loading @@ -45,7 +42,6 @@ import android.widget.Switch; import android.widget.TextView; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; import com.android.server.wm.WindowManagerInternal; Loading @@ -53,8 +49,7 @@ import com.android.server.wm.WindowManagerInternal; import java.util.List; /** A controller to show/hide the input method menu */ @VisibleForTesting(visibility = PACKAGE) public class InputMethodMenuController { final class InputMethodMenuController { private static final String TAG = InputMethodMenuController.class.getSimpleName(); private final InputMethodManagerService mService; Loading @@ -64,17 +59,18 @@ public class InputMethodMenuController { private final KeyguardManager mKeyguardManager; private final WindowManagerInternal mWindowManagerInternal; private Context mSettingsContext; private AlertDialog.Builder mDialogBuilder; private AlertDialog mSwitchingDialog; private IBinder mSwitchingDialogToken; private View mSwitchingDialogTitleView; private InputMethodInfo[] mIms; private int[] mSubtypeIds; private boolean mShowImeWithHardKeyboard; @VisibleForTesting(visibility = PACKAGE) @GuardedBy("ImfLock.class") @Nullable private InputMethodDialogWindowContext mDialogWindowContext; public InputMethodMenuController(InputMethodManagerService service) { mService = service; mSettings = mService.mSettings; Loading Loading @@ -132,8 +128,11 @@ public class InputMethodMenuController { } } final Context settingsContext = getSettingsContext(displayId); mDialogBuilder = new AlertDialog.Builder(settingsContext); if (mDialogWindowContext == null) { mDialogWindowContext = new InputMethodDialogWindowContext(); } final Context dialogWindowContext = mDialogWindowContext.get(displayId); mDialogBuilder = new AlertDialog.Builder(dialogWindowContext); mDialogBuilder.setOnCancelListener(dialog -> hideInputMethodMenu()); final Context dialogContext = mDialogBuilder.getContext(); Loading Loading @@ -199,7 +198,7 @@ public class InputMethodMenuController { // Use an alternate token for the dialog for that window manager can group the token // with other IME windows based on type vs. grouping based on whichever token happens // to get selected by the system later on. attrs.token = mSwitchingDialogToken; attrs.token = dialogWindowContext.getWindowContextToken(); attrs.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; attrs.setTitle("Select input method"); w.setAttributes(attrs); Loading @@ -208,27 +207,6 @@ public class InputMethodMenuController { } } /** * Returns the window context for IME switch dialogs to receive configuration changes. * * This method initializes the window context if it was not initialized. This method also moves * the context to the targeted display if the current display of context is different than * the display specified by {@code displayId}. */ @VisibleForTesting public Context getSettingsContext(int displayId) { if (mSettingsContext == null || mSettingsContext.getDisplayId() != displayId) { final Context systemUiContext = ActivityThread.currentActivityThread() .getSystemUiContext(displayId); final Context windowContext = systemUiContext.createWindowContext( WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, null /* options */); mSettingsContext = new ContextThemeWrapper( windowContext, com.android.internal.R.style.Theme_DeviceDefault_Settings); mSwitchingDialogToken = mSettingsContext.getWindowContextToken(); } return mSettingsContext; } private boolean isScreenLocked() { return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure(); Loading
services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java→services/tests/wmtests/src/com/android/server/wm/InputMethodDialogWindowContextTest.java +9 −11 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; Loading @@ -48,8 +47,7 @@ import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.window.WindowTokenClient; import com.android.server.inputmethod.InputMethodManagerService; import com.android.server.inputmethod.InputMethodMenuController; import com.android.server.inputmethod.InputMethodDialogWindowContext; import org.junit.After; import org.junit.Before; Loading @@ -61,13 +59,13 @@ import org.mockito.Mockito; // scenario there. /** * Build/Install/Run: * atest WmTests:InputMethodMenuControllerTest * atest WmTests:InputMethodDialogWindowContextTest */ @Presubmit @RunWith(WindowTestRunner.class) public class InputMethodMenuControllerTest extends WindowTestsBase { public class InputMethodDialogWindowContextTest extends WindowTestsBase { private InputMethodMenuController mController; private InputMethodDialogWindowContext mWindowContext; private DualDisplayAreaGroupPolicyTest.DualDisplayContent mSecondaryDisplay; private IWindowManager mIWindowManager; Loading @@ -80,7 +78,7 @@ public class InputMethodMenuControllerTest extends WindowTestsBase { new DualDisplayAreaGroupPolicyTest.DualDisplayTestPolicyProvider(); Mockito.doReturn(policyProvider).when(mWm).getDisplayAreaPolicyProvider(); mController = new InputMethodMenuController(mock(InputMethodManagerService.class)); mWindowContext = new InputMethodDialogWindowContext(); mSecondaryDisplay = new DualDisplayAreaGroupPolicyTest.DualDisplayContent .Builder(mAtm, 1000, 1000).build(); mSecondaryDisplay.getDisplayInfo().state = STATE_ON; Loading Loading @@ -119,21 +117,21 @@ public class InputMethodMenuControllerTest extends WindowTestsBase { @Test public void testGetSettingsContext() { final Context contextOnDefaultDisplay = mController.getSettingsContext(DEFAULT_DISPLAY); final Context contextOnDefaultDisplay = mWindowContext.get(DEFAULT_DISPLAY); assertImeSwitchContextMetricsValidity(contextOnDefaultDisplay, mDefaultDisplay); // Obtain the context again and check if the window metrics match the IME container bounds // of the secondary display. final Context contextOnSecondaryDisplay = mController.getSettingsContext( mSecondaryDisplay.getDisplayId()); final Context contextOnSecondaryDisplay = mWindowContext.get(mSecondaryDisplay.getDisplayId()); assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mSecondaryDisplay); } @Test public void testGetSettingsContextOnDualDisplayContent() { final Context context = mController.getSettingsContext(mSecondaryDisplay.getDisplayId()); final Context context = mWindowContext.get(mSecondaryDisplay.getDisplayId()); final WindowTokenClient tokenClient = (WindowTokenClient) context.getWindowContextToken(); assertNotNull(tokenClient); spyOn(tokenClient); Loading