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

Commit 0d289f64 authored by Nick Chameyev's avatar Nick Chameyev
Browse files

[Unfold transition] Fully manage the vignette on the background thread

Updates onScreenTurningOn/device state callbacks
in the unfold overlay class to be executed on
the background thread.

This allows to draw the first black frame even
if SystemUI's main thread is busy at the moment,
so it will be less likely to have flicker because
of that.

Also this CL adds a separate thread to render
the vignette to avoid conflicting with the other
operations made on the shared background thread.

Bug: 262381044
Bug: 262518402
Bug: 233045200
Test: manual fold/unfolds with/without AOD enabled
Test: add artifical delay to SystemUI configChanged
 that exceeds WM keyguard drawn timeout
 => test that there is a flicker without changes
    test that there is no flicker with the changes
Test: atest com.android.keyguard.mediator.ScreenOnCoordinatorTest
Change-Id: Ic5a61839500dbbf63e9c5422bfc0085827526d92
parent 679ef9c1
Loading
Loading
Loading
Loading
+15 −22
Original line number Diff line number Diff line
@@ -16,31 +16,25 @@

package com.android.keyguard.mediator

import android.annotation.BinderThread
import android.os.Trace

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.ScreenLifecycle
import com.android.systemui.util.concurrency.Execution
import com.android.systemui.util.concurrency.PendingTasksContainer
import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.util.concurrency.PendingTasksContainer
import com.android.systemui.util.kotlin.getOrNull

import java.util.Optional

import javax.inject.Inject

/**
 * Coordinates screen on/turning on animations for the KeyguardViewMediator. Specifically for
 * screen on events, this will invoke the onDrawn Runnable after all tasks have completed. This
 * should route back to the KeyguardService, which informs the system_server that keyguard has
 * drawn.
 * should route back to the [com.android.systemui.keyguard.KeyguardService], which informs
 * the system_server that keyguard has drawn.
 */
