summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/power/DisplayPowerController.java54
-rw-r--r--services/java/com/android/server/power/DisplayPowerRequest.java15
-rw-r--r--services/java/com/android/server/power/Notifier.java30
-rw-r--r--services/java/com/android/server/power/PowerManagerService.java93
-rw-r--r--services/java/com/android/server/power/ScreenOnBlocker.java41
-rwxr-xr-xservices/java/com/android/server/wm/WindowManagerService.java28
6 files changed, 216 insertions, 45 deletions
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index b9f9df7..23df701 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -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();
diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/java/com/android/server/power/DisplayPowerRequest.java
index 2d74292..5f94414 100644
--- a/services/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/java/com/android/server/power/DisplayPowerRequest.java
@@ -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;
}
}
diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java
index 3042124..5e05693 100644
--- a/services/java/com/android/server/power/Notifier.java
+++ b/services/java/com/android/server/power/Notifier.java
@@ -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) {
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index ae7b2d1..f584302 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -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;
+ }
+ }
+ };
}
diff --git a/services/java/com/android/server/power/ScreenOnBlocker.java b/services/java/com/android/server/power/ScreenOnBlocker.java
new file mode 100644
index 0000000..2bf0bcf
--- /dev/null
+++ b/services/java/com/android/server/power/ScreenOnBlocker.java
@@ -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();
+}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 8cc3d61..8f5103c 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -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();
}
}