diff options
7 files changed, 187 insertions, 106 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 0dc781f..335c66b 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -23,6 +23,7 @@ import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Point; +import android.os.IRemoteCallback; import android.view.IApplicationToken; import android.view.IOnKeyguardExitResult; import android.view.IRotationWatcher; @@ -220,7 +221,7 @@ interface IWindowManager void setPointerSpeed(int speed); /** - * Block until all windows the window manager knows about have been drawn. + * Block until the given window has been drawn to the screen. */ - void waitForAllDrawn(); + void waitForWindowDrawn(IBinder token, in IRemoteCallback callback); } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 980e454..fdbda4c 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -772,10 +772,16 @@ public interface WindowManagerPolicy { */ public void screenTurnedOff(int why); + public interface ScreenOnListener { + void onScreenOn(); + }; + /** - * Called after the screen turns on. + * Called when the power manager would like to turn the screen on. + * Must call back on the listener to tell it when the higher-level system + * is ready for the screen to go on (i.e. the lock screen is shown). */ - public void screenTurnedOn(); + public void screenTurningOn(ScreenOnListener screenOnListener); /** * Return whether the screen is currently on. diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java index cbf1c90..91f1527 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java @@ -24,6 +24,7 @@ import android.content.pm.ActivityInfo; import android.content.res.Resources; import android.graphics.PixelFormat; import android.graphics.Canvas; +import android.os.IBinder; import android.os.SystemProperties; import android.util.Log; import android.view.View; @@ -59,6 +60,10 @@ public class KeyguardViewManager implements KeyguardWindowController { private boolean mScreenOn = false; + public interface ShowListener { + void onShown(IBinder windowToken); + }; + /** * @param context Used to create views. * @param viewManager Keyguard will be attached to this. @@ -206,7 +211,8 @@ public class KeyguardViewManager implements KeyguardWindowController { } } - public synchronized void onScreenTurnedOn() { + public synchronized void onScreenTurnedOn( + final KeyguardViewManager.ShowListener showListener) { if (DEBUG) Log.d(TAG, "onScreenTurnedOn()"); mScreenOn = true; if (mKeyguardView != null) { @@ -214,6 +220,26 @@ public class KeyguardViewManager implements KeyguardWindowController { // When screen is turned on, need to bind to FaceLock service if we are using FaceLock mKeyguardView.bindToFaceLock(); + + // Caller should wait for this window to be shown before turning + // on the screen. + if (mKeyguardHost.getVisibility() == View.VISIBLE) { + // Keyguard may be in the process of being shown, but not yet + // updated with the window manager... give it a chance to do so. + mKeyguardHost.post(new Runnable() { + @Override public void run() { + if (mKeyguardHost.getVisibility() == View.VISIBLE) { + showListener.onShown(mKeyguardHost.getWindowToken()); + } else { + showListener.onShown(null); + } + } + }); + } else { + showListener.onShown(null); + } + } else { + showListener.onShown(null); } } diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index ab81875..6a48fc3 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -116,7 +116,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private static final int KEYGUARD_DONE_AUTHENTICATING = 11; private static final int SET_HIDDEN = 12; private static final int KEYGUARD_TIMEOUT = 13; - private static final int REPORT_SHOW_DONE = 14; /** * The default amount of time we stay awake (used for all key input) @@ -239,8 +238,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private boolean mScreenOn = false; - private boolean mShowPending = false; - // last known state of the cellular connection private String mPhoneState = TelephonyManager.EXTRA_STATE_IDLE; @@ -383,19 +380,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) { // Do not enable the keyguard if the prox sensor forced the screen off. } else { - if (!doKeyguardLocked() && why == WindowManagerPolicy.OFF_BECAUSE_OF_USER) { - // The user has explicitly turned off the screen, causing it - // to lock. We want to block here until the keyguard window - // has shown, so the power manager won't complete the screen - // off flow until that point, so we know it won't turn *on* - // the screen until this is done. - while (mShowPending) { - try { - wait(); - } catch (InterruptedException e) { - } - } - } + doKeyguardLocked(); } } } @@ -403,12 +388,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback, /** * Let's us know the screen was turned on. */ - public void onScreenTurnedOn() { + public void onScreenTurnedOn(KeyguardViewManager.ShowListener showListener) { synchronized (this) { mScreenOn = true; mDelayedShowingSequence++; if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence); - notifyScreenOnLocked(); + notifyScreenOnLocked(showListener); } } @@ -573,7 +558,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * work that will happen is done; returns false if the caller can wait for * the keyguard to be shown. */ - private boolean doKeyguardLocked() { + private void doKeyguardLocked() { // if another app is disabling us, don't show if (!mExternallyEnabled) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); @@ -587,13 +572,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback, // ends (see the broadcast receiver below) // TODO: clean this up when we have better support at the window manager level // for apps that wish to be on top of the keyguard - return true; + return; } // if the keyguard is already showing, don't bother if (mKeyguardViewManager.isShowing()) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing"); - return true; + return; } // if the setup wizard hasn't run yet, don't show @@ -609,18 +594,16 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (!lockedOrMissing && !provisioned) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned" + " and the sim is not locked or missing"); - return true; + return; } if (mLockPatternUtils.isLockScreenDisabled()) { if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off"); - return true; + return; } if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); - mShowPending = true; showLocked(); - return false; } /** @@ -658,9 +641,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * @see #onScreenTurnedOn() * @see #handleNotifyScreenOn */ - private void notifyScreenOnLocked() { + private void notifyScreenOnLocked(KeyguardViewManager.ShowListener showListener) { if (DEBUG) Log.d(TAG, "notifyScreenOnLocked"); - mHandler.sendEmptyMessage(NOTIFY_SCREEN_ON); + Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_ON, showListener); + mHandler.sendMessage(msg); } /** @@ -974,7 +958,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, handleNotifyScreenOff(); return; case NOTIFY_SCREEN_ON: - handleNotifyScreenOn(); + handleNotifyScreenOn((KeyguardViewManager.ShowListener)msg.obj); return; case WAKE_WHEN_READY: handleWakeWhenReady(msg.arg1); @@ -996,12 +980,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, doKeyguardLocked(); } break; - case REPORT_SHOW_DONE: - synchronized (KeyguardViewMediator.this) { - mShowPending = false; - KeyguardViewMediator.this.notifyAll(); - } - break; } } }; @@ -1113,12 +1091,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, playSounds(true); mShowKeyguardWakeLock.release(); - - // We won't say the show is done yet because the view hierarchy - // still needs to do the traversal. Posting this message allows - // us to hold off until that is done. - Message msg = mHandler.obtainMessage(REPORT_SHOW_DONE); - mHandler.sendMessage(msg); } } @@ -1284,10 +1256,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback, * Handle message sent by {@link #notifyScreenOnLocked()} * @see #NOTIFY_SCREEN_ON */ - private void handleNotifyScreenOn() { + private void handleNotifyScreenOn(KeyguardViewManager.ShowListener showListener) { synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleNotifyScreenOn"); - mKeyguardViewManager.onScreenTurnedOn(); + mKeyguardViewManager.onScreenTurnedOn(showListener); } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 10447ad..b229615 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -40,8 +40,10 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; import android.os.Binder; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.IRemoteCallback; import android.os.LocalPowerManager; import android.os.Message; import android.os.Messenger; @@ -125,6 +127,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.ScreenOnListener; import android.view.accessibility.AccessibilityEvent; import android.view.animation.Animation; import android.view.animation.AnimationUtils; @@ -2814,23 +2817,30 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateLockScreenTimeout(); updateScreenSaverTimeoutLocked(); } - try { - mWindowManager.waitForAllDrawn(); - } catch (RemoteException e) { - } - // Wait for one frame to give surface flinger time to do its - // compositing. Yes this is a hack, but I am really not up right now for - // implementing some mechanism to block until SF is done. :p - try { - Thread.sleep(20); - } catch (InterruptedException e) { - } } /** {@inheritDoc} */ - public void screenTurnedOn() { + public void screenTurningOn(final ScreenOnListener screenOnListener) { EventLog.writeEvent(70000, 1); - mKeyguardMediator.onScreenTurnedOn(); + //Slog.i(TAG, "Screen turning on..."); + mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() { + @Override public void onShown(IBinder windowToken) { + if (windowToken != null) { + try { + mWindowManager.waitForWindowDrawn(windowToken, new IRemoteCallback.Stub() { + @Override public void sendResult(Bundle data) { + Slog.i(TAG, "Lock screen displayed!"); + screenOnListener.onScreenOn(); + } + }); + } catch (RemoteException e) { + } + } else { + Slog.i(TAG, "No lock screen!"); + screenOnListener.onScreenOn(); + } + } + }); synchronized (mLock) { mScreenOn = true; updateOrientationListenerLp(); diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index bb21d81..0934cd0 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -161,7 +161,7 @@ public class PowerManagerService extends IPowerManager.Stub private int mStayOnConditions = 0; private final int[] mBroadcastQueue = new int[] { -1, -1, -1 }; private final int[] mBroadcastWhy = new int[3]; - private boolean mBroadcastingScreenOff = false; + private boolean mPreparingForScreenOn = false; private int mPartialCount = 0; private int mPowerState; // mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER, @@ -1122,7 +1122,8 @@ public class PowerManagerService extends IPowerManager.Stub pw.println(" mNextTimeout=" + mNextTimeout + " now=" + now + " " + ((mNextTimeout-now)/1000) + "s from now"); pw.println(" mDimScreen=" + mDimScreen - + " mStayOnConditions=" + mStayOnConditions); + + " mStayOnConditions=" + mStayOnConditions + + " mPreparingForScreenOn=" + mPreparingForScreenOn); pw.println(" mScreenOffReason=" + mScreenOffReason + " mUserState=" + mUserState); pw.println(" mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1] @@ -1341,7 +1342,9 @@ public class PowerManagerService extends IPowerManager.Stub mBroadcastQueue[0] = on ? 1 : 0; mBroadcastQueue[1] = -1; mBroadcastQueue[2] = -1; + EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount); mBroadcastWakeLock.release(); + EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount); mBroadcastWakeLock.release(); index = 0; } @@ -1371,6 +1374,21 @@ public class PowerManagerService extends IPowerManager.Stub } } + private WindowManagerPolicy.ScreenOnListener mScreenOnListener = + new WindowManagerPolicy.ScreenOnListener() { + @Override public void onScreenOn() { + synchronized (mLocks) { + if (mPreparingForScreenOn) { + mPreparingForScreenOn = false; + updateNativePowerStateLocked(); + EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, + 4, mBroadcastWakeLock.mCount); + mBroadcastWakeLock.release(); + } + } + } + }; + private Runnable mNotificationTask = new Runnable() { public void run() @@ -1387,14 +1405,17 @@ public class PowerManagerService extends IPowerManager.Stub mBroadcastWhy[i] = mBroadcastWhy[i+1]; } policy = getPolicyLocked(); - if (value == 0) { - mBroadcastingScreenOff = true; + if (value == 1 && !mPreparingForScreenOn) { + mPreparingForScreenOn = true; + mBroadcastWakeLock.acquire(); + EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, + mBroadcastWakeLock.mCount); } } if (value == 1) { mScreenOnStart = SystemClock.uptimeMillis(); - policy.screenTurnedOn(); + policy.screenTurningOn(mScreenOnListener); try { ActivityManagerNative.getDefault().wakingUp(); } catch (RemoteException e) { @@ -1432,7 +1453,6 @@ public class PowerManagerService extends IPowerManager.Stub synchronized (mLocks) { EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, mBroadcastWakeLock.mCount); - mBroadcastingScreenOff = false; updateNativePowerStateLocked(); mBroadcastWakeLock.release(); } @@ -1464,10 +1484,6 @@ public class PowerManagerService extends IPowerManager.Stub synchronized (mLocks) { EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0, SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount); - synchronized (mLocks) { - mBroadcastingScreenOff = false; - updateNativePowerStateLocked(); - } mBroadcastWakeLock.release(); } } @@ -1795,17 +1811,18 @@ public class PowerManagerService extends IPowerManager.Stub private void updateNativePowerStateLocked() { if ((mPowerState & SCREEN_ON_BIT) != 0) { - // Don't turn screen on if we are currently reporting a screen off. + // Don't turn screen on until we know we are really ready to. // This is to avoid letting the screen go on before things like the - // lock screen have been displayed due to it going off. - if (mBroadcastingScreenOff) { - // Currently broadcasting that the screen is off. Don't - // allow screen to go on until that is done. + // lock screen have been displayed. + if (mPreparingForScreenOn) { + // Currently waiting for confirmation from the policy that it + // is okay to turn on the screen. Don't allow the screen to go + // on until that is done. return; } for (int i=0; i<mBroadcastQueue.length; i++) { - if (mBroadcastQueue[i] == 0) { - // A screen off is currently enqueued. + if (mBroadcastQueue[i] == 1) { + // A screen on is currently enqueued. return; } } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 609016b..755a8b8 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -73,6 +73,7 @@ import android.os.Bundle; import android.os.Debug; import android.os.Handler; import android.os.IBinder; +import android.os.IRemoteCallback; import android.os.LocalPowerManager; import android.os.Looper; import android.os.Message; @@ -91,6 +92,7 @@ import android.provider.Settings; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; +import android.util.Pair; import android.util.Slog; import android.util.SparseIntArray; import android.util.TypedValue; @@ -384,6 +386,12 @@ public class WindowManagerService extends IWindowManager.Stub ArrayList<WindowState> mForceRemoves; /** + * Windows that clients are waiting to have drawn. + */ + ArrayList<Pair<WindowState, IRemoteCallback>> mWaitingForDrawn + = new ArrayList<Pair<WindowState, IRemoteCallback>>(); + + /** * Used when rebuilding window list to keep track of windows that have * been removed. */ @@ -6295,6 +6303,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int DRAG_END_TIMEOUT = 21; public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22; public static final int BOOT_TIMEOUT = 23; + public static final int WAITING_FOR_DRAWN_TIMEOUT = 24; private Session mLastReportedHold; @@ -6605,11 +6614,6 @@ public class WindowManagerService extends IWindowManager.Stub break; } - case BOOT_TIMEOUT: { - performBootTimeout(); - break; - } - case APP_FREEZE_TIMEOUT: { synchronized (mWindowMap) { Slog.w(TAG, "App freeze timeout expired."); @@ -6678,6 +6682,27 @@ public class WindowManagerService extends IWindowManager.Stub notifyHardKeyboardStatusChange(); break; } + + case BOOT_TIMEOUT: { + performBootTimeout(); + break; + } + + case WAITING_FOR_DRAWN_TIMEOUT: { + Pair<WindowState, IRemoteCallback> pair; + synchronized (mWindowMap) { + pair = (Pair<WindowState, IRemoteCallback>)msg.obj; + Slog.w(TAG, "Timeout waiting for drawn: " + pair.first); + if (!mWaitingForDrawn.remove(pair)) { + return; + } + } + try { + pair.second.sendResult(null); + } catch (RemoteException e) { + } + break; + } } } } @@ -8582,43 +8607,58 @@ public class WindowManagerService extends IWindowManager.Stub } } - mWindowMap.notifyAll(); + checkDrawnWindowsLocked(); // Check to see if we are now in a state where the screen should // be enabled, because the window obscured flags have changed. enableScreenIfNeededLocked(); } - public void waitForAllDrawn() { - synchronized (mWindowMap) { - while (true) { - final int N = mWindows.size(); - boolean okay = true; - for (int i=0; i<N && okay; i++) { - WindowState w = mWindows.get(i); - if (DEBUG_SCREEN_ON) { - Slog.i(TAG, "Window " + w + " vis=" + w.isVisibleLw() - + " obscured=" + w.mObscured + " drawn=" + w.isDrawnLw()); + void checkDrawnWindowsLocked() { + if (mWaitingForDrawn.size() > 0) { + for (int j=mWaitingForDrawn.size()-1; j>=0; j--) { + Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j); + WindowState win = pair.first; + //Slog.i(TAG, "Waiting for drawn " + win + ": removed=" + // + win.mRemoved + " visible=" + win.isVisibleLw() + // + " shown=" + win.mSurfaceShown); + if (win.mRemoved || !win.isVisibleLw()) { + // Window has been removed or made invisible; no draw + // will now happen, so stop waiting. + Slog.w(TAG, "Aborted waiting for drawn: " + pair.first); + try { + pair.second.sendResult(null); + } catch (RemoteException e) { } - if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { - if (DEBUG_SCREEN_ON) { - Slog.i(TAG, "Window not yet drawn: " + w); - } - okay = false; - break; + mWaitingForDrawn.remove(pair); + mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair); + } else if (win.mSurfaceShown) { + // Window is now drawn (and shown). + try { + pair.second.sendResult(null); + } catch (RemoteException e) { } - } - if (okay) { - return; - } - try { - mWindowMap.wait(); - } catch (InterruptedException e) { + mWaitingForDrawn.remove(pair); + mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair); } } } } + public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) { + synchronized (mWindowMap) { + WindowState win = windowForClientLocked(null, token, true); + if (win != null) { + Pair<WindowState, IRemoteCallback> pair = + new Pair<WindowState, IRemoteCallback>(win, callback); + Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair); + mH.sendMessageDelayed(m, 2000); + mWaitingForDrawn.add(pair); + checkDrawnWindowsLocked(); + } + } + } + /** * Must be called with the main window manager lock held. */ @@ -9284,6 +9324,15 @@ public class WindowManagerService extends IWindowManager.Stub } } } + if (mWaitingForDrawn.size() > 0) { + pw.println(); + pw.println(" Clients waiting for these windows to be drawn:"); + for (int i=mWaitingForDrawn.size()-1; i>=0; i--) { + Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i); + pw.print(" Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first); + pw.print(": "); pw.println(pair.second); + } + } pw.println(); if (mDisplay != null) { pw.print(" Display: init="); pw.print(mInitialDisplayWidth); pw.print("x"); |