@SysUISingleton
class ScreenOnCoordinator @Inject constructor(
    screenLifecycle: ScreenLifecycle,
    unfoldComponent: Optional<SysUIUnfoldComponent>,
    private val execution: Execution
) : ScreenLifecycle.Observer {
    unfoldComponent: Optional<SysUIUnfoldComponent>
) {

    private val unfoldLightRevealAnimation = unfoldComponent.map(
        SysUIUnfoldComponent::getUnfoldLightRevealOverlayAnimation).getOrNull()
@@ -48,15 +42,12 @@ class ScreenOnCoordinator @Inject constructor(
        SysUIUnfoldComponent::getFoldAodAnimationController).getOrNull()
    private val pendingTasks = PendingTasksContainer()

    init {
        screenLifecycle.addObserver(this)
    }

    /**
     * When turning on, registers tasks that may need to run before invoking [onDrawn].
     * This is called on a binder thread from [com.android.systemui.keyguard.KeyguardService].
     */
    override fun onScreenTurningOn(onDrawn: Runnable) {
        execution.assertIsMainThread()
    @BinderThread
    fun onScreenTurningOn(onDrawn: Runnable) {
        Trace.beginSection("ScreenOnCoordinator#onScreenTurningOn")

        pendingTasks.reset()
@@ -68,11 +59,13 @@ class ScreenOnCoordinator @Inject constructor(
        Trace.endSection()
    }

    override fun onScreenTurnedOn() {
        execution.assertIsMainThread()

    /**
     * Called when screen is fully turned on and screen on blocker is removed.
     * This is called on a binder thread from [com.android.systemui.keyguard.KeyguardService].
     */
    @BinderThread
    fun onScreenTurnedOn() {
        foldAodAnimationController?.onScreenTurnedOn()

        pendingTasks.reset()
    }
}
+1 −27
Original line number Diff line number Diff line
@@ -18,11 +18,8 @@ package com.android.systemui.keyguard;

import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;

import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.systemui.dagger.SysUISingleton;

import javax.inject.Inject;
@@ -80,33 +77,10 @@ public class KeyguardLifecyclesDispatcher {
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            final Object obj = msg.obj;
            switch (msg.what) {
                case SCREEN_TURNING_ON:
                    Trace.beginSection("KeyguardLifecyclesDispatcher#SCREEN_TURNING_ON");
                    final String onDrawWaitingTraceTag =
                            "Waiting for KeyguardDrawnCallback#onDrawn";
                    int traceCookie = System.identityHashCode(msg);
                    Trace.beginAsyncSection(onDrawWaitingTraceTag, traceCookie);
                    // Ensure the drawn callback is only ever called once
                    mScreenLifecycle.dispatchScreenTurningOn(new Runnable() {
                            boolean mInvoked;
                            @Override
                            public void run() {
                                if (obj == null) return;
                                if (!mInvoked) {
                                    mInvoked = true;
                                    try {
                                        Trace.endAsyncSection(onDrawWaitingTraceTag, traceCookie);
                                        ((IKeyguardDrawnCallback) obj).onDrawn();
                                    } catch (RemoteException e) {
                                        Log.w(TAG, "Exception calling onDrawn():", e);
                                    }
                                } else {
                                    Log.w(TAG, "KeyguardDrawnCallback#onDrawn() invoked > 1 times");
                                }
                            }
                        });
                    mScreenLifecycle.dispatchScreenTurningOn();
                    Trace.endSection();
                    break;
                case SCREEN_TURNED_ON:
+30 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
import com.android.internal.policy.IKeyguardStateCallback;
import com.android.keyguard.mediator.ScreenOnCoordinator;
import com.android.systemui.SystemUIApplication;
import com.android.wm.shell.transition.ShellTransitions;
import com.android.wm.shell.transition.Transitions;
@@ -120,6 +121,7 @@ public class KeyguardService extends Service {

    private final KeyguardViewMediator mKeyguardViewMediator;
    private final KeyguardLifecyclesDispatcher mKeyguardLifecyclesDispatcher;
    private final ScreenOnCoordinator mScreenOnCoordinator;
    private final ShellTransitions mShellTransitions;

    private static int newModeToLegacyMode(int newMode) {
@@ -283,10 +285,12 @@ public class KeyguardService extends Service {
    @Inject
    public KeyguardService(KeyguardViewMediator keyguardViewMediator,
                           KeyguardLifecyclesDispatcher keyguardLifecyclesDispatcher,
                           ScreenOnCoordinator screenOnCoordinator,
                           ShellTransitions shellTransitions) {
        super();
        mKeyguardViewMediator = keyguardViewMediator;
        mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
        mScreenOnCoordinator = screenOnCoordinator;
        mShellTransitions = shellTransitions;
    }

@@ -583,6 +587,31 @@ public class KeyguardService extends Service {
            checkPermission();
            mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNING_ON,
                    callback);

            final String onDrawWaitingTraceTag = "Waiting for KeyguardDrawnCallback#onDrawn";
            final int traceCookie = System.identityHashCode(callback);
            Trace.beginAsyncSection(onDrawWaitingTraceTag, traceCookie);

            // Ensure the drawn callback is only ever called once
            mScreenOnCoordinator.onScreenTurningOn(new Runnable() {
                boolean mInvoked;
                @Override
                public void run() {
                    if (callback == null) return;
                    if (!mInvoked) {
                        mInvoked = true;
                        try {
                            Trace.endAsyncSection(onDrawWaitingTraceTag, traceCookie);
                            callback.onDrawn();
                        } catch (RemoteException e) {
                            Log.w(TAG, "Exception calling onDrawn():", e);
                        }
                    } else {
                        Log.w(TAG, "KeyguardDrawnCallback#onDrawn() invoked > 1 times");
                    }
                }
            });

            Trace.endSection();
        }

@@ -591,6 +620,7 @@ public class KeyguardService extends Service {
            Trace.beginSection("KeyguardService.mBinder#onScreenTurnedOn");
            checkPermission();
            mKeyguardLifecyclesDispatcher.dispatch(KeyguardLifecyclesDispatcher.SCREEN_TURNED_ON);
            mScreenOnCoordinator.onScreenTurnedOn();
            Trace.endSection();
        }

+1 −1
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ class LifecycleScreenStatusProvider @Inject constructor(screenLifecycle: ScreenL
        listeners.forEach(ScreenListener::onScreenTurningOff)
    }

    override fun onScreenTurningOn(ignored: Runnable) {
    override fun onScreenTurningOn() {
        listeners.forEach(ScreenListener::onScreenTurningOn)
    }
}
+3 −15
Original line number Diff line number Diff line
@@ -18,8 +18,6 @@ package com.android.systemui.keyguard;

import android.os.Trace;

import androidx.annotation.NonNull;

import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;

@@ -50,14 +48,9 @@ public class ScreenLifecycle extends Lifecycle<ScreenLifecycle.Observer> impleme
        return mScreenState;
    }

    /**
     * Dispatch screen turning on events to the registered observers
     *
     * @param onDrawn Invoke to notify the caller that the event has been processed
     */
    public void dispatchScreenTurningOn(@NonNull Runnable onDrawn) {
    public void dispatchScreenTurningOn() {
        setScreenState(SCREEN_TURNING_ON);
        dispatch(Observer::onScreenTurningOn, onDrawn);
        dispatch(Observer::onScreenTurningOn);
    }

    public void dispatchScreenTurnedOn() {
@@ -87,12 +80,7 @@ public class ScreenLifecycle extends Lifecycle<ScreenLifecycle.Observer> impleme
    }

    public interface Observer {
        /**
         * Receive the screen turning on event
         *
         * @param onDrawn Invoke to notify the caller that the event has been processed
         */
        default void onScreenTurningOn(@NonNull Runnable onDrawn) {}
        default void onScreenTurningOn() {}
        default void onScreenTurnedOn() {}
        default void onScreenTurningOff() {}
        default void onScreenTurnedOff() {}
Loading