Loading core/java/com/android/internal/policy/DecorView.java +3 −0 Original line number Diff line number Diff line Loading @@ -1639,6 +1639,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind @Override public void onRootViewScrollYChanged(int rootScrollY) { mRootScrollY = rootScrollY; if (mDecorCaptionView != null) { mDecorCaptionView.onRootViewScrollYChanged(rootScrollY); } updateColorViewTranslations(); } Loading core/java/com/android/internal/widget/DecorCaptionView.java +16 −2 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, private final Rect mCloseRect = new Rect(); private final Rect mMaximizeRect = new Rect(); private View mClickTarget; private int mRootScrollY; public DecorCaptionView(Context context) { super(context); Loading Loading @@ -154,10 +155,11 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, if (ev.getAction() == MotionEvent.ACTION_DOWN) { final int x = (int) ev.getX(); final int y = (int) ev.getY(); if (mMaximizeRect.contains(x, y)) { // Only offset y for containment tests because the actual views are already translated. if (mMaximizeRect.contains(x, y - mRootScrollY)) { mClickTarget = mMaximize; } if (mCloseRect.contains(x, y)) { if (mCloseRect.contains(x, y - mRootScrollY)) { mClickTarget = mClose; } } Loading Loading @@ -417,4 +419,16 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } /** * Called when {@link android.view.ViewRootImpl} scrolls for adjustPan. */ public void onRootViewScrollYChanged(int scrollY) { // Offset the caption opposite the root scroll. This keeps the caption at the // top of the window during adjustPan. if (mCaption != null) { mRootScrollY = scrollY; mCaption.setTranslationY(scrollY); } } } services/core/java/com/android/server/wm/TaskPositioner.java +4 −7 Original line number Diff line number Diff line Loading @@ -43,16 +43,15 @@ import android.util.Slog; import android.view.BatchedInputEventReceiver; import android.view.Choreographer; import android.view.Display; import android.view.InputApplicationHandle; import android.view.InputChannel; import android.view.InputDevice; import android.view.InputEvent; import android.view.InputWindowHandle; import android.view.MotionEvent; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import android.view.InputApplicationHandle; import android.view.InputWindowHandle; import com.android.server.wm.WindowManagerService.H; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -356,12 +355,10 @@ class TaskPositioner { + startY + "}"); } mTask = win.getTask(); // Use the dim bounds, not the original task bounds. The cursor // movement should be calculated relative to the visible bounds. // Also, use the dim bounds of the task which accounts for // Use the bounds of the task which accounts for // multiple app windows. Don't use any bounds from win itself as it // may not be the same size as the task. mTask.getDimBounds(mTmpRect); mTask.getBounds(mTmpRect); startDrag(resize, preserveOrientation, startX, startY, mTmpRect); } Loading services/core/java/com/android/server/wm/WindowState.java +27 −8 Original line number Diff line number Diff line Loading @@ -842,6 +842,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // The offset from the layout containing frame to the actual containing frame. final int layoutXDiff; final int layoutYDiff; final WindowState imeWin = mWmService.mRoot.getCurrentInputMethodWindow(); final boolean isImeTarget = imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget(); if (inFullscreenContainer || layoutInParentFrame()) { // We use the parent frame as the containing frame for fullscreen and child windows mWindowFrames.mContainingFrame.set(mWindowFrames.mParentFrame); Loading @@ -861,15 +864,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWindowFrames.mContainingFrame.bottom = mWindowFrames.mContainingFrame.top + frozen.height(); } final WindowState imeWin = mWmService.mRoot.getCurrentInputMethodWindow(); // IME is up and obscuring this window. Adjust the window position so it is visible. if (imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget()) { if (inFreeformWindowingMode() && mWindowFrames.mContainingFrame.bottom > mWindowFrames.mContentFrame.bottom) { // In freeform we want to move the top up directly. // TODO: Investigate why this is contentFrame not parentFrame. mWindowFrames.mContainingFrame.top -= mWindowFrames.mContainingFrame.bottom - mWindowFrames.mContentFrame.bottom; if (isImeTarget) { if (inFreeformWindowingMode()) { // Push the freeform window up to make room for the IME. However, don't push // it up past the top of the screen. final int bottomOverlap = mWindowFrames.mContainingFrame.bottom - mWindowFrames.mVisibleFrame.bottom; if (bottomOverlap > 0) { final int distanceToTop = Math.max(mWindowFrames.mContainingFrame.top - mWindowFrames.mDisplayFrame.top, 0); int offs = Math.min(bottomOverlap, distanceToTop); mWindowFrames.mContainingFrame.top -= offs; } } else if (!inPinnedWindowingMode() && mWindowFrames.mContainingFrame.bottom > mWindowFrames.mParentFrame.bottom) { // But in docked we want to behave like fullscreen and behave as if the task Loading Loading @@ -955,9 +962,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final int left = Math.max(limitFrame.left + minVisibleWidth - width, Math.min( mWindowFrames.mFrame.left, limitFrame.right - minVisibleWidth)); mWindowFrames.mFrame.set(left, top, left + width, top + height); final int visBottom = mWindowFrames.mVisibleFrame.bottom; final int contentBottom = mWindowFrames.mContentFrame.bottom; mWindowFrames.mContentFrame.set( mWindowFrames.mFrame); mWindowFrames.mVisibleFrame.set(mWindowFrames.mContentFrame); mWindowFrames.mStableFrame.set(mWindowFrames.mContentFrame); if (isImeTarget && inFreeformWindowingMode()) { // After displacing a freeform window to make room for the ime, any part of // the window still covered by IME should be inset. if (contentBottom + layoutYDiff < mWindowFrames.mContentFrame.bottom) { mWindowFrames.mContentFrame.bottom = contentBottom + layoutYDiff; } if (visBottom + layoutYDiff < mWindowFrames.mVisibleFrame.bottom) { mWindowFrames.mVisibleFrame.bottom = visBottom + layoutYDiff; } } } else if (mAttrs.type == TYPE_DOCK_DIVIDER) { dc.getDockedDividerController().positionDockedStackedDivider(mWindowFrames.mFrame); mWindowFrames.mContentFrame.set(mWindowFrames.mFrame); Loading services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +69 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.fromBoundingRect; Loading @@ -41,6 +42,7 @@ import com.android.server.wm.utils.WmDisplayCutout; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; /** * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery. Loading Loading @@ -78,16 +80,21 @@ public class WindowFrameTests extends WindowTestsBase { } private static class TaskWithBounds extends Task { final Rect mBounds; Rect mBounds; final Rect mOverrideDisplayedBounds = new Rect(); boolean mFullscreenForTest = true; TaskWithBounds(TaskStack stack, WindowManagerService wm, Rect bounds) { super(0, stack, 0, wm, 0, false, new TaskDescription(), null); mBounds = bounds; setBounds(bounds); } @Override public int setBounds(Rect bounds) { mBounds = bounds; return super.setBounds(bounds); } @Override public Rect getBounds() { return mBounds; Loading Loading @@ -513,6 +520,66 @@ public class WindowFrameTests extends WindowTestsBase { assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetRight(), 0); } @Test public void testFreeformContentInsets() { // fullscreen task doesn't use bounds for computeFrame final Task task = new TaskWithBounds(mStubStack, mWm, null); WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; task.setWindowingMode(WINDOWING_MODE_FREEFORM); ((TaskWithBounds) task).mFullscreenForTest = false; w.setWindowingMode(WINDOWING_MODE_FREEFORM); DisplayContent dc = mWm.getDefaultDisplayContentLocked(); dc.mInputMethodTarget = w; WindowState mockIme = mock(WindowState.class); Mockito.doReturn(true).when(mockIme).isVisibleNow(); dc.mInputMethodWindow = mockIme; // With no insets or system decor all the frames incoming from PhoneWindowManager // are identical. final Rect pf = new Rect(0, 0, 1000, 800); final Rect df = pf; final Rect of = df; final Rect cf = new Rect(pf); cf.bottom -= 400; final Rect vf = new Rect(cf); final Rect sf = new Rect(pf); final Rect dcf = pf; // First check that it only gets moved up enough to show window. final Rect winRect = new Rect(200, 200, 300, 500); task.setBounds(winRect); w.setBounds(winRect); w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect); w.computeFrameLw(); final Rect expected = new Rect(winRect.left, cf.bottom - winRect.height(), winRect.right, cf.bottom); assertEquals(expected, w.getFrameLw()); assertEquals(expected, w.getContentFrameLw()); assertEquals(expected, w.getVisibleFrameLw()); // Now check that it won't get moved beyond the top and then has appropriate insets winRect.bottom = 600; task.setBounds(winRect); w.setBounds(winRect); w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect); w.computeFrameLw(); assertFrame(w, winRect.left, 0, winRect.right, winRect.height()); expected.top = 0; expected.bottom = cf.bottom; assertContentFrame(w, expected); assertVisibleFrame(w, expected); // Check that it's moved back without ime insets w.getWindowFrames().setFrames(pf, df, of, pf, pf, dcf, sf, mEmptyRect); w.computeFrameLw(); assertEquals(winRect, w.getFrameLw()); } private WindowStateWithTask createWindow(Task task, int width, int height) { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); attrs.width = width; Loading Loading
core/java/com/android/internal/policy/DecorView.java +3 −0 Original line number Diff line number Diff line Loading @@ -1639,6 +1639,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind @Override public void onRootViewScrollYChanged(int rootScrollY) { mRootScrollY = rootScrollY; if (mDecorCaptionView != null) { mDecorCaptionView.onRootViewScrollYChanged(rootScrollY); } updateColorViewTranslations(); } Loading
core/java/com/android/internal/widget/DecorCaptionView.java +16 −2 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, private final Rect mCloseRect = new Rect(); private final Rect mMaximizeRect = new Rect(); private View mClickTarget; private int mRootScrollY; public DecorCaptionView(Context context) { super(context); Loading Loading @@ -154,10 +155,11 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, if (ev.getAction() == MotionEvent.ACTION_DOWN) { final int x = (int) ev.getX(); final int y = (int) ev.getY(); if (mMaximizeRect.contains(x, y)) { // Only offset y for containment tests because the actual views are already translated. if (mMaximizeRect.contains(x, y - mRootScrollY)) { mClickTarget = mMaximize; } if (mCloseRect.contains(x, y)) { if (mCloseRect.contains(x, y - mRootScrollY)) { mClickTarget = mClose; } } Loading Loading @@ -417,4 +419,16 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } /** * Called when {@link android.view.ViewRootImpl} scrolls for adjustPan. */ public void onRootViewScrollYChanged(int scrollY) { // Offset the caption opposite the root scroll. This keeps the caption at the // top of the window during adjustPan. if (mCaption != null) { mRootScrollY = scrollY; mCaption.setTranslationY(scrollY); } } }
services/core/java/com/android/server/wm/TaskPositioner.java +4 −7 Original line number Diff line number Diff line Loading @@ -43,16 +43,15 @@ import android.util.Slog; import android.view.BatchedInputEventReceiver; import android.view.Choreographer; import android.view.Display; import android.view.InputApplicationHandle; import android.view.InputChannel; import android.view.InputDevice; import android.view.InputEvent; import android.view.InputWindowHandle; import android.view.MotionEvent; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import android.view.InputApplicationHandle; import android.view.InputWindowHandle; import com.android.server.wm.WindowManagerService.H; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -356,12 +355,10 @@ class TaskPositioner { + startY + "}"); } mTask = win.getTask(); // Use the dim bounds, not the original task bounds. The cursor // movement should be calculated relative to the visible bounds. // Also, use the dim bounds of the task which accounts for // Use the bounds of the task which accounts for // multiple app windows. Don't use any bounds from win itself as it // may not be the same size as the task. mTask.getDimBounds(mTmpRect); mTask.getBounds(mTmpRect); startDrag(resize, preserveOrientation, startX, startY, mTmpRect); } Loading
services/core/java/com/android/server/wm/WindowState.java +27 −8 Original line number Diff line number Diff line Loading @@ -842,6 +842,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // The offset from the layout containing frame to the actual containing frame. final int layoutXDiff; final int layoutYDiff; final WindowState imeWin = mWmService.mRoot.getCurrentInputMethodWindow(); final boolean isImeTarget = imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget(); if (inFullscreenContainer || layoutInParentFrame()) { // We use the parent frame as the containing frame for fullscreen and child windows mWindowFrames.mContainingFrame.set(mWindowFrames.mParentFrame); Loading @@ -861,15 +864,19 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWindowFrames.mContainingFrame.bottom = mWindowFrames.mContainingFrame.top + frozen.height(); } final WindowState imeWin = mWmService.mRoot.getCurrentInputMethodWindow(); // IME is up and obscuring this window. Adjust the window position so it is visible. if (imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget()) { if (inFreeformWindowingMode() && mWindowFrames.mContainingFrame.bottom > mWindowFrames.mContentFrame.bottom) { // In freeform we want to move the top up directly. // TODO: Investigate why this is contentFrame not parentFrame. mWindowFrames.mContainingFrame.top -= mWindowFrames.mContainingFrame.bottom - mWindowFrames.mContentFrame.bottom; if (isImeTarget) { if (inFreeformWindowingMode()) { // Push the freeform window up to make room for the IME. However, don't push // it up past the top of the screen. final int bottomOverlap = mWindowFrames.mContainingFrame.bottom - mWindowFrames.mVisibleFrame.bottom; if (bottomOverlap > 0) { final int distanceToTop = Math.max(mWindowFrames.mContainingFrame.top - mWindowFrames.mDisplayFrame.top, 0); int offs = Math.min(bottomOverlap, distanceToTop); mWindowFrames.mContainingFrame.top -= offs; } } else if (!inPinnedWindowingMode() && mWindowFrames.mContainingFrame.bottom > mWindowFrames.mParentFrame.bottom) { // But in docked we want to behave like fullscreen and behave as if the task Loading Loading @@ -955,9 +962,21 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final int left = Math.max(limitFrame.left + minVisibleWidth - width, Math.min( mWindowFrames.mFrame.left, limitFrame.right - minVisibleWidth)); mWindowFrames.mFrame.set(left, top, left + width, top + height); final int visBottom = mWindowFrames.mVisibleFrame.bottom; final int contentBottom = mWindowFrames.mContentFrame.bottom; mWindowFrames.mContentFrame.set( mWindowFrames.mFrame); mWindowFrames.mVisibleFrame.set(mWindowFrames.mContentFrame); mWindowFrames.mStableFrame.set(mWindowFrames.mContentFrame); if (isImeTarget && inFreeformWindowingMode()) { // After displacing a freeform window to make room for the ime, any part of // the window still covered by IME should be inset. if (contentBottom + layoutYDiff < mWindowFrames.mContentFrame.bottom) { mWindowFrames.mContentFrame.bottom = contentBottom + layoutYDiff; } if (visBottom + layoutYDiff < mWindowFrames.mVisibleFrame.bottom) { mWindowFrames.mVisibleFrame.bottom = visBottom + layoutYDiff; } } } else if (mAttrs.type == TYPE_DOCK_DIVIDER) { dc.getDockedDividerController().positionDockedStackedDivider(mWindowFrames.mFrame); mWindowFrames.mContentFrame.set(mWindowFrames.mFrame); Loading
services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java +69 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.fromBoundingRect; Loading @@ -41,6 +42,7 @@ import com.android.server.wm.utils.WmDisplayCutout; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; /** * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery. Loading Loading @@ -78,16 +80,21 @@ public class WindowFrameTests extends WindowTestsBase { } private static class TaskWithBounds extends Task { final Rect mBounds; Rect mBounds; final Rect mOverrideDisplayedBounds = new Rect(); boolean mFullscreenForTest = true; TaskWithBounds(TaskStack stack, WindowManagerService wm, Rect bounds) { super(0, stack, 0, wm, 0, false, new TaskDescription(), null); mBounds = bounds; setBounds(bounds); } @Override public int setBounds(Rect bounds) { mBounds = bounds; return super.setBounds(bounds); } @Override public Rect getBounds() { return mBounds; Loading Loading @@ -513,6 +520,66 @@ public class WindowFrameTests extends WindowTestsBase { assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetRight(), 0); } @Test public void testFreeformContentInsets() { // fullscreen task doesn't use bounds for computeFrame final Task task = new TaskWithBounds(mStubStack, mWm, null); WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT); w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP; task.setWindowingMode(WINDOWING_MODE_FREEFORM); ((TaskWithBounds) task).mFullscreenForTest = false; w.setWindowingMode(WINDOWING_MODE_FREEFORM); DisplayContent dc = mWm.getDefaultDisplayContentLocked(); dc.mInputMethodTarget = w; WindowState mockIme = mock(WindowState.class); Mockito.doReturn(true).when(mockIme).isVisibleNow(); dc.mInputMethodWindow = mockIme; // With no insets or system decor all the frames incoming from PhoneWindowManager // are identical. final Rect pf = new Rect(0, 0, 1000, 800); final Rect df = pf; final Rect of = df; final Rect cf = new Rect(pf); cf.bottom -= 400; final Rect vf = new Rect(cf); final Rect sf = new Rect(pf); final Rect dcf = pf; // First check that it only gets moved up enough to show window. final Rect winRect = new Rect(200, 200, 300, 500); task.setBounds(winRect); w.setBounds(winRect); w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect); w.computeFrameLw(); final Rect expected = new Rect(winRect.left, cf.bottom - winRect.height(), winRect.right, cf.bottom); assertEquals(expected, w.getFrameLw()); assertEquals(expected, w.getContentFrameLw()); assertEquals(expected, w.getVisibleFrameLw()); // Now check that it won't get moved beyond the top and then has appropriate insets winRect.bottom = 600; task.setBounds(winRect); w.setBounds(winRect); w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect); w.computeFrameLw(); assertFrame(w, winRect.left, 0, winRect.right, winRect.height()); expected.top = 0; expected.bottom = cf.bottom; assertContentFrame(w, expected); assertVisibleFrame(w, expected); // Check that it's moved back without ime insets w.getWindowFrames().setFrames(pf, df, of, pf, pf, dcf, sf, mEmptyRect); w.computeFrameLw(); assertEquals(winRect, w.getFrameLw()); } private WindowStateWithTask createWindow(Task task, int width, int height) { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); attrs.width = width; Loading