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

Commit 3d7e6c22 authored by Felix Stern's avatar Felix Stern
Browse files

Remove ImeTargetVisibilityPolicy

With the changes in [1] and [2] and the removal of the DefaultImeVisibilityApplier, the ImeTargetVisibilityPolicy is not needed as a separate class. We can move the reamining methods directly into WindowManagerInternal and DisplayContent.

[1]: I8e3a74ee579f085cb582040fdba725e7a63d6b85
[2]: I1399ec6c9e3f5ed70f02ba2326edd0c73eb930b4

Fix: 433659053
Test: atest InputMethodManagerServiceScreenshotTest
Flag: EXEMPT removing file
Change-Id: I004098c8e4a029fcc709e03bc375785e59c21d48
parent 539679cd
Loading
Loading
Loading
Loading
+2 −6
Original line number Diff line number Diff line
@@ -192,7 +192,6 @@ import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeS
import com.android.server.pm.UserManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.utils.PriorityDump;
import com.android.server.wm.ImeTargetVisibilityPolicy;
import com.android.server.wm.WindowManagerInternal;

import java.io.FileDescriptor;
@@ -435,8 +434,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
    @MultiUserUnawareField
    private final InputMethodMenuController mMenuController;
    private final InputMethodMenuControllerNew mMenuControllerNew;
    @NonNull
    private final ImeTargetVisibilityPolicy mImeTargetVisibilityPolicy;

    /**
     * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
@@ -1243,7 +1240,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
            mImePlatformCompatUtils = new ImePlatformCompatUtils();
            mInputMethodDeviceConfigs = new InputMethodDeviceConfigs();
            mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
            mImeTargetVisibilityPolicy = LocalServices.getService(ImeTargetVisibilityPolicy.class);

            mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);

@@ -5422,7 +5418,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
    @VisibleForTesting
    @GuardedBy("ImfLock.class")
    void showImeScreenshot(IBinder imeTarget, int displayId, @UserIdInt int userId) {
        if (mImeTargetVisibilityPolicy.showImeScreenshot(imeTarget, displayId)) {
        if (mWindowManagerInternal.showImeScreenshot(imeTarget, displayId)) {
            onShowHideSoftInputRequested(false /* show */, imeTarget,
                    SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS, null /* statsToken */,
                    userId);
