summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java2
-rw-r--r--services/core/java/com/android/server/wm/BarController.java5
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java11
-rw-r--r--services/core/java/com/android/server/wm/InsetsControlTarget.java24
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java103
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java22
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java104
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java168
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java61
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java2
-rw-r--r--tests/utils/testutils/java/android/view/test/InsetsModeSession.java2
13 files changed, 417 insertions, 99 deletions
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index bdd3038cfee5..be2c4e96fdd7 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -86,7 +86,7 @@ public class InsetsAnimationControlImplTest {
}
@AfterClass
- public static void tearDownOnce() throws Exception {
+ public static void tearDownOnce() {
sInsetsModeSession.close();
}
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 90bb494232c7..5c4332dc8a6a 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -27,6 +27,7 @@ import android.os.SystemClock;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.View;
+import android.view.ViewRootImpl;
import android.view.WindowManager;
import com.android.server.LocalServices;
@@ -89,6 +90,10 @@ public class BarController {
}
void setWindow(WindowState win) {
+ if (ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL) {
+ // BarController gets replaced with InsetsPolicy in the full insets mode.
+ return;
+ }
mWin = win;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 126765221c51..5ec167e495e0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -549,6 +549,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private final PointerEventDispatcher mPointerEventDispatcher;
private final InsetsStateController mInsetsStateController;
+ private final InsetsPolicy mInsetsPolicy;
/** @see #getParentWindow() */
private WindowState mParentWindow;
@@ -968,6 +969,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
mWmService.mAnimator.addDisplayLocked(mDisplayId);
mInputMonitor = new InputMonitor(service, mDisplayId);
mInsetsStateController = new InsetsStateController(this);
+ mInsetsPolicy = new InsetsPolicy(mInsetsStateController, this);
}
boolean isReady() {
@@ -1126,6 +1128,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
return mInsetsStateController;
}
+ InsetsPolicy getInsetsPolicy() {
+ return mInsetsPolicy;
+ }
+
@Surface.Rotation
int getRotation() {
return mDisplayRotation.getRotation();
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 8328770b6cb2..aecbca391735 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1029,6 +1029,14 @@ public class DisplayPolicy {
displayFrames.mDisplayCutoutSafe.top);
}
+ WindowState getStatusBar() {
+ return mStatusBar;
+ }
+
+ WindowState getNavigationBar() {
+ return mNavigationBar;
+ }
+
/**
* Control the animation to run when a window's state changes. Return a
* non-0 number to force the animation to a specific resource ID, or 0
@@ -3108,8 +3116,7 @@ public class DisplayPolicy {
return 0;
}
- mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(
- mTopFullscreenOpaqueWindowState);
+ mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
& ~mResettingSystemUiFlags
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
new file mode 100644
index 000000000000..3db6dcf07abf
--- /dev/null
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 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;
+
+/**
+ * Generalization of an object that can control insets state.
+ */
+interface InsetsControlTarget {
+ void notifyInsetsControlChanged();
+}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
new file mode 100644
index 000000000000..2dc50d86eaea
--- /dev/null
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 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.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+
+import android.annotation.Nullable;
+
+/**
+ * Policy that implements who gets control over the windows generating insets.
+ */
+class InsetsPolicy {
+
+ private final InsetsStateController mStateController;
+ private final DisplayContent mDisplayContent;
+ private final DisplayPolicy mPolicy;
+
+ InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
+ mStateController = stateController;
+ mDisplayContent = displayContent;
+ mPolicy = displayContent.getDisplayPolicy();
+ }
+
+ /** Updates the target which can control system bars. */
+ void updateBarControlTarget(@Nullable WindowState focusedWin) {
+ mStateController.onBarControlTargetChanged(getTopControlTarget(focusedWin),
+ getNavControlTarget(focusedWin));
+ }
+
+ private @Nullable InsetsControlTarget getTopControlTarget(@Nullable WindowState focusedWin) {
+ if (areSystemBarsForciblyVisible() || isStatusBarForciblyVisible()) {
+ return null;
+ }
+ return focusedWin;
+ }
+
+ private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin) {
+ if (areSystemBarsForciblyVisible() || isNavBarForciblyVisible()) {
+ return null;
+ }
+ return focusedWin;
+ }
+
+ private boolean isStatusBarForciblyVisible() {
+ final WindowState statusBar = mPolicy.getStatusBar();
+ if (statusBar == null) {
+ return false;
+ }
+ final int privateFlags = statusBar.mAttrs.privateFlags;
+
+ // TODO: Pretend to the app that it's still able to control it?
+ if ((privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
+ return true;
+ }
+ if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isNavBarForciblyVisible() {
+ final WindowState statusBar = mPolicy.getStatusBar();
+ if (statusBar == null) {
+ return false;
+ }
+ if ((statusBar.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean areSystemBarsForciblyVisible() {
+ final boolean isDockedStackVisible =
+ mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ final boolean isFreeformStackVisible =
+ mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
+ final boolean isResizing = mDisplayContent.getDockedDividerController().isResizing();
+
+ // We need to force system bars when the docked stack is visible, when the freeform stack
+ // is visible but also when we are resizing for the transitions when docked stack
+ // visibility changes.
+ return isDockedStackVisible || isFreeformStackVisible || isResizing;
+ }
+
+}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index b7835aa1c04e..1b7b92bca250 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -52,7 +52,7 @@ class InsetsSourceProvider {
private final DisplayContent mDisplayContent;
private final InsetsStateController mStateController;
private @Nullable InsetsSourceControl mControl;
- private @Nullable WindowState mControllingWin;
+ private @Nullable InsetsControlTarget mControlTarget;
private @Nullable ControlAdapter mAdapter;
private WindowState mWin;
private TriConsumer<DisplayFrames, WindowState, Rect> mFrameProvider;
@@ -119,8 +119,8 @@ class InsetsSourceProvider {
mSource.setFrame(new Rect());
} else {
mWin.setInsetProvider(this);
- if (mControllingWin != null) {
- updateControlForTarget(mControllingWin, true /* force */);
+ if (mControlTarget != null) {
+ updateControlForTarget(mControlTarget, true /* force */);
}
}
}
@@ -143,19 +143,19 @@ class InsetsSourceProvider {
if (mControl != null) {
final Rect frame = mWin.getWindowFrames().mFrame;
if (mControl.setSurfacePosition(frame.left, frame.top)) {
- mStateController.notifyControlChanged(mControllingWin);
+ mStateController.notifyControlChanged(mControlTarget);
}
}
setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy()
&& !mWin.mGivenInsetsPending);
}
- void updateControlForTarget(@Nullable WindowState target, boolean force) {
+ void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) {
if (mWin == null) {
- mControllingWin = target;
+ mControlTarget = target;
return;
}
- if (target == mControllingWin && !force) {
+ if (target == mControlTarget && !force) {
return;
}
if (target == null) {
@@ -167,13 +167,13 @@ class InsetsSourceProvider {
setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
mWin.startAnimation(mDisplayContent.getPendingTransaction(), mAdapter,
!mClientVisible /* hidden */);
- mControllingWin = target;
+ mControlTarget = target;
mControl = new InsetsSourceControl(mSource.getType(), mAdapter.mCapturedLeash,
new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top));
}
boolean onInsetsModified(WindowState caller, InsetsSource modifiedSource) {
- if (mControllingWin != caller || modifiedSource.isVisible() == mClientVisible) {
+ if (mControlTarget != caller || modifiedSource.isVisible() == mClientVisible) {
return false;
}
setClientVisible(modifiedSource.isVisible());
@@ -232,10 +232,10 @@ class InsetsSourceProvider {
@Override
public void onAnimationCancelled(SurfaceControl animationLeash) {
if (mAdapter == this) {
- mStateController.notifyControlRevoked(mControllingWin, InsetsSourceProvider.this);
+ mStateController.notifyControlRevoked(mControlTarget, InsetsSourceProvider.this);
setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
mControl = null;
- mControllingWin = null;
+ mControlTarget = null;
mAdapter = null;
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a1b52f424fee..bb704957a55a 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -16,12 +16,10 @@
package com.android.server.wm;
+import static android.view.InsetsState.InternalInsetType;
import static android.view.InsetsState.TYPE_IME;
import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
import static android.view.InsetsState.TYPE_TOP_BAR;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
-import static android.view.ViewRootImpl.sNewInsetsMode;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,7 +29,6 @@ import android.util.SparseArray;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
-import android.view.ViewRootImpl;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -46,10 +43,11 @@ class InsetsStateController {
private final InsetsState mState = new InsetsState();
private final DisplayContent mDisplayContent;
- private final ArrayMap<Integer, InsetsSourceProvider> mControllers = new ArrayMap<>();
- private final ArrayMap<WindowState, ArrayList<Integer>> mWinControlTypeMap = new ArrayMap<>();
- private final SparseArray<WindowState> mTypeWinControlMap = new SparseArray<>();
- private final ArraySet<WindowState> mPendingControlChanged = new ArraySet<>();
+ private final ArrayMap<Integer, InsetsSourceProvider> mProviders = new ArrayMap<>();
+ private final ArrayMap<InsetsControlTarget, ArrayList<Integer>> mControlTargetTypeMap =
+ new ArrayMap<>();
+ private final SparseArray<InsetsControlTarget> mTypeControlTargetMap = new SparseArray<>();
+ private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>();
private final Consumer<WindowState> mDispatchInsetsChanged = w -> {
if (w.isVisible()) {
@@ -87,15 +85,15 @@ class InsetsStateController {
return state;
}
- @Nullable InsetsSourceControl[] getControlsForDispatch(WindowState target) {
- ArrayList<Integer> controlled = mWinControlTypeMap.get(target);
+ @Nullable InsetsSourceControl[] getControlsForDispatch(InsetsControlTarget target) {
+ ArrayList<Integer> controlled = mControlTargetTypeMap.get(target);
if (controlled == null) {
return null;
}
final int size = controlled.size();
final InsetsSourceControl[] result = new InsetsSourceControl[size];
for (int i = 0; i < size; i++) {
- result[i] = mControllers.get(controlled.get(i)).getControl();
+ result[i] = mProviders.get(controlled.get(i)).getControl();
}
return result;
}
@@ -103,8 +101,8 @@ class InsetsStateController {
/**
* @return The provider of a specific type.
*/
- InsetsSourceProvider getSourceProvider(int type) {
- return mControllers.computeIfAbsent(type,
+ InsetsSourceProvider getSourceProvider(@InternalInsetType int type) {
+ return mProviders.computeIfAbsent(type,
key -> new InsetsSourceProvider(mState.getSource(key), this, mDisplayContent));
}
@@ -113,8 +111,8 @@ class InsetsStateController {
*/
void onPostLayout() {
mState.setDisplayFrame(mDisplayContent.getBounds());
- for (int i = mControllers.size() - 1; i>= 0; i--) {
- mControllers.valueAt(i).onPostLayout();
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ mProviders.valueAt(i).onPostLayout();
}
if (!mLastState.equals(mState)) {
mLastState.set(mState, true /* copySources */);
@@ -126,7 +124,7 @@ class InsetsStateController {
boolean changed = false;
for (int i = state.getSourcesCount() - 1; i >= 0; i--) {
final InsetsSource source = state.sourceAt(i);
- final InsetsSourceProvider provider = mControllers.get(source.getType());
+ final InsetsSourceProvider provider = mProviders.get(source.getType());
if (provider == null) {
continue;
}
@@ -137,75 +135,77 @@ class InsetsStateController {
}
}
- void onImeTargetChanged(@Nullable WindowState imeTarget) {
+ void onImeTargetChanged(@Nullable InsetsControlTarget imeTarget) {
onControlChanged(TYPE_IME, imeTarget);
notifyPendingInsetsControlChanged();
}
/**
- * Called when the top opaque fullscreen window that is able to control the system bars changes.
+ * Called when the focused window that is able to control the system bars changes.
*
- * @param controllingWindow The window that is now able to control the system bars appearance
- * and visibility.
+ * @param topControlling The target that is now able to control the top bar appearance
+ * and visibility.
+ * @param navControlling The target that is now able to control the nav bar appearance
+ * and visibility.
*/
- void onBarControllingWindowChanged(@Nullable WindowState controllingWindow) {
- // TODO: Apply policy that determines whether controllingWindow is able to control system
- // bars
-
- // TODO: Depending on the form factor, mapping is different
- onControlChanged(TYPE_TOP_BAR, controllingWindow);
- onControlChanged(TYPE_NAVIGATION_BAR, controllingWindow);
+ void onBarControlTargetChanged(@Nullable InsetsControlTarget topControlling,
+ @Nullable InsetsControlTarget navControlling) {
+ onControlChanged(TYPE_TOP_BAR, topControlling);
+ onControlChanged(TYPE_NAVIGATION_BAR, navControlling);
notifyPendingInsetsControlChanged();
}
- void notifyControlRevoked(@NonNull WindowState previousControllingWin,
+ void notifyControlRevoked(@NonNull InsetsControlTarget previousControlTarget,
InsetsSourceProvider provider) {
- removeFromControlMaps(previousControllingWin, provider.getSource().getType());
+ removeFromControlMaps(previousControlTarget, provider.getSource().getType());
}
- private void onControlChanged(int type, @Nullable WindowState win) {
- final WindowState previous = mTypeWinControlMap.get(type);
- if (win == previous) {
+ private void onControlChanged(@InternalInsetType int type,
+ @Nullable InsetsControlTarget target) {
+ final InsetsControlTarget previous = mTypeControlTargetMap.get(type);
+ if (target == previous) {
return;
}
- final InsetsSourceProvider controller = getSourceProvider(type);
- if (controller == null) {
+ final InsetsSourceProvider provider = getSourceProvider(type);
+ if (provider == null) {
return;
}
- if (!controller.isControllable()) {
+ if (!provider.isControllable()) {
return;
}
- controller.updateControlForTarget(win, false /* force */);
+ provider.updateControlForTarget(target, false /* force */);
if (previous != null) {
removeFromControlMaps(previous, type);
mPendingControlChanged.add(previous);
}
- if (win != null) {
- addToControlMaps(win, type);
- mPendingControlChanged.add(win);
+ if (target != null) {
+ addToControlMaps(target, type);
+ mPendingControlChanged.add(target);
}
}
- private void removeFromControlMaps(@NonNull WindowState win, int type) {
- final ArrayList<Integer> array = mWinControlTypeMap.get(win);
+ private void removeFromControlMaps(@NonNull InsetsControlTarget target,
+ @InternalInsetType int type) {
+ final ArrayList<Integer> array = mControlTargetTypeMap.get(target);
if (array == null) {
return;
}
array.remove((Integer) type);
if (array.isEmpty()) {
- mWinControlTypeMap.remove(win);
+ mControlTargetTypeMap.remove(target);
}
- mTypeWinControlMap.remove(type);
+ mTypeControlTargetMap.remove(type);
}
- private void addToControlMaps(@NonNull WindowState win, int type) {
- final ArrayList<Integer> array = mWinControlTypeMap.computeIfAbsent(win,
+ private void addToControlMaps(@NonNull InsetsControlTarget target,
+ @InternalInsetType int type) {
+ final ArrayList<Integer> array = mControlTargetTypeMap.computeIfAbsent(target,
key -> new ArrayList<>());
array.add(type);
- mTypeWinControlMap.put(type, win);
+ mTypeControlTargetMap.put(type, target);
}
- void notifyControlChanged(WindowState target) {
+ void notifyControlChanged(InsetsControlTarget target) {
mPendingControlChanged.add(target);
notifyPendingInsetsControlChanged();
}
@@ -216,8 +216,8 @@ class InsetsStateController {
}
mDisplayContent.mWmService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
for (int i = mPendingControlChanged.size() - 1; i >= 0; i--) {
- final WindowState controllingWin = mPendingControlChanged.valueAt(i);
- controllingWin.notifyInsetsControlChanged();
+ final InsetsControlTarget controlTarget = mPendingControlChanged.valueAt(i);
+ controlTarget.notifyInsetsControlChanged();
}
mPendingControlChanged.clear();
});
@@ -231,10 +231,10 @@ class InsetsStateController {
pw.println(prefix + "WindowInsetsStateController");
mState.dump(prefix + " ", pw);
pw.println(prefix + " " + "Control map:");
- for (int i = mTypeWinControlMap.size() - 1; i >= 0; i--) {
+ for (int i = mTypeControlTargetMap.size() - 1; i >= 0; i--) {
pw.print(prefix + " ");
- pw.println(InsetsState.typeToString(mTypeWinControlMap.keyAt(i)) + " -> "
- + mTypeWinControlMap.valueAt(i));
+ pw.println(InsetsState.typeToString(mTypeControlTargetMap.keyAt(i)) + " -> "
+ + mTypeControlTargetMap.valueAt(i));
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4900869f209d..cbb0b3aab687 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -217,7 +217,8 @@ import java.util.List;
import java.util.function.Predicate;
/** A window in the window manager. */
-class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {
+class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState,
+ InsetsControlTarget {
static final String TAG = TAG_WITH_CLASS_NAME ? "WindowState" : TAG_WM;
// The minimal size of a window within the usable area of the freeform stack.
@@ -3329,7 +3330,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- void notifyInsetsControlChanged() {
+ @Override
+ public void notifyInsetsControlChanged() {
final InsetsStateController stateController =
getDisplayContent().getInsetsStateController();
try {
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
new file mode 100644
index 000000000000..f3a8e1a0bd5e
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 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.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.platform.test.annotations.Presubmit;
+import android.view.InsetsSourceControl;
+import android.view.test.InsetsModeSession;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class InsetsPolicyTest extends WindowTestsBase {
+ private static InsetsModeSession sInsetsModeSession;
+
+ @BeforeClass
+ public static void setUpOnce() {
+ // To let the insets provider control the insets visibility, the insets mode has to be
+ // NEW_INSETS_MODE_FULL.
+ sInsetsModeSession = new InsetsModeSession(NEW_INSETS_MODE_FULL);
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ sInsetsModeSession.close();
+ }
+
+ @Test
+ public void testControlsForDispatch_regular() {
+ addWindow(TYPE_STATUS_BAR, "topBar");
+ addWindow(TYPE_NAVIGATION_BAR, "navBar");
+
+ final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
+
+ // The app can control both system bars.
+ assertNotNull(controls);
+ assertEquals(2, controls.length);
+ }
+
+ @Test
+ public void testControlsForDispatch_dockedStackVisible() {
+ addWindow(TYPE_STATUS_BAR, "topBar");
+ addWindow(TYPE_NAVIGATION_BAR, "navBar");
+
+ final WindowState win = createWindowOnStack(null, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
+ final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
+
+ // The app must not control any system bars.
+ assertNull(controls);
+ }
+
+ @Test
+ public void testControlsForDispatch_freeformStackVisible() {
+ addWindow(TYPE_STATUS_BAR, "topBar");
+ addWindow(TYPE_NAVIGATION_BAR, "navBar");
+
+ final WindowState win = createWindowOnStack(null, WINDOWING_MODE_FREEFORM,
+ ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
+ final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
+
+ // The app must not control any bars.
+ assertNull(controls);
+ }
+
+ @Test
+ public void testControlsForDispatch_dockedDividerControllerResizing() {
+ addWindow(TYPE_STATUS_BAR, "topBar");
+ addWindow(TYPE_NAVIGATION_BAR, "navBar");
+ mDisplayContent.getDockedDividerController().setResizing(true);
+
+ final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
+
+ // The app must not control any system bars.
+ assertNull(controls);
+ }
+
+ @Test
+ public void testControlsForDispatch_keyguard() {
+ addWindow(TYPE_STATUS_BAR, "topBar").mAttrs.privateFlags |= PRIVATE_FLAG_KEYGUARD;
+ addWindow(TYPE_NAVIGATION_BAR, "navBar");
+
+ final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
+
+ // The app must not control the top bar.
+ assertNotNull(controls);
+ assertEquals(1, controls.length);
+ }
+
+ // TODO: adjust this test if we pretend to the app that it's still able to control it.
+ @Test
+ public void testControlsForDispatch_forceStatusBarVisibleTransparent() {
+ addWindow(TYPE_STATUS_BAR, "topBar").mAttrs.privateFlags |=
+ PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+ addWindow(TYPE_NAVIGATION_BAR, "navBar");
+
+ final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
+
+ // The app must not control the top bar.
+ assertNotNull(controls);
+ assertEquals(1, controls.length);
+ }
+
+ @Test
+ public void testControlsForDispatch_statusBarForceShowNavigation() {
+ addWindow(TYPE_STATUS_BAR, "topBar").mAttrs.privateFlags |=
+ PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+ addWindow(TYPE_NAVIGATION_BAR, "navBar");
+
+ final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
+
+ // The app must not control the navigation bar.
+ assertNotNull(controls);
+ assertEquals(1, controls.length);
+ }
+
+ private WindowState addWindow(int type, String name) {
+ final WindowState win = createWindow(null, type, name);
+ mDisplayContent.getDisplayPolicy().addWindowLw(win, win.mAttrs);
+ return win;
+ }
+
+ private InsetsSourceControl[] addAppWindowAndGetControlsForDispatch() {
+ return addWindowAndGetControlsForDispatch(addWindow(TYPE_APPLICATION, "app"));
+ }
+
+ private InsetsSourceControl[] addWindowAndGetControlsForDispatch(WindowState win) {
+ mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
+ return mDisplayContent.getInsetsStateController().getControlsForDispatch(win);
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 9fce78b292f5..81ea32bb4f73 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -23,13 +23,15 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import android.platform.test.annotations.Presubmit;
+import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
-import android.view.ViewRootImpl;
+import android.view.test.InsetsModeSession;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
@@ -37,90 +39,91 @@ import androidx.test.filters.SmallTest;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.junit.runner.RunWith;
@SmallTest
+@FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Presubmit
+@RunWith(WindowTestRunner.class)
public class InsetsStateControllerTest extends WindowTestsBase {
- private static int sPreviousNewInsetsMode;
+ private static InsetsModeSession sInsetsModeSession;
@BeforeClass
public static void setUpOnce() {
- // TODO: Make use of SettingsSession when it becomes feasible for this.
- sPreviousNewInsetsMode = ViewRootImpl.sNewInsetsMode;
// To let the insets provider control the insets visibility, the insets mode has to be
// NEW_INSETS_MODE_FULL.
- ViewRootImpl.sNewInsetsMode = NEW_INSETS_MODE_FULL;
+ sInsetsModeSession = new InsetsModeSession(NEW_INSETS_MODE_FULL);
}
@AfterClass
public static void tearDownOnce() {
- ViewRootImpl.sNewInsetsMode = sPreviousNewInsetsMode;
+ sInsetsModeSession.close();
}
@Test
@FlakyTest(bugId = 131005232)
public void testStripForDispatch_notOwn() {
- final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
- final WindowState app = createWindow(null, TYPE_APPLICATION, "parentWindow");
+ final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
getController().getSourceProvider(TYPE_TOP_BAR).setWindow(topBar, null);
topBar.setInsetProvider(getController().getSourceProvider(TYPE_TOP_BAR));
assertNotNull(getController().getInsetsForDispatch(app).getSource(TYPE_TOP_BAR));
}
- @FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Test
public void testStripForDispatch_own() {
- final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
+ final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar");
mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR)
.setWindow(topBar, null);
topBar.setInsetProvider(getController().getSourceProvider(TYPE_TOP_BAR));
- assertEquals(new InsetsState(), getController().getInsetsForDispatch(topBar));
+ final InsetsState state = getController().getInsetsForDispatch(topBar);
+ for (int i = state.getSourcesCount() - 1; i >= 0; i--) {
+ final InsetsSource source = state.sourceAt(i);
+ assertNotEquals(TYPE_TOP_BAR, source.getType());
+ }
}
- @FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Test
public void testStripForDispatch_navBar() {
- final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
- final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
- final WindowState ime = createWindow(null, TYPE_APPLICATION, "parentWindow");
+ final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+ final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar");
+ final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
getController().getSourceProvider(TYPE_TOP_BAR).setWindow(topBar, null);
getController().getSourceProvider(TYPE_NAVIGATION_BAR).setWindow(navBar, null);
getController().getSourceProvider(TYPE_IME).setWindow(ime, null);
- assertEquals(new InsetsState(), getController().getInsetsForDispatch(navBar));
+ assertEquals(0, getController().getInsetsForDispatch(navBar).getSourcesCount());
}
- @FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Test
public void testBarControllingWinChanged() {
- final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
- final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
- final WindowState app = createWindow(null, TYPE_APPLICATION, "parentWindow");
+ final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+ final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
getController().getSourceProvider(TYPE_TOP_BAR).setWindow(topBar, null);
getController().getSourceProvider(TYPE_NAVIGATION_BAR).setWindow(navBar, null);
- getController().onBarControllingWindowChanged(app);
+ getController().onBarControlTargetChanged(app, app);
InsetsSourceControl[] controls = getController().getControlsForDispatch(app);
assertEquals(2, controls.length);
}
- @FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
@Test
public void testControlRevoked() {
- final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
- final WindowState app = createWindow(null, TYPE_APPLICATION, "parentWindow");
+ final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
getController().getSourceProvider(TYPE_TOP_BAR).setWindow(topBar, null);
- getController().onBarControllingWindowChanged(app);
+ getController().onBarControlTargetChanged(app, null);
assertNotNull(getController().getControlsForDispatch(app));
- getController().onBarControllingWindowChanged(null);
+ getController().onBarControlTargetChanged(null, null);
assertNull(getController().getControlsForDispatch(app));
}
@FlakyTest(bugId = 124088319)
@Test
public void testControlRevoked_animation() {
- final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
- final WindowState app = createWindow(null, TYPE_APPLICATION, "parentWindow");
+ final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
getController().getSourceProvider(TYPE_TOP_BAR).setWindow(topBar, null);
- getController().onBarControllingWindowChanged(app);
+ getController().onBarControlTargetChanged(app, null);
assertNotNull(getController().getControlsForDispatch(app));
topBar.cancelAnimation();
assertNull(getController().getControlsForDispatch(app));
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index d5e84405edd1..f41f126593de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -403,7 +403,7 @@ public class WindowStateTests extends WindowTestsBase {
assertTrue(topBar.isVisible());
mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR)
.setWindow(topBar, null);
- mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(app);
+ mDisplayContent.getInsetsStateController().onBarControlTargetChanged(app, app);
mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR)
.onInsetsModified(app, new InsetsSource(TYPE_TOP_BAR));
waitUntilHandlersIdle();
diff --git a/tests/utils/testutils/java/android/view/test/InsetsModeSession.java b/tests/utils/testutils/java/android/view/test/InsetsModeSession.java
index c83dfa41d260..e05fdce0ca0c 100644
--- a/tests/utils/testutils/java/android/view/test/InsetsModeSession.java
+++ b/tests/utils/testutils/java/android/view/test/InsetsModeSession.java
@@ -31,7 +31,7 @@ public class InsetsModeSession implements AutoCloseable {
}
@Override
- public void close() throws Exception {
+ public void close() {
ViewRootImpl.sNewInsetsMode = mOldMode;
}
}