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

Commit f3710c72 authored by Charles Chen's avatar Charles Chen Committed by Android (Google) Code Review
Browse files

Merge "Add unit tests for SplitAttributes runtime APIs" into udc-dev

parents ad325995 22db2a30
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);