Skip to content

Commit e26ab70

Browse files
author
Dianne Hackborn
committed
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
1 parent e6b6803 commit e26ab70

File tree

1 file changed

+77
-32
lines changed

1 file changed

+77
-32
lines changed

policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

Lines changed: 77 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,13 @@ public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finished
353353
int mDockLeft, mDockTop, mDockRight, mDockBottom;
354354
// During layout, the layer at which the doc window is placed.
355355
int mDockLayer;
356-
int mLastSystemUiVisibility;
357-
int mForceClearingStatusBarVisibility = 0;
356+
int mLastSystemUiFlags;
357+
// Bits that we are in the process of clearing, so we want to prevent
358+
// them from being set by applications until everything has been updated
359+
// to have them clear.
360+
int mResettingSystemUiFlags = 0;
361+
// Bits that we are currently always keeping cleared.
362+
int mForceClearedSystemUiFlags = 0;
358363

359364
FakeWindow mHideNavFakeWindow = null;
360365

@@ -1719,6 +1724,21 @@ public void onKeyguardExitResult(boolean success) {
17191724
}
17201725
}
17211726

1727+
/**
1728+
* A delayed callback use to determine when it is okay to re-allow applications
1729+
* to use certain system UI flags. This is used to prevent applications from
1730+
* spamming system UI changes that prevent the navigation bar from being shown.
1731+
*/
1732+
final Runnable mAllowSystemUiDelay = new Runnable() {
1733+
@Override public void run() {
1734+
}
1735+
};
1736+
1737+
/**
1738+
* Input handler used while nav bar is hidden. Captures any touch on the screen,
1739+
* to determine when the nav bar should be shown and prevent applications from
1740+
* receiving those touches.
1741+
*/
17221742
final InputHandler mHideNavInputHandler = new BaseInputHandler() {
17231743
@Override
17241744
public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
@@ -1731,11 +1751,29 @@ public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finished
17311751
synchronized (mLock) {
17321752
// Any user activity always causes us to show the navigation controls,
17331753
// if they had been hidden.
1734-
int newVal = mForceClearingStatusBarVisibility
1754+
int newVal = mResettingSystemUiFlags
1755+
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1756+
if (mResettingSystemUiFlags != newVal) {
1757+
mResettingSystemUiFlags = newVal;
1758+
changed = true;
1759+
}
1760+
// We don't allow the system's nav bar to be hidden
1761+
// again for 1 second, to prevent applications from
1762+
// spamming us and keeping it from being shown.
1763+
newVal = mForceClearedSystemUiFlags
17351764
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1736-
if (mForceClearingStatusBarVisibility != newVal) {
1737-
mForceClearingStatusBarVisibility = newVal;
1765+
if (mForceClearedSystemUiFlags != newVal) {
1766+
mForceClearedSystemUiFlags = newVal;
17381767
changed = true;
1768+
mHandler.postDelayed(new Runnable() {
1769+
@Override public void run() {
1770+
synchronized (mLock) {
1771+
mForceClearedSystemUiFlags &=
1772+
~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1773+
}
1774+
mWindowManagerFuncs.reevaluateStatusBarVisibility();
1775+
}
1776+
}, 1000);
17391777
}
17401778
}
17411779
if (changed) {
@@ -1753,10 +1791,11 @@ public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finished
17531791
public int adjustSystemUiVisibilityLw(int visibility) {
17541792
// Reset any bits in mForceClearingStatusBarVisibility that
17551793
// are now clear.
1756-
mForceClearingStatusBarVisibility &= visibility;
1794+
mResettingSystemUiFlags &= visibility;
17571795
// Clear any bits in the new visibility that are currently being
17581796
// force cleared, before reporting it.
1759-
return visibility & ~mForceClearingStatusBarVisibility;
1797+
return visibility & ~mResettingSystemUiFlags
1798+
& ~mForceClearedSystemUiFlags;
17601799
}
17611800

17621801
public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
@@ -1795,11 +1834,28 @@ public void beginLayoutLw(int displayWidth, int displayHeight, int displayRotati
17951834
pf.right = df.right = vf.right = mDockRight;
17961835
pf.bottom = df.bottom = vf.bottom = mDockBottom;
17971836

1837+
final boolean navVisible = mNavigationBar != null && mNavigationBar.isVisibleLw() &&
1838+
(mLastSystemUiFlags&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
1839+
1840+
// When the navigation bar isn't visible, we put up a fake
1841+
// input window to catch all touch events. This way we can
1842+
// detect when the user presses anywhere to bring back the nav
1843+
// bar and ensure the application doesn't see the event.
1844+
if (navVisible) {
1845+
if (mHideNavFakeWindow != null) {
1846+
mHideNavFakeWindow.dismiss();
1847+
mHideNavFakeWindow = null;
1848+
}
1849+
} else if (mHideNavFakeWindow == null) {
1850+
mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
1851+
mHandler.getLooper(), mHideNavInputHandler,
1852+
"hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER,
1853+
0, false, false, true);
1854+
}
1855+
17981856
// decide where the status bar goes ahead of time
17991857
if (mStatusBar != null) {
18001858
if (mNavigationBar != null) {
1801-
final boolean navVisible = mNavigationBar.isVisibleLw() &&
1802-
(mLastSystemUiVisibility&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
18031859
// Force the navigation bar to its appropriate place and
18041860
// size. We need to do this directly, instead of relying on
18051861
// it to bubble up from the nav bar, because this needs to
@@ -1831,21 +1887,6 @@ public void beginLayoutLw(int displayWidth, int displayHeight, int displayRotati
18311887
mTmpNavigationFrame.offset(mNavigationBarWidth, 0);
18321888
}
18331889
}
1834-
// When the navigation bar isn't visible, we put up a fake
1835-
// input window to catch all touch events. This way we can
1836-
// detect when the user presses anywhere to bring back the nav
1837-
// bar and ensure the application doesn't see the event.
1838-
if (navVisible) {
1839-
if (mHideNavFakeWindow != null) {
1840-
mHideNavFakeWindow.dismiss();
1841-
mHideNavFakeWindow = null;
1842-
}
1843-
} else if (mHideNavFakeWindow == null) {
1844-
mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
1845-
mHandler.getLooper(), mHideNavInputHandler,
1846-
"hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER,
1847-
0, false, false, true);
1848-
}
18491890
// And compute the final frame.
18501891
mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
18511892
mTmpNavigationFrame, mTmpNavigationFrame);
@@ -3653,12 +3694,13 @@ private int updateSystemUiVisibilityLw() {
36533694
return 0;
36543695
}
36553696
final int visibility = mFocusedWindow.getSystemUiVisibility()
3656-
& ~mForceClearingStatusBarVisibility;
3657-
int diff = visibility ^ mLastSystemUiVisibility;
3697+
& ~mResettingSystemUiFlags
3698+
& ~mForceClearedSystemUiFlags;
3699+
int diff = visibility ^ mLastSystemUiFlags;
36583700
if (diff == 0) {
36593701
return 0;
36603702
}
3661-
mLastSystemUiVisibility = visibility;
3703+
mLastSystemUiFlags = visibility;
36623704
mHandler.post(new Runnable() {
36633705
public void run() {
36643706
if (mStatusBarService == null) {
@@ -3685,11 +3727,14 @@ public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args
36853727
pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen);
36863728
pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
36873729
pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
3688-
if (mLastSystemUiVisibility != 0 || mForceClearingStatusBarVisibility != 0) {
3689-
pw.print(prefix); pw.print("mLastSystemUiVisibility=0x");
3690-
pw.println(Integer.toHexString(mLastSystemUiVisibility));
3691-
pw.print(" mForceClearingStatusBarVisibility=0x");
3692-
pw.println(Integer.toHexString(mForceClearingStatusBarVisibility));
3730+
if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3731+
|| mForceClearedSystemUiFlags != 0) {
3732+
pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3733+
pw.print(Integer.toHexString(mLastSystemUiFlags));
3734+
pw.print(" mResettingSystemUiFlags=0x");
3735+
pw.print(Integer.toHexString(mResettingSystemUiFlags));
3736+
pw.print(" mForceClearedSystemUiFlags=0x");
3737+
pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
36933738
}
36943739
pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
36953740
pw.print(" mDockMode="); pw.print(mDockMode);

0 commit comments

Comments
 (0)