Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a0da018 authored by Craig Mautner's avatar Craig Mautner
Browse files

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
parent 4327e2fb
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -215,12 +215,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).
     */
+8 −1
Original line number Diff line number Diff line
@@ -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);
}
+79 −45
Original line number Diff line number Diff line
@@ -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();
                    }
                })) {
    // 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! waitForWindowDrawn false");

            } catch (RemoteException ex) {
                // Can't happen in system process.
            }
        }

        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;
+75 −61
Original line number Diff line number Diff line
@@ -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,18 +7554,19 @@ 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;
                    }
                    if (callback != null) {
                        try {
                        pair.second.sendResult(null);
                            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,54 +9574,31 @@ public class WindowManagerService extends IWindowManager.Stub
    }

    void checkDrawnWindowsLocked() {
        if (mWaitingForDrawn.size() > 0) {
        if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
            return;
        }
        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) {
            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.
                    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) {
                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).
                    try {
                        pair.second.sendResult(null);
                    } catch (RemoteException e) {
                if (DEBUG_SCREEN_ON) Slog.d(TAG, "Window drawn win=" + win);
                mWaitingForDrawn.remove(win);
            }
                    mWaitingForDrawn.remove(pair);
                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
        }
        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);
        }
    }
    }

    @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");
            }
        }
        return false;
    }

    void setHoldScreenLocked(final Session newHoldScreen) {
        final boolean hold = newHoldScreen != null;
@@ -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();
@@ -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();
        }
    }
}
+0 −5
Original line number Diff line number Diff line
@@ -418,11 +418,6 @@ public class IWindowManagerImpl implements IWindowManager {
    public void removeRotationWatcher(IRotationWatcher arg0) throws RemoteException {
    }

    @Override
    public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
        return false;
    }

    @Override
    public IBinder asBinder() {
        // TODO Auto-generated method stub