diff options
11 files changed, 328 insertions, 120 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index c7bf8e3..0dc781f 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 6b09049..fdd9b2c 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; @@ -401,6 +402,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. */ public static final int LAST_SYSTEM_WINDOW = 2999; diff --git a/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java b/core/java/com/android/internal/widget/multiwaveview/TargetDrawable.java index d3baa2b..aa9fa45 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 afa92f1..9629702 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 431f8e0..5661116 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"); - - // 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; - } + 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 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; - } + // 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 (mLockPatternUtils.isLockScreenDisabled()) { - if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off"); - 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 true; + } - if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen"); - showLocked(); + 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 1d5fbc0a..be129a8 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; @@ -1095,6 +1097,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; @@ -2797,13 +2801,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void screenTurnedOff(int why) { EventLog.writeEvent(70000, 0); - mKeyguardMediator.onScreenTurnedOff(why); synchronized (mLock) { mScreenOn = false; + } + mKeyguardMediator.onScreenTurnedOff(why); + synchronized (mLock) { 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} */ @@ -3092,7 +3109,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 d80a2cd..cbd986f 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -161,6 +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 int mPartialCount = 0; private int mPowerState; // mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER, @@ -1342,6 +1343,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 @@ -1370,6 +1375,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(); @@ -1412,6 +1420,8 @@ public class PowerManagerService extends IPowerManager.Stub synchronized (mLocks) { EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, mBroadcastWakeLock.mCount); + mBroadcastingScreenOff = false; + updateNativePowerStateLocked(); mBroadcastWakeLock.release(); } } @@ -1442,6 +1452,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(); } } @@ -1768,6 +1782,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<mBroadcastQueue.length; i++) { + if (mBroadcastQueue[i] == 0) { + // A screen off is currently enqueued. + return; + } + } + } nativeSetPowerState( (mPowerState & SCREEN_ON_BIT) != 0, (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index b817598..c935733 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -6564,7 +6564,7 @@ public final class ActivityManagerService extends ActivityManagerNative i--; } } - + for (int i=0; i<ris.size(); i++) { ActivityInfo ai = ris.get(i).activityInfo; ComponentName comp = new ComponentName(ai.packageName, ai.name); diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 6f0779f..4ad0f45 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -3163,7 +3163,7 @@ final class ActivityStack { //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout); if (mMainStack) { - if (!mService.mBooted && !fromTimeout) { + if (!mService.mBooted) { mService.mBooted = true; enableScreen = true; } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index dc5555e..3df94a6 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -50,11 +50,9 @@ import com.android.server.am.BatteryStatsService; import android.Manifest; import android.app.ActivityManagerNative; import android.app.IActivityManager; -import android.app.ProgressDialog; import android.app.StatusBarManager; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -164,6 +162,7 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean DEBUG_REORDER = false; static final boolean DEBUG_WALLPAPER = false; static final boolean DEBUG_DRAG = false; + static final boolean DEBUG_SCREEN_ON = false; static final boolean SHOW_SURFACE_ALLOC = false; static final boolean SHOW_TRANSACTIONS = false; static final boolean HIDE_STACK_CRAWLS = true; @@ -408,6 +407,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean mSafeMode; boolean mDisplayEnabled = false; boolean mSystemBooted = false; + boolean mForceDisplayEnabled = false; boolean mShowingBootMessages = false; int mInitialDisplayWidth = 0; int mInitialDisplayHeight = 0; @@ -2189,7 +2189,7 @@ public class WindowManagerService extends IWindowManager.Stub // to hold off on removing the window until the animation is done. // If the display is frozen, just remove immediately, since the // animation wouldn't be seen. - if (win.mSurface != null && !mDisplayFrozen && mPolicy.isScreenOn()) { + if (win.mSurface != null && !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { // If we are not currently running the exit animation, we // need to see about starting one. if (wasVisible=win.isWinVisibleLw()) { @@ -2536,6 +2536,12 @@ public class WindowManagerService extends IWindowManager.Stub win.mRelayoutCalled = true; final int oldVisibility = win.mViewVisibility; win.mViewVisibility = viewVisibility; + if (DEBUG_SCREEN_ON) { + RuntimeException stack = new RuntimeException(); + stack.fillInStackTrace(); + Slog.i(TAG, "Relayout " + win + ": oldVis=" + oldVisibility + + " newVis=" + viewVisibility, stack); + } if (viewVisibility == View.VISIBLE && (win.mAppToken == null || !win.mAppToken.clientHidden)) { displayed = !win.isVisibleLw(); @@ -2556,7 +2562,7 @@ public class WindowManagerService extends IWindowManager.Stub if (displayed) { if (win.mSurface != null && !win.mDrawPending && !win.mCommitDrawPending && !mDisplayFrozen - && mPolicy.isScreenOn()) { + && mDisplayEnabled && mPolicy.isScreenOn()) { applyEnterAnimationLocked(win); } if ((win.mAttrs.flags @@ -2849,7 +2855,7 @@ public class WindowManagerService extends IWindowManager.Stub // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - if (!mDisplayFrozen && mPolicy.isScreenOn()) { + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { int anim = mPolicy.selectAnimationLw(win, transit); int attr = -1; Animation a = null; @@ -2935,7 +2941,7 @@ public class WindowManagerService extends IWindowManager.Stub // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - if (!mDisplayFrozen && mPolicy.isScreenOn()) { + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { Animation a; if (mNextAppTransitionPackage != null) { a = loadAnimation(mNextAppTransitionPackage, enter ? @@ -3501,7 +3507,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS) Slog.v( TAG, "Prepare app transition: transit=" + transit + " mNextAppTransition=" + mNextAppTransition); - if (!mDisplayFrozen && mPolicy.isScreenOn()) { + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) { mNextAppTransition = transit; @@ -3585,7 +3591,7 @@ public class WindowManagerService extends IWindowManager.Stub // If the display is frozen, we won't do anything until the // actual window is displayed so there is no reason to put in // the starting window. - if (mDisplayFrozen || !mPolicy.isScreenOn()) { + if (mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOn()) { return; } @@ -3867,7 +3873,7 @@ public class WindowManagerService extends IWindowManager.Stub // If we are preparing an app transition, then delay changing // the visibility of this token until we execute that transition. - if (!mDisplayFrozen && mPolicy.isScreenOn() + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn() && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { // Already in requested state, don't do anything more. if (wtoken.hiddenRequested != visible) { @@ -4688,6 +4694,10 @@ public class WindowManagerService extends IWindowManager.Stub } mSystemBooted = true; hideBootMessagesLocked(); + // If the screen still doesn't come up after 30 seconds, give + // up and turn it on. + Message msg = mH.obtainMessage(H.BOOT_TIMEOUT); + mH.sendMessageDelayed(msg, 30*1000); } performEnableScreen(); @@ -4703,6 +4713,17 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN)); } + public void performBootTimeout() { + synchronized(mWindowMap) { + if (mDisplayEnabled) { + return; + } + Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled"); + mForceDisplayEnabled = true; + } + performEnableScreen(); + } + public void performEnableScreen() { synchronized(mWindowMap) { if (mDisplayEnabled) { @@ -4712,19 +4733,55 @@ public class WindowManagerService extends IWindowManager.Stub return; } - // Don't enable the screen until all existing windows - // have been drawn. - final int N = mWindows.size(); - for (int i=0; i<N; i++) { - WindowState w = mWindows.get(i); - if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { + if (!mForceDisplayEnabled) { + // Don't enable the screen until all existing windows + // have been drawn. + boolean haveBootMsg = false; + boolean haveApp = false; + boolean haveWallpaper = false; + boolean haveKeyguard = false; + final int N = mWindows.size(); + for (int i=0; i<N; i++) { + WindowState w = mWindows.get(i); + if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { + return; + } + if (w.isDrawnLw()) { + if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) { + haveBootMsg = true; + } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) { + haveApp = true; + } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) { + haveWallpaper = true; + } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) { + haveKeyguard = true; + } + } + } + + if (DEBUG_SCREEN_ON) { + Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages + + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp + + " haveWall=" + haveWallpaper + " haveKeyguard=" + haveKeyguard); + } + + // If we are turning on the screen to show the boot message, + // don't do it until the boot message is actually displayed. + if (!mSystemBooted && !haveBootMsg) { + return; + } + + // If we are turning on the screen after the boot is completed + // normally, don't do so until we have the application and + // wallpaper. + if (mSystemBooted && ((!haveApp && !haveKeyguard) || !haveWallpaper)) { return; } } mDisplayEnabled = true; + if (DEBUG_SCREEN_ON) Slog.i(TAG, "******************** ENABLING SCREEN!"); if (false) { - Slog.i(TAG, "ENABLING SCREEN!"); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); this.dump(null, pw, null); @@ -6239,6 +6296,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int DRAG_START_TIMEOUT = 20; 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; private Session mLastReportedHold; @@ -6549,6 +6607,11 @@ 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."); @@ -8300,7 +8363,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mDimAnimator != null && mDimAnimator.mDimShown) { animating |= mDimAnimator.updateSurface(dimming, currentTime, - mDisplayFrozen || !mPolicy.isScreenOn()); + mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOn()); } if (!blurring && mBlurShown) { @@ -8498,12 +8561,44 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } - + + mWindowMap.notifyAll(); + // 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()); + } + if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { + if (DEBUG_SCREEN_ON) { + Slog.i(TAG, "Window not yet drawn: " + w); + } + okay = false; + break; + } + } + if (okay) { + return; + } + try { + mWindowMap.wait(); + } catch (InterruptedException e) { + } + } + } + } + /** * Must be called with the main window manager lock held. */ diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java index 7d83a9f..ed29a78 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java @@ -451,6 +451,10 @@ public class BridgeWindowManager implements IWindowManager { return 0; } + public void waitForAllDrawn() { + // TODO Auto-generated method stub + } + public IBinder asBinder() { // TODO Auto-generated method stub return null; |