diff options
author | Dianne Hackborn <hackbod@google.com> | 2011-10-07 15:12:17 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-10-07 15:12:17 -0700 |
commit | ba8ecd206cc6f175767f952d380c88f70ece04cf (patch) | |
tree | f463b4123ae906ac81eb16460aa8443ecefa12d9 | |
parent | 270928bd4a1db1dc0d989f4e9897a81ab865e30e (diff) | |
parent | df89e65bf0fcc651d20b208c8d8d0b848fb43418 (diff) | |
download | frameworks_base-ba8ecd206cc6f175767f952d380c88f70ece04cf.zip frameworks_base-ba8ecd206cc6f175767f952d380c88f70ece04cf.tar.gz frameworks_base-ba8ecd206cc6f175767f952d380c88f70ece04cf.tar.bz2 |
Merge "Fix how we hide and show the nav bar."
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); } |