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

Commit e124ea53 authored by Wilson Wu's avatar Wilson Wu
Browse files

Introduce ImeTargetVisibilityPolicy

This class provides ime target visibility
utility functions from IMMS to WM as:
-. update ime screenshot
-. update ime parent

This change only build the class and no module
rely on it so it shouldn't have behavior changes.

Bug: 258048231
Test: atest WmTests:ZOrderingTests#testImeScreenshotLayer
Change-Id: Ie567ba578dca65be0a9a11d9a4aa27a13fe69900
parent 76024233
Loading
Loading
Loading
Loading
+28 −11
Original line number Diff line number Diff line
@@ -4320,6 +4320,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            return mImeTarget;
        }

        @VisibleForTesting
        SurfaceControl getImeScreenshotSurface() {
            return mImeSurface;
        }

        private SurfaceControl createImeSurface(ScreenCapture.ScreenshotHardwareBuffer b,
                Transaction t) {
            final HardwareBuffer buffer = b.getHardwareBuffer();
@@ -4429,33 +4434,45 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        }
    }

    private void attachAndShowImeScreenshotOnTarget() {
    private void attachImeScreenshotOnTargetIfNeeded() {
        // No need to attach screenshot if the IME target not exists or screen is off.
        if (!shouldImeAttachedToApp() || !mWmService.mPolicy.isScreenOn()) {
            return;
        }

        final SurfaceControl.Transaction t = getPendingTransaction();
        // Prepare IME screenshot for the target if it allows to attach into.
        if (mInputMethodWindow != null && mInputMethodWindow.isVisible()) {
            attachImeScreenshotOnTarget(mImeLayeringTarget);
        }
    }

    private void attachImeScreenshotOnTarget(WindowState imeTarget) {
        final SurfaceControl.Transaction t = getPendingTransaction();
        // Remove the obsoleted IME snapshot first in case the new snapshot happens to
        // override the current one before the transition finish and the surface never be
        // removed on the task.
        removeImeSurfaceImmediately();
        mImeScreenshot = new ImeScreenshot(
                    mWmService.mSurfaceControlFactory.apply(null), mImeLayeringTarget);
                mWmService.mSurfaceControlFactory.apply(null), imeTarget);
        mImeScreenshot.attachAndShow(t);
    }
    }

    /**
     * Shows the IME screenshot and attach to the IME target window.
     * Shows the IME screenshot and attach to the IME layering target window.
     *
     * Used when the IME target window with IME visible is transitioning to the next target.
     * e.g. App transitioning or swiping this the task of the IME target window to recents app.
     */
    void showImeScreenshot() {
        attachAndShowImeScreenshotOnTarget();
        attachImeScreenshotOnTargetIfNeeded();
    }

    /**
     * Shows the IME screenshot and attach it to the given IME target window.
     */
    @VisibleForTesting
    void showImeScreenshot(WindowState imeTarget) {
        attachImeScreenshotOnTarget(imeTarget);
    }

    /**
+45 −0
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 android.os.IBinder;

/**
 * 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 attach it to the given IME target window.
     *
     * @param imeTarget The target window to show the IME screenshot.
     * @param displayId A unique id to identify the display.
     * @return {@code true} if success, {@code false} otherwise.
     */
    public abstract boolean showImeScreenShot(IBinder imeTarget, int displayId);

    /**
     * Updates the IME parent for target window.
     *
     * @param imeTarget The target window to update the IME parent.
     * @param displayId A unique id to identify the display.
     * @return {@code true} if success, {@code false} otherwise.
     */
    public abstract boolean updateImeParent(IBinder imeTarget, int displayId);
}
+43 −0
Original line number Diff line number Diff line
@@ -1333,6 +1333,8 @@ 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);

        mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
@@ -8333,6 +8335,47 @@ public class WindowManagerService extends IWindowManager.Stub
        }
    }

    private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy {

        // TODO(b/258048231): Track IME visibility change in bugreport when invocations.
        @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;
            }
        }

        // TODO(b/258048231): Track IME visibility change in bugreport when invocations.
        @Override
        public boolean updateImeParent(@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 update ime parent");
                    return false;
                }

                dc.updateImeParent();
                return true;
            }
        }
    }

    void registerAppFreezeListener(AppFreezeListener listener) {
        if (!mAppFreezeListeners.contains(listener)) {
            mAppFreezeListeners.add(listener);
+1 −0
Original line number Diff line number Diff line
@@ -419,6 +419,7 @@ public class SystemServicesTestRule implements TestRule {
        LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
        LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
        LocalServices.removeServiceForTest(UserManagerInternal.class);
        LocalServices.removeServiceForTest(ImeTargetVisibilityPolicy.class);
    }

    Description getDescription() {
+27 −0
Original line number Diff line number Diff line
@@ -45,16 +45,21 @@ import static com.android.server.wm.WindowStateAnimator.PRESERVED_SURFACE_LAYER;

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

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;
import android.view.IRecentsAnimationRunner;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.window.ScreenCapture;

import androidx.test.filters.SmallTest;

@@ -569,4 +574,26 @@ public class ZOrderingTests extends WindowTestsBase {
        assertZOrderGreaterThan(mTransaction, systemDialogWindow.getSurfaceControl(),
                mDisplayContent.getImeContainer().getSurfaceControl());
    }

    @Test
    public void testImeScreenshotLayer() {
        final Task task = createTask(mDisplayContent);
        final WindowState imeAppTarget = createAppWindow(task, TYPE_APPLICATION, "imeAppTarget");
        final Rect bounds = mImeWindow.getParentFrame();
        final ScreenCapture.ScreenshotHardwareBuffer imeBuffer =
                ScreenCapture.captureLayersExcluding(mImeWindow.getSurfaceControl(),
                bounds, 1.0f, PixelFormat.RGB_565, null);

        spyOn(mDisplayContent.mWmService.mTaskSnapshotController);
        doReturn(imeBuffer).when(mDisplayContent.mWmService.mTaskSnapshotController)
                .snapshotImeFromAttachedTask(task);

        mDisplayContent.showImeScreenshot(imeAppTarget);

        assertEquals(imeAppTarget, mDisplayContent.mImeScreenshot.getImeTarget());
        assertNotNull(mDisplayContent.mImeScreenshot);
        assertZOrderGreaterThan(mTransaction,
                mDisplayContent.mImeScreenshot.getImeScreenshotSurface(),
                imeAppTarget.mSurfaceControl);
    }
}