Fix issue #5242779: Device not responding to touch on unlock screen

Rework how we decide when it is okay to turn on the screen by having
the policy call back to the power manager when it knows the lock screen
has been drawn.

Change-Id: Ie8f3f72111dcf7f168723e6dce24e0343b4afe5d
This commit is contained in:
Dianne Hackborn
2011-09-18 14:43:08 -07:00
committed by Dave Burke
parent d908b40d0b
commit 6ea4da95d9
7 changed files with 189 additions and 108 deletions

View File

@@ -23,6 +23,7 @@ import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.os.IRemoteCallback;
import android.view.IApplicationToken;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
@@ -220,7 +221,7 @@ interface IWindowManager
void setPointerSpeed(int speed);
/**
* Block until all windows the window manager knows about have been drawn.
* Block until the given window has been drawn to the screen.
*/
void waitForAllDrawn();
void waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
}

View File

@@ -772,10 +772,16 @@ public interface WindowManagerPolicy {
*/
public void screenTurnedOff(int why);
public interface ScreenOnListener {
void onScreenOn();
};
/**
* Called after the screen turns on.
* Called when the power manager would like to turn the screen on.
* Must call back on the listener to tell it when the higher-level system
* is ready for the screen to go on (i.e. the lock screen is shown).
*/
public void screenTurnedOn();
public void screenTurningOn(ScreenOnListener screenOnListener);
/**
* Return whether the screen is currently on.

View File

@@ -24,6 +24,7 @@ import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Canvas;
import android.os.IBinder;
import android.os.SystemProperties;
import android.util.Log;
import android.view.View;
@@ -59,6 +60,10 @@ public class KeyguardViewManager implements KeyguardWindowController {
private boolean mScreenOn = false;
public interface ShowListener {
void onShown(IBinder windowToken);
};
/**
* @param context Used to create views.
* @param viewManager Keyguard will be attached to this.
@@ -206,7 +211,8 @@ public class KeyguardViewManager implements KeyguardWindowController {
}
}
public synchronized void onScreenTurnedOn() {
public synchronized void onScreenTurnedOn(
final KeyguardViewManager.ShowListener showListener) {
if (DEBUG) Log.d(TAG, "onScreenTurnedOn()");
mScreenOn = true;
if (mKeyguardView != null) {
@@ -214,6 +220,26 @@ public class KeyguardViewManager implements KeyguardWindowController {
// When screen is turned on, need to bind to FaceLock service if we are using FaceLock
mKeyguardView.bindToFaceLock();
// Caller should wait for this window to be shown before turning
// on the screen.
if (mKeyguardHost.getVisibility() == View.VISIBLE) {
// Keyguard may be in the process of being shown, but not yet
// updated with the window manager... give it a chance to do so.
mKeyguardHost.post(new Runnable() {
@Override public void run() {
if (mKeyguardHost.getVisibility() == View.VISIBLE) {
showListener.onShown(mKeyguardHost.getWindowToken());
} else {
showListener.onShown(null);
}
}
});
} else {
showListener.onShown(null);
}
} else {
showListener.onShown(null);
}
}

View File

@@ -116,7 +116,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
private static final int KEYGUARD_DONE_AUTHENTICATING = 11;
private static final int SET_HIDDEN = 12;
private static final int KEYGUARD_TIMEOUT = 13;
private static final int REPORT_SHOW_DONE = 14;
/**
* The default amount of time we stay awake (used for all key input)
@@ -239,8 +238,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
private boolean mScreenOn = false;
private boolean mShowPending = false;
// last known state of the cellular connection
private String mPhoneState = TelephonyManager.EXTRA_STATE_IDLE;
@@ -383,19 +380,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
} else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
// Do not enable the keyguard if the prox sensor forced the screen off.
} else {
if (!doKeyguardLocked() && why == WindowManagerPolicy.OFF_BECAUSE_OF_USER) {
// The user has explicitly turned off the screen, causing it
// to lock. We want to block here until the keyguard window
// has shown, so the power manager won't complete the screen
// off flow until that point, so we know it won't turn *on*
// the screen until this is done.
while (mShowPending) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
doKeyguardLocked();
}
}
}
@@ -403,12 +388,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
/**
* Let's us know the screen was turned on.
*/
public void onScreenTurnedOn() {
public void onScreenTurnedOn(KeyguardViewManager.ShowListener showListener) {
synchronized (this) {
mScreenOn = true;
mDelayedShowingSequence++;
if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence);
notifyScreenOnLocked();
notifyScreenOnLocked(showListener);
}
}
@@ -573,7 +558,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
* work that will happen is done; returns false if the caller can wait for
* the keyguard to be shown.
*/
private boolean doKeyguardLocked() {
private void doKeyguardLocked() {
// if another app is disabling us, don't show
if (!mExternallyEnabled) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
@@ -587,13 +572,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
// ends (see the broadcast receiver below)
// TODO: clean this up when we have better support at the window manager level
// for apps that wish to be on top of the keyguard
return true;
return;
}
// if the keyguard is already showing, don't bother
if (mKeyguardViewManager.isShowing()) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
return true;
return;
}
// if the setup wizard hasn't run yet, don't show
@@ -609,18 +594,16 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
if (!lockedOrMissing && !provisioned) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
+ " and the sim is not locked or missing");
return true;
return;
}
if (mLockPatternUtils.isLockScreenDisabled()) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
return true;
return;
}
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
mShowPending = true;
showLocked();
return false;
}
/**
@@ -658,9 +641,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
* @see #onScreenTurnedOn()
* @see #handleNotifyScreenOn
*/
private void notifyScreenOnLocked() {
private void notifyScreenOnLocked(KeyguardViewManager.ShowListener showListener) {
if (DEBUG) Log.d(TAG, "notifyScreenOnLocked");
mHandler.sendEmptyMessage(NOTIFY_SCREEN_ON);
Message msg = mHandler.obtainMessage(NOTIFY_SCREEN_ON, showListener);
mHandler.sendMessage(msg);
}
/**
@@ -974,7 +958,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
handleNotifyScreenOff();
return;
case NOTIFY_SCREEN_ON:
handleNotifyScreenOn();
handleNotifyScreenOn((KeyguardViewManager.ShowListener)msg.obj);
return;
case WAKE_WHEN_READY:
handleWakeWhenReady(msg.arg1);
@@ -996,12 +980,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
doKeyguardLocked();
}
break;
case REPORT_SHOW_DONE:
synchronized (KeyguardViewMediator.this) {
mShowPending = false;
KeyguardViewMediator.this.notifyAll();
}
break;
}
}
};
@@ -1113,12 +1091,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
playSounds(true);
mShowKeyguardWakeLock.release();
// We won't say the show is done yet because the view hierarchy
// still needs to do the traversal. Posting this message allows
// us to hold off until that is done.
Message msg = mHandler.obtainMessage(REPORT_SHOW_DONE);
mHandler.sendMessage(msg);
}
}
@@ -1284,10 +1256,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
* Handle message sent by {@link #notifyScreenOnLocked()}
* @see #NOTIFY_SCREEN_ON
*/
private void handleNotifyScreenOn() {
private void handleNotifyScreenOn(KeyguardViewManager.ShowListener showListener) {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleNotifyScreenOn");
mKeyguardViewManager.onScreenTurnedOn();
mKeyguardViewManager.onScreenTurnedOn(showListener);
}
}

View File

@@ -40,8 +40,10 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.LocalPowerManager;
import android.os.Message;
import android.os.Messenger;
@@ -125,6 +127,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
import android.view.KeyCharacterMap.FallbackAction;
import android.view.WindowManagerPolicy.ScreenOnListener;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -2814,23 +2817,30 @@ public class PhoneWindowManager implements WindowManagerPolicy {
updateLockScreenTimeout();
updateScreenSaverTimeoutLocked();
}
try {
mWindowManager.waitForAllDrawn();
} catch (RemoteException e) {
}
// Wait for one frame to give surface flinger time to do its
// compositing. Yes this is a hack, but I am really not up right now for
// implementing some mechanism to block until SF is done. :p
try {
Thread.sleep(20);
} catch (InterruptedException e) {
}
}
/** {@inheritDoc} */
public void screenTurnedOn() {
public void screenTurningOn(final ScreenOnListener screenOnListener) {
EventLog.writeEvent(70000, 1);
mKeyguardMediator.onScreenTurnedOn();
//Slog.i(TAG, "Screen turning on...");
mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() {
@Override public void onShown(IBinder windowToken) {
if (windowToken != null) {
try {
mWindowManager.waitForWindowDrawn(windowToken, new IRemoteCallback.Stub() {
@Override public void sendResult(Bundle data) {
Slog.i(TAG, "Lock screen displayed!");
screenOnListener.onScreenOn();
}
});
} catch (RemoteException e) {
}
} else {
Slog.i(TAG, "No lock screen!");
screenOnListener.onScreenOn();
}
}
});
synchronized (mLock) {
mScreenOn = true;
updateOrientationListenerLp();

View File

@@ -161,7 +161,7 @@ public class PowerManagerService extends IPowerManager.Stub
private int mStayOnConditions = 0;
private final int[] mBroadcastQueue = new int[] { -1, -1, -1 };
private final int[] mBroadcastWhy = new int[3];
private boolean mBroadcastingScreenOff = false;
private boolean mPreparingForScreenOn = false;
private int mPartialCount = 0;
private int mPowerState;
// mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER,
@@ -1122,7 +1122,8 @@ public class PowerManagerService extends IPowerManager.Stub
pw.println(" mNextTimeout=" + mNextTimeout + " now=" + now
+ " " + ((mNextTimeout-now)/1000) + "s from now");
pw.println(" mDimScreen=" + mDimScreen
+ " mStayOnConditions=" + mStayOnConditions);
+ " mStayOnConditions=" + mStayOnConditions
+ " mPreparingForScreenOn=" + mPreparingForScreenOn);
pw.println(" mScreenOffReason=" + mScreenOffReason
+ " mUserState=" + mUserState);
pw.println(" mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1]
@@ -1341,7 +1342,9 @@ public class PowerManagerService extends IPowerManager.Stub
mBroadcastQueue[0] = on ? 1 : 0;
mBroadcastQueue[1] = -1;
mBroadcastQueue[2] = -1;
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
mBroadcastWakeLock.release();
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
mBroadcastWakeLock.release();
index = 0;
}
@@ -1371,6 +1374,21 @@ public class PowerManagerService extends IPowerManager.Stub
}
}
private WindowManagerPolicy.ScreenOnListener mScreenOnListener =
new WindowManagerPolicy.ScreenOnListener() {
@Override public void onScreenOn() {
synchronized (mLocks) {
if (mPreparingForScreenOn) {
mPreparingForScreenOn = false;
updateNativePowerStateLocked();
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP,
4, mBroadcastWakeLock.mCount);
mBroadcastWakeLock.release();
}
}
}
};
private Runnable mNotificationTask = new Runnable()
{
public void run()
@@ -1387,14 +1405,17 @@ public class PowerManagerService extends IPowerManager.Stub
mBroadcastWhy[i] = mBroadcastWhy[i+1];
}
policy = getPolicyLocked();
if (value == 0) {
mBroadcastingScreenOff = true;
if (value == 1 && !mPreparingForScreenOn) {
mPreparingForScreenOn = true;
mBroadcastWakeLock.acquire();
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND,
mBroadcastWakeLock.mCount);
}
}
if (value == 1) {
mScreenOnStart = SystemClock.uptimeMillis();
policy.screenTurnedOn();
policy.screenTurningOn(mScreenOnListener);
try {
ActivityManagerNative.getDefault().wakingUp();
} catch (RemoteException e) {
@@ -1432,7 +1453,6 @@ public class PowerManagerService extends IPowerManager.Stub
synchronized (mLocks) {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3,
mBroadcastWakeLock.mCount);
mBroadcastingScreenOff = false;
updateNativePowerStateLocked();
mBroadcastWakeLock.release();
}
@@ -1464,10 +1484,6 @@ public class PowerManagerService extends IPowerManager.Stub
synchronized (mLocks) {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount);
synchronized (mLocks) {
mBroadcastingScreenOff = false;
updateNativePowerStateLocked();
}
mBroadcastWakeLock.release();
}
}
@@ -1795,17 +1811,18 @@ public class PowerManagerService extends IPowerManager.Stub
private void updateNativePowerStateLocked() {
if ((mPowerState & SCREEN_ON_BIT) != 0) {
// Don't turn screen on if we are currently reporting a screen off.
// Don't turn screen on until we know we are really ready to.
// This is to avoid letting the screen go on before things like the
// lock screen have been displayed due to it going off.
if (mBroadcastingScreenOff) {
// Currently broadcasting that the screen is off. Don't
// allow screen to go on until that is done.
// lock screen have been displayed.
if (mPreparingForScreenOn) {
// Currently waiting for confirmation from the policy that it
// is okay to turn on the screen. Don't allow the screen to go
// on until that is done.
return;
}
for (int i=0; i<mBroadcastQueue.length; i++) {
if (mBroadcastQueue[i] == 0) {
// A screen off is currently enqueued.
if (mBroadcastQueue[i] == 1) {
// A screen on is currently enqueued.
return;
}
}

View File

@@ -73,6 +73,7 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.LocalPowerManager;
import android.os.Looper;
import android.os.Message;
@@ -91,6 +92,7 @@ import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.TypedValue;
@@ -383,6 +385,12 @@ public class WindowManagerService extends IWindowManager.Stub
*/
ArrayList<WindowState> mForceRemoves;
/**
* Windows that clients are waiting to have drawn.
*/
ArrayList<Pair<WindowState, IRemoteCallback>> mWaitingForDrawn
= new ArrayList<Pair<WindowState, IRemoteCallback>>();
/**
* Used when rebuilding window list to keep track of windows that have
* been removed.
@@ -6295,6 +6303,7 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int DRAG_END_TIMEOUT = 21;
public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
public static final int BOOT_TIMEOUT = 23;
public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
private Session mLastReportedHold;
@@ -6605,11 +6614,6 @@ public class WindowManagerService extends IWindowManager.Stub
break;
}
case BOOT_TIMEOUT: {
performBootTimeout();
break;
}
case APP_FREEZE_TIMEOUT: {
synchronized (mWindowMap) {
Slog.w(TAG, "App freeze timeout expired.");
@@ -6678,6 +6682,27 @@ public class WindowManagerService extends IWindowManager.Stub
notifyHardKeyboardStatusChange();
break;
}
case BOOT_TIMEOUT: {
performBootTimeout();
break;
}
case WAITING_FOR_DRAWN_TIMEOUT: {
Pair<WindowState, IRemoteCallback> pair;
synchronized (mWindowMap) {
pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
if (!mWaitingForDrawn.remove(pair)) {
return;
}
}
try {
pair.second.sendResult(null);
} catch (RemoteException e) {
}
break;
}
}
}
}
@@ -8582,39 +8607,54 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
mWindowMap.notifyAll();
checkDrawnWindowsLocked();
// Check to see if we are now in a state where the screen should
// be enabled, because the window obscured flags have changed.
enableScreenIfNeededLocked();
}
public void waitForAllDrawn() {
void checkDrawnWindowsLocked() {
if (mWaitingForDrawn.size() > 0) {
for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
WindowState win = pair.first;
//Slog.i(TAG, "Waiting for drawn " + win + ": removed="
// + win.mRemoved + " visible=" + win.isVisibleLw()
// + " shown=" + win.mSurfaceShown);
if (win.mRemoved || !win.isVisibleLw()) {
// Window has been removed or made invisible; no draw
// will now happen, so stop waiting.
Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
try {
pair.second.sendResult(null);
} catch (RemoteException e) {
}
mWaitingForDrawn.remove(pair);
mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
} else if (win.mSurfaceShown) {
// Window is now drawn (and shown).
try {
pair.second.sendResult(null);
} catch (RemoteException e) {
}
mWaitingForDrawn.remove(pair);
mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
}
}
}
}
public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
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) {
}
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();
}
}
}
@@ -9284,6 +9324,15 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
}
if (mWaitingForDrawn.size() > 0) {
pw.println();
pw.println(" Clients waiting for these windows to be drawn:");
for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
pw.print(" Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
pw.print(": "); pw.println(pair.second);
}
}
pw.println();
if (mDisplay != null) {
pw.print(" Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");