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

Commit 22db2a30 authored by Charles Chen's avatar Charles Chen
Browse files

Add unit tests for SplitAttributes runtime APIs

Test: atest WMJetpackUnitTests
Bug: 236764532

Change-Id: If46bf1ca9e1db7848655dd3d26a88b64660f2874
parent 29073686
Loading
Loading
Loading
Loading
+15 −9
Original line number Diff line number Diff line
@@ -308,7 +308,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
                synchronized (mLock) {
                    final List<TaskFragmentContainer> containers = taskContainer.mContainers;
                    // Clean up the TaskFragmentContainers by the z-order from the lowest.
                    for (int i = 0; i < containers.size() - 1; i++) {
                    for (int i = 0; i < containers.size(); i++) {
                        final TaskFragmentContainer container = containers.get(i);
                        if (pendingFinishingContainers.contains(container)) {
                            // Don't update records here to prevent double invocation.
@@ -318,7 +318,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
                    }
                    // Remove container records.
                    removeContainers(taskContainer, pendingFinishingContainers);
                    // Update the change to the client side.
                    // Update the change to the server side.
                    updateContainersInTaskIfVisible(wct, taskContainer.getTaskId());
                }
            });
@@ -353,21 +353,25 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
    @Override
    public void updateSplitAttributes(@NonNull IBinder splitInfoToken,
            @NonNull SplitAttributes splitAttributes) {
        Objects.requireNonNull(splitInfoToken);
        Objects.requireNonNull(splitAttributes);
        synchronized (mLock) {
            final SplitContainer splitContainer = getSplitContainer(splitInfoToken);
            if (splitContainer == null) {
                Log.w(TAG, "Cannot find SplitContainer for token:" + splitInfoToken);
                return;
            }
            WindowContainerTransaction wct = mTransactionManager.startNewTransaction()
                    .getTransaction();
            if (updateSplitContainerIfNeeded(splitContainer, wct, splitAttributes)) {
            // Override the default split Attributes so that it will be applied
            // if the SplitContainer is not visible currently.
            splitContainer.updateDefaultSplitAttributes(splitAttributes);
                mTransactionManager.getCurrentTransactionRecord()
                        .apply(false /* shouldApplyIndependently */);

            final TransactionRecord transactionRecord = mTransactionManager.startNewTransaction();
            final WindowContainerTransaction wct = transactionRecord.getTransaction();
            if (updateSplitContainerIfNeeded(splitContainer, wct, splitAttributes)) {
                transactionRecord.apply(false /* shouldApplyIndependently */);
            } else {
                // Abort if the SplitContainer wasn't updated.
                mTransactionManager.getCurrentTransactionRecord().abort();
                transactionRecord.abort();
            }
        }
    }
@@ -1559,8 +1563,9 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
     *
     * @return {@code true} if the update succeed. Otherwise, returns {@code false}.
     */
    @VisibleForTesting
    @GuardedBy("mLock")
    private boolean updateSplitContainerIfNeeded(@NonNull SplitContainer splitContainer,
    boolean updateSplitContainerIfNeeded(@NonNull SplitContainer splitContainer,
            @NonNull WindowContainerTransaction wct, @Nullable SplitAttributes splitAttributes) {
        if (!isTopMostSplit(splitContainer)) {
            // Skip position update - it isn't the topmost split.
@@ -1904,6 +1909,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
        return null;
    }

    @VisibleForTesting
    @Nullable
    @GuardedBy("mLock")
    SplitContainer getSplitContainer(@NonNull IBinder token) {
+123 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;

import android.annotation.NonNull;
import android.app.Activity;
@@ -82,6 +83,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.util.ArraySet;
import android.view.WindowInsets;
import android.view.WindowMetrics;
import android.window.TaskFragmentInfo;
@@ -100,12 +102,14 @@ import androidx.window.extensions.layout.WindowLayoutInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;

/**
@@ -1323,6 +1327,125 @@ public class SplitControllerTest {
        verify(mTransaction).startActivityInTaskFragment(any(), any(), any(), any());
    }

    @Test
    public void testFinishActivityStacks_emptySet_earlyReturn() {
        mSplitController.finishActivityStacks(Collections.emptySet());

        verify(mSplitController, never()).updateContainersInTaskIfVisible(any(), anyInt());
    }

    @Test
    public void testFinishActivityStacks_invalidStacks_earlyReturn() {
        mSplitController.finishActivityStacks(Collections.singleton(new Binder()));

        verify(mSplitController, never()).updateContainersInTaskIfVisible(any(), anyInt());
    }

    @Test
    public void testFinishActivityStacks_finishSingleActivityStack() {
        TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID);
        tf.setInfo(mTransaction, createMockTaskFragmentInfo(tf, mActivity));

        List<TaskFragmentContainer> containers = mSplitController.mTaskContainers.get(TASK_ID)
                .mContainers;

        assertEquals(containers.get(0), tf);

        mSplitController.finishActivityStacks(Collections.singleton(tf.getTaskFragmentToken()));

        verify(mSplitPresenter).deleteTaskFragment(any(), eq(tf.getTaskFragmentToken()));
        assertTrue(containers.isEmpty());
    }

    @Test
    public void testFinishActivityStacks_finishActivityStacksInOrder() {
        TaskFragmentContainer bottomTf = mSplitController.newContainer(mActivity, TASK_ID);
        TaskFragmentContainer topTf = mSplitController.newContainer(mActivity, TASK_ID);
        bottomTf.setInfo(mTransaction, createMockTaskFragmentInfo(bottomTf, mActivity));
        topTf.setInfo(mTransaction, createMockTaskFragmentInfo(topTf, createMockActivity()));

        List<TaskFragmentContainer> containers = mSplitController.mTaskContainers.get(TASK_ID)
                .mContainers;

        assertEquals(containers.size(), 2);

        Set<IBinder> activityStackTokens = new ArraySet<>(new IBinder[]{
                topTf.getTaskFragmentToken(), bottomTf.getTaskFragmentToken()});

        mSplitController.finishActivityStacks(activityStackTokens);

        ArgumentCaptor<IBinder> argumentCaptor = ArgumentCaptor.forClass(IBinder.class);

        verify(mSplitPresenter, times(2)).deleteTaskFragment(any(), argumentCaptor.capture());

        List<IBinder> fragmentTokens = argumentCaptor.getAllValues();
        assertEquals("The ActivityStack must be deleted from the lowest z-order "
                + "regardless of the order in ActivityStack set",
                bottomTf.getTaskFragmentToken(), fragmentTokens.get(0));
        assertEquals("The ActivityStack must be deleted from the lowest z-order "
                        + "regardless of the order in ActivityStack set",
                topTf.getTaskFragmentToken(), fragmentTokens.get(1));

        assertTrue(containers.isEmpty());
    }

    @Test
    public void testUpdateSplitAttributes_invalidSplitContainerToken_earlyReturn() {
        mSplitController.updateSplitAttributes(new Binder(), SPLIT_ATTRIBUTES);

        verify(mTransactionManager, never()).startNewTransaction();
    }

    @Test
    public void testUpdateSplitAttributes_nullParams_throwException() {
        assertThrows(NullPointerException.class,
                () -> mSplitController.updateSplitAttributes(null, SPLIT_ATTRIBUTES));

        final SplitContainer splitContainer = mock(SplitContainer.class);
        final IBinder token = new Binder();
        doReturn(token).when(splitContainer).getToken();
        doReturn(splitContainer).when(mSplitController).getSplitContainer(eq(token));

        assertThrows(NullPointerException.class,
                () -> mSplitController.updateSplitAttributes(token, null));
    }

    @Test
    public void testUpdateSplitAttributes_doNotNeedToUpdateSplitContainer_doNotApplyTransaction() {
        final SplitContainer splitContainer = mock(SplitContainer.class);
        final IBinder token = new Binder();
        doReturn(token).when(splitContainer).getToken();
        doReturn(splitContainer).when(mSplitController).getSplitContainer(eq(token));
        doReturn(false).when(mSplitController).updateSplitContainerIfNeeded(
                eq(splitContainer), any(), eq(SPLIT_ATTRIBUTES));
        TransactionManager.TransactionRecord testRecord =
                mock(TransactionManager.TransactionRecord.class);
        doReturn(testRecord).when(mTransactionManager).startNewTransaction();

        mSplitController.updateSplitAttributes(token, SPLIT_ATTRIBUTES);

        verify(splitContainer).updateDefaultSplitAttributes(eq(SPLIT_ATTRIBUTES));
        verify(testRecord).abort();
    }

    @Test
    public void testUpdateSplitAttributes_splitContainerUpdated_updateAttrs() {
        final SplitContainer splitContainer = mock(SplitContainer.class);
        final IBinder token = new Binder();
        doReturn(token).when(splitContainer).getToken();
        doReturn(splitContainer).when(mSplitController).getSplitContainer(eq(token));
        doReturn(true).when(mSplitController).updateSplitContainerIfNeeded(
                eq(splitContainer), any(), eq(SPLIT_ATTRIBUTES));
        TransactionManager.TransactionRecord testRecord =
                mock(TransactionManager.TransactionRecord.class);
        doReturn(testRecord).when(mTransactionManager).startNewTransaction();

        mSplitController.updateSplitAttributes(token, SPLIT_ATTRIBUTES);

        verify(splitContainer).updateDefaultSplitAttributes(eq(SPLIT_ATTRIBUTES));
        verify(testRecord).apply(eq(false));
    }

    /** Creates a mock activity in the organizer process. */
    private Activity createMockActivity() {
        return createMockActivity(TASK_ID);