Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d0a66b21 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Add a test for updateLightNavigationBarLw()

As a preparation to allow IME windows to use
SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, this CL makes
PhoneWindowManager#updateLightNavigationBarLw() testable and adds
several test cases to clarify how this method currently works.

This is a mechanical change and there should be no behavior change.

Bug: 69002467
Test: atest com.android.server.policy.PhoneWindowManagerTest
Change-Id: I2761cc037b013da52507592369a33e86a3138c14
parent 8f162c6e
Loading
Loading
Loading
Loading
+22 −10
Original line number Diff line number Diff line
@@ -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];
@@ -4684,6 +4685,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) {
@@ -7851,17 +7853,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
@@ -7869,7 +7876,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;
            }
@@ -8008,8 +8016,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;
    }
+7 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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}.
@@ -1637,6 +1643,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
     * @see #NAV_BAR_RIGHT
     * @see #NAV_BAR_BOTTOM
     */
    @NavigationBarPosition
    int getNavBarPosition();

    /**
+1 −0
Original line number Diff line number Diff line
@@ -5874,6 +5874,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
+2 −1
Original line number Diff line number Diff line
@@ -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;

@@ -221,7 +222,7 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState {

    @Override
    public boolean isDimming() {
        throw new UnsupportedOperationException("not implemented");
        return isDimming;
    }

    @Override
+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