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

Commit 33285cfb authored by Wale Ogunwale's avatar Wale Ogunwale Committed by Android (Google) Code Review
Browse files

Merge "Consume pending display config change with multiple remote callbacks" into udc-qpr-dev

parents 64d58195 c793afe3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1162,7 +1162,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
        mDisplaySwitchTransitionLauncher = new PhysicalDisplaySwitchTransitionLauncher(this,
                mTransitionController);
        mRemoteDisplayChangeController = new RemoteDisplayChangeController(mWmService, mDisplayId);
        mRemoteDisplayChangeController = new RemoteDisplayChangeController(this);

        final InputChannel inputChannel = mWmService.mInputManager.monitorInput(
                "PointerEventDispatcher" + mDisplayId, mDisplayId);
+27 −8
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.view.IDisplayChangeWindowCallback;
import android.window.DisplayAreaInfo;
import android.window.WindowContainerTransaction;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;

import java.util.ArrayList;
@@ -44,16 +45,16 @@ public class RemoteDisplayChangeController {
    private static final int REMOTE_DISPLAY_CHANGE_TIMEOUT_MS = 800;

    private final WindowManagerService mService;
    private final int mDisplayId;
    private final DisplayContent mDisplayContent;

    private final Runnable mTimeoutRunnable = this::onContinueTimedOut;

    // all remote changes that haven't finished yet.
    private final List<ContinueRemoteDisplayChangeCallback> mCallbacks = new ArrayList<>();

    public RemoteDisplayChangeController(WindowManagerService service, int displayId) {
        mService = service;
        mDisplayId = displayId;
    RemoteDisplayChangeController(@NonNull DisplayContent displayContent) {
        mService = displayContent.mWmService;
        mDisplayContent = displayContent;
    }

    /**
@@ -99,8 +100,8 @@ public class RemoteDisplayChangeController {
        try {
            mService.mH.removeCallbacks(mTimeoutRunnable);
            mService.mH.postDelayed(mTimeoutRunnable, REMOTE_DISPLAY_CHANGE_TIMEOUT_MS);
            mService.mDisplayChangeController.onDisplayChange(mDisplayId, fromRotation, toRotation,
                    newDisplayAreaInfo, remoteCallback);
            mService.mDisplayChangeController.onDisplayChange(mDisplayContent.mDisplayId,
                    fromRotation, toRotation, newDisplayAreaInfo, remoteCallback);
            return true;
        } catch (RemoteException e) {
            Slog.e(TAG, "Exception while dispatching remote display-change", e);
@@ -117,10 +118,23 @@ public class RemoteDisplayChangeController {
                mCallbacks.get(i).onContinueRemoteDisplayChange(null /* transaction */);
            }
            mCallbacks.clear();
            onCompleted();
        }
    }

    private void continueDisplayChange(@NonNull ContinueRemoteDisplayChangeCallback callback,
    /** Called when all remote callbacks are done. */
    private void onCompleted() {
        // Because DisplayContent#sendNewConfiguration() will be skipped if there are pending remote
        // changes, check again when all remote callbacks are done. E.g. callback X is done but
        // there is a pending callback Y so its invocation is skipped, and when the callback Y is
        // done, it doesn't call sendNewConfiguration().
        if (mDisplayContent.mWaitingForConfig) {
            mDisplayContent.sendNewConfiguration();
        }
    }

    @VisibleForTesting
    void continueDisplayChange(@NonNull ContinueRemoteDisplayChangeCallback callback,
            @Nullable WindowContainerTransaction transaction) {
        synchronized (mService.mGlobalLock) {
            int idx = mCallbacks.indexOf(callback);
@@ -133,11 +147,16 @@ public class RemoteDisplayChangeController {
                // ordering by continuing everything up until this one with empty transactions.
                mCallbacks.get(i).onContinueRemoteDisplayChange(null /* transaction */);
            }
            // The "toIndex" is exclusive, so it needs +1 to clear the current calling callback.
            mCallbacks.subList(0, idx + 1).clear();
            if (mCallbacks.isEmpty()) {
            final boolean completed = mCallbacks.isEmpty();
            if (completed) {
                mService.mH.removeCallbacks(mTimeoutRunnable);
            }
            callback.onContinueRemoteDisplayChange(transaction);
            if (completed) {
                onCompleted();
            }
        }
    }

+48 −0
Original line number Diff line number Diff line
@@ -144,6 +144,7 @@ import android.window.DisplayAreaInfo;
import android.window.IDisplayAreaOrganizer;
import android.window.ScreenCapture;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

import androidx.test.filters.SmallTest;

@@ -2012,6 +2013,53 @@ public class DisplayContentTests extends WindowTestsBase {
        assertFalse(mWm.mDisplayFrozen);
    }

    @Test
    public void testRemoteDisplayChange() {
        mWm.mDisplayChangeController = mock(IDisplayChangeWindowController.class);
        final Boolean[] isWaitingForRemote = new Boolean[2];
        final var callbacks = new RemoteDisplayChangeController.ContinueRemoteDisplayChangeCallback[
                isWaitingForRemote.length];
        for (int i = 0; i < isWaitingForRemote.length; i++) {
            final int index = i;
            var callback = new RemoteDisplayChangeController.ContinueRemoteDisplayChangeCallback() {
                @Override
                public void onContinueRemoteDisplayChange(WindowContainerTransaction transaction) {
                    isWaitingForRemote[index] =
                            mDisplayContent.mRemoteDisplayChangeController
                                    .isWaitingForRemoteDisplayChange();
                }
            };
            mDisplayContent.mRemoteDisplayChangeController.performRemoteDisplayChange(
                    ROTATION_0, ROTATION_0, null /* newDisplayAreaInfo */, callback);
            callbacks[i] = callback;
        }

        // The last callback is completed, all callbacks should be notified.
        mDisplayContent.mRemoteDisplayChangeController.continueDisplayChange(callbacks[1],
                null /* transaction */);
        // When notifying 0, the callback 1 still exists.
        assertTrue(isWaitingForRemote[0]);
        assertFalse(isWaitingForRemote[1]);

        // The first callback is completed, other callbacks after it should remain.
        for (int i = 0; i < isWaitingForRemote.length; i++) {
            isWaitingForRemote[i] = null;
            mDisplayContent.mRemoteDisplayChangeController.performRemoteDisplayChange(
                    ROTATION_0, ROTATION_0, null /* newDisplayAreaInfo */, callbacks[i]);
        }
        mDisplayContent.mRemoteDisplayChangeController.continueDisplayChange(callbacks[0],
                null /* transaction */);
        assertTrue(isWaitingForRemote[0]);
        assertNull(isWaitingForRemote[1]);

        // Complete the last callback. It should be able to consume pending config change.
        mDisplayContent.mWaitingForConfig = true;
        mDisplayContent.mRemoteDisplayChangeController.continueDisplayChange(callbacks[1],
                null /* transaction */);
        assertFalse(isWaitingForRemote[1]);
        assertFalse(mDisplayContent.mWaitingForConfig);
    }

    @Test
    public void testShellTransitRotation() {
        DisplayContent dc = createNewDisplay();