diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index c7bf8e3aa3d82..0dc781f18c534 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -218,4 +218,9 @@ interface IWindowManager * Called by the settings application to temporarily set the pointer speed. */ void setPointerSpeed(int speed); + + /** + * Block until all windows the window manager knows about have been drawn. + */ + void waitForAllDrawn(); } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 6b09049966a96..fdd9b2c5e047b 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -177,7 +177,8 @@ public interface WindowManager extends ViewManager { @ViewDebug.IntToString(from = TYPE_SYSTEM_ERROR, to = "TYPE_SYSTEM_ERROR"), @ViewDebug.IntToString(from = TYPE_INPUT_METHOD, to = "TYPE_INPUT_METHOD"), @ViewDebug.IntToString(from = TYPE_INPUT_METHOD_DIALOG, to = "TYPE_INPUT_METHOD_DIALOG"), - @ViewDebug.IntToString(from = TYPE_SECURE_SYSTEM_OVERLAY, to = "TYPE_SECURE_SYSTEM_OVERLAY") + @ViewDebug.IntToString(from = TYPE_SECURE_SYSTEM_OVERLAY, to = "TYPE_SECURE_SYSTEM_OVERLAY"), + @ViewDebug.IntToString(from = TYPE_BOOT_PROGRESS, to = "TYPE_BOOT_PROGRESS") }) public int type; @@ -400,6 +401,13 @@ public interface WindowManager extends ViewManager { */ public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20; + /** + * Window type: The boot progress dialog, goes on top of everything + * in the world. + * @hide + */ + public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21; + /** * End of types of system windows. */ diff --git a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java index d3baa2bb73a38..aa9fa451b0681 100644 --- a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java +++ b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java @@ -25,6 +25,8 @@ import android.util.Log; public class TargetDrawable { private static final String TAG = "TargetDrawable"; + private static final boolean DEBUG = false; + public static final int[] STATE_ACTIVE = { android.R.attr.state_enabled, android.R.attr.state_active }; public static final int[] STATE_INACTIVE = @@ -139,11 +141,13 @@ public class TargetDrawable { maxWidth = Math.max(maxWidth, childDrawable.getIntrinsicWidth()); maxHeight = Math.max(maxHeight, childDrawable.getIntrinsicHeight()); } - Log.v(TAG, "union of childDrawable rects " + d + " to: " + maxWidth + "x" + maxHeight); + if (DEBUG) Log.v(TAG, "union of childDrawable rects " + d + " to: " + + maxWidth + "x" + maxHeight); d.setBounds(0, 0, maxWidth, maxHeight); for (int i = 0; i < d.getStateCount(); i++) { Drawable childDrawable = d.getStateDrawable(i); - Log.v(TAG, "sizing drawable " + childDrawable + " to: " + maxWidth + "x" + maxHeight); + if (DEBUG) Log.v(TAG, "sizing drawable " + childDrawable + " to: " + + maxWidth + "x" + maxHeight); childDrawable.setBounds(0, 0, maxWidth, maxHeight); } } else if (mDrawable != null) { diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java index afa92f1a9eed9..9629702bbb1f0 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java @@ -43,7 +43,7 @@ import android.widget.TextView; * */ class KeyguardStatusViewManager implements OnClickListener { - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private static final String TAG = "KeyguardStatusView"; public static final int LOCK_ICON = 0; // R.drawable.ic_lock_idle_lock; diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index 431f8e0bf1150..56611169899b4 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -116,6 +116,7 @@ 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) @@ -238,6 +239,8 @@ 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; @@ -306,7 +309,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, synchronized (this) { if (DEBUG) Log.d(TAG, "onSystemReady"); mSystemReady = true; - doKeyguard(); + doKeyguardLocked(); } } @@ -363,7 +366,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (timeout <= 0) { // Lock now mSuppressNextLockSound = true; - doKeyguard(); + doKeyguardLocked(); } else { // Lock in the future long when = SystemClock.elapsedRealtime() + timeout; @@ -379,7 +382,19 @@ 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 { - doKeyguard(); + 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) { + } + } + } } } } @@ -553,56 +568,58 @@ public class KeyguardViewMediator implements KeyguardViewCallback, } /** - * Enable the keyguard if the settings are appropriate. + * Enable the keyguard if the settings are appropriate. Return true if all + * work that will happen is done; returns false if the caller can wait for + * the keyguard to be shown. */ - private void doKeyguard() { - synchronized (this) { - // if another app is disabling us, don't show - if (!mExternallyEnabled) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); + private boolean doKeyguardLocked() { + // if another app is disabling us, don't show + if (!mExternallyEnabled) { + if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled"); - // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes - // for an occasional ugly flicker in this situation: - // 1) receive a call with the screen on (no keyguard) or make a call - // 2) screen times out - // 3) user hits key to turn screen back on - // instead, we reenable the keyguard when we know the screen is off and the call - // 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; - } - - // 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; - } - - // if the setup wizard hasn't run yet, don't show - final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", - false); - final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); - final IccCard.State state = mUpdateMonitor.getSimState(); - final boolean lockedOrMissing = state.isPinLocked() - || ((state == IccCard.State.ABSENT - || state == IccCard.State.PERM_DISABLED) - && requireSim); - - 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; - } - - if (mLockPatternUtils.isLockScreenDisabled()) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off"); - return; - } - - if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); - showLocked(); + // note: we *should* set mNeedToReshowWhenReenabled=true here, but that makes + // for an occasional ugly flicker in this situation: + // 1) receive a call with the screen on (no keyguard) or make a call + // 2) screen times out + // 3) user hits key to turn screen back on + // instead, we reenable the keyguard when we know the screen is off and the call + // 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; } + + // 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; + } + + // if the setup wizard hasn't run yet, don't show + final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", + false); + final boolean provisioned = mUpdateMonitor.isDeviceProvisioned(); + final IccCard.State state = mUpdateMonitor.getSimState(); + final boolean lockedOrMissing = state.isPinLocked() + || ((state == IccCard.State.ABSENT + || state == IccCard.State.PERM_DISABLED) + && requireSim); + + 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; + } + + if (mLockPatternUtils.isLockScreenDisabled()) { + if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off"); + return true; + } + + if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); + mShowPending = true; + showLocked(); + return false; } /** @@ -696,41 +713,49 @@ public class KeyguardViewMediator implements KeyguardViewCallback, case ABSENT: // only force lock screen in case of missing sim if user hasn't // gone through setup wizard - if (!mUpdateMonitor.isDeviceProvisioned()) { - if (!isShowing()) { - if (DEBUG) Log.d(TAG, "ICC_ABSENT isn't showing," - + " we need to show the keyguard since the " - + "device isn't provisioned yet."); - doKeyguard(); - } else { - resetStateLocked(); + synchronized (this) { + if (!mUpdateMonitor.isDeviceProvisioned()) { + if (!isShowing()) { + if (DEBUG) Log.d(TAG, "ICC_ABSENT isn't showing," + + " we need to show the keyguard since the " + + "device isn't provisioned yet."); + doKeyguardLocked(); + } else { + resetStateLocked(); + } } } break; case PIN_REQUIRED: case PUK_REQUIRED: - if (!isShowing()) { - if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't showing, we need " - + "to show the keyguard so the user can enter their sim pin"); - doKeyguard(); - } else { - resetStateLocked(); + synchronized (this) { + if (!isShowing()) { + if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_LOCKED and keygaurd isn't showing, we need " + + "to show the keyguard so the user can enter their sim pin"); + doKeyguardLocked(); + } else { + resetStateLocked(); + } } break; case PERM_DISABLED: - if (!isShowing()) { - if (DEBUG) Log.d(TAG, "PERM_DISABLED and " - + "keygaurd isn't showing."); - doKeyguard(); - } else { - if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to" - + "show permanently disabled message in lockscreen."); - resetStateLocked(); + synchronized (this) { + if (!isShowing()) { + if (DEBUG) Log.d(TAG, "PERM_DISABLED and " + + "keygaurd isn't showing."); + doKeyguardLocked(); + } else { + if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to" + + "show permanently disabled message in lockscreen."); + resetStateLocked(); + } } break; case READY: - if (isShowing()) { - resetStateLocked(); + synchronized (this) { + if (isShowing()) { + resetStateLocked(); + } } break; } @@ -751,27 +776,31 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = " + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence); - if (mDelayedShowingSequence == sequence) { - // Don't play lockscreen SFX if the screen went off due to - // timeout. - mSuppressNextLockSound = true; - - doKeyguard(); + synchronized (KeyguardViewMediator.this) { + if (mDelayedShowingSequence == sequence) { + // Don't play lockscreen SFX if the screen went off due to + // timeout. + mSuppressNextLockSound = true; + + doKeyguardLocked(); + } } } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { mPhoneState = intent.getStringExtra(TelephonyManager.EXTRA_STATE); - if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState) // call ending - && !mScreenOn // screen off - && mExternallyEnabled) { // not disabled by any app - - // note: this is a way to gracefully reenable the keyguard when the call - // ends and the screen is off without always reenabling the keyguard - // each time the screen turns off while in call (and having an occasional ugly - // flicker while turning back on the screen and disabling the keyguard again). - if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the " - + "keyguard is showing"); - doKeyguard(); + synchronized (KeyguardViewMediator.this) { + if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState) // call ending + && !mScreenOn // screen off + && mExternallyEnabled) { // not disabled by any app + + // note: this is a way to gracefully reenable the keyguard when the call + // ends and the screen is off without always reenabling the keyguard + // each time the screen turns off while in call (and having an occasional ugly + // flicker while turning back on the screen and disabling the keyguard again). + if (DEBUG) Log.d(TAG, "screen is off and call ended, let's make sure the " + + "keyguard is showing"); + doKeyguardLocked(); + } } } } @@ -962,7 +991,15 @@ public class KeyguardViewMediator implements KeyguardViewCallback, handleSetHidden(msg.arg1 != 0); break; case KEYGUARD_TIMEOUT: - doKeyguard(); + synchronized (KeyguardViewMediator.this) { + doKeyguardLocked(); + } + break; + case REPORT_SHOW_DONE: + synchronized (KeyguardViewMediator.this) { + mShowPending = false; + KeyguardViewMediator.this.notifyAll(); + } break; } } @@ -1062,8 +1099,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback, if (DEBUG) Log.d(TAG, "handleShow"); if (!mSystemReady) return; - playSounds(true); - mKeyguardViewManager.show(); mShowing = true; adjustUserActivityLocked(); @@ -1072,7 +1107,17 @@ public class KeyguardViewMediator implements KeyguardViewCallback, ActivityManagerNative.getDefault().closeSystemDialogs("lock"); } catch (RemoteException e) { } + + // Do this at the end to not slow down display of the keyguard. + 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); } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 1871d68ec8b34..69bbfaa87dc9d 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -120,6 +120,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_POINTER; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; import android.view.KeyCharacterMap.FallbackAction; @@ -197,8 +198,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // things in here CAN NOT take focus, but are shown on top of everything else. static final int SYSTEM_OVERLAY_LAYER = 20; static final int SECURE_SYSTEM_OVERLAY_LAYER = 21; + static final int BOOT_PROGRESS_LAYER = 22; // the (mouse) pointer layer - static final int POINTER_LAYER = 22; + static final int POINTER_LAYER = 23; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -1098,6 +1100,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return POINTER_LAYER; case TYPE_NAVIGATION_BAR: return NAVIGATION_BAR_LAYER; + case TYPE_BOOT_PROGRESS: + return BOOT_PROGRESS_LAYER; } Log.e(TAG, "Unknown window type: " + type); return APPLICATION_LAYER; @@ -2804,15 +2808,29 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void screenTurnedOff(int why) { EventLog.writeEvent(70000, 0); + + synchronized (mLock) { + mScreenOn = false; + } if (mKeyguardMediator != null) { mKeyguardMediator.onScreenTurnedOff(why); } synchronized (mLock) { - mScreenOn = false; updateOrientationListenerLp(); 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} */ @@ -3112,7 +3130,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mBootMsgDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); mBootMsgDialog.setIndeterminate(true); mBootMsgDialog.getWindow().setType( - WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY); + WindowManager.LayoutParams.TYPE_BOOT_PROGRESS); mBootMsgDialog.getWindow().addFlags( WindowManager.LayoutParams.FLAG_DIM_BEHIND | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 532eca2168785..bd9df200a2d99 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -163,6 +163,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 int mPartialCount = 0; private int mPowerState; // mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER, @@ -1345,6 +1346,10 @@ public class PowerManagerService extends IPowerManager.Stub mBroadcastWakeLock.release(); } + // The broadcast queue has changed; make sure the screen is on if it + // is now possible for it to be. + updateNativePowerStateLocked(); + // Now send the message. if (index >= 0) { // Acquire the broadcast wake lock before changing the power @@ -1373,6 +1378,9 @@ public class PowerManagerService extends IPowerManager.Stub mBroadcastWhy[i] = mBroadcastWhy[i+1]; } policy = getPolicyLocked(); + if (value == 0) { + mBroadcastingScreenOff = true; + } } if (value == 1) { mScreenOnStart = SystemClock.uptimeMillis(); @@ -1415,6 +1423,8 @@ public class PowerManagerService extends IPowerManager.Stub synchronized (mLocks) { EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, mBroadcastWakeLock.mCount); + mBroadcastingScreenOff = false; + updateNativePowerStateLocked(); mBroadcastWakeLock.release(); } } @@ -1445,6 +1455,10 @@ 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(); } } @@ -1771,6 +1785,22 @@ 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. + // 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. + return; + } + for (int i=0; i