am 05cd6c39: Merge "Force all windows to redraw before unblanking screen" into lmp-preview-dev

* commit '05cd6c39824653e0f7e8641444a7134e8cac72f4':
  Force all windows to redraw before unblanking screen
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 @@
     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.Region;
 import android.hardware.display.DisplayManagerInternal;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 
 import java.util.List;
 
@@ -105,7 +106,7 @@
      * 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 @@
      * @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 d7ad4c2..b883c5f6 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.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.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 @@
     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 @@
     Context mContext;
     IWindowManager mWindowManager;
     WindowManagerFuncs mWindowManagerFuncs;
+    WindowManagerInternal mWindowManagerInternal;
     PowerManager mPowerManager;
     IStatusBarService mStatusBarService;
     boolean mPreloadedRecentApps;
@@ -264,6 +270,25 @@
     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;
@@ -486,6 +511,10 @@
     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
@@ -503,6 +532,25 @@
                 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;
             }
         }
     }
@@ -876,6 +924,8 @@
         mContext = context;
         mWindowManager = windowManager;
         mWindowManagerFuncs = windowManagerFuncs;
+        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+
         mHandler = new PolicyHandler();
         mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
         mOrientationListener = new MyOrientationListener(mContext, mHandler);
@@ -4465,10 +4515,15 @@
     @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) {
@@ -4478,51 +4533,28 @@
             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;
         }
@@ -4532,9 +4564,11 @@
         } catch (RemoteException unhandled) {
         }
 
-        if (screenOnListener != null) {
-            screenOnListener.onScreenOn();
+        for (int i = mScreenOnListeners.size() - 1; i >=0; --i) {
+            mScreenOnListeners.remove(i).onScreenOn();
         }
+
+        setKeyguardDrawn();
     }
 
     @Override
@@ -4907,7 +4941,7 @@
         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 05502cf..616db42 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 @@
     /**
      * 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 @@
 
         mAnimator = new WindowAnimator(this);
 
+        LocalServices.addService(WindowManagerInternal.class, new LocalService());
         initPolicy();
 
         // Add ourself to the Watchdog monitors.
@@ -828,7 +832,6 @@
             SurfaceControl.closeTransaction();
         }
 
-        LocalServices.addService(WindowManagerInternal.class, new LocalService());
         showCircularDisplayMaskIfNeeded();
     }
 
@@ -7176,6 +7179,7 @@
         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) {
@@ -7552,17 +7556,18 @@
                 }
 
                 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;
                 }
@@ -7620,6 +7625,19 @@
                     } 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");
@@ -9558,53 +9576,30 @@
     }
 
     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;
+        }
+        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);
             }
         }
-    }
-
-    @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");
-            }
+        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);
         }
-        return false;
     }
 
     void setHoldScreenLocked(final Session newHoldScreen) {
@@ -10552,9 +10547,8 @@
             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();
@@ -11064,7 +11058,7 @@
                 }
                 mAccessibilityController.setMagnificationCallbacksLocked(callbacks);
                 if (!mAccessibilityController.hasCallbacksLocked()) {
-                     mAccessibilityController = null;
+                    mAccessibilityController = null;
                 }
             }
         }
@@ -11078,7 +11072,7 @@
                 }
                 mAccessibilityController.setWindowsForAccessibilityCallback(callback);
                 if (!mAccessibilityController.hasCallbacksLocked()) {
-                     mAccessibilityController = null;
+                    mAccessibilityController = null;
                 }
             }
         }
@@ -11115,5 +11109,25 @@
                 }
             }
         }
+
+        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 @@
     }
 
     @Override
-    public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
-        return false;
-    }
-
-    @Override
     public IBinder asBinder() {
         // TODO Auto-generated method stub
         return null;