From 501ee91b957eab6feb05832168573f51573efced Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 26 Jan 2022 10:49:18 -0800 Subject: Reland "SurfaceControlViewHost: Restrict disclosure of input token"" The original CL only updated one of the two implementations of grantEmbeddedWindowFocus, and for as of yet unknown reasons presubmit did not detect the failure until after it landed. Bug: 215912712 Test: SurfaceControlViewHostTests Change-Id: Ie278f678f12f50c32f142a4260ff7d1c2a9ca57c --- core/java/android/view/IWindowSession.aidl | 2 +- core/java/android/view/SurfaceControlViewHost.java | 2 +- .../java/android/view/WindowlessWindowManager.java | 12 +++++-- .../server/wm/EmbeddedWindowController.java | 39 ++++++++++++++++++---- .../core/java/com/android/server/wm/Session.java | 4 +-- .../android/server/wm/WindowManagerService.java | 22 +++++++----- 6 files changed, 60 insertions(+), 21 deletions(-) diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index ccf1e44f8b6d..32054b1cdc13 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -298,7 +298,7 @@ interface IWindowSession { */ void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window, in IBinder hostInputToken, int flags, int privateFlags, int type, - out InputChannel outInputChannel); + in IBinder focusGrantToken, out InputChannel outInputChannel); /** * Update the flags on an input channel associated with a particular surface. diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 85a9dbd736ed..22baa692428a 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -274,7 +274,7 @@ public class SurfaceControlViewHost { public @Nullable SurfacePackage getSurfacePackage() { if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) { return new SurfacePackage(mSurfaceControl, mAccessibilityEmbeddedConnection, - mViewRoot.getInputToken(), mRemoteInterface); + mWm.getFocusGrantToken(), mRemoteInterface); } else { return null; } diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 3392edce479d..5ec9654d5b1c 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -21,6 +21,7 @@ import android.content.res.Configuration; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; +import android.os.Binder; import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; @@ -75,6 +76,7 @@ public class WindowlessWindowManager implements IWindowSession { private final Configuration mConfiguration; private final IWindowSession mRealWm; private final IBinder mHostInputToken; + private final IBinder mFocusGrantToken = new Binder(); private int mForceHeight = -1; private int mForceWidth = -1; @@ -91,6 +93,10 @@ public class WindowlessWindowManager implements IWindowSession { mConfiguration.setTo(configuration); } + IBinder getFocusGrantToken() { + return mFocusGrantToken; + } + /** * Utility API. */ @@ -153,10 +159,10 @@ public class WindowlessWindowManager implements IWindowSession { mRealWm.grantInputChannel(displayId, new SurfaceControl(sc, "WindowlessWindowManager.addToDisplay"), window, mHostInputToken, attrs.flags, attrs.privateFlags, attrs.type, - outInputChannel); + mFocusGrantToken, outInputChannel); } else { mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags, - attrs.privateFlags, attrs.type, outInputChannel); + attrs.privateFlags, attrs.type, mFocusGrantToken, outInputChannel); } } catch (RemoteException e) { Log.e(TAG, "Failed to grant input to surface: ", e); @@ -469,7 +475,7 @@ public class WindowlessWindowManager implements IWindowSession { @Override public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window, - IBinder hostInputToken, int flags, int privateFlags, int type, + IBinder hostInputToken, int flags, int privateFlags, int type, IBinder focusGrantToken, InputChannel outInputChannel) { } diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java index 0e2d84779602..8db43066eae5 100644 --- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java +++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java @@ -41,6 +41,8 @@ class EmbeddedWindowController { private static final String TAG = TAG_WITH_CLASS_NAME ? "EmbeddedWindowController" : TAG_WM; /* maps input token to an embedded window */ private ArrayMap mWindows = new ArrayMap<>(); + private ArrayMap mWindowsByFocusToken = + new ArrayMap<>(); private final Object mGlobalLock; private final ActivityTaskManagerService mAtmService; @@ -59,10 +61,13 @@ class EmbeddedWindowController { void add(IBinder inputToken, EmbeddedWindow window) { try { mWindows.put(inputToken, window); + final IBinder focusToken = window.getFocusGrantToken(); + mWindowsByFocusToken.put(focusToken, window); updateProcessController(window); window.mClient.asBinder().linkToDeath(()-> { synchronized (mGlobalLock) { mWindows.remove(inputToken); + mWindowsByFocusToken.remove(focusToken); } }, 0); } catch (RemoteException e) { @@ -98,8 +103,8 @@ class EmbeddedWindowController { return embeddedWindow != null ? embeddedWindow.getIsOverlay() : false; } - void setIsOverlay(IBinder inputToken) { - EmbeddedWindow embeddedWindow = mWindows.get(inputToken); + void setIsOverlay(IBinder focusGrantToken) { + EmbeddedWindow embeddedWindow = mWindowsByFocusToken.get(focusGrantToken); if (embeddedWindow != null) { embeddedWindow.setIsOverlay(); } @@ -107,8 +112,10 @@ class EmbeddedWindowController { void remove(IWindow client) { for (int i = mWindows.size() - 1; i >= 0; i--) { - if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) { + EmbeddedWindow ew = mWindows.valueAt(i); + if (ew.mClient.asBinder() == client.asBinder()) { mWindows.removeAt(i).onRemoved(); + mWindowsByFocusToken.remove(ew.getFocusGrantToken()); return; } } @@ -116,8 +123,10 @@ class EmbeddedWindowController { void onWindowRemoved(WindowState host) { for (int i = mWindows.size() - 1; i >= 0; i--) { - if (mWindows.valueAt(i).mHostWindowState == host) { + EmbeddedWindow ew = mWindows.valueAt(i); + if (ew.mHostWindowState == host) { mWindows.removeAt(i).onRemoved(); + mWindowsByFocusToken.remove(ew.getFocusGrantToken()); } } } @@ -126,6 +135,10 @@ class EmbeddedWindowController { return mWindows.get(inputToken); } + EmbeddedWindow getByFocusToken(IBinder focusGrantToken) { + return mWindowsByFocusToken.get(focusGrantToken); + } + void onActivityRemoved(ActivityRecord activityRecord) { for (int i = mWindows.size() - 1; i >= 0; i--) { final EmbeddedWindow window = mWindows.valueAt(i); @@ -157,6 +170,8 @@ class EmbeddedWindowController { // and this variable is mostly used for tracking that. boolean mIsOverlay = false; + private IBinder mFocusGrantToken; + /** * @param session calling session to check ownership of the window * @param clientToken client token used to clean up the map if the embedding process dies @@ -171,7 +186,7 @@ class EmbeddedWindowController { */ EmbeddedWindow(Session session, WindowManagerService service, IWindow clientToken, WindowState hostWindowState, int ownerUid, int ownerPid, int windowType, - int displayId) { + int displayId, IBinder focusGrantToken) { mSession = session; mWmService = service; mClient = clientToken; @@ -182,6 +197,7 @@ class EmbeddedWindowController { mOwnerPid = ownerPid; mWindowType = windowType; mDisplayId = displayId; + mFocusGrantToken = focusGrantToken; } @Override @@ -242,6 +258,17 @@ class EmbeddedWindowController { return mIsOverlay; } + IBinder getFocusGrantToken() { + return mFocusGrantToken; + } + + IBinder getInputChannelToken() { + if (mInputChannel != null) { + return mInputChannel.getToken(); + } + return null; + } + /** * System hosted overlays need the WM to invoke grantEmbeddedWindowFocus and * so we need to participate inside handlePointerDownOutsideFocus logic @@ -255,7 +282,7 @@ class EmbeddedWindowController { private void handleTap(boolean grantFocus) { if (mInputChannel != null) { - mWmService.grantEmbeddedWindowFocus(mSession, mInputChannel.getToken(), grantFocus); + mWmService.grantEmbeddedWindowFocus(mSession, mFocusGrantToken, grantFocus); } } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 9b94f44be714..98acc4607d18 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -813,7 +813,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type, - InputChannel outInputChannel) { + IBinder focusGrantToken, InputChannel outInputChannel) { if (hostInputToken == null && !mCanAddInternalSystemWindow) { // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to // embedded windows without providing a host window input token @@ -829,7 +829,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { try { mService.grantInputChannel(this, mUid, mPid, displayId, surface, window, hostInputToken, flags, mCanAddInternalSystemWindow ? privateFlags : 0, - mCanAddInternalSystemWindow ? type : 0, outInputChannel); + mCanAddInternalSystemWindow ? type : 0, focusGrantToken, outInputChannel); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index eb1274c18147..db022161e2c3 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -8276,7 +8276,8 @@ public class WindowManagerService extends IWindowManager.Stub */ void grantInputChannel(Session session, int callingUid, int callingPid, int displayId, SurfaceControl surface, IWindow window, IBinder hostInputToken, - int flags, int privateFlags, int type, InputChannel outInputChannel) { + int flags, int privateFlags, int type, IBinder focusGrantToken, + InputChannel outInputChannel) { final InputApplicationHandle applicationHandle; final String name; final InputChannel clientChannel; @@ -8284,7 +8285,7 @@ public class WindowManagerService extends IWindowManager.Stub EmbeddedWindowController.EmbeddedWindow win = new EmbeddedWindowController.EmbeddedWindow(session, this, window, mInputToWindowMap.get(hostInputToken), callingUid, callingPid, type, - displayId); + displayId, focusGrantToken); clientChannel = win.openInputChannel(); mEmbeddedWindowController.add(clientChannel.getToken(), win); applicationHandle = win.getApplicationHandle(); @@ -8563,10 +8564,10 @@ public class WindowManagerService extends IWindowManager.Stub } } - void grantEmbeddedWindowFocus(Session session, IBinder inputToken, boolean grantFocus) { + void grantEmbeddedWindowFocus(Session session, IBinder focusToken, boolean grantFocus) { synchronized (mGlobalLock) { final EmbeddedWindowController.EmbeddedWindow embeddedWindow = - mEmbeddedWindowController.get(inputToken); + mEmbeddedWindowController.getByFocusToken(focusToken); if (embeddedWindow == null) { Slog.e(TAG, "Embedded window not found"); return; @@ -8575,6 +8576,11 @@ public class WindowManagerService extends IWindowManager.Stub Slog.e(TAG, "Window not in session:" + session); return; } + IBinder inputToken = embeddedWindow.getInputChannelToken(); + if (inputToken == null) { + Slog.e(TAG, "Focus token found but input channel token not found"); + return; + } SurfaceControl.Transaction t = mTransactionFactory.get(); final int displayId = embeddedWindow.mDisplayId; if (grantFocus) { @@ -8604,7 +8610,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - void grantEmbeddedWindowFocus(Session session, IWindow callingWindow, IBinder targetInputToken, + void grantEmbeddedWindowFocus(Session session, IWindow callingWindow, IBinder targetFocusToken, boolean grantFocus) { synchronized (mGlobalLock) { final WindowState hostWindow = @@ -8618,7 +8624,7 @@ public class WindowManagerService extends IWindowManager.Stub return; } final EmbeddedWindowController.EmbeddedWindow embeddedWindow = - mEmbeddedWindowController.get(targetInputToken); + mEmbeddedWindowController.getByFocusToken(targetFocusToken); if (embeddedWindow == null) { Slog.e(TAG, "Embedded window not found"); return; @@ -8629,7 +8635,7 @@ public class WindowManagerService extends IWindowManager.Stub } SurfaceControl.Transaction t = mTransactionFactory.get(); if (grantFocus) { - t.requestFocusTransfer(targetInputToken, embeddedWindow.toString(), + t.requestFocusTransfer(embeddedWindow.getInputChannelToken(), embeddedWindow.toString(), hostWindow.mInputChannel.getToken(), hostWindow.getName(), hostWindow.getDisplayId()).apply(); @@ -8638,7 +8644,7 @@ public class WindowManagerService extends IWindowManager.Stub "reason=grantEmbeddedWindowFocus(true)"); } else { t.requestFocusTransfer(hostWindow.mInputChannel.getToken(), hostWindow.getName(), - targetInputToken, + embeddedWindow.getInputChannelToken(), embeddedWindow.toString(), hostWindow.getDisplayId()).apply(); EventLog.writeEvent(LOGTAG_INPUT_FOCUS, -- cgit v1.2.3-59-g8ed1b From b41528c5b3c24963e9608763d1bee8de18c07168 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 18 Jan 2022 19:57:52 -0800 Subject: WM/SurfacePackage: Forward insets to WindowContainer overlays We add support for forwarding InsetsState over SurfacePackage to reach embedded ViewRootImpl. As a next step we hook up forwarding of insets from the main visible window of a task with overlays, to said overlays. We provide a frame so that the remote ViewRootImpl can interpret the insets relative to this frame. In the TaskOverlay case everything in the remote SurfaceControlViewHost is in a world relative to the task bounds, and so we send the task bounds. Transient insets are also forwarded via this channel. This is due to the specific requirements of game service overlay, but seems to make sense in general for overlays, who will need to be able to intelligently handle immersive mode. Bug: 213603716 Bug: 214239892 Test: SurfaceControlWindowInsetsTest Change-Id: I22e22050a5dec71d8120ef4fea4a1c9bc452e02f --- .../java/android/view/ISurfaceControlViewHost.aidl | 3 + core/java/android/view/SurfaceControlViewHost.java | 12 ++ core/java/android/view/ViewRootImpl.java | 18 ++- .../java/android/view/WindowlessWindowManager.java | 24 +++- .../view/SurfaceControlViewHostInsetsTest.java | 122 +++++++++++++++++++++ .../java/com/android/server/wm/InsetsPolicy.java | 14 ++- .../java/com/android/server/wm/OverlayHost.java | 12 ++ services/core/java/com/android/server/wm/Task.java | 14 +++ .../com/android/server/wm/WindowContainer.java | 10 +- .../android/server/wm/WindowManagerInternal.java | 7 +- .../java/com/android/server/wm/WindowState.java | 4 + 11 files changed, 233 insertions(+), 7 deletions(-) create mode 100644 core/tests/coretests/src/android/view/SurfaceControlViewHostInsetsTest.java diff --git a/core/java/android/view/ISurfaceControlViewHost.aidl b/core/java/android/view/ISurfaceControlViewHost.aidl index fc9661a0e61a..bf72a307220d 100644 --- a/core/java/android/view/ISurfaceControlViewHost.aidl +++ b/core/java/android/view/ISurfaceControlViewHost.aidl @@ -17,6 +17,8 @@ package android.view; import android.content.res.Configuration; +import android.graphics.Rect; +import android.view.InsetsState; /** * API from content embedder back to embedded content in SurfaceControlViewHost @@ -25,4 +27,5 @@ import android.content.res.Configuration; oneway interface ISurfaceControlViewHost { void onConfigurationChanged(in Configuration newConfig); void onDispatchDetachedFromWindow(); + void onInsetsChanged(in InsetsState state, in Rect insetFrame); } diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index 22baa692428a..b461faf70296 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -22,10 +22,12 @@ import android.annotation.TestApi; import android.content.Context; import android.content.res.Configuration; import android.graphics.PixelFormat; +import android.graphics.Rect; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.view.accessibility.IAccessibilityEmbeddedConnection; +import android.view.InsetsState; import java.util.Objects; @@ -71,6 +73,16 @@ public class SurfaceControlViewHost { release(); }); } + + @Override + public void onInsetsChanged(InsetsState state, Rect frame) { + if (mViewRoot != null) { + mViewRoot.mHandler.post(() -> { + mViewRoot.setOverrideInsetsFrame(frame); + }); + } + mWm.setInsetsState(state); + } } private ISurfaceControlViewHost mRemoteInterface = new ISurfaceControlViewHostImpl(); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 1496a4a7c6b3..eaa12e53c321 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -643,6 +643,7 @@ public final class ViewRootImpl implements ViewParent, // These are accessed by multiple threads. final Rect mWinFrame; // frame given by window manager. + Rect mOverrideInsetsFrame; final Rect mPendingBackDropFrame = new Rect(); @@ -8069,7 +8070,22 @@ public final class ViewRootImpl implements ViewParent, private void setFrame(Rect frame) { mWinFrame.set(frame); - mInsetsController.onFrameChanged(frame); + mInsetsController.onFrameChanged(mOverrideInsetsFrame != null ? + mOverrideInsetsFrame : frame); + } + + /** + * In the normal course of operations we compute insets relative to + * the frame returned from relayout window. In the case of + * SurfaceControlViewHost, this frame is in local coordinates + * instead of global coordinates. We support this override + * frame so we can allow SurfaceControlViewHost to set a frame + * to be used to calculate insets, without disturbing the main + * mFrame. + */ + void setOverrideInsetsFrame(Rect frame) { + mOverrideInsetsFrame = new Rect(frame); + mInsetsController.onFrameChanged(mOverrideInsetsFrame); } /** diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 5ec9654d5b1c..56f0915b785e 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -27,6 +27,8 @@ import android.os.RemoteCallback; import android.os.RemoteException; import android.util.Log; import android.util.MergedConfiguration; +import android.view.InsetsState; +import android.view.IWindow; import android.window.ClientWindowFrames; import android.window.IOnBackInvokedCallback; @@ -49,12 +51,14 @@ public class WindowlessWindowManager implements IWindowSession { int mDisplayId; IBinder mInputChannelToken; Region mInputRegion; + IWindow mClient; State(SurfaceControl sc, WindowManager.LayoutParams p, int displayId, - IBinder inputChannelToken) { + IBinder inputChannelToken, IWindow client) { mSurfaceControl = sc; mParams.copyFrom(p); mDisplayId = displayId; mInputChannelToken = inputChannelToken; + mClient = client; } }; @@ -77,6 +81,7 @@ public class WindowlessWindowManager implements IWindowSession { private final IWindowSession mRealWm; private final IBinder mHostInputToken; private final IBinder mFocusGrantToken = new Binder(); + private InsetsState mInsetsState; private int mForceHeight = -1; private int mForceWidth = -1; @@ -170,7 +175,7 @@ public class WindowlessWindowManager implements IWindowSession { } final State state = new State(sc, attrs, displayId, - outInputChannel != null ? outInputChannel.getToken() : null); + outInputChannel != null ? outInputChannel.getToken() : null, window); synchronized (this) { mStateForWindow.put(window.asBinder(), state); } @@ -318,6 +323,10 @@ public class WindowlessWindowManager implements IWindowSession { } } + if (mInsetsState != null) { + outInsetsState.set(mInsetsState); + } + // Include whether the window is in touch mode. return isInTouchMode() ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0; } @@ -507,4 +516,15 @@ public class WindowlessWindowManager implements IWindowSession { public boolean dropForAccessibility(IWindow window, int x, int y) { return false; } + + public void setInsetsState(InsetsState state) { + mInsetsState = state; + for (State s : mStateForWindow.values()) { + try { + s.mClient.insetsChanged(state, false, false); + } catch (RemoteException e) { + // Too bad + } + } + } } diff --git a/core/tests/coretests/src/android/view/SurfaceControlViewHostInsetsTest.java b/core/tests/coretests/src/android/view/SurfaceControlViewHostInsetsTest.java new file mode 100644 index 000000000000..4731e8172dca --- /dev/null +++ b/core/tests/coretests/src/android/view/SurfaceControlViewHostInsetsTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2022 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 android.view; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import static android.view.InsetsState.ITYPE_STATUS_BAR; + +import android.app.Instrumentation; +import android.content.Context; +import android.graphics.Insets; +import android.graphics.Point; +import android.graphics.Rect; +import android.os.Binder; +import android.platform.test.annotations.Presubmit; +import android.view.InsetsState.InternalInsetsType; +import android.view.SurfaceControlViewHost; +import android.view.View; +import android.view.WindowInsets; +import android.view.WindowInsets.Type; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +@Presubmit +@RunWith(AndroidJUnit4.class) +public class SurfaceControlViewHostInsetsTest { + SurfaceControlViewHost mSurfaceControlViewHost; + private boolean mStatusBarIsVisible = false; + private Insets mStatusBarInsets; + private Instrumentation mInstrumentation; + + private void createViewHierarchy() { + Context context = mInstrumentation.getTargetContext(); + + View v = new View(context); + v.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { + public WindowInsets onApplyWindowInsets(View v, WindowInsets w) { + mStatusBarIsVisible = w.isVisible(WindowInsets.Type.statusBars()); + mStatusBarInsets = w.getInsets(WindowInsets.Type.statusBars()); + return w; + } + }); + mSurfaceControlViewHost = new SurfaceControlViewHost(context, + context.getDisplayNoVerify(), new Binder()); + mSurfaceControlViewHost.setView(v, 100, 100); + } + + @Before + public void setup() { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mInstrumentation.runOnMainSync(() -> { createViewHierarchy(); }); + mInstrumentation.waitForIdleSync(); + } + + private InsetsState statusBarState(boolean visible) { + final InsetsState insetsState = new InsetsState(); + insetsState.setDisplayFrame(new Rect(0, 0, 1000, 1000)); + insetsState.getSource(ITYPE_STATUS_BAR).setVisible(visible); + insetsState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 10)); + return insetsState; + } + + private InsetsState statusBarVisibleState() { + return statusBarState(true); + } + + private void sendInsetsSync(InsetsState s, Rect f) { + try { + mSurfaceControlViewHost.getSurfacePackage().getRemoteInterface() + .onInsetsChanged(s, f); + } catch (Exception e) { + } + mInstrumentation.waitForIdleSync(); + } + + @Test + public void sendInsetsToSurfaceControlViewHost() { + final InsetsState insetsState = statusBarVisibleState(); + sendInsetsSync(insetsState, new Rect(0, 0, 100, 100)); + assertTrue(mStatusBarIsVisible); + + final InsetsState insetsState2 = statusBarState(false); + sendInsetsSync(insetsState2, new Rect(0, 0, 100, 100)); + assertFalse(mStatusBarIsVisible); + } + + @Test + public void insetsAreRelativeToFrame() { + final InsetsState insetsState = statusBarVisibleState(); + sendInsetsSync(insetsState, new Rect(0, 0, 100, 100)); + + assertTrue(mStatusBarIsVisible); + assertEquals(10, mStatusBarInsets.top); + + sendInsetsSync(insetsState, new Rect(0, 5, 100, 100)); + assertEquals(5, mStatusBarInsets.top); + } +} diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 9326a2ebb331..10776abee51e 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -219,13 +219,23 @@ class InsetsPolicy { /** * @see InsetsStateController#getInsetsForWindow */ - InsetsState getInsetsForWindow(WindowState target) { + InsetsState getInsetsForWindow(WindowState target, boolean includesTransient) { final InsetsState originalState = mStateController.getInsetsForWindow(target); - InsetsState state = adjustVisibilityForTransientTypes(originalState); + InsetsState state; + if (!includesTransient) { + state = adjustVisibilityForTransientTypes(originalState); + } else { + state = originalState; + } state = adjustVisibilityForIme(target, state, state == originalState); return adjustInsetsForRoundedCorners(target, state, state == originalState); } + InsetsState getInsetsForWindow(WindowState target) { + return getInsetsForWindow(target, false); + } + + /** * @see InsetsStateController#getInsetsForWindowMetrics */ diff --git a/services/core/java/com/android/server/wm/OverlayHost.java b/services/core/java/com/android/server/wm/OverlayHost.java index 724e1247b100..90f5b09968ea 100644 --- a/services/core/java/com/android/server/wm/OverlayHost.java +++ b/services/core/java/com/android/server/wm/OverlayHost.java @@ -17,6 +17,8 @@ package com.android.server.wm; import android.content.res.Configuration; +import android.graphics.Rect; +import android.view.InsetsState; import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; @@ -121,6 +123,16 @@ class OverlayHost { } } + void dispatchInsetsChanged(InsetsState s, Rect insetFrame) { + for (int i = mOverlays.size() - 1; i >= 0; i--) { + SurfaceControlViewHost.SurfacePackage l = mOverlays.get(i); + try { + l.getRemoteInterface().onInsetsChanged(s, insetFrame); + } catch (Exception e) { + } + } + } + void release() { dispatchDetachedFromWindow(); mOverlays.clear(); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 91c13746f726..7d06526e18b5 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -6588,4 +6588,18 @@ class Task extends TaskFragment { mLaunchCookie, mDeferTaskAppear, mRemoveWithTaskOrganizer); } } + + @Override + void updateOverlayInsetsState(WindowState originalChange) { + super.updateOverlayInsetsState(originalChange); + if (originalChange != getTopVisibleAppMainWindow()) { + return; + } + if (mOverlayHost != null) { + final InsetsState s = getDisplayContent().getInsetsPolicy() + .getInsetsForWindow(originalChange, true); + getBounds(mTmpRect); + mOverlayHost.dispatchInsetsChanged(s, mTmpRect); + } + } } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 11d19839d401..98ecd0ae0b61 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -81,6 +81,7 @@ import android.util.Pools; import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; +import android.view.InsetsState; import android.view.MagnificationSpec; import android.view.RemoteAnimationDefinition; import android.view.RemoteAnimationTarget; @@ -313,7 +314,7 @@ class WindowContainer extends ConfigurationContainer< private final List mListeners = new ArrayList<>(); - private OverlayHost mOverlayHost; + protected OverlayHost mOverlayHost; WindowContainer(WindowManagerService wms) { mWmService = wms; @@ -3612,4 +3613,11 @@ class WindowContainer extends ConfigurationContainer< mOverlayHost = null; } } + + void updateOverlayInsetsState(WindowState originalChange) { + final WindowContainer p = getParent(); + if (p != null) { + p.updateOverlayInsetsState(originalChange); + } + } } diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index b9fa29733aa6..7e901e33a71e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -796,7 +796,12 @@ public abstract class WindowManagerInternal { * Callers prepare a view hierarchy with SurfaceControlViewHost * and send the package to WM here. The remote view hierarchy will receive * configuration change, lifecycle events, etc, forwarded over the - * ISurfaceControlViewHost interface inside the SurfacePackage. + * ISurfaceControlViewHost interface inside the SurfacePackage. Embedded + * hierarchies will receive inset changes, including transient inset changes + * (to avoid the status bar in immersive mode). + * + * The embedded hierarchy exists in a coordinate space relative to the task + * bounds. */ public abstract void addTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay); public abstract void removeTaskOverlay(int taskId, SurfaceControlViewHost.SurfacePackage overlay); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 8864b9847ff8..0a02b4442518 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3848,6 +3848,10 @@ class WindowState extends WindowContainer implements WindowManagerP } catch (RemoteException e) { Slog.w(TAG, "Failed to deliver inset state change w=" + this, e); } + final WindowContainer p = getParent(); + if (p != null) { + p.updateOverlayInsetsState(this); + } } @Override -- cgit v1.2.3-59-g8ed1b