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

Commit 9329fbdd authored by Charles Chen's avatar Charles Chen
Browse files

Migrate IME switch dialog to WindowContext

Bug: 157888351
Test: manual - reproducible steps mentioned in the bug
Test: atest InputMethodMenuControllerTest
Test: atest WindowManagerServiceTests

Change-Id: I8adb0c569ea6c208aee659603ee1d69df9939267
parent c88452c3
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -2467,6 +2467,12 @@
      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
    },
    "781471998": {
      "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
      "level": "WARN",
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "791468751": {
      "message": "Pausing rotation during re-position",
      "level": "DEBUG",
@@ -2671,6 +2677,12 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "1033274509": {
      "message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
      "level": "WARN",
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "1040675582": {
      "message": "Can't report activity configuration update - client not running, activityRecord=%s",
      "level": "WARN",
@@ -3457,6 +3469,12 @@
      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
    },
    "2060978050": {
      "message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d",
      "level": "WARN",
      "group": "WM_ERROR",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "2081291430": {
      "message": "Focus not requested for window=%s because it has no surface",
      "level": "DEBUG",
+27 −4
Original line number Diff line number Diff line
@@ -136,10 +136,7 @@ public class InputMethodMenuController {
                }
            }

            final ActivityThread currentThread = ActivityThread.currentActivityThread();
            final Context settingsContext = new ContextThemeWrapper(
                    currentThread.createSystemUiContext(displayId),
                    com.android.internal.R.style.Theme_DeviceDefault_Settings);
            final Context settingsContext = getSettingsContext(displayId);
            mDialogBuilder = new AlertDialog.Builder(settingsContext);
            mDialogBuilder.setOnCancelListener(dialog -> hideInputMethodMenu());

@@ -214,6 +211,32 @@ 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) {
            final Context systemUiContext = ActivityThread.currentActivityThread()
                    .createSystemUiContext(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.getActivityToken();
        }
        // TODO(b/159767464): register the listener to another display again if window token is not
        // yet created.
        if (mSettingsContext.getDisplayId() != displayId) {
            mWindowManagerInternal.moveWindowTokenToDisplay(mSwitchingDialogToken, displayId);
        }
        return mSettingsContext;
    }

    private boolean isScreenLocked() {
        return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()
                && mKeyguardManager.isKeyguardSecure();
+5 −0
Original line number Diff line number Diff line
@@ -597,4 +597,9 @@ public abstract class WindowManagerInternal {
     * @return The corresponding {@link WindowState#getName()}
     */
    public abstract @Nullable String getImeTargetNameForLogging(int displayId);

    /**
     * Moves the {@link WindowToken} {@code binder} to the display specified by {@code displayId}.
     */
    public abstract void moveWindowTokenToDisplay(IBinder binder, int displayId);
}
+31 −0
Original line number Diff line number Diff line
@@ -2723,6 +2723,32 @@ public class WindowManagerService extends IWindowManager.Stub
        }
    }

    /** @see WindowManagerInternal#moveWindowTokenToDisplay(IBinder, int)  */
    public void moveWindowTokenToDisplay(IBinder binder, int displayId) {
        synchronized (mGlobalLock) {
            final DisplayContent dc = mRoot.getDisplayContentOrCreate(displayId);
            if (dc == null) {
                ProtoLog.w(WM_ERROR, "moveWindowTokenToDisplay: Attempted to move token: %s"
                        + " to non-exiting displayId=%d", binder, displayId);
                return;
            }
            final WindowToken token = mRoot.getWindowToken(binder);
            if (token == null) {
                ProtoLog.w(WM_ERROR,
                        "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
                        binder);
                return;
            }
            if (token.getDisplayContent() == dc) {
                ProtoLog.w(WM_ERROR,
                        "moveWindowTokenToDisplay: Cannot move to the original display "
                                + "for token: %s", binder);
                return;
            }
            dc.reParentWindowToken(token);
        }
    }

    void setNewDisplayOverrideConfiguration(Configuration overrideConfig,
            @NonNull DisplayContent dc) {
        if (dc.mWaitingForConfig) {
@@ -7355,6 +7381,11 @@ public class WindowManagerService extends IWindowManager.Stub
            }
        }

        @Override
        public void moveWindowTokenToDisplay(IBinder binder, int displayId) {
            WindowManagerService.this.moveWindowTokenToDisplay(binder, displayId);
        }

        // TODO(multi-display): currently only used by PWM to notify keyguard transitions as well
        // forwarding it to SystemUI for synchronizing status and navigation bar animations.
        @Override
+78 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.wm;

import static android.view.Display.DEFAULT_DISPLAY;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.mock;

import android.content.Context;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.WindowManager;

import com.android.server.inputmethod.InputMethodManagerService;
import com.android.server.inputmethod.InputMethodMenuController;

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

// TODO(b/157888351): Move the test to inputmethod package once we find the way to test the
//  scenario there.
/**
 * Build/Install/Run:
 *  atest WmTests:InputMethodMenuControllerTest
 */
@Presubmit
@RunWith(WindowTestRunner.class)
public class InputMethodMenuControllerTest extends WindowTestsBase {

    private InputMethodMenuController mController;

    @Before
    public void setUp() {
        mController = new InputMethodMenuController(mock(InputMethodManagerService.class));
    }

    @Test
    public void testGetSettingsContext() {
        final Context contextOnDefaultDisplay = mController.getSettingsContext(DEFAULT_DISPLAY);

        assertImeSwitchContextMetricsValidity(contextOnDefaultDisplay, mDefaultDisplay);

        // Obtain the context again and check they are the same instance and match the display
        // metrics of the secondary display.
        final Context contextOnSecondaryDisplay = mController.getSettingsContext(
                mDisplayContent.getDisplayId());

        assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mDisplayContent);
        assertThat(contextOnDefaultDisplay.getActivityToken())
                .isEqualTo(contextOnSecondaryDisplay.getActivityToken());
    }

    private void assertImeSwitchContextMetricsValidity(Context context, DisplayContent dc) {
        assertThat(context.getDisplayId()).isEqualTo(dc.getDisplayId());

        final Rect contextBounds = context.getSystemService(WindowManager.class)
                .getMaximumWindowMetrics().getBounds();
        final Rect imeContainerBounds = dc.getImeContainer().getBounds();
        assertThat(contextBounds).isEqualTo(imeContainerBounds);
    }
}
Loading