diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-10-06 22:35:11 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2011-10-07 14:32:01 -0700 |
commit | df89e65bf0fcc651d20b208c8d8d0b848fb43418 (patch) | |
tree | f8e48a203c551b8fd834aad34c1f5fe6d2755461 | |
parent | 25d888b5ff23acf1a9d41bef3e74ee897baf5ad7 (diff) | |
download | frameworks_base-df89e65bf0fcc651d20b208c8d8d0b848fb43418.zip frameworks_base-df89e65bf0fcc651d20b208c8d8d0b848fb43418.tar.gz frameworks_base-df89e65bf0fcc651d20b208c8d8d0b848fb43418.tar.bz2 |
Fix how we hide and show the nav bar.
The PhoneWindowManager is now responsible for hiding and showing
the nav bar.
For hiding, it just moves it off the screen (easy way to get a
nice slide animation on and off). At the same time, we use a
new WM facility to put up a fake input window to capture all
touch events.
When a touch event is received, we force the system UI to clear
the navigation hiding bit so it will be shown again.
This removes a bunch of code from the system UI for hiding and
showing the nav bar. Also removes the code calling from userActivity()
to the system UI, which was bad. (Also no longer using userActivity()
fixes bugs around re-showing the nav bar due to key presses and
other wrong things.)
Change-Id: I8c3174873b5bcaa36a92322a51e8f7993e88e551
14 files changed, 413 insertions, 150 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 99acb3f..e8ab227 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -416,6 +416,13 @@ public interface WindowManager extends ViewManager { public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21; /** + * Window type: Fake window to consume touch events when the navigation + * bar is hidden. + * @hide + */ + public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22; + + /** * End of types of system windows. */ public static final int LAST_SYSTEM_WINDOW = 2999; diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index aaf45e5..bfd2959 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -23,6 +23,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.os.IBinder; import android.os.LocalPowerManager; +import android.os.Looper; import android.view.animation.Animation; import java.io.FileDescriptor; @@ -315,6 +316,36 @@ public interface WindowManagerPolicy { } /** + * Representation of a "fake window" that the policy has added to the + * window manager to consume events. + */ + public interface FakeWindow { + /** + * Remove the fake window from the window manager. + */ + void dismiss(); + } + + /** + * Interface for calling back in to the window manager that is private + * between it and the policy. + */ + public interface WindowManagerFuncs { + /** + * Ask the window manager to re-evaluate the system UI flags. + */ + public void reevaluateStatusBarVisibility(); + + /** + * Add a fake window to the window manager. This window sits + * at the top of the other windows and consumes events. + */ + public FakeWindow addFakeWindow(Looper looper, InputHandler inputHandler, + String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys, + boolean hasFocus, boolean touchFullscreen); + } + + /** * Bit mask that is set for all enter transition. */ public final int TRANSIT_ENTER_MASK = 0x1000; @@ -395,6 +426,7 @@ public interface WindowManagerPolicy { * @param powerManager */ public void init(Context context, IWindowManager windowManager, + WindowManagerFuncs windowManagerFuncs, LocalPowerManager powerManager); /** @@ -762,7 +794,7 @@ public interface WindowManagerPolicy { /** * A new window has been focused. */ - public void focusChanged(WindowState lastFocus, WindowState newFocus); + public int focusChangedLw(WindowState lastFocus, WindowState newFocus); /** * Called after the screen turns off. @@ -968,6 +1000,14 @@ public interface WindowManagerPolicy { public void setUserRotationMode(int mode, int rotation); /** + * Called when a new system UI visibility is being reported, allowing + * the policy to adjust what is actually reported. + * @param visibility The raw visiblity reported by the status bar. + * @return The new desired visibility. + */ + public int adjustSystemUiVisibilityLw(int visibility); + + /** * Print the WindowManagerPolicy's state into the given stream. * * @param prefix Text to print at the front of each line. diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 3916e86..aca1fa2 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -34,7 +34,6 @@ oneway interface IStatusBar void topAppWindowChanged(boolean menuVisible); void setImeWindowStatus(in IBinder token, int vis, int backDisposition); void setHardKeyboardStatus(boolean available, boolean enabled); - void userActivity(); void toggleRecentApps(); } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 07430e7..ecebfc0 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -46,6 +46,5 @@ interface IStatusBarService void onNotificationClear(String pkg, String tag, int id); void setSystemUiVisibility(int vis); void setHardKeyboardEnabled(boolean enabled); - void userActivity(); void toggleRecentApps(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index c91f513..bf2d5e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -60,8 +60,7 @@ public class CommandQueue extends IStatusBar.Stub { private static final int MSG_SHOW_IME_BUTTON = 9 << MSG_SHIFT; private static final int MSG_SET_HARD_KEYBOARD_STATUS = 10 << MSG_SHIFT; - private static final int MSG_USER_ACTIVITY = 11 << MSG_SHIFT; - private static final int MSG_TOGGLE_RECENT_APPS = 12 << MSG_SHIFT; + private static final int MSG_TOGGLE_RECENT_APPS = 11 << MSG_SHIFT; private StatusBarIconList mList; private Callbacks mCallbacks; @@ -90,7 +89,6 @@ public class CommandQueue extends IStatusBar.Stub { public void topAppWindowChanged(boolean visible); public void setImeWindowStatus(IBinder token, int vis, int backDisposition); public void setHardKeyboardStatus(boolean available, boolean enabled); - public void userActivity(); public void toggleRecentApps(); } @@ -191,13 +189,6 @@ public class CommandQueue extends IStatusBar.Stub { } } - public void userActivity() { - synchronized (mList) { - mHandler.removeMessages(MSG_USER_ACTIVITY); - mHandler.obtainMessage(MSG_USER_ACTIVITY, 0, 0, null).sendToTarget(); - } - } - public void toggleRecentApps() { synchronized (mList) { mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS); @@ -271,9 +262,6 @@ public class CommandQueue extends IStatusBar.Stub { case MSG_SET_HARD_KEYBOARD_STATUS: mCallbacks.setHardKeyboardStatus(msg.arg1 != 0, msg.arg2 != 0); break; - case MSG_USER_ACTIVITY: - mCallbacks.userActivity(); - break; case MSG_TOGGLE_RECENT_APPS: mCallbacks.toggleRecentApps(); break; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index d260e6d..e3a64a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -17,9 +17,7 @@ package com.android.systemui.statusbar.phone; import android.animation.Animator; -import android.animation.AnimatorSet; import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.Resources; import android.os.ServiceManager; @@ -27,14 +25,12 @@ import android.util.AttributeSet; import android.util.Slog; import android.view.animation.AccelerateInterpolator; import android.view.Display; -import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.Surface; import android.view.WindowManager; import android.widget.LinearLayout; -import android.content.res.Configuration; import com.android.internal.statusbar.IStatusBarService; @@ -54,7 +50,6 @@ public class NavigationBarView extends LinearLayout { final Display mDisplay; View mCurrentView = null; View[] mRotatedViews = new View[4]; - AnimatorSet mLastAnimator = null; int mBarSize; boolean mVertical; @@ -204,43 +199,6 @@ public class NavigationBarView extends LinearLayout { // bring up the lights no matter what setLowProfile(false); - - if (!ANIMATE_HIDE_TRANSITION) { - setVisibility(hide ? View.GONE : View.VISIBLE); - return; - } - - float oldAlpha = mCurrentView.getAlpha(); - if (DEBUG) { - Slog.d(TAG, "animating alpha: " + oldAlpha + " -> " - + (!hide ? 1f : 0f)); - } - - if (mLastAnimator != null && mLastAnimator.isRunning()) mLastAnimator.cancel(); - - if (!hide) { - setVisibility(View.VISIBLE); - } - - // play us off, animatorset - mLastAnimator = new AnimatorSet(); - mLastAnimator.playTogether( - ObjectAnimator.ofFloat(mCurrentView, "alpha", hide ? 0f : 1f), - ObjectAnimator.ofFloat(mCurrentView, - mVertical ? "translationX" : "translationY", - hide ? mBarSize : 0) - ); - mLastAnimator.setDuration(!hide ? 250 : 1000); - mLastAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator _a) { - mLastAnimator = null; - if (hide) { - setVisibility(View.GONE); - } - } - }); - mLastAnimator.start(); } public void onFinishInflate() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index d6e4d1b..09ea6ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -31,12 +31,8 @@ import android.content.IntentFilter; import android.content.res.Resources; import android.content.res.Configuration; import android.graphics.PixelFormat; -import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.net.Uri; -import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.Handler; @@ -471,6 +467,7 @@ public class PhoneStatusBar extends StatusBar { 0 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH | WindowManager.LayoutParams.FLAG_SLIPPERY, PixelFormat.OPAQUE); @@ -2028,19 +2025,6 @@ public class PhoneStatusBar extends StatusBar { } } - // The user is not allowed to get stuck without navigation UI. Upon the slightest user - // interaction we bring the navigation back. - public void userActivity() { - if (0 != (mSystemUiVisibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) { - try { - mBarService.setSystemUiVisibility( - mSystemUiVisibility & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); - } catch (RemoteException ex) { - // weep softly - } - } - } - public void toggleRecentApps() { int msg = (mRecentsPanel.getVisibility() == View.GONE) ? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 54b45a9..ba52fb8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -1822,9 +1822,6 @@ public class TabletStatusBar extends StatusBar implements visibilityChanged(false); } - public void userActivity() { - } - public void toggleRecentApps() { int msg = (mRecentsPanel.getVisibility() == View.GONE) ? MSG_OPEN_RECENTS_PANEL : MSG_CLOSE_RECENTS_PANEL; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 9e1dec7..487063d 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -103,6 +103,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_DRAG; +import static android.view.WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_PHONE; @@ -127,6 +128,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; import android.view.KeyCharacterMap.FallbackAction; +import android.view.WindowManagerPolicy.WindowManagerFuncs; import android.view.accessibility.AccessibilityEvent; import android.view.animation.Animation; import android.view.animation.AnimationUtils; @@ -205,6 +207,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final int BOOT_PROGRESS_LAYER = 22; // the (mouse) pointer layer static final int POINTER_LAYER = 23; + static final int HIDDEN_NAV_CONSUMER_LAYER = 24; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -220,10 +223,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int SW_LID = 0x00; private static final int BTN_MOUSE = 0x110; + /** + * Lock protecting internal state. Must not call out into window + * manager with lock held. (This lock will be acquired in places + * where the window manager is calling in with its own lock held.) + */ final Object mLock = new Object(); - + Context mContext; IWindowManager mWindowManager; + WindowManagerFuncs mWindowManagerFuncs; LocalPowerManager mPowerManager; IStatusBarService mStatusBarService; Vibrator mVibrator; // Vibrator for giving feedback of orientation changes @@ -344,7 +353,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mDockLeft, mDockTop, mDockRight, mDockBottom; // During layout, the layer at which the doc window is placed. int mDockLayer; - + int mLastSystemUiVisibility; + int mForceClearingStatusBarVisibility = 0; + + FakeWindow mHideNavFakeWindow = null; + static final Rect mTmpParentFrame = new Rect(); static final Rect mTmpDisplayFrame = new Rect(); static final Rect mTmpContentFrame = new Rect(); @@ -647,9 +660,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void init(Context context, IWindowManager windowManager, + WindowManagerFuncs windowManagerFuncs, LocalPowerManager powerManager) { mContext = context; mWindowManager = windowManager; + mWindowManagerFuncs = windowManagerFuncs; mPowerManager = powerManager; mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager); mHandler = new Handler(); @@ -1068,6 +1083,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return NAVIGATION_BAR_LAYER; case TYPE_BOOT_PROGRESS: return BOOT_PROGRESS_LAYER; + case TYPE_HIDDEN_NAV_CONSUMER: + return HIDDEN_NAV_CONSUMER_LAYER; } Log.e(TAG, "Unknown window type: " + type); return APPLICATION_LAYER; @@ -1646,6 +1663,46 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + final InputHandler mHideNavInputHandler = new BaseInputHandler() { + @Override + public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) { + boolean handled = false; + try { + if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + // When the user taps down, we re-show the nav bar. + boolean changed = false; + synchronized (mLock) { + // Any user activity always causes us to show the navigation controls, + // if they had been hidden. + int newVal = mForceClearingStatusBarVisibility + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + if (mForceClearingStatusBarVisibility != newVal) { + mForceClearingStatusBarVisibility = newVal; + changed = true; + } + } + if (changed) { + mWindowManagerFuncs.reevaluateStatusBarVisibility(); + } + } + } + } finally { + finishedCallback.finished(handled); + } + } + }; + + @Override + public int adjustSystemUiVisibilityLw(int visibility) { + // Reset any bits in mForceClearingStatusBarVisibility that + // are now clear. + mForceClearingStatusBarVisibility &= visibility; + // Clear any bits in the new visibility that are currently being + // force cleared, before reporting it. + return visibility & ~mForceClearingStatusBarVisibility; + } + public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) { final int fl = attrs.flags; @@ -1684,8 +1741,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // decide where the status bar goes ahead of time if (mStatusBar != null) { - Rect navr = 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 // size. We need to do this directly, instead of relying on // it to bubble up from the nav bar, because this needs to @@ -1694,19 +1752,45 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Portrait screen; nav bar goes on bottom. mTmpNavigationFrame.set(0, displayHeight-mNavigationBarHeight, displayWidth, displayHeight); - if (mNavigationBar.isVisibleLw()) { + if (navVisible) { mDockBottom = mTmpNavigationFrame.top; mRestrictedScreenHeight = mDockBottom - mDockTop; + } else { + // We currently want to hide the navigation UI. Do this by just + // moving it off the screen, so it can still receive input events + // to know when to be re-shown. + mTmpNavigationFrame.offset(0, mNavigationBarHeight); } } else { // Landscape screen; nav bar goes to the right. mTmpNavigationFrame.set(displayWidth-mNavigationBarWidth, 0, displayWidth, displayHeight); - if (mNavigationBar.isVisibleLw()) { + if (navVisible) { mDockRight = mTmpNavigationFrame.left; mRestrictedScreenWidth = mDockRight - mDockLeft; + } else { + // We currently want to hide the navigation UI. Do this by just + // moving it off the screen, so it can still receive input events + // to know when to be re-shown. + 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. mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame); if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); @@ -2214,7 +2298,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - updateSystemUiVisibility(); + if ((updateSystemUiVisibilityLw()&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) { + // If the navigation bar has been hidden or shown, we need to do another + // layout pass to update that window. + changes |= FINISH_LAYOUT_REDO_LAYOUT; + } // update since mAllowLockscreenWhenOn might have changed updateLockScreenTimeout(); @@ -2255,9 +2343,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } - public void focusChanged(WindowState lastFocus, WindowState newFocus) { + public int focusChangedLw(WindowState lastFocus, WindowState newFocus) { mFocusedWindow = newFocus; - updateSystemUiVisibility(); + if ((updateSystemUiVisibilityLw()&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) { + // If the navigation bar has been hidden or shown, we need to do another + // layout pass to update that window. + return FINISH_LAYOUT_REDO_LAYOUT; + } + return 0; } /** {@inheritDoc} */ @@ -3200,6 +3293,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void userActivity() { + // *************************************** + // NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE + // *************************************** + // THIS IS CALLED FROM DEEP IN THE POWER MANAGER + // WITH ITS LOCKS HELD. + // + // This code must be VERY careful about the locks + // it acquires. + // In fact, the current code acquires way too many, + // and probably has lurking deadlocks. + synchronized (mScreenLockTimeout) { if (mLockScreenTimerActive) { // reset the timer @@ -3208,14 +3312,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - if (mStatusBarService != null) { - try { - mStatusBarService.userActivity(); - } catch (RemoteException ex) {} - } - - synchronized (mLock) { - updateScreenSaverTimeoutLocked(); + // Turn this off for now, screen savers not currently enabled. + if (false) { + synchronized (mLock) { + updateScreenSaverTimeoutLocked(); + } } } @@ -3257,6 +3358,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void updateScreenSaverTimeoutLocked() { if (mScreenSaverActivator == null) return; + // GAH... acquiring a lock within a lock? Please let's fix this. + // (Also note this is called from userActivity, with the power manager + // lock held. Not good.) synchronized (mScreenSaverActivator) { mHandler.removeCallbacks(mScreenSaverActivator); if (mScreenSaverEnabled && mScreenOnEarly && mScreenSaverTimeout > 0) { @@ -3493,32 +3597,36 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mScreenOnEarly; } - private void updateSystemUiVisibility() { + private int updateSystemUiVisibilityLw() { // If there is no window focused, there will be nobody to handle the events // anyway, so just hang on in whatever state we're in until things settle down. - if (mFocusedWindow != null) { - final int visibility = mFocusedWindow.getSystemUiVisibility(); - mHandler.post(new Runnable() { - public void run() { - if (mStatusBarService == null) { - mStatusBarService = IStatusBarService.Stub.asInterface( - ServiceManager.getService("statusbar")); - } - if (mStatusBarService != null) { - // need to assume status bar privileges to invoke lights on - long origId = Binder.clearCallingIdentity(); - try { - mStatusBarService.setSystemUiVisibility(visibility); - } catch (RemoteException e) { - // not much to be done - mStatusBarService = null; - } finally { - Binder.restoreCallingIdentity(origId); - } + if (mFocusedWindow == null) { + return 0; + } + final int visibility = mFocusedWindow.getSystemUiVisibility() + & ~mForceClearingStatusBarVisibility; + int diff = visibility ^ mLastSystemUiVisibility; + if (diff == 0) { + return 0; + } + mLastSystemUiVisibility = visibility; + mHandler.post(new Runnable() { + public void run() { + if (mStatusBarService == null) { + mStatusBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService("statusbar")); + } + if (mStatusBarService != null) { + try { + mStatusBarService.setSystemUiVisibility(visibility); + } catch (RemoteException e) { + // not much to be done + mStatusBarService = null; } } - }); - } + } + }); + return diff; } public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) { @@ -3528,6 +3636,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen); pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation); pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged); + if (mLastSystemUiVisibility != 0 || mForceClearingStatusBarVisibility != 0) { + pw.print(prefix); pw.print("mLastSystemUiVisibility=0x"); + pw.println(Integer.toHexString(mLastSystemUiVisibility)); + pw.print(" mForceClearingStatusBarVisibility=0x"); + pw.println(Integer.toHexString(mForceClearingStatusBarVisibility)); + } pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode); pw.print(" mDockMode="); pw.print(mDockMode); pw.print(" mCarDockRotation="); pw.print(mCarDockRotation); diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java index bab9f8a..a9ff6c5 100644 --- a/services/java/com/android/server/StatusBarManagerService.java +++ b/services/java/com/android/server/StatusBarManagerService.java @@ -117,11 +117,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub // ================================================================================ // From IStatusBarService // ================================================================================ - public void userActivity() { - if (mBar != null) try { - mBar.userActivity(); - } catch (RemoteException ex) {} - } public void expand() { enforceExpandStatusBar(); diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java index f2e7485..25cc259 100644 --- a/services/java/com/android/server/wm/DragState.java +++ b/services/java/com/android/server/wm/DragState.java @@ -32,7 +32,6 @@ import android.view.InputQueue; import android.view.Surface; import android.view.View; import android.view.WindowManager; -import android.view.WindowManagerPolicy; import java.util.ArrayList; diff --git a/services/java/com/android/server/wm/FakeWindowImpl.java b/services/java/com/android/server/wm/FakeWindowImpl.java new file mode 100644 index 0000000..0e72f7d --- /dev/null +++ b/services/java/com/android/server/wm/FakeWindowImpl.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2011 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.wm; + +import android.os.Looper; +import android.os.Process; +import android.util.Slog; +import android.view.InputChannel; +import android.view.InputHandler; +import android.view.InputQueue; +import android.view.WindowManagerPolicy; + +public final class FakeWindowImpl implements WindowManagerPolicy.FakeWindow { + final WindowManagerService mService; + final InputChannel mServerChannel, mClientChannel; + final InputApplicationHandle mApplicationHandle; + final InputWindowHandle mWindowHandle; + final int mWindowLayer; + + boolean mTouchFullscreen; + + public FakeWindowImpl(WindowManagerService service, Looper looper, InputHandler inputHandler, + String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys, + boolean hasFocus, boolean touchFullscreen) { + mService = service; + + InputChannel[] channels = InputChannel.openInputChannelPair(name); + mServerChannel = channels[0]; + mClientChannel = channels[1]; + mService.mInputManager.registerInputChannel(mServerChannel, null); + InputQueue.registerInputChannel(mClientChannel, inputHandler, looper.getQueue()); + + mApplicationHandle = new InputApplicationHandle(null); + mApplicationHandle.name = name; + mApplicationHandle.dispatchingTimeoutNanos = + WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; + + mWindowHandle = new InputWindowHandle(mApplicationHandle, null); + mWindowHandle.name = name; + mWindowHandle.inputChannel = mServerChannel; + mWindowLayer = getLayerLw(windowType); + mWindowHandle.layer = mWindowLayer; + mWindowHandle.layoutParamsFlags = layoutParamsFlags; + mWindowHandle.layoutParamsType = windowType; + mWindowHandle.dispatchingTimeoutNanos = + WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; + mWindowHandle.visible = true; + mWindowHandle.canReceiveKeys = canReceiveKeys; + mWindowHandle.hasFocus = hasFocus; + mWindowHandle.hasWallpaper = false; + mWindowHandle.paused = false; + mWindowHandle.ownerPid = Process.myPid(); + mWindowHandle.ownerUid = Process.myUid(); + mWindowHandle.inputFeatures = 0; + mWindowHandle.scaleFactor = 1.0f; + + mTouchFullscreen = touchFullscreen; + } + + void layout(int dw, int dh) { + if (mTouchFullscreen) { + mWindowHandle.touchableRegion.set(0, 0, dw, dh); + } else { + mWindowHandle.touchableRegion.setEmpty(); + } + mWindowHandle.frameLeft = 0; + mWindowHandle.frameTop = 0; + mWindowHandle.frameRight = dw; + mWindowHandle.frameBottom = dh; + } + + @Override + public void dismiss() { + synchronized (mService.mWindowMap) { + if (mService.removeFakeWindowLocked(this)) { + mService.mInputManager.unregisterInputChannel(mServerChannel); + InputQueue.unregisterInputChannel(mClientChannel); + mClientChannel.dispose(); + mServerChannel.dispose(); + } + } + } + + private int getLayerLw(int windowType) { + return mService.mPolicy.windowTypeToLayerLw(windowType) + * WindowManagerService.TYPE_LAYER_MULTIPLIER + + WindowManagerService.TYPE_LAYER_OFFSET; + } +} diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java index 573a7d4..9a559e0 100644 --- a/services/java/com/android/server/wm/InputMonitor.java +++ b/services/java/com/android/server/wm/InputMonitor.java @@ -169,6 +169,11 @@ final class InputMonitor { } } + final int NFW = mService.mFakeWindows.size(); + for (int i = 0; i < NFW; i++) { + addInputWindowHandleLw(mService.mFakeWindows.get(i).mWindowHandle); + } + final int N = windows.size(); for (int i = N - 1; i >= 0; i--) { final WindowState child = windows.get(i); diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 540c518..73a9601 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -118,6 +118,7 @@ import android.view.WindowManager; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; import android.view.WindowManager.LayoutParams; +import android.view.WindowManagerPolicy.FakeWindow; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Transformation; @@ -142,7 +143,7 @@ import java.util.List; /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub - implements Watchdog.Monitor { + implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { static final String TAG = "WindowManager"; static final boolean DEBUG = false; static final boolean DEBUG_ADD_REMOVE = false; @@ -352,6 +353,12 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<WindowState> mWindows = new ArrayList<WindowState>(); /** + * Fake windows added to the window manager. Note: ordered from top to + * bottom, opposite of mWindows. + */ + final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<FakeWindowImpl>(); + + /** * Windows that are being resized. Used so we can tell the client about * the resize after closing the transaction in which we resized the * underlying surface. @@ -442,7 +449,9 @@ public class WindowManagerService extends IWindowManager.Stub int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; int mLayoutSeq = 0; - + + int mLastStatusBarVisibility = 0; + // State while inside of layoutAndPlaceSurfacesLocked(). boolean mFocusMayChange; @@ -702,7 +711,7 @@ public class WindowManagerService extends IWindowManager.Stub android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false); - mPolicy.init(mContext, mService, mPM); + mPolicy.init(mContext, mService, mService, mPM); synchronized (this) { mRunning = true; @@ -6368,8 +6377,6 @@ public class WindowManagerService extends IWindowManager.Stub // Ignore if process has died. } } - - mPolicy.focusChanged(lastFocus, newFocus); } } break; @@ -7184,6 +7191,11 @@ public class WindowManagerService extends IWindowManager.Stub final int dw = mCurDisplayWidth; final int dh = mCurDisplayHeight; + final int NFW = mFakeWindows.size(); + for (int i=0; i<NFW; i++) { + mFakeWindows.get(i).layout(dw, dh); + } + final int N = mWindows.size(); int i; @@ -8835,6 +8847,7 @@ public class WindowManagerService extends IWindowManager.Stub final WindowState oldFocus = mCurrentFocus; mCurrentFocus = newFocus; mLosingFocus.remove(newFocus); + int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus); final WindowState imWindow = mInputMethodWindow; if (newFocus != imWindow && oldFocus != imWindow) { @@ -8845,13 +8858,22 @@ public class WindowManagerService extends IWindowManager.Stub } if (mode == UPDATE_FOCUS_PLACING_SURFACES) { performLayoutLockedInner(true /*initial*/, updateInputWindows); + focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) { // Client will do the layout, but we need to assign layers // for handleNewWindowLocked() below. assignLayersLocked(); } } - + + if ((focusChanged&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) { + // The change in focus caused us to need to do a layout. Okay. + mLayoutNeeded = true; + if (mode == UPDATE_FOCUS_PLACING_SURFACES) { + performLayoutLockedInner(true /*initial*/, updateInputWindows); + } + } + if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) { // If we defer assigning layers, then the caller is responsible for // doing this part. @@ -9097,33 +9119,82 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void statusBarVisibilityChanged(int visibility) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Caller does not hold permission " + + android.Manifest.permission.STATUS_BAR); + } + + synchronized (mWindowMap) { + mLastStatusBarVisibility = visibility; + visibility = mPolicy.adjustSystemUiVisibilityLw(visibility); + updateStatusBarVisibilityLocked(visibility); + } + } + + void updateStatusBarVisibilityLocked(int visibility) { mInputManager.setSystemUiVisibility(visibility); + final int N = mWindows.size(); + for (int i = 0; i < N; i++) { + WindowState ws = mWindows.get(i); + try { + 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 + } + } + } + + @Override + public void reevaluateStatusBarVisibility() { + synchronized (mWindowMap) { + int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility); + updateStatusBarVisibilityLocked(visibility); + performLayoutAndPlaceSurfacesLocked(); + } + } + @Override + public FakeWindow addFakeWindow(Looper looper, InputHandler inputHandler, + String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys, + boolean hasFocus, boolean touchFullscreen) { synchronized (mWindowMap) { - final int N = mWindows.size(); - for (int i = 0; i < N; i++) { - WindowState ws = mWindows.get(i); - try { - 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 + FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputHandler, name, windowType, + layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen); + int i=0; + while (i<mFakeWindows.size()) { + if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) { + break; } } + mFakeWindows.add(i, fw); + mInputMonitor.updateInputWindowsLw(true); + return fw; + } + } + + boolean removeFakeWindowLocked(FakeWindow window) { + synchronized (mWindowMap) { + if (mFakeWindows.remove(window)) { + mInputMonitor.updateInputWindowsLw(true); + return true; + } + return false; } } @@ -9387,6 +9458,10 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mInTouchMode="); pw.print(mInTouchMode); pw.print(" mLayoutSeq="); pw.println(mLayoutSeq); if (dumpAll) { + if (mLastStatusBarVisibility != 0) { + pw.print(" mLastStatusBarVisibility=0x"); + pw.println(Integer.toHexString(mLastStatusBarVisibility)); + } if (mInputMethodWindow != null) { pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow); } |