Support for specifying orientation in WindowContainer
Also,
- Fixed failing tests when they are ran as a package vs.
individual classes due to multiple window manager instance.
- Correct some isVisible logic to so a window container that
is invisible is not said to be visible, because one of its
children is visible.
Bug: 30060889
Change-Id: I1bb8730361be2a9f5ce88cd59b7d57d5a459bde6
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index af68137..305e47f 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -146,7 +146,7 @@
this.mSkipFirstFrame = skipFirstFrame;
- if (!mAppToken.appFullscreen) {
+ if (!mAppToken.fillsParent()) {
anim.setBackgroundColor(0);
}
if (mClearProlongedAnimation) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index d7e7f81..e176c44 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.ActivityManager.StackId;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -40,7 +41,6 @@
import com.android.server.wm.WindowManagerService.H;
import android.annotation.NonNull;
-import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -75,9 +75,8 @@
final boolean voiceInteraction;
Task mTask;
- // TODO: Have a fillParent variable in WindowContainer to this?
- boolean appFullscreen;
- int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ /** @see WindowContainer#fillsParent() */
+ private boolean mFillsParent;
boolean layoutConfigChanges;
boolean showForAllUsers;
int targetSdk;
@@ -985,6 +984,18 @@
}
}
+ /**
+ * We override because this class doesn't want its children affecting its reported orientation
+ * in anyway.
+ */
+ @Override
+ int getOrientation() {
+ if (hidden || hiddenRequested) {
+ return SCREEN_ORIENTATION_UNSET;
+ }
+ return mOrientation;
+ }
+
@Override
AppWindowToken asAppWindowToken() {
// I am an app window token!
@@ -992,14 +1003,23 @@
}
@Override
+ boolean fillsParent() {
+ return mFillsParent;
+ }
+
+ void setFillsParent(boolean fillsParent) {
+ mFillsParent = fillsParent;
+ }
+
+ @Override
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
if (appToken != null) {
pw.print(prefix); pw.print("app=true voiceInteraction="); pw.println(voiceInteraction);
}
pw.print(prefix); pw.print("task="); pw.println(mTask);
- pw.print(prefix); pw.print(" appFullscreen="); pw.print(appFullscreen);
- pw.print(" requestedOrientation="); pw.println(requestedOrientation);
+ pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
+ pw.print(" mOrientation="); pw.println(mOrientation);
pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
pw.print(" clientHidden="); pw.print(clientHidden);
pw.print(" reportedDrawn="); pw.print(reportedDrawn);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3a3c017..69d01ed 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -17,13 +17,18 @@
package com.android.server.wm;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
@@ -201,6 +206,50 @@
return null;
}
+ int getOrientation() {
+ // TODO: Most of the logic here can be removed once this class is converted to use
+ // WindowContainer which has an abstract implementation of getOrientation that
+ // should cover this.
+ if (mService.isStackVisibleLocked(DOCKED_STACK_ID)
+ || mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
+ // Apps and their containers are not allowed to specify an orientation while the docked
+ // or freeform stack is visible...except for the home stack/task if the docked stack is
+ // minimized and it actually set something.
+ if (mHomeStack.isVisible() && mDividerControllerLocked.isMinimizedDock()) {
+ final int orientation = mHomeStack.getOrientation();
+ if (orientation != SCREEN_ORIENTATION_UNSET) {
+ return orientation;
+ }
+ }
+ return SCREEN_ORIENTATION_UNSPECIFIED;
+ }
+
+ for (int i = mStacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mStacks.get(i);
+ if (!stack.isVisible()) {
+ continue;
+ }
+
+ final int orientation = stack.getOrientation();
+
+ if (orientation == SCREEN_ORIENTATION_BEHIND) {
+ continue;
+ }
+
+ if (orientation != SCREEN_ORIENTATION_UNSET) {
+ if (stack.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+ return orientation;
+ }
+ }
+ }
+
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
+ "No app is requesting an orientation, return " + mService.mLastOrientation);
+ // The next app has not been requested to be visible, so we keep the current orientation
+ // to prevent freezing/unfreezing the display too early.
+ return mService.mLastOrientation;
+ }
+
void updateDisplayInfo() {
mDisplay.getDisplayInfo(mDisplayInfo);
mDisplay.getMetrics(mDisplayMetrics);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 545a439..f2f2474 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -21,6 +21,9 @@
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -681,6 +684,33 @@
return false;
}
+ boolean fillsParent() {
+ return mFullscreen || !StackId.isTaskResizeAllowed(mStack.mStackId);
+ }
+
+ // TODO: Remove once switched to use WindowContainer
+ int getOrientation() {
+ int candidate = SCREEN_ORIENTATION_UNSET;
+
+ for (int i = mAppTokens.size() - 1; i >= 0; --i) {
+ final AppWindowToken token = mAppTokens.get(i);
+ final int orientation = token.getOrientation();
+
+ if (orientation == SCREEN_ORIENTATION_BEHIND) {
+ candidate = orientation;
+ continue;
+ }
+
+ if (orientation != SCREEN_ORIENTATION_UNSET) {
+ if (token.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+ return orientation;
+ }
+ }
+ }
+
+ return candidate;
+ }
+
@Override
public String toString() {
return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index cf31310..f5fa9fd 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -21,6 +21,9 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.DOCKED_BOTTOM;
@@ -1305,4 +1308,40 @@
mTasks.get(i).overridePlayingAppAnimations(a);
}
}
+
+ // TODO: Remove once switched to use WindowContainer
+ int getOrientation() {
+ if (!StackId.canSpecifyOrientation(mStackId)) {
+ return SCREEN_ORIENTATION_UNSET;
+ }
+
+ int candidate = SCREEN_ORIENTATION_UNSET;
+
+ for (int i = mTasks.size() - 1; i >= 0; --i) {
+ final Task task = mTasks.get(i);
+
+ if (!task.isVisible()) {
+ continue;
+ }
+
+ final int orientation = task.getOrientation();
+ if (orientation == SCREEN_ORIENTATION_BEHIND) {
+ candidate = orientation;
+ continue;
+ }
+
+ if (orientation != SCREEN_ORIENTATION_UNSET) {
+ if (task.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+ return orientation;
+ }
+ }
+ }
+
+ return candidate;
+ }
+
+ // TODO: Remove once switched to use WindowContainer
+ boolean fillsParent() {
+ return mFullscreen;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index fa05c0c..0ed3a33 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -21,9 +21,13 @@
import java.util.Comparator;
import java.util.LinkedList;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
/**
* Defines common functionality for classes that can hold windows directly or through their
- * children.
+ * children in a hierarchy form.
* The test class is {@link WindowContainerTests} which must be kept up-to-date and ran anytime
* changes are made to this class.
*/
@@ -36,7 +40,10 @@
// screen with the top-most window container at the tail of the list.
protected final LinkedList<WindowContainer> mChildren = new LinkedList();
- protected WindowContainer getParent() {
+ // The specified orientation for this window container.
+ protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+
+ final protected WindowContainer getParent() {
return mParent;
}
@@ -221,6 +228,10 @@
* the container has any content to display.
*/
boolean isVisible() {
+ // TODO: Will this be more correct if it checks the visibility of its parents? Yes.
+ // That is this container is only visible if its parents are visible vs visible if it has a
+ // visible child. In that case all overrides will need to call super and return false if
+ // this returns false.
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
if (wc.isVisible()) {
@@ -234,4 +245,70 @@
WindowContainer getTop() {
return mChildren.isEmpty() ? this : mChildren.peekLast();
}
+
+ void setOrientation(int orientation) {
+ mOrientation = orientation;
+ }
+
+ /**
+ * Returns the specified orientation for this window container or one of its children is there
+ * is one set, or {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSET} if no
+ * specification is set.
+ * NOTE: {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} is a
+ * specification...
+ */
+ int getOrientation() {
+
+ if (!fillsParent() || !isVisible()) {
+ // Ignore invisible containers or containers that don't completely fills their parents.
+ return SCREEN_ORIENTATION_UNSET;
+ }
+
+ // The container fills its parent so we can use it orientation if it has one specified,
+ // otherwise we prefer to use the orientation of its topmost child that has one
+ // specified and fall back on this container's unset or unspecified value as a candidate
+ // if none of the children have a better candidate for the orientation.
+ if (mOrientation != SCREEN_ORIENTATION_UNSET
+ && mOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+ return mOrientation;
+ }
+ int candidate = mOrientation;
+
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer wc = mChildren.get(i);
+
+ final int orientation = wc.getOrientation();
+ if (orientation == SCREEN_ORIENTATION_BEHIND) {
+ // container wants us to use the orientation of the container behind it. See if we
+ // can find one. Else return SCREEN_ORIENTATION_BEHIND so the caller can choose to
+ // look behind this container.
+ candidate = orientation;
+ continue;
+ }
+
+ if (orientation == SCREEN_ORIENTATION_UNSET) {
+ continue;
+ }
+
+ if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+ // Use the orientation if the container fills its parent or requested an explicit
+ // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED.
+ return orientation;
+ }
+ }
+
+ return candidate;
+ }
+
+ /**
+ * Returns true if this container is opaque and fills all the space made available by its parent
+ * container.
+ *
+ * NOTE: It is possible for this container to occupy more space than the parent has (or less),
+ * this is just a signal from the client to window manager stating its intent, but not what it
+ * actually does.
+ */
+ boolean fillsParent() {
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1cc7dad..5e279fe 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2839,10 +2839,10 @@
}
atoken = new AppWindowToken(this, token, voiceInteraction);
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
- atoken.appFullscreen = fullscreen;
+ atoken.setFillsParent(fullscreen);
atoken.showForAllUsers = showForAllUsers;
atoken.targetSdk = targetSdkVersion;
- atoken.requestedOrientation = requestedOrientation;
+ atoken.setOrientation(requestedOrientation);
atoken.layoutConfigChanges = (configChanges &
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
atoken.mLaunchTaskBehind = launchTaskBehind;
@@ -2947,7 +2947,7 @@
AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
null : winShowWhenLocked.mAppToken;
if (appShowWhenLocked != null) {
- int req = appShowWhenLocked.requestedOrientation;
+ int req = appShowWhenLocked.getOrientation();
if (req == SCREEN_ORIENTATION_BEHIND) {
req = mLastKeyguardForcedOrientation;
}
@@ -2962,91 +2962,7 @@
}
// Top system windows are not requesting an orientation. Start searching from apps.
- return getAppSpecifiedOrientation();
- }
-
- private int getAppSpecifiedOrientation() {
- int lastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
- boolean findingBehind = false;
- boolean lastFullscreen = false;
- DisplayContent displayContent = getDefaultDisplayContentLocked();
- final ArrayList<Task> tasks = displayContent.getTasks();
- final boolean inMultiWindow = isStackVisibleLocked(DOCKED_STACK_ID)
- || isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID);
- final boolean dockMinimized =
- getDefaultDisplayContentLocked().mDividerControllerLocked.isMinimizedDock();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
- final int firstToken = tokens.size() - 1;
- for (int tokenNdx = firstToken; tokenNdx >= 0; --tokenNdx) {
- final AppWindowToken atoken = tokens.get(tokenNdx);
-
- if (DEBUG_APP_ORIENTATION) Slog.v(TAG_WM, "Checking app orientation: " + atoken);
-
- // if we're about to tear down this window and not seek for
- // the behind activity, don't use it for orientation
- if (!findingBehind && !atoken.hidden && atoken.hiddenRequested) {
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
- "Skipping " + atoken + " -- going to hide");
- continue;
- }
-
- if (tokenNdx == firstToken) {
- // If we have hit a new Task, and the bottom of the previous group didn't
- // explicitly say to use the orientation behind it, and the last app was
- // full screen, then we'll stick with the user's orientation.
- if (lastOrientation != SCREEN_ORIENTATION_BEHIND && lastFullscreen) {
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Done at " + atoken
- + " -- end of group, return " + lastOrientation);
- return lastOrientation;
- }
- }
-
- // We ignore any hidden applications on the top.
- if (atoken.hiddenRequested) {
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
- "Skipping " + atoken + " -- hidden on top");
- continue;
- }
-
- // No app except the home app may specify the screen orientation in multi-window,
- // and only if the docked stack is minimized to avoid weirdness when home task
- // temporarily gets moved to the front.
- if (inMultiWindow && (!atoken.mTask.isHomeTask() || !dockMinimized)) {
- continue;
- }
-
- if (tokenNdx == 0) {
- // Last token in this task.
- lastOrientation = atoken.requestedOrientation;
- }
-
- int or = atoken.requestedOrientation;
- // If this application is fullscreen, and didn't explicitly say
- // to use the orientation behind it, then just take whatever
- // orientation it has and ignores whatever is under it.
- lastFullscreen = atoken.appFullscreen;
- if (lastFullscreen && or != SCREEN_ORIENTATION_BEHIND) {
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
- "Done at " + atoken + " -- full screen, return " + or);
- return or;
- }
- // If this application has requested an explicit orientation, then use it.
- if (or != SCREEN_ORIENTATION_UNSPECIFIED && or != SCREEN_ORIENTATION_BEHIND) {
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
- "Done at " + atoken + " -- explicitly set, return " + or);
- return or;
- }
- findingBehind |= (or == SCREEN_ORIENTATION_BEHIND);
- }
- }
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
- "No app is requesting an orientation, return " + mLastOrientation);
- // The next app has not been requested to be visible, so we keep the current orientation
- // to prevent freezing/unfreezing the display too early unless we are in multi-window, in
- // which we don't let the app customize the orientation unless it was the home task that
- // is handled above.
- return inMultiWindow ? SCREEN_ORIENTATION_UNSPECIFIED : mLastOrientation;
+ return getDefaultDisplayContentLocked().getOrientation();
}
@Override
@@ -3222,13 +3138,13 @@
}
synchronized(mWindowMap) {
- AppWindowToken atoken = findAppWindowToken(token.asBinder());
+ final AppWindowToken atoken = findAppWindowToken(token.asBinder());
if (atoken == null) {
Slog.w(TAG_WM, "Attempted to set orientation of non-existing app token: " + token);
return;
}
- atoken.requestedOrientation = requestedOrientation;
+ atoken.setOrientation(requestedOrientation);
}
}
@@ -3240,7 +3156,7 @@
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- return wtoken.requestedOrientation;
+ return wtoken.getOrientation();
}
}
@@ -3556,9 +3472,9 @@
public void setAppFullscreen(IBinder token, boolean toOpaque) {
synchronized (mWindowMap) {
- AppWindowToken atoken = findAppWindowToken(token);
+ final AppWindowToken atoken = findAppWindowToken(token);
if (atoken != null) {
- atoken.appFullscreen = toOpaque;
+ atoken.setFillsParent(toOpaque);
setWindowOpaqueLocked(token, toOpaque);
mWindowPlacerLocked.requestTraversal();
}
@@ -3963,7 +3879,6 @@
mInputMonitor.setUpdateInputWindowsNeededLw();
mWindowPlacerLocked.performSurfacePlacement();
mInputMonitor.updateInputWindowsLw(false /*force*/);
- //dump();
}
public void moveTaskToTop(int taskId) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fccd2d9..7b14c6b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1202,7 +1202,7 @@
// has been hidden.
return true;
}
- return super.isVisible();
+ return false;
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index e03456f..a2d02a3 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -1154,7 +1154,7 @@
voiceInteraction |= wtoken.voiceInteraction;
- if (wtoken.appFullscreen) {
+ if (wtoken.fillsParent()) {
WindowState ws = wtoken.findMainWindow();
if (ws != null) {
animLp = ws.mAttrs;
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 32fd43a..740d30c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -46,17 +46,12 @@
public class AppWindowTokenTests {
private static WindowManagerService sWm = null;
- private final WindowManagerPolicy mPolicy = new TestWindowManagerPolicy();
private final IWindow mIWindow = new TestIWindow();
@Before
public void setUp() throws Exception {
final Context context = InstrumentationRegistry.getTargetContext();
- if (sWm == null) {
- // We only want to do this once for the test process as we don't want WM to try to
- // register a bunch of local services again.
- sWm = WindowManagerService.main(context, null, true, false, false, mPolicy);
- }
+ sWm = TestWindowManagerPolicy.getWindowManagerService(context);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 8c6b007..0afbd0c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -82,6 +82,18 @@
public class TestWindowManagerPolicy implements WindowManagerPolicy {
private static final String TAG = "TestWindowManagerPolicy";
+ private static WindowManagerService sWm = null;
+
+ static synchronized WindowManagerService getWindowManagerService(Context context) {
+ if (sWm == null) {
+ // We only want to do this once for the test process as we don't want WM to try to
+ // register a bunch of local services again.
+ sWm = WindowManagerService.main(
+ context, null, true, false, false, new TestWindowManagerPolicy());
+ }
+ return sWm;
+ }
+
@Override
public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
throws RemoteException {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index a15b74b..354aa34 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -23,8 +23,12 @@
import android.support.test.runner.AndroidJUnit4;
import java.util.Comparator;
-import java.util.LinkedList;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -195,7 +199,7 @@
final TestWindowContainer child12 = child1.addChildWindow(builder.setIsVisible(true));
final TestWindowContainer child21 = child2.addChildWindow();
- assertTrue(root.isVisible());
+ assertFalse(root.isVisible());
assertTrue(child1.isVisible());
assertFalse(child11.isVisible());
assertTrue(child12.isVisible());
@@ -230,15 +234,105 @@
assertTrue(gotException);
}
+ @Test
+ public void testGetOrientation_Unset() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
+ // Unspecified well because we didn't specify anything...
+ assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
+ }
+
+ @Test
+ public void testGetOrientation_InvisibleParentUnsetVisibleChildren() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
+
+ builder.setIsVisible(false).setLayer(-1);
+ final TestWindowContainer invisible = root.addChildWindow(builder);
+ builder.setIsVisible(true).setLayer(-2);
+ final TestWindowContainer invisibleChild1VisibleAndSet = invisible.addChildWindow(builder);
+ invisibleChild1VisibleAndSet.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ // Landscape well because the container is visible and that is what we set on it above.
+ assertEquals(SCREEN_ORIENTATION_LANDSCAPE, invisibleChild1VisibleAndSet.getOrientation());
+ // Unset because the container isn't visible even though it has a child that thinks it is
+ // visible.
+ assertEquals(SCREEN_ORIENTATION_UNSET, invisible.getOrientation());
+ // Unspecified because we are visible and we didn't specify an orientation and there isn't
+ // a visible child.
+ assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
+
+ builder.setIsVisible(true).setLayer(-3);
+ final TestWindowContainer visibleUnset = root.addChildWindow(builder);
+ visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
+ assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
+
+ }
+
+ @Test
+ public void testGetOrientation_setBehind() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
+
+ builder.setIsVisible(true).setLayer(-1);
+ final TestWindowContainer visibleUnset = root.addChildWindow(builder);
+ visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
+
+ builder.setIsVisible(true).setLayer(-2);
+ final TestWindowContainer visibleUnsetChild1VisibleSetBehind =
+ visibleUnset.addChildWindow(builder);
+ visibleUnsetChild1VisibleSetBehind.setOrientation(SCREEN_ORIENTATION_BEHIND);
+ // Setting to visible behind will be used by the parents if there isn't another other
+ // container behind this one that has an orientation set.
+ assertEquals(SCREEN_ORIENTATION_BEHIND,
+ visibleUnsetChild1VisibleSetBehind.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_BEHIND, visibleUnset.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
+ }
+
+ @Test
+ public void testGetOrientation_fillsParent() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
+
+ builder.setIsVisible(true).setLayer(-1);
+ final TestWindowContainer visibleUnset = root.addChildWindow(builder);
+ visibleUnset.setOrientation(SCREEN_ORIENTATION_BEHIND);
+
+ builder.setLayer(1).setIsVisible(true);
+ final TestWindowContainer visibleUnspecifiedRootChild = root.addChildWindow(builder);
+ visibleUnspecifiedRootChild.setFillsParent(false);
+ visibleUnspecifiedRootChild.setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
+ // Unset because the child doesn't fill the parent. May as well be invisible...
+ assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
+ // The parent uses whatever orientation is set behind this container since it doesn't fill
+ // the parent.
+ assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
+
+ // Test case of child filling its parent, but its parent isn't filling its own parent.
+ builder.setLayer(2).setIsVisible(true);
+ final TestWindowContainer visibleUnspecifiedRootChildChildFillsParent =
+ visibleUnspecifiedRootChild.addChildWindow(builder);
+ visibleUnspecifiedRootChildChildFillsParent.setOrientation(
+ SCREEN_ORIENTATION_PORTRAIT);
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT,
+ visibleUnspecifiedRootChildChildFillsParent.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnspecifiedRootChild.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_BEHIND, root.getOrientation());
+
+
+ visibleUnspecifiedRootChild.setFillsParent(true);
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, visibleUnspecifiedRootChild.getOrientation());
+ assertEquals(SCREEN_ORIENTATION_PORTRAIT, root.getOrientation());
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private class TestWindowContainer extends WindowContainer {
private final int mLayer;
- private final LinkedList<String> mUsers = new LinkedList();
private final boolean mCanDetach;
private boolean mIsAnimating;
private boolean mIsVisible;
- private int mRemoveIfPossibleCount;
- private int mRemoveImmediatelyCount;
+ private boolean mFillsParent;
/**
* Compares 2 window layers and returns -1 if the first is lesser than the second in terms
@@ -256,13 +350,12 @@
return 1;
};
- TestWindowContainer(int layer, LinkedList<String> users, boolean canDetach,
- boolean isAnimating, boolean isVisible) {
+ TestWindowContainer(int layer, boolean canDetach, boolean isAnimating, boolean isVisible) {
mLayer = layer;
- mUsers.addAll(users);
mCanDetach = canDetach;
mIsAnimating = isAnimating;
mIsVisible = isVisible;
+ mFillsParent = true;
}
TestWindowContainer getParentWindow() {
@@ -299,36 +392,31 @@
@Override
boolean isVisible() {
- return mIsVisible || super.isVisible();
+ return mIsVisible;
}
@Override
- void removeImmediately() {
- super.removeImmediately();
- mRemoveImmediatelyCount++;
+ boolean fillsParent() {
+ return mFillsParent;
}
- @Override
- void removeIfPossible() {
- super.removeIfPossible();
- mRemoveIfPossibleCount++;
+ void setFillsParent(boolean fillsParent) {
+ mFillsParent = fillsParent;
}
}
private class TestWindowContainerBuilder {
private int mLayer;
- private LinkedList<String> mUsers = new LinkedList();
private boolean mCanDetach;
private boolean mIsAnimating;
private boolean mIsVisible;
- TestWindowContainerBuilder setLayer(int layer) {
- mLayer = layer;
- return this;
+ public TestWindowContainerBuilder() {
+ reset();
}
- TestWindowContainerBuilder addUser(String user) {
- mUsers.add(user);
+ TestWindowContainerBuilder setLayer(int layer) {
+ mLayer = layer;
return this;
}
@@ -349,7 +437,6 @@
TestWindowContainerBuilder reset() {
mLayer = 0;
- mUsers.clear();
mCanDetach = false;
mIsAnimating = false;
mIsVisible = false;
@@ -357,7 +444,7 @@
}
TestWindowContainer build() {
- return new TestWindowContainer(mLayer, mUsers, mCanDetach, mIsAnimating, mIsVisible);
+ return new TestWindowContainer(mLayer, mCanDetach, mIsAnimating, mIsVisible);
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 4b29a60..789c067 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -21,6 +21,7 @@
import org.junit.runner.RunWith;
import android.content.Context;
+import android.os.Binder;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -50,18 +51,13 @@
private static WindowManagerService sWm = null;
private WindowToken mWindowToken;
- private final WindowManagerPolicy mPolicy = new TestWindowManagerPolicy();
private final IWindow mIWindow = new TestIWindow();
@Before
public void setUp() throws Exception {
final Context context = InstrumentationRegistry.getTargetContext();
- if (sWm == null) {
- // We only want to do this once for the test process as we don't want WM to try to
- // register a bunch of local services again.
- sWm = WindowManagerService.main(context, null, true, false, false, mPolicy);
- }
- mWindowToken = new WindowToken(sWm, null, 0, false);
+ sWm = TestWindowManagerPolicy.getWindowManagerService(context);
+ mWindowToken = new WindowToken(sWm, new Binder(), 0, false);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 4505254..1a0ce5b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -46,18 +46,13 @@
@RunWith(AndroidJUnit4.class)
public class WindowTokenTests {
- private static WindowManagerService sWm = null;
- private final WindowManagerPolicy mPolicy = new TestWindowManagerPolicy();
+ private WindowManagerService mWm = null;
private final IWindow mIWindow = new TestIWindow();
@Before
public void setUp() throws Exception {
final Context context = InstrumentationRegistry.getTargetContext();
- if (sWm == null) {
- // We only want to do this once for the test process as we don't want WM to try to
- // register a bunch of local services again.
- sWm = WindowManagerService.main(context, null, true, false, false, mPolicy);
- }
+ mWm = TestWindowManagerPolicy.getWindowManagerService(context);
}
@Test
@@ -161,15 +156,15 @@
private WindowState createWindow(WindowState parent, int type, WindowToken token) {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
- return new WindowState(sWm, null, mIWindow, token, parent, 0, 0, attrs, 0,
- sWm.getDefaultDisplayContentLocked(), 0);
+ return new WindowState(mWm, null, mIWindow, token, parent, 0, 0, attrs, 0,
+ mWm.getDefaultDisplayContentLocked(), 0);
}
/* Used so we can gain access to some protected members of the {@link WindowToken} class */
private class TestWindowToken extends WindowToken {
TestWindowToken() {
- super(sWm, null, 0, false);
+ super(mWm, null, 0, false);
}
int getWindowsCount() {