From 9a230e01a1237749a8a19a5de8d46531b0c8ca6a Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 6 Oct 2011 11:51:27 -0700 Subject: [PATCH] Fix issue #5371530: SYSTEMUI_FLAG_HIDE_NAVIGATION reasserts itself immediately This cleans up how ui flags are managed between the client and window manager. It still reports the global UI mode state to the callback, but we now only clear certain flags when the system goes out of a state (currently this just means the hide nav bar mode), and don't corrupt other flags in the application when the global state changes. Also introduces a sequence number between the app and window manager, to avoid using bad old data coming from the app during these transitions. Change-Id: I40bbd12d9b7b69fc0ff1c7dc0cb58a933d4dfb23 --- .../service/wallpaper/WallpaperService.java | 4 +- core/java/android/view/IWindow.aidl | 3 +- core/java/android/view/IWindowSession.aidl | 7 +- core/java/android/view/SurfaceView.java | 6 +- core/java/android/view/View.java | 30 ++++++++- core/java/android/view/ViewGroup.java | 12 ++++ core/java/android/view/ViewRootImpl.java | 67 ++++++++++++++----- .../android/view/WindowManagerPolicy.java | 6 ++ .../android/internal/view/BaseIWindow.java | 5 +- .../policy/impl/PhoneWindowManager.java | 3 +- .../java/com/android/server/wm/Session.java | 12 ++-- .../server/wm/WindowManagerService.java | 35 +++++++--- .../com/android/server/wm/WindowState.java | 12 +++- .../bridge/android/BridgeWindow.java | 3 +- .../bridge/android/BridgeWindowSession.java | 6 +- 15 files changed, 161 insertions(+), 50 deletions(-) diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 713bb9108c8ae..ba94ab26e0448 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -565,7 +565,7 @@ public abstract class WallpaperService extends Service { mLayout.windowAnimations = com.android.internal.R.style.Animation_Wallpaper; mInputChannel = new InputChannel(); - if (mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets, + if (mSession.add(mWindow, mWindow.mSeq, mLayout, View.VISIBLE, mContentInsets, mInputChannel) < 0) { Log.w(TAG, "Failed to add window while updating wallpaper surface."); return; @@ -580,7 +580,7 @@ public abstract class WallpaperService extends Service { mDrawingAllowed = true; final int relayoutResult = mSession.relayout( - mWindow, mLayout, mWidth, mHeight, + mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, View.VISIBLE, false, mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurfaceHolder.mSurface); diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index 0e482d6046ab4..715fa7b4eacb4 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -74,5 +74,6 @@ oneway interface IWindow { /** * System chrome visibility changes */ - void dispatchSystemUiVisibilityChanged(int visibility); + void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, + int localValue, int localChanges); } diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 990af083d859d..282d7be6d9fbb 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -34,10 +34,10 @@ import android.view.Surface; * {@hide} */ interface IWindowSession { - int add(IWindow window, in WindowManager.LayoutParams attrs, + int add(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, out Rect outContentInsets, out InputChannel outInputChannel); - int addWithoutInputChannel(IWindow window, in WindowManager.LayoutParams attrs, + int addWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, out Rect outContentInsets); void remove(IWindow window); @@ -49,6 +49,7 @@ interface IWindowSession { * to draw the window's contents. * * @param window The window being modified. + * @param seq Ordering sequence number. * @param attrs If non-null, new attributes to apply to the window. * @param requestedWidth The width the window wants to be. * @param requestedHeight The height the window wants to be. @@ -77,7 +78,7 @@ interface IWindowSession { * @return int Result flags: {@link WindowManagerImpl#RELAYOUT_SHOW_FOCUS}, * {@link WindowManagerImpl#RELAYOUT_FIRST_TIME}. */ - int relayout(IWindow window, in WindowManager.LayoutParams attrs, + int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, boolean insetsPending, out Rect outFrame, out Rect outContentInsets, out Rect outVisibleInsets, out Configuration outConfig, diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index cbdb38e3181a4..9a57ea0679c44 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -266,7 +266,7 @@ public class SurfaceView extends View { try { DisplayMetrics metrics = getResources().getDisplayMetrics(); mLayout.x = metrics.widthPixels * 3; - mSession.relayout(mWindow, mLayout, mWidth, mHeight, VISIBLE, false, + mSession.relayout(mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, VISIBLE, false, mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurface); } catch (RemoteException e) { // Ignore @@ -492,7 +492,7 @@ public class SurfaceView extends View { mWindow = new MyWindow(this); mLayout.type = mWindowType; mLayout.gravity = Gravity.LEFT|Gravity.TOP; - mSession.addWithoutInputChannel(mWindow, mLayout, + mSession.addWithoutInputChannel(mWindow, mWindow.mSeq, mLayout, mVisible ? VISIBLE : GONE, mContentInsets); } @@ -513,7 +513,7 @@ public class SurfaceView extends View { mDrawingStopped = !visible; final int relayoutResult = mSession.relayout( - mWindow, mLayout, mWidth, mHeight, + mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets, mVisibleInsets, mConfiguration, mSurface); if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 8e5aefdff0e86..c7507f8cf6355 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1924,6 +1924,15 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal */ public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF; + /** + * These are the system UI flags that can be cleared by events outside + * of an application. Currently this is just the ability to tap on the + * screen while hiding the navigation bar to have it return. + * @hide + */ + public static final int SYSTEM_UI_CLEARABLE_FLAGS = + SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION; + /** * Find views that render the specified text. * @@ -13027,6 +13036,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } /** + * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down + * the view hierarchy. */ public void dispatchSystemUiVisibilityChanged(int visibility) { if (mOnSystemUiVisibilityChangeListener != null) { @@ -13035,6 +13046,13 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } } + void updateLocalSystemUiVisibility(int localValue, int localChanges) { + int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); + if (val != mSystemUiVisibility) { + setSystemUiVisibility(val); + } + } + /** * Creates an image that the system displays during the drag and drop * operation. This is called a "drag shadow". The default implementation @@ -14108,7 +14126,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal /** * Interface definition for a callback to be invoked when the status bar changes - * visibility. + * visibility. This reports global changes to the system UI + * state, not just what the application is requesting. * * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) */ @@ -14118,7 +14137,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * {@link View#setSystemUiVisibility(int)}. * * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE} or - * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. + * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. This tells you the + * global state of the UI visibility flags, not what your + * app is currently applying. */ public void onSystemUiVisibilityChange(int visibility); } @@ -14375,6 +14396,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal */ boolean mRecomputeGlobalAttributes; + /** + * Always report new attributes at next traversal. + */ + boolean mForceReportNewAttributes; + /** * Set during a traveral if any views want to keep the screen on. */ diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 5b4a6f8a78e62..9266ae25bcdd4 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -1200,6 +1200,18 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } + @Override + void updateLocalSystemUiVisibility(int localValue, int localChanges) { + super.updateLocalSystemUiVisibility(localValue, localChanges); + + final int count = mChildrenCount; + final View[] children = mChildren; + for (int i=0; i >>>>> ENTERED relayout from " + Binder.getCallingPid()); - int res = mService.relayoutWindow(this, window, attrs, + int res = mService.relayoutWindow(this, window, seq, attrs, requestedWidth, requestedHeight, viewFlags, insetsPending, outFrame, outContentInsets, outVisibleInsets, outConfig, outSurface); if (false) Slog.d(WindowManagerService.TAG, "<<<<<< EXITING relayout to " diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 8e98ec4da19df..f8525adcee99f 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -1948,7 +1948,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - public int addWindow(Session session, IWindow client, + public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) { int res = mPolicy.checkAddPermission(attrs); @@ -2040,7 +2040,7 @@ public class WindowManagerService extends IWindowManager.Stub } win = new WindowState(this, session, client, token, - attachedWindow, attrs, viewVisibility); + attachedWindow, seq, attrs, viewVisibility); if (win.mDeathRecipient == null) { // Client has apparently died, so there is no reason to // continue. @@ -2467,7 +2467,7 @@ public class WindowManagerService extends IWindowManager.Stub return null; } - public int relayoutWindow(Session session, IWindow client, + public int relayoutWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, boolean insetsPending, Rect outFrame, Rect outContentInsets, Rect outVisibleInsets, @@ -2477,13 +2477,13 @@ public class WindowManagerService extends IWindowManager.Stub boolean configChanged; // if they don't have this permission, mask out the status bar bits + int systemUiVisibility = 0; if (attrs != null) { - if (((attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility) - & StatusBarManager.DISABLE_MASK) != 0) { + systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility); + if ((systemUiVisibility & StatusBarManager.DISABLE_MASK) != 0) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) != PackageManager.PERMISSION_GRANTED) { - attrs.systemUiVisibility &= ~StatusBarManager.DISABLE_MASK; - attrs.subtreeSystemUiVisibility &= ~StatusBarManager.DISABLE_MASK; + systemUiVisibility &= ~StatusBarManager.DISABLE_MASK; } } } @@ -2496,6 +2496,9 @@ public class WindowManagerService extends IWindowManager.Stub } win.mRequestedWidth = requestedWidth; win.mRequestedHeight = requestedHeight; + if (attrs != null && seq == win.mSeq) { + win.mSystemUiVisibility = systemUiVisibility; + } if (attrs != null) { mPolicy.adjustWindowParamsLw(attrs); @@ -9088,13 +9091,27 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void statusBarVisibilityChanged(int visibility) { mInputManager.setSystemUiVisibility(visibility); + synchronized (mWindowMap) { final int N = mWindows.size(); for (int i = 0; i < N; i++) { WindowState ws = mWindows.get(i); try { - if (ws.getAttrs().hasSystemUiListeners) { - ws.mClient.dispatchSystemUiVisibilityChanged(visibility); + int curValue = ws.mSystemUiVisibility; + int diff = curValue ^ visibility; + // We are only interested in differences of one of the + // clearable flags... + diff &= View.SYSTEM_UI_CLEARABLE_FLAGS; + // ...if it has actually been cleared. + diff &= ~visibility; + int newValue = (curValue&~diff) | (visibility&diff); + if (newValue != curValue) { + ws.mSeq++; + ws.mSystemUiVisibility = newValue; + } + if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) { + ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq, + visibility, newValue, diff); } } catch (RemoteException e) { // so sorry diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 3640a15284b2d..47f74fb4a676e 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -76,8 +76,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { final boolean mIsImWindow; final boolean mIsWallpaper; final boolean mIsFloatingLayer; + int mSeq; boolean mEnforceSizeCompat; int mViewVisibility; + int mSystemUiVisibility; boolean mPolicyVisibility = true; boolean mPolicyVisibilityAfterAnim = true; boolean mAppFreezing; @@ -282,7 +284,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean mWasPaused; WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, - WindowState attachedWindow, WindowManager.LayoutParams a, + WindowState attachedWindow, int seq, WindowManager.LayoutParams a, int viewVisibility) { mService = service; mSession = s; @@ -292,6 +294,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mViewVisibility = viewVisibility; DeathRecipient deathRecipient = new DeathRecipient(); mAlpha = a.alpha; + mSeq = seq; mEnforceSizeCompat = (mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0; if (WindowManagerService.localLOGV) Slog.v( WindowManagerService.TAG, "Window " + this + " client=" + c.asBinder() @@ -551,6 +554,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { return mAttrs; } + public int getSystemUiVisibility() { + return mSystemUiVisibility; + } + public int getSurfaceLayer() { return mLayer; } @@ -1597,6 +1604,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { pw.print(" mLastHidden="); pw.print(mLastHidden); pw.print(" mHaveFrame="); pw.print(mHaveFrame); pw.print(" mObscured="); pw.println(mObscured); + pw.print(prefix); pw.print("mSeq="); pw.print(mSeq); + pw.print(" mSystemUiVisibility=0x"); + pw.println(Integer.toHexString(mSystemUiVisibility)); } if (!mPolicyVisibility || !mPolicyVisibilityAfterAnim || mAttachedHidden) { pw.print(prefix); pw.print("mPolicyVisibility="); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java index 8e673adc77f14..e13380e7e2ddb 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java @@ -85,7 +85,8 @@ public final class BridgeWindow implements IWindow { // pass for now. } - public void dispatchSystemUiVisibilityChanged(int visibility) { + public void dispatchSystemUiVisibilityChanged(int seq, int globalUi, + int localValue, int localChanges) { // pass for now. } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java index ab8c4ec75152f..1d97e1506866c 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java @@ -37,14 +37,14 @@ import android.view.WindowManager.LayoutParams; */ public final class BridgeWindowSession implements IWindowSession { - public int add(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3, + public int add(IWindow arg0, int seq, LayoutParams arg1, int arg2, Rect arg3, InputChannel outInputchannel) throws RemoteException { // pass for now. return 0; } - public int addWithoutInputChannel(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3) + public int addWithoutInputChannel(IWindow arg0, int seq, LayoutParams arg1, int arg2, Rect arg3) throws RemoteException { // pass for now. return 0; @@ -78,7 +78,7 @@ public final class BridgeWindowSession implements IWindowSession { return null; } - public int relayout(IWindow arg0, LayoutParams arg1, int arg2, int arg3, int arg4, + public int relayout(IWindow arg0, int seq, LayoutParams arg1, int arg2, int arg3, int arg4, boolean arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8) throws RemoteException { // pass for now.