Merge "Coordinate screen on with the window manager." into jb-mr1-dev

This commit is contained in:
Jeff Brown
2012-10-05 14:55:25 -07:00
committed by Android (Google) Code Review
10 changed files with 296 additions and 115 deletions

View File

@ -201,8 +201,9 @@ interface IWindowManager
/**
* Block until the given window has been drawn to the screen.
* Returns true if really waiting, false if the window does not exist.
*/
void waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
boolean waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
/**
* Device has a software navigation bar (separate from the status bar).

View File

@ -1058,18 +1058,13 @@ public interface WindowManagerPolicy {
* Called when we have started keeping the screen on because a window
* requesting this has become visible.
*/
public void screenOnStartedLw();
public void keepScreenOnStartedLw();
/**
* Called when we have stopped keeping the screen on because the last window
* requesting this is no longer visible.
*/
public void screenOnStoppedLw();
/**
* Return false to disable key repeat events from being generated.
*/
public boolean allowKeyRepeat();
public void keepScreenOnStoppedLw();
/**
* Inform the policy that the user has chosen a preferred orientation ("rotation lock").

View File

@ -3580,7 +3580,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
};
/** {@inheritDoc} */
@Override
public void screenTurnedOff(int why) {
EventLog.writeEvent(70000, 0);
synchronized (mLock) {
@ -3596,7 +3596,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
/** {@inheritDoc} */
@Override
public void screenTurningOn(final ScreenOnListener screenOnListener) {
EventLog.writeEvent(70000, 1);
if (false) {
@ -3604,64 +3604,83 @@ public class PhoneWindowManager implements WindowManagerPolicy {
here.fillInStackTrace();
Slog.i(TAG, "Screen turning on...", here);
}
if (screenOnListener != null) {
if (mKeyguardMediator != null) {
try {
mWindowManager.setEventDispatching(true);
} catch (RemoteException unhandled) {
}
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();
synchronized (mLock) {
mScreenOnFully = true;
}
}
});
} catch (RemoteException e) {
}
} else {
Slog.i(TAG, "No lock screen!");
screenOnListener.onScreenOn();
synchronized (mLock) {
mScreenOnFully = true;
}
}
}
});
}
} else {
if (mKeyguardMediator != null) {
// Must set mScreenOn = true.
mKeyguardMediator.onScreenTurnedOn(null);
}
synchronized (mLock) {
mScreenOnFully = true;
}
}
synchronized (mLock) {
mScreenOnEarly = true;
updateOrientationListenerLp();
updateLockScreenTimeout();
}
try {
mWindowManager.setEventDispatching(true);
} catch (RemoteException unhandled) {
}
waitForKeyguard(screenOnListener);
}
/** {@inheritDoc} */
private void waitForKeyguard(final ScreenOnListener screenOnListener) {
if (mKeyguardMediator != null) {
if (screenOnListener != null) {
mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
@Override
public void onShown(IBinder windowToken) {
waitForKeyguardWindowDrawn(windowToken, screenOnListener);
}
});
return;
} else {
mKeyguardMediator.onScreenTurnedOn(null);
}
} else {
Slog.i(TAG, "No keyguard mediator!");
}
finishScreenTurningOn(screenOnListener);
}
private void waitForKeyguardWindowDrawn(IBinder windowToken,
final ScreenOnListener screenOnListener) {
if (windowToken != null) {
try {
if (mWindowManager.waitForWindowDrawn(
windowToken, new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle data) {
Slog.i(TAG, "Lock screen displayed!");
finishScreenTurningOn(screenOnListener);
}
})) {
return;
}
} catch (RemoteException ex) {
// Can't happen in system process.
}
}
Slog.i(TAG, "No lock screen!");
finishScreenTurningOn(screenOnListener);
}
private void finishScreenTurningOn(ScreenOnListener screenOnListener) {
synchronized (mLock) {
mScreenOnFully = true;
}
if (screenOnListener != null) {
screenOnListener.onScreenOn();
}
}
@Override
public boolean isScreenOnEarly() {
return mScreenOnEarly;
}
/** {@inheritDoc} */
@Override
public boolean isScreenOnFully() {
return mScreenOnFully;
}
/** {@inheritDoc} */
public void enableKeyguard(boolean enabled) {
if (mKeyguardMediator != null) {
@ -4236,24 +4255,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
return true;
}
public void screenOnStartedLw() {
@Override
public void keepScreenOnStartedLw() {
}
public void screenOnStoppedLw() {
if (mPowerManager.isScreenOn()) {
if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
long curTime = SystemClock.uptimeMillis();
mPowerManager.userActivity(curTime, false);
}
@Override
public void keepScreenOnStoppedLw() {
if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
long curTime = SystemClock.uptimeMillis();
mPowerManager.userActivity(curTime, false);
}
}
public boolean allowKeyRepeat() {
// disable key repeat when screen is off
return mScreenOnEarly;
}
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.

View File

@ -531,6 +531,7 @@ final class DisplayPowerController {
final boolean mustNotify;
boolean mustInitialize = false;
boolean updateAutoBrightness = mTwilightChanged;
boolean screenOnWasBlocked = false;
mTwilightChanged = false;
synchronized (mLock) {
@ -588,7 +589,6 @@ final class DisplayPowerController {
if (mScreenOffBecauseOfProximity
&& mProximity != PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = false;
setScreenOn(true);
sendOnProximityNegative();
}
} else {
@ -639,20 +639,43 @@ final class DisplayPowerController {
// It is relatively short but if we cancel it and switch to the
// on animation immediately then the results are pretty ugly.
if (!mElectronBeamOffAnimator.isStarted()) {
setScreenOn(true);
if (USE_ELECTRON_BEAM_ON_ANIMATION) {
if (!mElectronBeamOnAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 1.0f) {
mPowerState.dismissElectronBeam();
} else if (mPowerState.prepareElectronBeam(true)) {
mElectronBeamOnAnimator.start();
} else {
mElectronBeamOnAnimator.end();
}
if (mPowerRequest.blockScreenOn && !mPowerState.isScreenOn()) {
if (DEBUG) {
Slog.d(TAG, "Blocked screen on while screen currently off.");
}
screenOnWasBlocked = true;
} else {
mPowerState.setElectronBeamLevel(1.0f);
mPowerState.dismissElectronBeam();
setScreenOn(true);
if (USE_ELECTRON_BEAM_ON_ANIMATION) {
if (!mElectronBeamOnAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 1.0f) {
mPowerState.dismissElectronBeam();
} else if (mPowerState.prepareElectronBeam(true)) {
mElectronBeamOnAnimator.start();
} else {
mElectronBeamOnAnimator.end();
}
}
} else {
mPowerState.setElectronBeamLevel(1.0f);
mPowerState.dismissElectronBeam();
}
}
} else {
// FIXME: If the electron beam off animation is playing then we have a bit
// of a problem. The window manager policy would only have requested
// to block screen on if it was about to start preparing the keyguard.
// It's already too late to do anything about that. Ideally we would
// let the animation play out first but that would require making
// some pretty deep changes to the power manager and we don't have
// time just now. For now, short-circuit the animation and get ready.
if (mPowerRequest.blockScreenOn) {
if (DEBUG) {
Slog.d(TAG, "Blocked screen on while screen off animation running.");
}
screenOnWasBlocked = true;
setScreenOn(false);
mElectronBeamOffAnimator.end();
}
}
} else {
@ -677,12 +700,17 @@ final class DisplayPowerController {
// We mostly care about the screen state here, ignoring brightness changes
// which will be handled asynchronously.
if (mustNotify
&& !screenOnWasBlocked
&& !mElectronBeamOnAnimator.isStarted()
&& !mElectronBeamOffAnimator.isStarted()
&& mPowerState.waitUntilClean(mCleanListener)) {
synchronized (mLock) {
if (!mPendingRequestChangedLocked) {
mDisplayReadyLocked = true;
if (DEBUG) {
Slog.d(TAG, "Display ready!");
}
}
}
sendOnStateChanged();

View File

@ -52,12 +52,20 @@ final class DisplayPowerRequest {
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
// If true, prevents the screen from turning on if it is currently off.
// The display does not enter a "ready" state if this flag is true and the screen
// is off and is being prevented from turning on. The window manager policy blocks
// screen on while it prepares the keyguard to prevent the user from seeing
// intermediate updates.
public boolean blockScreenOn;
public DisplayPowerRequest() {
screenState = SCREEN_STATE_BRIGHT;
useProximitySensor = false;
screenBrightness = PowerManager.BRIGHTNESS_ON;
screenAutoBrightnessAdjustment = 0.0f;
useAutoBrightness = false;
blockScreenOn = false;
}
public DisplayPowerRequest(DisplayPowerRequest other) {
@ -70,6 +78,7 @@ final class DisplayPowerRequest {
screenBrightness = other.screenBrightness;
screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
useAutoBrightness = other.useAutoBrightness;
blockScreenOn = other.blockScreenOn;
}
@Override
@ -84,7 +93,8 @@ final class DisplayPowerRequest {
&& useProximitySensor == other.useProximitySensor
&& screenBrightness == other.screenBrightness
&& screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
&& useAutoBrightness == other.useAutoBrightness;
&& useAutoBrightness == other.useAutoBrightness
&& blockScreenOn == other.blockScreenOn;
}
@Override
@ -98,6 +108,7 @@ final class DisplayPowerRequest {
+ ", useProximitySensor=" + useProximitySensor
+ ", screenBrightness=" + screenBrightness
+ ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
+ ", useAutoBrightness=" + useAutoBrightness;
+ ", useAutoBrightness=" + useAutoBrightness
+ ", blockScreenOn=" + blockScreenOn;
}
}

View File

@ -35,7 +35,6 @@ import android.os.WorkSource;
import android.util.EventLog;
import android.util.Slog;
import android.view.WindowManagerPolicy;
import android.view.WindowManagerPolicy.ScreenOnListener;
/**
* Sends broadcasts about important power state changes.
@ -71,8 +70,8 @@ final class Notifier {
private final Context mContext;
private final IBatteryStats mBatteryStats;
private final SuspendBlocker mSuspendBlocker;
private final ScreenOnBlocker mScreenOnBlocker;
private final WindowManagerPolicy mPolicy;
private final ScreenOnListener mScreenOnListener;
private final NotifierHandler mHandler;
private final Intent mScreenOnIntent;
@ -95,14 +94,17 @@ final class Notifier {
// True if a user activity message should be sent.
private boolean mUserActivityPending;
// True if the screen on blocker has been acquired.
private boolean mScreenOnBlockerAcquired;
public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
ScreenOnListener screenOnListener) {
SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
WindowManagerPolicy policy) {
mContext = context;
mBatteryStats = batteryStats;
mSuspendBlocker = suspendBlocker;
mScreenOnBlocker = screenOnBlocker;
mPolicy = policy;
mScreenOnListener = screenOnListener;
mHandler = new NotifierHandler(looper);
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@ -227,6 +229,10 @@ final class Notifier {
if (mActualPowerState != POWER_STATE_AWAKE) {
mActualPowerState = POWER_STATE_AWAKE;
mPendingWakeUpBroadcast = true;
if (!mScreenOnBlockerAcquired) {
mScreenOnBlockerAcquired = true;
mScreenOnBlocker.acquire();
}
updatePendingBroadcastLocked();
}
}
@ -387,6 +393,7 @@ final class Notifier {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
mPolicy.screenTurningOn(mScreenOnListener);
try {
ActivityManagerNative.getDefault().wakingUp();
} catch (RemoteException e) {
@ -402,6 +409,19 @@ final class Notifier {
}
}
private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
new WindowManagerPolicy.ScreenOnListener() {
@Override
public void onScreenOn() {
synchronized (mLock) {
if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) {
mScreenOnBlockerAcquired = false;
mScreenOnBlocker.release();
}
}
}
};
private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {

View File

@ -79,6 +79,8 @@ public final class PowerManagerService extends IPowerManager.Stub
private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
// Message: Sent when the device enters or exits a napping or dreaming state.
private static final int MSG_SANDMAN = 2;
// Message: Sent when the screen on blocker is released.
private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
// Dirty bit: mWakeLocks changed
private static final int DIRTY_WAKE_LOCKS = 1 << 0;
@ -100,6 +102,8 @@ public final class PowerManagerService extends IPowerManager.Stub
private static final int DIRTY_BATTERY_STATE = 1 << 8;
// Dirty bit: proximity state changed
private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
// Dirty bit: screen on blocker state became held or unheld
private static final int DIRTY_SCREEN_ON_BLOCKER_RELEASED = 1 << 10;
// Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
// The screen should be off or in the process of being turned off by the display controller.
@ -222,6 +226,10 @@ public final class PowerManagerService extends IPowerManager.Stub
// The suspend blocker used to keep the CPU alive when wake locks have been acquired.
private final SuspendBlocker mWakeLockSuspendBlocker;
// The screen on blocker used to keep the screen from turning on while the lock
// screen is coming up.
private final ScreenOnBlockerImpl mScreenOnBlocker;
// True if systemReady() has been called.
private boolean mSystemReady;
@ -318,6 +326,7 @@ public final class PowerManagerService extends IPowerManager.Stub
synchronized (mLock) {
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService");
mWakeLockSuspendBlocker.acquire();
mScreenOnBlocker = new ScreenOnBlockerImpl();
mHoldingWakeLockSuspendBlocker = true;
mWakefulness = WAKEFULNESS_AWAKE;
}
@ -368,9 +377,14 @@ public final class PowerManagerService extends IPowerManager.Stub
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
mNotifier = new Notifier(mHandler.getLooper(), mContext, mBatteryStats,
// The notifier runs on the system server's main looper so as not to interfere
// with the animations and other critical functions of the power manager.
mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
mPolicy, mScreenOnListener);
mScreenOnBlocker, mPolicy);
// The display power controller runs on the power manager service's
// own handler thread.
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
mContext, mNotifier, mLightsService, twilight,
createSuspendBlockerLocked("PowerManagerService.Display"),
@ -1433,6 +1447,13 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
private void handleScreenOnBlockerReleased() {
synchronized (mLock) {
mDirty |= DIRTY_SCREEN_ON_BLOCKER_RELEASED;
updatePowerStateLocked();
}
}
/**
* Updates the display power state asynchronously.
* When the update is finished, mDisplayReady will be set to true. The display
@ -1444,8 +1465,8 @@ public final class PowerManagerService extends IPowerManager.Stub
private void updateDisplayPowerStateLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS)) != 0) {
int newScreenState = getDesiredScreenPowerState();
| DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
int newScreenState = getDesiredScreenPowerStateLocked();
if (newScreenState != mDisplayPowerRequest.screenState) {
if (newScreenState == DisplayPowerRequest.SCREEN_STATE_OFF
&& mDisplayPowerRequest.screenState
@ -1493,12 +1514,14 @@ public final class PowerManagerService extends IPowerManager.Stub
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld();
mDisplayReady = mDisplayPowerController.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
if (DEBUG_SPEW) {
Slog.d(TAG, "updateScreenStateLocked: displayReady=" + mDisplayReady
Slog.d(TAG, "updateScreenStateLocked: mDisplayReady=" + mDisplayReady
+ ", newScreenState=" + newScreenState
+ ", mWakefulness=" + mWakefulness
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
@ -1517,7 +1540,7 @@ public final class PowerManagerService extends IPowerManager.Stub
return value >= -1.0f && value <= 1.0f;
}
private int getDesiredScreenPowerState() {
private int getDesiredScreenPowerStateLocked() {
if (mWakefulness == WAKEFULNESS_ASLEEP) {
return DisplayPowerRequest.SCREEN_STATE_OFF;
}
@ -2070,6 +2093,9 @@ public final class PowerManagerService extends IPowerManager.Stub
pw.println(" " + sb);
}
pw.println();
pw.println("Screen On Blocker: " + mScreenOnBlocker);
dpc = mDisplayPowerController;
}
@ -2152,13 +2178,6 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
new WindowManagerPolicy.ScreenOnListener() {
@Override
public void onScreenOn() {
}
};
/**
* Handler for asynchronous operations performed by the power manager.
*/
@ -2176,6 +2195,9 @@ public final class PowerManagerService extends IPowerManager.Stub
case MSG_SANDMAN:
handleSandman();
break;
case MSG_SCREEN_ON_BLOCKER_RELEASED:
handleScreenOnBlockerReleased();
break;
}
}
}
@ -2321,4 +2343,49 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
}
private final class ScreenOnBlockerImpl implements ScreenOnBlocker {
private int mNestCount;
public boolean isHeld() {
synchronized (this) {
return mNestCount != 0;
}
}
@Override
public void acquire() {
synchronized (this) {
mNestCount += 1;
if (DEBUG) {
Slog.d(TAG, "Screen on blocked: mNestCount=" + mNestCount);
}
}
}
@Override
public void release() {
synchronized (this) {
mNestCount -= 1;
if (mNestCount < 0) {
Log.wtf(TAG, "Screen on blocker was released without being acquired!",
new Throwable());
mNestCount = 0;
}
if (mNestCount == 0) {
mHandler.sendEmptyMessage(MSG_SCREEN_ON_BLOCKER_RELEASED);
}
if (DEBUG) {
Slog.d(TAG, "Screen on unblocked: mNestCount=" + mNestCount);
}
}
}
@Override
public String toString() {
synchronized (this) {
return "held=" + (mNestCount != 0) + ", mNestCount=" + mNestCount;
}
}
};
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2012 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.power;
/**
* Low-level screen on blocker mechanism which is used to keep the screen off
* until the window manager is ready to show new content.
*/
interface ScreenOnBlocker {
/**
* Acquires the screen on blocker.
* Prevents the screen from turning on.
*
* Calls to acquire() nest and must be matched by the same number
* of calls to release().
*/
void acquire();
/**
* Releases the screen on blocker.
* Allows the screen to turn on.
*
* It is an error to call release() if the screen on blocker has not been acquired.
* The system may crash.
*/
void release();
}

View File

@ -9450,18 +9450,22 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
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();
public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
if (token != null && callback != null) {
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();
return true;
}
}
}
return false;
}
void setHoldScreenLocked(final Session newHoldScreen) {
@ -9475,10 +9479,10 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean state = mHoldingScreenWakeLock.isHeld();
if (hold != state) {
if (hold) {
mPolicy.screenOnStartedLw();
mHoldingScreenWakeLock.acquire();
mPolicy.keepScreenOnStartedLw();
} else {
mPolicy.screenOnStoppedLw();
mPolicy.keepScreenOnStoppedLw();
mHoldingScreenWakeLock.release();
}
}

View File

@ -414,8 +414,8 @@ public class BridgeWindowManager implements IWindowManager {
}
@Override
public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
// TODO Auto-generated method stub
public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
return false;
}
@Override