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

Commit e26ab70d authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #5398675: It's (too) easy to keep the navigation bar...

...from ever becoming visible

Now there is a 1 second delay from when the user dismisses the nav bar
until when it can be re-hidden.

Also move the code for capturing touch events while nav bar is hidden
out to be used even when there is no nav bar, so this API behaves
consistently across devices whether or not they have some element of
the UI that is being hidden.  On devices with a nav bar, this will
all work the same as prime (the flag is set, the app gets the callback
about the flag being set, when the user touches that touch is captured
so the app doesn't see it put does clear the flag and tell the app
about this).

Change-Id: Icb5ea0ddaf614aa3f12d2140796217f128761dee
parent e6b68036
Loading
Loading
Loading
Loading
+77 −32
Original line number Original line Diff line number Diff line
@@ -353,8 +353,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    int mDockLeft, mDockTop, mDockRight, mDockBottom;
    int mDockLeft, mDockTop, mDockRight, mDockBottom;
    // During layout, the layer at which the doc window is placed.
    // During layout, the layer at which the doc window is placed.
    int mDockLayer;
    int mDockLayer;
    int mLastSystemUiVisibility;
    int mLastSystemUiFlags;
    int mForceClearingStatusBarVisibility = 0;
    // Bits that we are in the process of clearing, so we want to prevent
    // them from being set by applications until everything has been updated
    // to have them clear.
    int mResettingSystemUiFlags = 0;
    // Bits that we are currently always keeping cleared.
    int mForceClearedSystemUiFlags = 0;


    FakeWindow mHideNavFakeWindow = null;
    FakeWindow mHideNavFakeWindow = null;


