Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +22 −10 Original line number Diff line number Diff line Loading @@ -469,6 +469,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mNavigationBar = null; boolean mHasNavigationBar = false; boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side? @NavigationBarPosition int mNavigationBarPosition = NAV_BAR_BOTTOM; int[] mNavigationBarHeightForRotationDefault = new int[4]; int[] mNavigationBarWidthForRotationDefault = new int[4]; Loading Loading @@ -4685,6 +4686,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mNavigationBarController.checkHiddenLw(); } @NavigationBarPosition private int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) { if (mNavigationBarCanMove && displayWidth > displayHeight) { if (displayRotation == Surface.ROTATION_270) { Loading Loading @@ -7852,17 +7854,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { return vis; } private int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) { final WindowState imeWin = mWindowManagerFuncs.getInputMethodWindowLw(); final WindowState navColorWin; if (imeWin != null && imeWin.isVisibleLw() && mNavigationBarPosition == NAV_BAR_BOTTOM) { navColorWin = imeWin; @VisibleForTesting @Nullable static WindowState chooseNavigationColorWindowLw(WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, @NavigationBarPosition int navBarPosition) { if (imeWindow != null && imeWindow.isVisibleLw() && navBarPosition == NAV_BAR_BOTTOM) { return imeWindow; } else { navColorWin = opaqueOrDimming; return opaqueOrDimming; } } @VisibleForTesting static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin) { if (navColorWin != null) { if (navColorWin == opaque) { // If the top fullscreen-or-dimming window is also the top fullscreen, respect Loading @@ -7870,7 +7877,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; vis |= PolicyControl.getSystemUiVisibility(navColorWin, null) & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; } else if (navColorWin.isDimming() || navColorWin == imeWin) { } else if ((navColorWin == opaqueOrDimming && navColorWin.isDimming()) || navColorWin == imeWindow) { // Otherwise if it's dimming or it's the IME window, clear the light flag. vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; } Loading Loading @@ -8009,8 +8017,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis); final WindowState navColorWin = chooseNavigationColorWindowLw( mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState, mWindowManagerFuncs.getInputMethodWindowLw(), mNavigationBarPosition); vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState); mTopFullscreenOpaqueOrDimmingWindowState, mWindowManagerFuncs.getInputMethodWindowLw(), navColorWin); return vis; } Loading services/core/java/com/android/server/policy/WindowManagerPolicy.java +7 −0 Original line number Diff line number Diff line Loading @@ -61,6 +61,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.Manifest; import android.annotation.IntDef; import android.annotation.Nullable; Loading Loading @@ -141,6 +143,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { int NAV_BAR_RIGHT = 1 << 1; int NAV_BAR_BOTTOM = 1 << 2; @Retention(SOURCE) @IntDef({NAV_BAR_LEFT, NAV_BAR_RIGHT, NAV_BAR_BOTTOM}) @interface NavigationBarPosition {} /** * Pass this event to the user / app. To be returned from * {@link #interceptKeyBeforeQueueing}. Loading Loading @@ -1637,6 +1643,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @see #NAV_BAR_RIGHT * @see #NAV_BAR_BOTTOM */ @NavigationBarPosition int getNavBarPosition(); /** Loading services/core/java/com/android/server/wm/WindowManagerService.java +1 −0 Original line number Diff line number Diff line Loading @@ -5894,6 +5894,7 @@ public class WindowManagerService extends IWindowManager.Stub * the screen is. * @see WindowManagerPolicy#getNavBarPosition() */ @WindowManagerPolicy.NavigationBarPosition public int getNavBarPosition() { synchronized (mWindowMap) { // Perform layout if it was scheduled before to make sure that we get correct nav bar Loading services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java +2 −1 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { public boolean inMultiWindowMode; public boolean visible = true; public int surfaceLayer = 1; public boolean isDimming = false; public boolean policyVisible = true; Loading Loading @@ -221,7 +222,7 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { @Override public boolean isDimming() { throw new UnsupportedOperationException("not implemented"); return isDimming; } @Override Loading services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java 0 → 100644 +202 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.policy; import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import android.graphics.PixelFormat; import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.WindowManager; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit public class PhoneWindowManagerTest { private static FakeWindowState createOpaqueFullscreen(boolean hasLightNavBar) { final FakeWindowState state = new FakeWindowState(); state.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT, TYPE_BASE_APPLICATION, FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, PixelFormat.OPAQUE); state.attrs.subtreeSystemUiVisibility = hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0; return state; } private static FakeWindowState createDimmingDialogWindow(boolean canBeImTarget) { final FakeWindowState state = new FakeWindowState(); state.attrs = new WindowManager.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, TYPE_APPLICATION, FLAG_DIM_BEHIND | (canBeImTarget ? 0 : FLAG_ALT_FOCUSABLE_IM), PixelFormat.TRANSLUCENT); state.isDimming = true; return state; } private static FakeWindowState createInputMethodWindow(boolean visible, boolean drawNavBar, boolean hasLightNavBar) { final FakeWindowState state = new FakeWindowState(); state.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT, TYPE_INPUT_METHOD, FLAG_NOT_FOCUSABLE | FLAG_LAYOUT_IN_SCREEN | (drawNavBar ? FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS : 0), PixelFormat.TRANSPARENT); state.attrs.subtreeSystemUiVisibility = hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0; state.visible = visible; state.policyVisible = visible; return state; } @Test public void testChooseNavigationColorWindowLw() throws Exception { final FakeWindowState opaque = createOpaqueFullscreen(false); final FakeWindowState dimmingImTarget = createDimmingDialogWindow(true); final FakeWindowState dimmingNonImTarget = createDimmingDialogWindow(false); final FakeWindowState visibleIme = createInputMethodWindow(true, true, false); final FakeWindowState invisibleIme = createInputMethodWindow(false, true, false); final FakeWindowState imeNonDrawNavBar = createInputMethodWindow(true, false, false); // If everything is null, return null assertNull(null, PhoneWindowManager.chooseNavigationColorWindowLw( null, null, null, NAV_BAR_BOTTOM)); assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, null, NAV_BAR_BOTTOM)); assertEquals(dimmingImTarget, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingImTarget, null, NAV_BAR_BOTTOM)); assertEquals(dimmingNonImTarget, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingNonImTarget, null, NAV_BAR_BOTTOM)); assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( null, null, visibleIme, NAV_BAR_BOTTOM)); assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( null, dimmingImTarget, visibleIme, NAV_BAR_BOTTOM)); // TODO(b/69002467): A dimming window that is shown above the IME window should win. assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( null, dimmingNonImTarget, visibleIme, NAV_BAR_BOTTOM)); assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, visibleIme, NAV_BAR_BOTTOM)); assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingImTarget, visibleIme, NAV_BAR_BOTTOM)); // TODO(b/69002467): A dimming window that is shown above the IME window should win. assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingNonImTarget, visibleIme, NAV_BAR_BOTTOM)); assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, invisibleIme, NAV_BAR_BOTTOM)); assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, invisibleIme, NAV_BAR_BOTTOM)); assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, visibleIme, NAV_BAR_RIGHT)); // Only IME windows that have FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS should be navigation color // window, but it's not yet implemented. // TODO(b/69002467): Support this. assertEquals(imeNonDrawNavBar, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, imeNonDrawNavBar, NAV_BAR_BOTTOM)); // TODO(b/69002467): Support this. assertEquals(imeNonDrawNavBar, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM)); // TODO(b/69002467): Support this. assertEquals(imeNonDrawNavBar, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingNonImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM)); } @Test public void testUpdateLightNavigationBarLw() throws Exception { final FakeWindowState opaqueDarkNavBar = createOpaqueFullscreen(false); final FakeWindowState opaqueLightNavBar = createOpaqueFullscreen(true); final FakeWindowState dimming = createDimmingDialogWindow(false); final FakeWindowState imeDrawDarkNavBar = createInputMethodWindow(true,true, false); final FakeWindowState imeDrawLightNavBar = createInputMethodWindow(true,true, true); assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null, null, null)); // Opaque top fullscreen window overrides SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR flag. assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( 0, opaqueDarkNavBar, opaqueDarkNavBar, null, opaqueDarkNavBar)); assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, opaqueDarkNavBar, null, opaqueDarkNavBar)); assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, PhoneWindowManager.updateLightNavigationBarLw(0, opaqueLightNavBar, opaqueLightNavBar, null, opaqueLightNavBar)); assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, PhoneWindowManager.updateLightNavigationBarLw(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, opaqueLightNavBar, null, opaqueLightNavBar)); // Dimming window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR. assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( 0, opaqueDarkNavBar, dimming, null, dimming)); assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( 0, opaqueLightNavBar, dimming, null, dimming)); assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, dimming, null, dimming)); assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, null, dimming)); assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, imeDrawLightNavBar, dimming)); // IME window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null, imeDrawDarkNavBar, imeDrawDarkNavBar)); // Even if the top fullscreen has SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, IME window wins. assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, opaqueLightNavBar, imeDrawDarkNavBar, imeDrawDarkNavBar)); // Currently SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR in IME windows is ignored. // TODO(b/69002467): Support this. assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( 0, opaqueDarkNavBar, opaqueDarkNavBar, imeDrawLightNavBar, imeDrawLightNavBar)); } } Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +22 −10 Original line number Diff line number Diff line Loading @@ -469,6 +469,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mNavigationBar = null; boolean mHasNavigationBar = false; boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side? @NavigationBarPosition int mNavigationBarPosition = NAV_BAR_BOTTOM; int[] mNavigationBarHeightForRotationDefault = new int[4]; int[] mNavigationBarWidthForRotationDefault = new int[4]; Loading Loading @@ -4685,6 +4686,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mNavigationBarController.checkHiddenLw(); } @NavigationBarPosition private int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) { if (mNavigationBarCanMove && displayWidth > displayHeight) { if (displayRotation == Surface.ROTATION_270) { Loading Loading @@ -7852,17 +7854,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { return vis; } private int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) { final WindowState imeWin = mWindowManagerFuncs.getInputMethodWindowLw(); final WindowState navColorWin; if (imeWin != null && imeWin.isVisibleLw() && mNavigationBarPosition == NAV_BAR_BOTTOM) { navColorWin = imeWin; @VisibleForTesting @Nullable static WindowState chooseNavigationColorWindowLw(WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, @NavigationBarPosition int navBarPosition) { if (imeWindow != null && imeWindow.isVisibleLw() && navBarPosition == NAV_BAR_BOTTOM) { return imeWindow; } else { navColorWin = opaqueOrDimming; return opaqueOrDimming; } } @VisibleForTesting static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin) { if (navColorWin != null) { if (navColorWin == opaque) { // If the top fullscreen-or-dimming window is also the top fullscreen, respect Loading @@ -7870,7 +7877,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; vis |= PolicyControl.getSystemUiVisibility(navColorWin, null) & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; } else if (navColorWin.isDimming() || navColorWin == imeWin) { } else if ((navColorWin == opaqueOrDimming && navColorWin.isDimming()) || navColorWin == imeWindow) { // Otherwise if it's dimming or it's the IME window, clear the light flag. vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; } Loading Loading @@ -8009,8 +8017,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis); final WindowState navColorWin = chooseNavigationColorWindowLw( mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState, mWindowManagerFuncs.getInputMethodWindowLw(), mNavigationBarPosition); vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState); mTopFullscreenOpaqueOrDimmingWindowState, mWindowManagerFuncs.getInputMethodWindowLw(), navColorWin); return vis; } Loading
services/core/java/com/android/server/policy/WindowManagerPolicy.java +7 −0 Original line number Diff line number Diff line Loading @@ -61,6 +61,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.Manifest; import android.annotation.IntDef; import android.annotation.Nullable; Loading Loading @@ -141,6 +143,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { int NAV_BAR_RIGHT = 1 << 1; int NAV_BAR_BOTTOM = 1 << 2; @Retention(SOURCE) @IntDef({NAV_BAR_LEFT, NAV_BAR_RIGHT, NAV_BAR_BOTTOM}) @interface NavigationBarPosition {} /** * Pass this event to the user / app. To be returned from * {@link #interceptKeyBeforeQueueing}. Loading Loading @@ -1637,6 +1643,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @see #NAV_BAR_RIGHT * @see #NAV_BAR_BOTTOM */ @NavigationBarPosition int getNavBarPosition(); /** Loading
services/core/java/com/android/server/wm/WindowManagerService.java +1 −0 Original line number Diff line number Diff line Loading @@ -5894,6 +5894,7 @@ public class WindowManagerService extends IWindowManager.Stub * the screen is. * @see WindowManagerPolicy#getNavBarPosition() */ @WindowManagerPolicy.NavigationBarPosition public int getNavBarPosition() { synchronized (mWindowMap) { // Perform layout if it was scheduled before to make sure that we get correct nav bar Loading
services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java +2 −1 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { public boolean inMultiWindowMode; public boolean visible = true; public int surfaceLayer = 1; public boolean isDimming = false; public boolean policyVisible = true; Loading Loading @@ -221,7 +222,7 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { @Override public boolean isDimming() { throw new UnsupportedOperationException("not implemented"); return isDimming; } @Override Loading
services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTest.java 0 → 100644 +202 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.policy; import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM; import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import android.graphics.PixelFormat; import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.WindowManager; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit public class PhoneWindowManagerTest { private static FakeWindowState createOpaqueFullscreen(boolean hasLightNavBar) { final FakeWindowState state = new FakeWindowState(); state.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT, TYPE_BASE_APPLICATION, FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, PixelFormat.OPAQUE); state.attrs.subtreeSystemUiVisibility = hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0; return state; } private static FakeWindowState createDimmingDialogWindow(boolean canBeImTarget) { final FakeWindowState state = new FakeWindowState(); state.attrs = new WindowManager.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, TYPE_APPLICATION, FLAG_DIM_BEHIND | (canBeImTarget ? 0 : FLAG_ALT_FOCUSABLE_IM), PixelFormat.TRANSLUCENT); state.isDimming = true; return state; } private static FakeWindowState createInputMethodWindow(boolean visible, boolean drawNavBar, boolean hasLightNavBar) { final FakeWindowState state = new FakeWindowState(); state.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT, TYPE_INPUT_METHOD, FLAG_NOT_FOCUSABLE | FLAG_LAYOUT_IN_SCREEN | (drawNavBar ? FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS : 0), PixelFormat.TRANSPARENT); state.attrs.subtreeSystemUiVisibility = hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0; state.visible = visible; state.policyVisible = visible; return state; } @Test public void testChooseNavigationColorWindowLw() throws Exception { final FakeWindowState opaque = createOpaqueFullscreen(false); final FakeWindowState dimmingImTarget = createDimmingDialogWindow(true); final FakeWindowState dimmingNonImTarget = createDimmingDialogWindow(false); final FakeWindowState visibleIme = createInputMethodWindow(true, true, false); final FakeWindowState invisibleIme = createInputMethodWindow(false, true, false); final FakeWindowState imeNonDrawNavBar = createInputMethodWindow(true, false, false); // If everything is null, return null assertNull(null, PhoneWindowManager.chooseNavigationColorWindowLw( null, null, null, NAV_BAR_BOTTOM)); assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, null, NAV_BAR_BOTTOM)); assertEquals(dimmingImTarget, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingImTarget, null, NAV_BAR_BOTTOM)); assertEquals(dimmingNonImTarget, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingNonImTarget, null, NAV_BAR_BOTTOM)); assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( null, null, visibleIme, NAV_BAR_BOTTOM)); assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( null, dimmingImTarget, visibleIme, NAV_BAR_BOTTOM)); // TODO(b/69002467): A dimming window that is shown above the IME window should win. assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( null, dimmingNonImTarget, visibleIme, NAV_BAR_BOTTOM)); assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, visibleIme, NAV_BAR_BOTTOM)); assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingImTarget, visibleIme, NAV_BAR_BOTTOM)); // TODO(b/69002467): A dimming window that is shown above the IME window should win. assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingNonImTarget, visibleIme, NAV_BAR_BOTTOM)); assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, invisibleIme, NAV_BAR_BOTTOM)); assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, invisibleIme, NAV_BAR_BOTTOM)); assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, visibleIme, NAV_BAR_RIGHT)); // Only IME windows that have FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS should be navigation color // window, but it's not yet implemented. // TODO(b/69002467): Support this. assertEquals(imeNonDrawNavBar, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, opaque, imeNonDrawNavBar, NAV_BAR_BOTTOM)); // TODO(b/69002467): Support this. assertEquals(imeNonDrawNavBar, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM)); // TODO(b/69002467): Support this. assertEquals(imeNonDrawNavBar, PhoneWindowManager.chooseNavigationColorWindowLw( opaque, dimmingNonImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM)); } @Test public void testUpdateLightNavigationBarLw() throws Exception { final FakeWindowState opaqueDarkNavBar = createOpaqueFullscreen(false); final FakeWindowState opaqueLightNavBar = createOpaqueFullscreen(true); final FakeWindowState dimming = createDimmingDialogWindow(false); final FakeWindowState imeDrawDarkNavBar = createInputMethodWindow(true,true, false); final FakeWindowState imeDrawLightNavBar = createInputMethodWindow(true,true, true); assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null, null, null)); // Opaque top fullscreen window overrides SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR flag. assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( 0, opaqueDarkNavBar, opaqueDarkNavBar, null, opaqueDarkNavBar)); assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, opaqueDarkNavBar, null, opaqueDarkNavBar)); assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, PhoneWindowManager.updateLightNavigationBarLw(0, opaqueLightNavBar, opaqueLightNavBar, null, opaqueLightNavBar)); assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, PhoneWindowManager.updateLightNavigationBarLw(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, opaqueLightNavBar, null, opaqueLightNavBar)); // Dimming window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR. assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( 0, opaqueDarkNavBar, dimming, null, dimming)); assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( 0, opaqueLightNavBar, dimming, null, dimming)); assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, dimming, null, dimming)); assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, null, dimming)); assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, imeDrawLightNavBar, dimming)); // IME window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null, imeDrawDarkNavBar, imeDrawDarkNavBar)); // Even if the top fullscreen has SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, IME window wins. assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, opaqueLightNavBar, imeDrawDarkNavBar, imeDrawDarkNavBar)); // Currently SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR in IME windows is ignored. // TODO(b/69002467): Support this. assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw( 0, opaqueDarkNavBar, opaqueDarkNavBar, imeDrawLightNavBar, imeDrawLightNavBar)); } }