@@ -5439,7 +5435,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
    @VisibleForTesting
    @GuardedBy("ImfLock.class")
    void removeImeScreenshot(IBinder imeTarget, int displayId, @UserIdInt int userId) {
        if (mImeTargetVisibilityPolicy.removeImeScreenshot(displayId)) {
        if (mWindowManagerInternal.removeImeScreenshot(displayId)) {
            onShowHideSoftInputRequested(false /* show */, imeTarget,
                    SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS, null /* statsToken */,
                    userId);
+81 −1
Original line number Diff line number Diff line
@@ -4902,7 +4902,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
    @VisibleForTesting
    @Nullable
    WindowContainer computeImeParent() {
        if (!ImeTargetVisibilityPolicy.canComputeImeParent(mImeLayeringTarget, mImeInputTarget)) {
        if (!canComputeImeParent(mImeLayeringTarget, mImeInputTarget)) {
            return null;
        }
        // Attach it to app if the IME layering target is part of an app that is covering the entire
@@ -4915,6 +4915,86 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        return mImeWindowsContainer.getParent();
    }

    /**
     * Called from {@link #computeImeParent()} to check if we can compute the new IME parent
     * based on the given IME layering and IME input target.
     *
     * @param imeLayeringTarget The window the IME is on top of.
     * @param imeInputTarget    The target which receives input from the IME.
     * @return {@code true} to keep computing the IME parent, {@code false} to defer this operation.
     */
    private static boolean canComputeImeParent(@Nullable WindowState imeLayeringTarget,
            @Nullable InputTarget imeInputTarget) {
        if (imeLayeringTarget == null) {
            return false;
        }
        if (shouldComputeImeParentForEmbeddedActivity(imeLayeringTarget, imeInputTarget)) {
            return true;
        }
        // Ensure changing the IME parent when the layering target that may use IME has
        // became to the input target for preventing IME flickers.
        // Note that:
        // 1) For the imeLayeringTarget that may not use IME but requires IME on top
        // of it (e.g. an overlay window with NOT_FOCUSABLE|ALT_FOCUSABLE_IM flags), we allow
        // it to re-parent the IME on top the display to keep the legacy behavior.
        // 2) Even though the starting window won't use IME, the associated activity
        // behind the starting window may request the input. If so, then we should still hold
        // the IME parent change until the activity started the input.
        boolean imeLayeringTargetMayUseIme =
                WindowManager.LayoutParams.mayUseInputMethod(imeLayeringTarget.mAttrs.flags)
                        || imeLayeringTarget.mAttrs.type == TYPE_APPLICATION_STARTING;
        // Do not change parent if the window hasn't requested IME.
        boolean inputAndLayeringTargetsDisagree = (imeInputTarget == null
                || imeLayeringTarget.mActivityRecord != imeInputTarget.getActivityRecord());
        boolean inputTargetStale = imeLayeringTargetMayUseIme && inputAndLayeringTargetsDisagree;

        return !inputTargetStale;
    }

    /**
     * Called from {@link #computeImeParent()} to check if the IME surface parent should be
     * updated in ActivityEmbeddings, based on the given IME layering and IME input target.
     *
     * <p>As the IME layering target is calculated according to the window hierarchy by
     * {@link #computeImeLayeringTarget}, the layering target and input target may be different
     * when the window hasn't started input connection, WindowManagerService hasn't yet received
     * the input target which reported from InputMethodManagerService. To make sure the IME
     * surface will be shown on the best fit IME layering target, we basically won't update IME
     * parent until both IME layering and input target are updated, for better IME transition.
     *
     * <p>However, in activity embedding, tapping a window won't update it to the top window so the
     * IME layering target may be higher than input target. Update IME parent in this case.
     *
     * @param imeLayeringTarget The window the IME is on top of.
     * @param imeInputTarget    The target which receives input from the IME.
     *
     * @return {@code true} means the layer of IME layering target is higher than the input target
     * and {@link #computeImeParent()} should keep progressing to update the IME surface parent
     * on the display in case the IME surface was left behind.
     */
    private static boolean shouldComputeImeParentForEmbeddedActivity(
            @Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) {
        if (imeInputTarget == null || imeLayeringTarget == null) {
            return false;
        }
        final WindowState inputTargetWindow = imeInputTarget.getWindowState();
        if (inputTargetWindow == null || !imeLayeringTarget.isAttached()
                || !inputTargetWindow.isAttached()) {
            return false;
        }

        final ActivityRecord inputTargetRecord = imeInputTarget.getActivityRecord();
        final ActivityRecord layeringTargetRecord = imeLayeringTarget.getActivityRecord();
        if (inputTargetRecord == null || layeringTargetRecord == null
                || inputTargetRecord == layeringTargetRecord
                || (inputTargetRecord.getTask() != layeringTargetRecord.getTask())
                || !inputTargetRecord.isEmbedded() || !layeringTargetRecord.isEmbedded()) {
            // Check whether the input target and layering target are embedded in the same Task.
            return false;
        }
        return imeLayeringTarget.compareTo(inputTargetWindow) > 0;
    }

    void setLayoutNeeded() {
        if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3));
        mLayoutNeeded = true;
+0 −131
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
import android.view.WindowManager;

/**
 * A class for {@link com.android.server.inputmethod.InputMethodManagerService} to
 * control IME visibility operations in {@link WindowManagerService}.
 */
public abstract class ImeTargetVisibilityPolicy {

    /**
     * Shows the IME screenshot and attaches it to the given IME target window.
     *
     * @param imeTarget the token of the IME target window.
     * @param displayId the ID of the display to show the screenshot on.
     * @return {@code true} if successful, {@code false} otherwise.
     */
    public abstract boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId);

    /**
     * Removes the IME screenshot from the given display.
     *
     * @param displayId The target display of showing IME screenshot.
     * @return {@code true} if successful, {@code false} otherwise.
     */
    public abstract boolean removeImeScreenshot(int displayId);

    /**
     * Called from {@link DisplayContent#computeImeParent()} to check if we can compute the new IME
     * parent based on the given IME layering and IME input target.
     *
     * @param imeLayeringTarget The window the IME is on top of.
     * @param imeInputTarget    The target which receives input from the IME.
     * @return {@code true} to keep computing the IME parent, {@code false} to defer this operation.
     */
    public static boolean canComputeImeParent(@Nullable WindowState imeLayeringTarget,
            @Nullable InputTarget imeInputTarget) {
        if (imeLayeringTarget == null) {
            return false;
        }
        if (shouldComputeImeParentForEmbeddedActivity(imeLayeringTarget, imeInputTarget)) {
            return true;
        }
        // Ensure changing the IME parent when the layering target that may use IME has
        // became to the input target for preventing IME flickers.
        // Note that:
        // 1) For the imeLayeringTarget that may not use IME but requires IME on top
        // of it (e.g. an overlay window with NOT_FOCUSABLE|ALT_FOCUSABLE_IM flags), we allow
        // it to re-parent the IME on top the display to keep the legacy behavior.
        // 2) Even though the starting window won't use IME, the associated activity
        // behind the starting window may request the input. If so, then we should still hold
        // the IME parent change until the activity started the input.
        boolean imeLayeringTargetMayUseIme =
                WindowManager.LayoutParams.mayUseInputMethod(imeLayeringTarget.mAttrs.flags)
                        || imeLayeringTarget.mAttrs.type == TYPE_APPLICATION_STARTING;
        // Do not change parent if the window hasn't requested IME.
        boolean inputAndLayeringTargetsDisagree = (imeInputTarget == null
                || imeLayeringTarget.mActivityRecord != imeInputTarget.getActivityRecord());
        boolean inputTargetStale = imeLayeringTargetMayUseIme && inputAndLayeringTargetsDisagree;

        return !inputTargetStale;
    }


    /**
     * Called from {@link DisplayContent#computeImeParent()} to check if the IME surface parent
     * should be updated in ActivityEmbeddings, based on the given IME layering and IME input
     * target.
     *
     * <p>As the IME layering target is calculated according to the window hierarchy by
     * {@link DisplayContent#computeImeLayeringTarget}, the layering target and input target may be
     * different when the window hasn't started input connection, WindowManagerService hasn't yet
     * received the input target which reported from InputMethodManagerService. To make sure the IME
     * surface will be shown on the best fit IME layering target, we basically won't update IME
     * parent until both IME layering and input target are updated, for better IME transition.
     *
     * <p>However, in activity embedding, tapping a window won't update it to the top window so the
     * IME layering target may be higher than input target. Update IME parent in this case.
     *
     * @param imeLayeringTarget The window the IME is on top of.
     * @param imeInputTarget    The target which receives input from the IME.
     *
     * @return {@code true} means the layer of IME layering target is higher than the input target
     * and {@link DisplayContent#computeImeParent()} should keep progressing to update the IME
     * surface parent on the display in case the IME surface was left behind.
     */
    private static boolean shouldComputeImeParentForEmbeddedActivity(
            @Nullable WindowState imeLayeringTarget, @Nullable InputTarget imeInputTarget) {
        if (imeInputTarget == null || imeLayeringTarget == null) {
            return false;
        }
        final WindowState inputTargetWindow = imeInputTarget.getWindowState();
        if (inputTargetWindow == null || !imeLayeringTarget.isAttached()
                || !inputTargetWindow.isAttached()) {
            return false;
        }

        final ActivityRecord inputTargetRecord = imeInputTarget.getActivityRecord();
        final ActivityRecord layeringTargetRecord = imeLayeringTarget.getActivityRecord();
        if (inputTargetRecord == null || layeringTargetRecord == null
                || inputTargetRecord == layeringTargetRecord
                || (inputTargetRecord.getTask() != layeringTargetRecord.getTask())
                || !inputTargetRecord.isEmbedded() || !layeringTargetRecord.isEmbedded()) {
            // Check whether the input target and layering target are embedded in the same Task.
            return false;
        }
        return imeLayeringTarget.compareTo(inputTargetWindow) > 0;
    }
}
+17 −0
Original line number Diff line number Diff line
@@ -713,6 +713,23 @@ public abstract class WindowManagerInternal {
     */
    public abstract void updateImeTargetWindow(@NonNull IBinder windowToken);

    /**
     * Shows the IME screenshot and attaches it to the given IME target window.
     *
     * @param imeTarget the token of the IME target window.
     * @param displayId the ID of the display to show the screenshot on.
     * @return {@code true} if successful, {@code false} otherwise.
     */
    public abstract boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId);

    /**
     * Removes the IME screenshot from the given display.
     *
     * @param displayId The target display of showing IME screenshot.
     * @return {@code true} if successful, {@code false} otherwise.
     */
    public abstract boolean removeImeScreenshot(int displayId);

    /**
      * Returns true when the hardware keyboard is available.
      */
+32 −36
Original line number Diff line number Diff line
@@ -1514,8 +1514,6 @@ public class WindowManagerService extends IWindowManager.Stub
        mConstants.start(new HandlerExecutor(mH));

        LocalServices.addService(WindowManagerInternal.class, new LocalService());
        LocalServices.addService(
                ImeTargetVisibilityPolicy.class, new ImeTargetVisibilityPolicyImpl());
        mEmbeddedWindowController = new EmbeddedWindowController(mAtmService, inputManager);

        mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
@@ -8345,6 +8343,38 @@ public class WindowManagerService extends IWindowManager.Stub
            }
        }

        @Override
        public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId) {
            synchronized (mGlobalLock) {
                final WindowState imeTargetWindow = mWindowMap.get(imeTarget);
                if (imeTargetWindow == null) {
                    return false;
                }
                final DisplayContent dc = mRoot.getDisplayContent(displayId);
                if (dc == null) {
                    Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to show IME screenshot");
                    return false;
                }

                dc.showImeScreenshot(imeTargetWindow);
                return true;
            }
        }

        @Override
        public boolean removeImeScreenshot(int displayId) {
            synchronized (mGlobalLock) {
                final DisplayContent dc = mRoot.getDisplayContent(displayId);
                if (dc == null) {
                    Slog.w(TAG, "Invalid displayId:" + displayId
                            + ", fail to remove IME screenshot");
                    return false;
                }
                dc.removeImeScreenshotImmediately();
                return true;
            }
        }

        @Override
        public boolean isHardKeyboardAvailable() {
            synchronized (mGlobalLock) {
@@ -9018,40 +9048,6 @@ public class WindowManagerService extends IWindowManager.Stub
        }
    }

    private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy {

        @Override
        public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId) {
            synchronized (mGlobalLock) {
                final WindowState imeTargetWindow = mWindowMap.get(imeTarget);
                if (imeTargetWindow == null) {
                    return false;
                }
                final DisplayContent dc = mRoot.getDisplayContent(displayId);
                if (dc == null) {
                    Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to show IME screenshot");
                    return false;
                }

                dc.showImeScreenshot(imeTargetWindow);
                return true;
            }
        }
        @Override
        public boolean removeImeScreenshot(int displayId) {
            synchronized (mGlobalLock) {
                final DisplayContent dc = mRoot.getDisplayContent(displayId);
                if (dc == null) {
                    Slog.w(TAG, "Invalid displayId:" + displayId
                            + ", fail to remove IME screenshot");
                    return false;
                }
                dc.removeImeScreenshotImmediately();
                return true;
            }
        }
    }

    /** Called to inform window manager if non-Vr UI shoul be disabled or not. */
    public void disableNonVrUi(boolean disable) {
        synchronized (mGlobalLock) {
Loading