diff options
author | Craig Mautner <cmautner@google.com> | 2014-05-31 15:13:37 -0700 |
---|---|---|
committer | Craig Mautner <cmautner@google.com> | 2014-06-03 17:08:02 -0700 |
commit | 8a0da0184f6c5c95d94ab6adfee79bace4040abd (patch) | |
tree | d426d7012d2cc62bfe18e4acf9f34a92ca6914e3 | |
parent | 4327e2fbcd68ec022a8d365bbe171dbc3cb97c65 (diff) | |
download | frameworks_base-8a0da0184f6c5c95d94ab6adfee79bace4040abd.zip frameworks_base-8a0da0184f6c5c95d94ab6adfee79bace4040abd.tar.gz frameworks_base-8a0da0184f6c5c95d94ab6adfee79bace4040abd.tar.bz2 |
Force all windows to redraw before unblanking screen
The screen turning on would show windows as they were when the screen
turned off. This fix forces all showing windows to redraw first and
only then allow the screen to turn on.
Fixes bug 15092354.
Change-Id: I52c3f47438176a5ac00ba9a4d5205b56a5aa48f9
5 files changed, 162 insertions, 118 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index af16185..a52ccdf 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -216,12 +216,6 @@ interface IWindowManager oneway void statusBarVisibilityChanged(int visibility); /** - * Block until the given window has been drawn to the screen. - * Returns true if really waiting, false if the window does not exist. - */ - boolean waitForWindowDrawn(IBinder token, in IRemoteCallback callback); - - /** * Device has a software navigation bar (separate from the status bar). */ boolean hasNavigationBar(); diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java index 14dc356..a92bf59 100644 --- a/core/java/android/view/WindowManagerInternal.java +++ b/core/java/android/view/WindowManagerInternal.java @@ -20,6 +20,7 @@ import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManagerInternal; import android.os.IBinder; +import android.os.IRemoteCallback; import java.util.List; @@ -105,7 +106,7 @@ public abstract class WindowManagerInternal { * Set by the accessibility layer to specify the magnification and panning to * be applied to all windows that should be magnified. * - * @param callbacks The callbacks to invoke. + * @param spec The MagnficationSpec to set. * * @see #setMagnificationCallbacks(MagnificationCallbacks) */ @@ -161,4 +162,10 @@ public abstract class WindowManagerInternal { * @param outBounds The frame to populate. */ public abstract void getWindowFrame(IBinder token, Rect outBounds); + + /** + * Invalidate all visible windows. Then report back on the callback once all windows have + * redrawn. + */ + public abstract void waitForAllWindowsDrawn(IRemoteCallback callback, long timeout); } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 30282dd..43aa2ba 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -91,6 +91,7 @@ import android.view.ViewConfiguration; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerGlobal; +import android.view.WindowManagerInternal; import android.view.WindowManagerPolicy; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -102,14 +103,17 @@ import com.android.internal.policy.IKeyguardService; import com.android.internal.policy.IKeyguardServiceConstants; import com.android.internal.policy.PolicyManager; import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate; +import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate.ShowListener; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.telephony.ITelephony; import com.android.internal.widget.PointerLocationView; +import com.android.server.LocalServices; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.HashSet; import static android.view.WindowManager.LayoutParams.*; @@ -131,6 +135,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean DEBUG_LAYOUT = false; static final boolean DEBUG_INPUT = false; static final boolean DEBUG_STARTING_WINDOW = false; + static final boolean DEBUG_WAKEUP = false; static final boolean SHOW_STARTING_ANIMATIONS = true; static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; @@ -223,6 +228,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Context mContext; IWindowManager mWindowManager; WindowManagerFuncs mWindowManagerFuncs; + WindowManagerInternal mWindowManagerInternal; PowerManager mPowerManager; IStatusBarService mStatusBarService; boolean mPreloadedRecentApps; @@ -264,6 +270,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { int[] mNavigationBarWidthForRotation = new int[4]; KeyguardServiceDelegate mKeyguardDelegate; + // The following are only accessed on the mHandler thread. + boolean mKeyguardDrawComplete; + boolean mWindowManagerDrawComplete; + ArrayList<ScreenOnListener> mScreenOnListeners = new ArrayList<ScreenOnListener>(); + final IRemoteCallback mWindowManagerDrawCallback = new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) { + if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for display!"); + mHandler.sendEmptyMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE); + } + }; + final ShowListener mKeyguardDelegateCallback = new ShowListener() { + @Override + public void onShown(IBinder windowToken) { + if (DEBUG_WAKEUP) Slog.d(TAG, "mKeyguardDelegate.ShowListener.onShown."); + mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE); + } + }; + GlobalActions mGlobalActions; volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread boolean mPendingPowerKeyUpCanceled; @@ -483,6 +508,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int MSG_DISABLE_POINTER_LOCATION = 2; private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3; private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4; + private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5; + private static final int MSG_KEYGUARD_DRAWN_TIMEOUT = 6; + private static final int MSG_WINDOW_MANAGER_DRAWN_COMPLETE = 7; + private static final int MSG_WAKING_UP = 8; private class PolicyHandler extends Handler { @Override @@ -500,6 +529,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { case MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK: dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj); break; + case MSG_KEYGUARD_DRAWN_COMPLETE: + if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mKeyguardDrawComplete"); + mKeyguardDrawComplete = true; + finishScreenTurningOn(); + break; + case MSG_KEYGUARD_DRAWN_TIMEOUT: + Slog.w(TAG, "Keyguard drawn timeout. Setting mKeyguardDrawComplete"); + mKeyguardDrawComplete = true; + finishScreenTurningOn(); + break; + case MSG_WINDOW_MANAGER_DRAWN_COMPLETE: + if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mWindowManagerDrawComplete"); + mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT); + mWindowManagerDrawComplete = true; + finishScreenTurningOn(); + break; + case MSG_WAKING_UP: + handleWakingUp((ScreenOnListener) msg.obj); + break; } } } @@ -855,6 +903,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mContext = context; mWindowManager = windowManager; mWindowManagerFuncs = windowManagerFuncs; + mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); + mHandler = new PolicyHandler(); mOrientationListener = new MyOrientationListener(mContext, mHandler); try { @@ -4418,10 +4468,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void wakingUp(final ScreenOnListener screenOnListener) { EventLog.writeEvent(70000, 1); - if (false) { - RuntimeException here = new RuntimeException("here"); - here.fillInStackTrace(); - Slog.i(TAG, "Screen turning on...", here); + if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...", + new RuntimeException("here").fillInStackTrace()); + mHandler.obtainMessage(MSG_WAKING_UP, screenOnListener).sendToTarget(); + } + + // Called on the mHandler thread. + private void handleWakingUp(final ScreenOnListener screenOnListener) { + if (screenOnListener != null) { + mScreenOnListeners.add(screenOnListener); } synchronized (mLock) { @@ -4430,51 +4485,28 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateLockScreenTimeout(); } - waitForKeyguard(screenOnListener); - } - - private void waitForKeyguard(final ScreenOnListener screenOnListener) { + mKeyguardDrawComplete = false; + mWindowManagerDrawComplete = false; if (mKeyguardDelegate != null) { - mKeyguardDelegate.onScreenTurnedOn(new KeyguardServiceDelegate.ShowListener() { - @Override - public void onShown(IBinder windowToken) { - waitForKeyguardWindowDrawn(windowToken, screenOnListener); - } - }); + mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT); + mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000); + mKeyguardDelegate.onScreenTurnedOn(mKeyguardDelegateCallback); } else { - Slog.i(TAG, "No keyguard interface!"); - finishScreenTurningOn(screenOnListener); + if (DEBUG_WAKEUP) Slog.d(TAG, "null mKeyguardDelegate: setting mKeyguardDrawComplete."); + mKeyguardDrawComplete = true; } + mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback, 500); } - private void waitForKeyguardWindowDrawn(IBinder windowToken, - final ScreenOnListener screenOnListener) { - if (windowToken != null && !mHideLockScreen) { - try { - if (mWindowManager.waitForWindowDrawn( - windowToken, new IRemoteCallback.Stub() { - @Override - public void sendResult(Bundle data) { - Slog.i(TAG, "Lock screen displayed!"); - finishScreenTurningOn(screenOnListener); - setKeyguardDrawn(); - } - })) { - return; - } - Slog.i(TAG, "No lock screen! waitForWindowDrawn false"); - - } catch (RemoteException ex) { - // Can't happen in system process. - } + // Called on the mHandler thread. + private void finishScreenTurningOn() { + if (DEBUG_WAKEUP) Slog.d(TAG, + "finishScreenTurningOn: mKeyguardDrawComplete=" + mKeyguardDrawComplete + + " mWindowManagerDrawComplete=" + mWindowManagerDrawComplete); + if (!mKeyguardDrawComplete || !mWindowManagerDrawComplete) { + return; } - Slog.i(TAG, "No lock screen! windowToken=" + windowToken); - finishScreenTurningOn(screenOnListener); - setKeyguardDrawn(); - } - - private void finishScreenTurningOn(ScreenOnListener screenOnListener) { synchronized (mLock) { mScreenOnFully = true; } @@ -4484,9 +4516,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException unhandled) { } - if (screenOnListener != null) { - screenOnListener.onScreenOn(); + for (int i = mScreenOnListeners.size() - 1; i >=0; --i) { + mScreenOnListeners.remove(i).onScreenOn(); } + + setKeyguardDrawn(); } @Override @@ -4859,7 +4893,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { mSystemBooted = true; } - waitForKeyguard(null); + wakingUp(null); } ProgressDialog mBootMsgDialog = null; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7382f4c..da584d8 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -407,8 +407,11 @@ public class WindowManagerService extends IWindowManager.Stub /** * Windows that clients are waiting to have drawn. */ - ArrayList<Pair<WindowState, IRemoteCallback>> mWaitingForDrawn - = new ArrayList<Pair<WindowState, IRemoteCallback>>(); + ArrayList<WindowState> mWaitingForDrawn = new ArrayList<WindowState>(); + /** + * And the callback to make when they've all been drawn. + */ + IRemoteCallback mWaitingForDrawnCallback; /** * Windows that have called relayout() while we were running animations, @@ -814,6 +817,7 @@ public class WindowManagerService extends IWindowManager.Stub mAnimator = new WindowAnimator(this); + LocalServices.addService(WindowManagerInternal.class, new LocalService()); initPolicy(); // Add ourself to the Watchdog monitors. @@ -828,7 +832,6 @@ public class WindowManagerService extends IWindowManager.Stub SurfaceControl.closeTransaction(); } - LocalServices.addService(WindowManagerInternal.class, new LocalService()); showCircularDisplayMaskIfNeeded(); } @@ -7174,6 +7177,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int NOTIFY_ACTIVITY_DRAWN = 32; public static final int SHOW_DISPLAY_MASK = 33; + public static final int ALL_WINDOWS_DRAWN = 34; @Override public void handleMessage(Message msg) { @@ -7550,17 +7554,18 @@ public class WindowManagerService extends IWindowManager.Stub } case WAITING_FOR_DRAWN_TIMEOUT: { - Pair<WindowState, IRemoteCallback> pair; + IRemoteCallback callback = null; synchronized (mWindowMap) { - pair = (Pair<WindowState, IRemoteCallback>)msg.obj; - Slog.w(TAG, "Timeout waiting for drawn: " + pair.first); - if (!mWaitingForDrawn.remove(pair)) { - return; - } + Slog.w(TAG, "Timeout waiting for drawn: undrawn=" + mWaitingForDrawn); + mWaitingForDrawn.clear(); + callback = mWaitingForDrawnCallback; + mWaitingForDrawnCallback = null; } - try { - pair.second.sendResult(null); - } catch (RemoteException e) { + if (callback != null) { + try { + callback.sendResult(null); + } catch (RemoteException e) { + } } break; } @@ -7618,6 +7623,19 @@ public class WindowManagerService extends IWindowManager.Stub } catch (RemoteException e) { } break; + case ALL_WINDOWS_DRAWN: { + IRemoteCallback callback; + synchronized (mWindowMap) { + callback = mWaitingForDrawnCallback; + mWaitingForDrawnCallback = null; + } + if (callback != null) { + try { + callback.sendResult(null); + } catch (RemoteException e) { + } + } + } } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG, "handleMessage: exit"); @@ -9556,53 +9574,30 @@ public class WindowManagerService extends IWindowManager.Stub } 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) { - // Window has been removed; 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.mWinAnimator.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); - } - } + if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) { + return; } - } - - @Override - 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; - } - Slog.i(TAG, "waitForWindowDrawn: win null"); + for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) { + WindowState win = mWaitingForDrawn.get(j); + if (DEBUG_SCREEN_ON) Slog.i(TAG, "Waiting for drawn " + win + + ": removed=" + win.mRemoved + " visible=" + win.isVisibleLw() + + " mHasSurface=" + win.mHasSurface + + " drawState=" + win.mWinAnimator.mDrawState); + if (win.mRemoved || !win.mHasSurface) { + // Window has been removed; no draw will now happen, so stop waiting. + if (DEBUG_SCREEN_ON) Slog.w(TAG, "Aborted waiting for drawn: " + win); + mWaitingForDrawn.remove(win); + } else if (win.hasDrawnLw()) { + // Window is now drawn (and shown). + if (DEBUG_SCREEN_ON) Slog.d(TAG, "Window drawn win=" + win); + mWaitingForDrawn.remove(win); } } - return false; + if (mWaitingForDrawn.isEmpty()) { + if (DEBUG_SCREEN_ON) Slog.d(TAG, "All windows drawn!"); + mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT); + mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN); + } } void setHoldScreenLocked(final Session newHoldScreen) { @@ -10550,9 +10545,8 @@ public class WindowManagerService extends IWindowManager.Stub 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); + WindowState win = mWaitingForDrawn.get(i); + pw.print(" Waiting #"); pw.print(i); pw.print(' '); pw.print(win); } } pw.println(); @@ -11062,7 +11056,7 @@ public class WindowManagerService extends IWindowManager.Stub } mAccessibilityController.setMagnificationCallbacksLocked(callbacks); if (!mAccessibilityController.hasCallbacksLocked()) { - mAccessibilityController = null; + mAccessibilityController = null; } } } @@ -11076,7 +11070,7 @@ public class WindowManagerService extends IWindowManager.Stub } mAccessibilityController.setWindowsForAccessibilityCallback(callback); if (!mAccessibilityController.hasCallbacksLocked()) { - mAccessibilityController = null; + mAccessibilityController = null; } } } @@ -11113,5 +11107,25 @@ public class WindowManagerService extends IWindowManager.Stub } } } + + public void waitForAllWindowsDrawn(IRemoteCallback callback, long timeout) { + synchronized (mWindowMap) { + mWaitingForDrawnCallback = callback; + final WindowList windows = getDefaultWindowListLocked(); + for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { + final WindowState win = windows.get(winNdx); + if (win.mHasSurface) { + win.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING; + // Force add to mResizingWindows. + win.mLastContentInsets.set(-1, -1, -1, -1); + mWaitingForDrawn.add(win); + } + } + requestTraversalLocked(); + mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT); + mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout); + } + checkDrawnWindowsLocked(); + } } } diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 3bf2b20..cfe8e15 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -419,11 +419,6 @@ public class IWindowManagerImpl implements IWindowManager { } @Override - public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) { - return false; - } - - @Override public IBinder asBinder() { // TODO Auto-generated method stub return null; |