@@ -1719,6 +1724,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }
        }
    }
    }


    /**
     * A delayed callback use to determine when it is okay to re-allow applications
     * to use certain system UI flags.  This is used to prevent applications from
     * spamming system UI changes that prevent the navigation bar from being shown.
     */
    final Runnable mAllowSystemUiDelay = new Runnable() {
        @Override public void run() {
        }
    };

    /**
     * Input handler used while nav bar is hidden.  Captures any touch on the screen,
     * to determine when the nav bar should be shown and prevent applications from
     * receiving those touches.
     */
    final InputHandler mHideNavInputHandler = new BaseInputHandler() {
    final InputHandler mHideNavInputHandler = new BaseInputHandler() {
        @Override
        @Override
        public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
        public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
@@ -1731,11 +1751,29 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                        synchronized (mLock) {
                        synchronized (mLock) {
                            // Any user activity always causes us to show the navigation controls,
                            // Any user activity always causes us to show the navigation controls,
                            // if they had been hidden.
                            // if they had been hidden.
                            int newVal = mForceClearingStatusBarVisibility
                            int newVal = mResettingSystemUiFlags
                                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                            if (mResettingSystemUiFlags != newVal) {
                                mResettingSystemUiFlags = newVal;
                                changed = true;
                            }
                            // We don't allow the system's nav bar to be hidden
                            // again for 1 second, to prevent applications from
                            // spamming us and keeping it from being shown.
                            newVal = mForceClearedSystemUiFlags
                                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                            if (mForceClearingStatusBarVisibility != newVal) {
                            if (mForceClearedSystemUiFlags != newVal) {
                                mForceClearingStatusBarVisibility = newVal;
                                mForceClearedSystemUiFlags = newVal;
                                changed = true;
                                changed = true;
                                mHandler.postDelayed(new Runnable() {
                                    @Override public void run() {
                                        synchronized (mLock) {
                                            mForceClearedSystemUiFlags &=
                                                    ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
                                        }
                                        mWindowManagerFuncs.reevaluateStatusBarVisibility();
                                    }
                                }, 1000);
                            }
                            }
                        }
                        }
                        if (changed) {
                        if (changed) {
@@ -1753,10 +1791,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    public int adjustSystemUiVisibilityLw(int visibility) {
    public int adjustSystemUiVisibilityLw(int visibility) {
        // Reset any bits in mForceClearingStatusBarVisibility that
        // Reset any bits in mForceClearingStatusBarVisibility that
        // are now clear.
        // are now clear.
        mForceClearingStatusBarVisibility &= visibility;
        mResettingSystemUiFlags &= visibility;
        // Clear any bits in the new visibility that are currently being
        // Clear any bits in the new visibility that are currently being
        // force cleared, before reporting it.
        // force cleared, before reporting it.
        return visibility & ~mForceClearingStatusBarVisibility;
        return visibility & ~mResettingSystemUiFlags
                & ~mForceClearedSystemUiFlags;
    }
    }


    public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
    public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
@@ -1795,11 +1834,28 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        pf.right = df.right = vf.right = mDockRight;
        pf.right = df.right = vf.right = mDockRight;
        pf.bottom = df.bottom = vf.bottom = mDockBottom;
        pf.bottom = df.bottom = vf.bottom = mDockBottom;


        final boolean navVisible = mNavigationBar != null && mNavigationBar.isVisibleLw() &&
                (mLastSystemUiFlags&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;

        // When the navigation bar isn't visible, we put up a fake
        // input window to catch all touch events.  This way we can
        // detect when the user presses anywhere to bring back the nav
        // bar and ensure the application doesn't see the event.
        if (navVisible) {
            if (mHideNavFakeWindow != null) {
                mHideNavFakeWindow.dismiss();
                mHideNavFakeWindow = null;
            }
        } else if (mHideNavFakeWindow == null) {
            mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
                    mHandler.getLooper(), mHideNavInputHandler,
                    "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER,
                    0, false, false, true);
        }

        // decide where the status bar goes ahead of time
        // decide where the status bar goes ahead of time
        if (mStatusBar != null) {
        if (mStatusBar != null) {
            if (mNavigationBar != null) {
            if (mNavigationBar != null) {
                final boolean navVisible = mNavigationBar.isVisibleLw() &&
                        (mLastSystemUiVisibility&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
                // Force the navigation bar to its appropriate place and
                // Force the navigation bar to its appropriate place and
                // size.  We need to do this directly, instead of relying on
                // size.  We need to do this directly, instead of relying on
                // it to bubble up from the nav bar, because this needs to
                // it to bubble up from the nav bar, because this needs to
@@ -1831,21 +1887,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                        mTmpNavigationFrame.offset(mNavigationBarWidth, 0);
                        mTmpNavigationFrame.offset(mNavigationBarWidth, 0);
                    }
                    }
                }
                }
                // When the navigation bar isn't visible, we put up a fake
                // input window to catch all touch events.  This way we can
                // detect when the user presses anywhere to bring back the nav
                // bar and ensure the application doesn't see the event.
                if (navVisible) {
                    if (mHideNavFakeWindow != null) {
                        mHideNavFakeWindow.dismiss();
                        mHideNavFakeWindow = null;
                    }
                } else if (mHideNavFakeWindow == null) {
                    mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
                            mHandler.getLooper(), mHideNavInputHandler,
                            "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER,
                            0, false, false, true);
                }
                // And compute the final frame.
                // And compute the final frame.
                mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
                mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
                        mTmpNavigationFrame, mTmpNavigationFrame);
                        mTmpNavigationFrame, mTmpNavigationFrame);
@@ -3653,12 +3694,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            return 0;
            return 0;
        }
        }
        final int visibility = mFocusedWindow.getSystemUiVisibility()
        final int visibility = mFocusedWindow.getSystemUiVisibility()
                & ~mForceClearingStatusBarVisibility;
                & ~mResettingSystemUiFlags
        int diff = visibility ^ mLastSystemUiVisibility;
                & ~mForceClearedSystemUiFlags;
        int diff = visibility ^ mLastSystemUiFlags;
        if (diff == 0) {
        if (diff == 0) {
            return 0;
            return 0;
        }
        }
        mLastSystemUiVisibility = visibility;
        mLastSystemUiFlags = visibility;
        mHandler.post(new Runnable() {
        mHandler.post(new Runnable() {
                public void run() {
                public void run() {
                    if (mStatusBarService == null) {
                    if (mStatusBarService == null) {
@@ -3685,11 +3727,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen);
        pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen);
                pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
                pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
                pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
                pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
        if (mLastSystemUiVisibility != 0 || mForceClearingStatusBarVisibility != 0) {
        if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
            pw.print(prefix); pw.print("mLastSystemUiVisibility=0x");
                || mForceClearedSystemUiFlags != 0) {
                    pw.println(Integer.toHexString(mLastSystemUiVisibility));
            pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
                    pw.print("  mForceClearingStatusBarVisibility=0x");
                    pw.print(Integer.toHexString(mLastSystemUiFlags));
                    pw.println(Integer.toHexString(mForceClearingStatusBarVisibility));
                    pw.print(" mResettingSystemUiFlags=0x");
                    pw.print(Integer.toHexString(mResettingSystemUiFlags));
                    pw.print(" mForceClearedSystemUiFlags=0x");
                    pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
        }
        }
        pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
        pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
                pw.print(" mDockMode="); pw.print(mDockMode);
                pw.print(" mDockMode="); pw.print(mDockMode);