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

Commit df46fd52 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Make child window inherit the scale of parent

The child window computes its layout in parent's frame.
If parent frame is scaled, the position and size of
child window is already based on parent. And the child
surface also has the same scale from parent surface.

This change makes mGlobalScale of child window to 1.
And use the unscaled containing frame display frame of
parent to apply gravity, so the child window can fit
in the scaled content of parent window.

Bug: 182362657
Test: atest WindowStateTests#testCompatOverrideScale

Change-Id: Ie8b9fabcfbccb63f54d51bdd55b23f835151202d
parent 9c1d0087
Loading
Loading
Loading
Loading
+23 −3
Original line number Diff line number Diff line
@@ -255,6 +255,7 @@ import com.android.internal.util.ToBooleanFunction;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.utils.CoordinateTransforms;

import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -624,6 +625,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
    private PowerManager.WakeLock mDrawLock;

    private final Rect mTmpRect = new Rect();
    private final Rect mTmpRect2 = new Rect();
    private final Point mTmpPoint = new Point();

    private final Transaction mTmpTransaction;
@@ -1136,13 +1138,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP

    /**
     * @return {@code true} if the application runs in size compatibility mode or has an app level
     * scaling override set.
     * scaling override set. This method always returns {@code false} on child window because it
     * should follow parent's scale.
     * @see CompatModePackages#getCompatScale
     * @see android.content.res.CompatibilityInfo#supportsScreen
     * @see ActivityRecord#hasSizeCompatBounds()
     */
    boolean hasCompatScale() {
        return mOverrideScale != 1f || hasCompatScale(mAttrs, mActivityRecord);
        return (mOverrideScale != 1f || hasCompatScale(mAttrs, mActivityRecord)) && !mIsChildWindow;
    }

    /**
@@ -1314,7 +1317,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
                }
            }

            layoutDisplayFrame = new Rect(windowFrames.mDisplayFrame);
            layoutDisplayFrame = mTmpRect2;
            layoutDisplayFrame.set(windowFrames.mDisplayFrame);
            windowFrames.mDisplayFrame.set(windowFrames.mContainingFrame);
            layoutXDiff = mInsetFrame.left - windowFrames.mContainingFrame.left;
            layoutYDiff = mInsetFrame.top - windowFrames.mContainingFrame.top;
@@ -4361,6 +4365,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
            h = Math.min(h, ph);
        }

        if (mIsChildWindow) {
            final WindowState parent = getTopParentWindow();
            if (parent.hasCompatScale()) {
                // Scale the containing and display frames because they are in screen coordinates.
                // The position of frames are already relative to parent so only size is scaled.
                mTmpRect.set(containingFrame);
                containingFrame = mTmpRect;
                CoordinateTransforms.scaleRectSize(containingFrame, parent.mInvGlobalScale);
                if (fitToDisplay) {
                    mTmpRect2.set(displayFrame);
                    displayFrame = mTmpRect2;
                    CoordinateTransforms.scaleRectSize(displayFrame, parent.mInvGlobalScale);
                }
            }
        }

        // Set mFrame
        Gravity.apply(mAttrs.gravity, w, h, containingFrame,
                (int) (x + mAttrs.horizontalMargin * pw),
+6 −0
Original line number Diff line number Diff line
@@ -152,4 +152,10 @@ public class CoordinateTransforms {
        transform.mapRect(tmp);
        inOutRect.set((int) tmp.left, (int) tmp.top, (int) tmp.right, (int) tmp.bottom);
    }

    /** Scales the rect without changing its position. */
    public static void scaleRectSize(Rect inOutRect, float scale) {
        inOutRect.right = inOutRect.left + (int) (inOutRect.width() * scale + .5f);
        inOutRect.bottom = inOutRect.top + (int) (inOutRect.height() * scale + .5f);
    }
}
+25 −2
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -570,21 +571,43 @@ public class WindowStateTests extends WindowTestsBase {
        spyOn(cmp);
        doReturn(overrideScale).when(cmp).getCompatScale(anyString(), anyInt());
        final WindowState w = createWindow(null, TYPE_APPLICATION_OVERLAY, "win");
        makeWindowVisible(w);
        final WindowState child = createWindow(w, TYPE_APPLICATION_PANEL, "child");

        assertTrue(w.hasCompatScale());
        assertFalse(child.hasCompatScale());

        makeWindowVisible(w, child);
        w.setRequestedSize(100, 200);
        child.setRequestedSize(50, 100);
        child.mAttrs.width = child.mAttrs.height = 0;
        w.mAttrs.x = w.mAttrs.y = 100;
        w.mAttrs.width = w.mAttrs.height = WindowManager.LayoutParams.WRAP_CONTENT;
        w.mAttrs.gravity = Gravity.TOP | Gravity.LEFT;
        child.mAttrs.gravity = Gravity.CENTER;
        DisplayContentTests.performLayout(mDisplayContent);

        // Frame on screen = 100x200. Compat frame on client = 50x100.
        // Frame on screen = 200x400 (200, 200 - 400, 600). Compat frame on client = 100x200.
        final Rect unscaledCompatFrame = new Rect(w.getWindowFrames().mCompatFrame);
        unscaledCompatFrame.scale(overrideScale);
        final Rect parentFrame = w.getFrame();
        assertEquals(w.getWindowFrames().mFrame, unscaledCompatFrame);

        final Rect childFrame = child.getFrame();
        assertEquals(childFrame, child.getWindowFrames().mCompatFrame);
        // Child frame = 50x100 (225, 250 - 275, 350) according to Gravity.CENTER.
        final int childX = parentFrame.left + child.mRequestedWidth / 2;
        final int childY = parentFrame.top + child.mRequestedHeight / 2;
        final Rect expectedChildFrame = new Rect(childX, childY, childX + child.mRequestedWidth,
                childY + child.mRequestedHeight);
        assertEquals(expectedChildFrame, childFrame);

        // Surface should apply the scale.
        w.prepareSurfaces();
        verify(w.getPendingTransaction()).setMatrix(w.getSurfaceControl(),
                overrideScale, 0, 0, overrideScale);
        // Child surface inherits parent's scale, so it doesn't need to scale.
        verify(child.getPendingTransaction(), never()).setMatrix(any(), anyInt(), anyInt(),
                anyInt(), anyInt());

        // According to "dp * density / 160 = px", density is scaled and the size in dp is the same.
        final CompatibilityInfo compatInfo = cmp.compatibilityInfoForPackageLocked(