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

This commit is contained in:
Charles Chen
2023-02-20 06:22:57 +00:00
committed by Android (Google) Code Review
2 changed files with 138 additions and 9 deletions

View File

@@ -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();
// Override the default split Attributes so that it will be applied
// if the SplitContainer is not visible currently.
splitContainer.updateDefaultSplitAttributes(splitAttributes);
final TransactionRecord transactionRecord = mTransactionManager.startNewTransaction();
final WindowContainerTransaction wct = transactionRecord.getTransaction();
if (updateSplitContainerIfNeeded(splitContainer, wct, splitAttributes)) {
splitContainer.updateDefaultSplitAttributes(splitAttributes);
mTransactionManager.getCurrentTransactionRecord()
.apply(false /* shouldApplyIndependently */);
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) {

View File

@@ -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);