Loading libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +113 −6 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.Application; import android.app.Instrumentation; import android.app.servertransaction.ClientTransactionListenerController; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -103,6 +104,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.BiConsumer; /** * Main controller class that manages split states and presentation. Loading Loading @@ -178,6 +180,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private final List<ActivityStack> mLastReportedActivityStacks = new ArrayList<>(); /** WM Jetpack set callback for {@link EmbeddedActivityWindowInfo}. */ @GuardedBy("mLock") @Nullable private Pair<Executor, Consumer<EmbeddedActivityWindowInfo>> mEmbeddedActivityWindowInfoCallback; /** Listener registered to {@link ClientTransactionListenerController}. */ @GuardedBy("mLock") @Nullable private final BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener = Flags.activityWindowInfoFlag() ? this::onActivityWindowInfoChanged : null; private final Handler mHandler; final Object mLock = new Object(); private final ActivityStartMonitor mActivityStartMonitor; Loading Loading @@ -2455,6 +2471,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return ActivityThread.currentActivityThread().getActivity(activityToken); } @VisibleForTesting @Nullable ActivityThread.ActivityClientRecord getActivityClientRecord(@NonNull Activity activity) { return ActivityThread.currentActivityThread() .getActivityClient(activity.getActivityToken()); } @VisibleForTesting ActivityStartMonitor getActivityStartMonitor() { return mActivityStartMonitor; Loading @@ -2468,8 +2491,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @VisibleForTesting @Nullable IBinder getTaskFragmentTokenFromActivityClientRecord(@NonNull Activity activity) { final ActivityThread.ActivityClientRecord record = ActivityThread.currentActivityThread() .getActivityClient(activity.getActivityToken()); final ActivityThread.ActivityClientRecord record = getActivityClientRecord(activity); return record != null ? record.mTaskFragmentToken : null; } Loading Loading @@ -2876,17 +2898,102 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } } @Override public void setEmbeddedActivityWindowInfoCallback(@NonNull Executor executor, @NonNull Consumer<EmbeddedActivityWindowInfo> callback) { if (!Flags.activityWindowInfoFlag()) { return; } Objects.requireNonNull(executor); Objects.requireNonNull(callback); synchronized (mLock) { if (mEmbeddedActivityWindowInfoCallback == null) { ClientTransactionListenerController.getInstance() .registerActivityWindowInfoChangedListener(getActivityWindowInfoListener()); } mEmbeddedActivityWindowInfoCallback = new Pair<>(executor, callback); } } @Override public void clearEmbeddedActivityWindowInfoCallback() { if (!Flags.activityWindowInfoFlag()) { return; } synchronized (mLock) { if (mEmbeddedActivityWindowInfoCallback == null) { return; } mEmbeddedActivityWindowInfoCallback = null; ClientTransactionListenerController.getInstance() .unregisterActivityWindowInfoChangedListener(getActivityWindowInfoListener()); } } @VisibleForTesting @GuardedBy("mLock") @Nullable BiConsumer<IBinder, ActivityWindowInfo> getActivityWindowInfoListener() { return mActivityWindowInfoListener; } @Nullable private static ActivityWindowInfo getActivityWindowInfo(@NonNull Activity activity) { @Override public EmbeddedActivityWindowInfo getEmbeddedActivityWindowInfo(@NonNull Activity activity) { if (!Flags.activityWindowInfoFlag()) { return null; } synchronized (mLock) { final ActivityWindowInfo activityWindowInfo = getActivityWindowInfo(activity); return activityWindowInfo != null ? translateActivityWindowInfo(activity, activityWindowInfo) : null; } } @VisibleForTesting void onActivityWindowInfoChanged(@NonNull IBinder activityToken, @NonNull ActivityWindowInfo activityWindowInfo) { synchronized (mLock) { if (mEmbeddedActivityWindowInfoCallback == null) { return; } final Executor executor = mEmbeddedActivityWindowInfoCallback.first; final Consumer<EmbeddedActivityWindowInfo> callback = mEmbeddedActivityWindowInfoCallback.second; final Activity activity = getActivity(activityToken); if (activity == null) { return; } final EmbeddedActivityWindowInfo info = translateActivityWindowInfo( activity, activityWindowInfo); executor.execute(() -> callback.accept(info)); } } @Nullable private ActivityWindowInfo getActivityWindowInfo(@NonNull Activity activity) { if (activity.isFinishing()) { return null; } final ActivityThread.ActivityClientRecord record = ActivityThread.currentActivityThread() .getActivityClient(activity.getActivityToken()); final ActivityThread.ActivityClientRecord record = getActivityClientRecord(activity); return record != null ? record.getActivityWindowInfo() : null; } @NonNull private static EmbeddedActivityWindowInfo translateActivityWindowInfo( @NonNull Activity activity, @NonNull ActivityWindowInfo activityWindowInfo) { final boolean isEmbedded = activityWindowInfo.isEmbedded(); final Rect activityBounds = new Rect(activity.getResources().getConfiguration() .windowConfiguration.getBounds()); final Rect taskBounds = new Rect(activityWindowInfo.getTaskBounds()); final Rect activityStackBounds = new Rect(activityWindowInfo.getTaskFragmentBounds()); return new EmbeddedActivityWindowInfo(activity, isEmbedded, activityBounds, taskBounds, activityStackBounds); } /** * If the two rules have the same presentation, and the calculated {@link SplitAttributes} * matches the {@link SplitAttributes} of {@link SplitContainer}, we can reuse the same Loading libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +90 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,8 @@ import static org.mockito.Mockito.times; import android.annotation.NonNull; import android.app.Activity; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.servertransaction.ClientTransactionListenerController; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; Loading @@ -83,9 +85,11 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.util.ArraySet; import android.view.WindowInsets; import android.view.WindowMetrics; import android.window.ActivityWindowInfo; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOrganizer; import android.window.TaskFragmentParentInfo; Loading @@ -99,7 +103,10 @@ import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; import androidx.window.extensions.layout.WindowLayoutComponentImpl; import androidx.window.extensions.layout.WindowLayoutInfo; import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; Loading @@ -110,6 +117,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.BiConsumer; import java.util.function.Consumer; /** Loading @@ -127,6 +136,9 @@ public class SplitControllerTest { private static final Intent PLACEHOLDER_INTENT = new Intent().setComponent( new ComponentName("test", "placeholder")); @Rule public final SetFlagsRule mSetFlagRule = new SetFlagsRule(); private Activity mActivity; @Mock private Resources mActivityResources; Loading @@ -138,6 +150,13 @@ public class SplitControllerTest { private Handler mHandler; @Mock private WindowLayoutComponentImpl mWindowLayoutComponent; @Mock private ActivityWindowInfo mActivityWindowInfo; @Mock private BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener; @Mock private androidx.window.extensions.core.util.function.Consumer<EmbeddedActivityWindowInfo> mEmbeddedActivityWindowInfoCallback; private SplitController mSplitController; private SplitPresenter mSplitPresenter; Loading Loading @@ -1529,6 +1548,73 @@ public class SplitControllerTest { .getTopNonFinishingActivity(), secondaryActivity); } @Test public void testIsActivityEmbedded() { mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG); assertFalse(mSplitController.isActivityEmbedded(mActivity)); doReturn(true).when(mActivityWindowInfo).isEmbedded(); assertTrue(mSplitController.isActivityEmbedded(mActivity)); } @Test public void testGetEmbeddedActivityWindowInfo() { mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG); final boolean isEmbedded = true; final Rect activityBounds = mActivity.getResources().getConfiguration().windowConfiguration .getBounds(); final Rect taskBounds = new Rect(0, 0, 1000, 2000); final Rect activityStackBounds = new Rect(0, 0, 500, 2000); doReturn(isEmbedded).when(mActivityWindowInfo).isEmbedded(); doReturn(taskBounds).when(mActivityWindowInfo).getTaskBounds(); doReturn(activityStackBounds).when(mActivityWindowInfo).getTaskFragmentBounds(); final EmbeddedActivityWindowInfo expected = new EmbeddedActivityWindowInfo(mActivity, isEmbedded, activityBounds, taskBounds, activityStackBounds); assertEquals(expected, mSplitController.getEmbeddedActivityWindowInfo(mActivity)); } @Test public void testSetEmbeddedActivityWindowInfoCallback() { mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG); final ClientTransactionListenerController controller = ClientTransactionListenerController .getInstance(); spyOn(controller); doNothing().when(controller).registerActivityWindowInfoChangedListener(any()); doReturn(mActivityWindowInfoListener).when(mSplitController) .getActivityWindowInfoListener(); final Executor executor = Runnable::run; // Register to ClientTransactionListenerController mSplitController.setEmbeddedActivityWindowInfoCallback(executor, mEmbeddedActivityWindowInfoCallback); verify(controller).registerActivityWindowInfoChangedListener(mActivityWindowInfoListener); verify(mEmbeddedActivityWindowInfoCallback, never()).accept(any()); // Test onActivityWindowInfoChanged triggered. mSplitController.onActivityWindowInfoChanged(mActivity.getActivityToken(), mActivityWindowInfo); verify(mEmbeddedActivityWindowInfoCallback).accept(any()); // Unregister to ClientTransactionListenerController mSplitController.clearEmbeddedActivityWindowInfoCallback(); verify(controller).unregisterActivityWindowInfoChangedListener(mActivityWindowInfoListener); // Test onActivityWindowInfoChanged triggered as no-op after clear callback. clearInvocations(mEmbeddedActivityWindowInfoCallback); mSplitController.onActivityWindowInfoChanged(mActivity.getActivityToken(), mActivityWindowInfo); verify(mEmbeddedActivityWindowInfoCallback, never()).accept(any()); } /** Creates a mock activity in the organizer process. */ private Activity createMockActivity() { return createMockActivity(TASK_ID); Loading @@ -1537,13 +1623,17 @@ public class SplitControllerTest { /** Creates a mock activity in the organizer process. */ private Activity createMockActivity(int taskId) { final Activity activity = mock(Activity.class); final ActivityThread.ActivityClientRecord activityClientRecord = mock(ActivityThread.ActivityClientRecord.class); doReturn(mActivityResources).when(activity).getResources(); final IBinder activityToken = new Binder(); doReturn(activityToken).when(activity).getActivityToken(); doReturn(activity).when(mSplitController).getActivity(activityToken); doReturn(activityClientRecord).when(mSplitController).getActivityClientRecord(activity); doReturn(taskId).when(activity).getTaskId(); doReturn(new ActivityInfo()).when(activity).getActivityInfo(); doReturn(DEFAULT_DISPLAY).when(activity).getDisplayId(); doReturn(mActivityWindowInfo).when(activityClientRecord).getActivityWindowInfo(); return activity; } Loading Loading
libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +113 −6 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.Application; import android.app.Instrumentation; import android.app.servertransaction.ClientTransactionListenerController; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -103,6 +104,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.BiConsumer; /** * Main controller class that manages split states and presentation. Loading Loading @@ -178,6 +180,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen private final List<ActivityStack> mLastReportedActivityStacks = new ArrayList<>(); /** WM Jetpack set callback for {@link EmbeddedActivityWindowInfo}. */ @GuardedBy("mLock") @Nullable private Pair<Executor, Consumer<EmbeddedActivityWindowInfo>> mEmbeddedActivityWindowInfoCallback; /** Listener registered to {@link ClientTransactionListenerController}. */ @GuardedBy("mLock") @Nullable private final BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener = Flags.activityWindowInfoFlag() ? this::onActivityWindowInfoChanged : null; private final Handler mHandler; final Object mLock = new Object(); private final ActivityStartMonitor mActivityStartMonitor; Loading Loading @@ -2455,6 +2471,13 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return ActivityThread.currentActivityThread().getActivity(activityToken); } @VisibleForTesting @Nullable ActivityThread.ActivityClientRecord getActivityClientRecord(@NonNull Activity activity) { return ActivityThread.currentActivityThread() .getActivityClient(activity.getActivityToken()); } @VisibleForTesting ActivityStartMonitor getActivityStartMonitor() { return mActivityStartMonitor; Loading @@ -2468,8 +2491,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen @VisibleForTesting @Nullable IBinder getTaskFragmentTokenFromActivityClientRecord(@NonNull Activity activity) { final ActivityThread.ActivityClientRecord record = ActivityThread.currentActivityThread() .getActivityClient(activity.getActivityToken()); final ActivityThread.ActivityClientRecord record = getActivityClientRecord(activity); return record != null ? record.mTaskFragmentToken : null; } Loading Loading @@ -2876,17 +2898,102 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen } } @Override public void setEmbeddedActivityWindowInfoCallback(@NonNull Executor executor, @NonNull Consumer<EmbeddedActivityWindowInfo> callback) { if (!Flags.activityWindowInfoFlag()) { return; } Objects.requireNonNull(executor); Objects.requireNonNull(callback); synchronized (mLock) { if (mEmbeddedActivityWindowInfoCallback == null) { ClientTransactionListenerController.getInstance() .registerActivityWindowInfoChangedListener(getActivityWindowInfoListener()); } mEmbeddedActivityWindowInfoCallback = new Pair<>(executor, callback); } } @Override public void clearEmbeddedActivityWindowInfoCallback() { if (!Flags.activityWindowInfoFlag()) { return; } synchronized (mLock) { if (mEmbeddedActivityWindowInfoCallback == null) { return; } mEmbeddedActivityWindowInfoCallback = null; ClientTransactionListenerController.getInstance() .unregisterActivityWindowInfoChangedListener(getActivityWindowInfoListener()); } } @VisibleForTesting @GuardedBy("mLock") @Nullable BiConsumer<IBinder, ActivityWindowInfo> getActivityWindowInfoListener() { return mActivityWindowInfoListener; } @Nullable private static ActivityWindowInfo getActivityWindowInfo(@NonNull Activity activity) { @Override public EmbeddedActivityWindowInfo getEmbeddedActivityWindowInfo(@NonNull Activity activity) { if (!Flags.activityWindowInfoFlag()) { return null; } synchronized (mLock) { final ActivityWindowInfo activityWindowInfo = getActivityWindowInfo(activity); return activityWindowInfo != null ? translateActivityWindowInfo(activity, activityWindowInfo) : null; } } @VisibleForTesting void onActivityWindowInfoChanged(@NonNull IBinder activityToken, @NonNull ActivityWindowInfo activityWindowInfo) { synchronized (mLock) { if (mEmbeddedActivityWindowInfoCallback == null) { return; } final Executor executor = mEmbeddedActivityWindowInfoCallback.first; final Consumer<EmbeddedActivityWindowInfo> callback = mEmbeddedActivityWindowInfoCallback.second; final Activity activity = getActivity(activityToken); if (activity == null) { return; } final EmbeddedActivityWindowInfo info = translateActivityWindowInfo( activity, activityWindowInfo); executor.execute(() -> callback.accept(info)); } } @Nullable private ActivityWindowInfo getActivityWindowInfo(@NonNull Activity activity) { if (activity.isFinishing()) { return null; } final ActivityThread.ActivityClientRecord record = ActivityThread.currentActivityThread() .getActivityClient(activity.getActivityToken()); final ActivityThread.ActivityClientRecord record = getActivityClientRecord(activity); return record != null ? record.getActivityWindowInfo() : null; } @NonNull private static EmbeddedActivityWindowInfo translateActivityWindowInfo( @NonNull Activity activity, @NonNull ActivityWindowInfo activityWindowInfo) { final boolean isEmbedded = activityWindowInfo.isEmbedded(); final Rect activityBounds = new Rect(activity.getResources().getConfiguration() .windowConfiguration.getBounds()); final Rect taskBounds = new Rect(activityWindowInfo.getTaskBounds()); final Rect activityStackBounds = new Rect(activityWindowInfo.getTaskFragmentBounds()); return new EmbeddedActivityWindowInfo(activity, isEmbedded, activityBounds, taskBounds, activityStackBounds); } /** * If the two rules have the same presentation, and the calculated {@link SplitAttributes} * matches the {@link SplitAttributes} of {@link SplitContainer}, we can reuse the same Loading
libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java +90 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,8 @@ import static org.mockito.Mockito.times; import android.annotation.NonNull; import android.app.Activity; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.servertransaction.ClientTransactionListenerController; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; Loading @@ -83,9 +85,11 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.util.ArraySet; import android.view.WindowInsets; import android.view.WindowMetrics; import android.window.ActivityWindowInfo; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOrganizer; import android.window.TaskFragmentParentInfo; Loading @@ -99,7 +103,10 @@ import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; import androidx.window.extensions.layout.WindowLayoutComponentImpl; import androidx.window.extensions.layout.WindowLayoutInfo; import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; Loading @@ -110,6 +117,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.BiConsumer; import java.util.function.Consumer; /** Loading @@ -127,6 +136,9 @@ public class SplitControllerTest { private static final Intent PLACEHOLDER_INTENT = new Intent().setComponent( new ComponentName("test", "placeholder")); @Rule public final SetFlagsRule mSetFlagRule = new SetFlagsRule(); private Activity mActivity; @Mock private Resources mActivityResources; Loading @@ -138,6 +150,13 @@ public class SplitControllerTest { private Handler mHandler; @Mock private WindowLayoutComponentImpl mWindowLayoutComponent; @Mock private ActivityWindowInfo mActivityWindowInfo; @Mock private BiConsumer<IBinder, ActivityWindowInfo> mActivityWindowInfoListener; @Mock private androidx.window.extensions.core.util.function.Consumer<EmbeddedActivityWindowInfo> mEmbeddedActivityWindowInfoCallback; private SplitController mSplitController; private SplitPresenter mSplitPresenter; Loading Loading @@ -1529,6 +1548,73 @@ public class SplitControllerTest { .getTopNonFinishingActivity(), secondaryActivity); } @Test public void testIsActivityEmbedded() { mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG); assertFalse(mSplitController.isActivityEmbedded(mActivity)); doReturn(true).when(mActivityWindowInfo).isEmbedded(); assertTrue(mSplitController.isActivityEmbedded(mActivity)); } @Test public void testGetEmbeddedActivityWindowInfo() { mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG); final boolean isEmbedded = true; final Rect activityBounds = mActivity.getResources().getConfiguration().windowConfiguration .getBounds(); final Rect taskBounds = new Rect(0, 0, 1000, 2000); final Rect activityStackBounds = new Rect(0, 0, 500, 2000); doReturn(isEmbedded).when(mActivityWindowInfo).isEmbedded(); doReturn(taskBounds).when(mActivityWindowInfo).getTaskBounds(); doReturn(activityStackBounds).when(mActivityWindowInfo).getTaskFragmentBounds(); final EmbeddedActivityWindowInfo expected = new EmbeddedActivityWindowInfo(mActivity, isEmbedded, activityBounds, taskBounds, activityStackBounds); assertEquals(expected, mSplitController.getEmbeddedActivityWindowInfo(mActivity)); } @Test public void testSetEmbeddedActivityWindowInfoCallback() { mSetFlagRule.enableFlags(Flags.FLAG_ACTIVITY_WINDOW_INFO_FLAG); final ClientTransactionListenerController controller = ClientTransactionListenerController .getInstance(); spyOn(controller); doNothing().when(controller).registerActivityWindowInfoChangedListener(any()); doReturn(mActivityWindowInfoListener).when(mSplitController) .getActivityWindowInfoListener(); final Executor executor = Runnable::run; // Register to ClientTransactionListenerController mSplitController.setEmbeddedActivityWindowInfoCallback(executor, mEmbeddedActivityWindowInfoCallback); verify(controller).registerActivityWindowInfoChangedListener(mActivityWindowInfoListener); verify(mEmbeddedActivityWindowInfoCallback, never()).accept(any()); // Test onActivityWindowInfoChanged triggered. mSplitController.onActivityWindowInfoChanged(mActivity.getActivityToken(), mActivityWindowInfo); verify(mEmbeddedActivityWindowInfoCallback).accept(any()); // Unregister to ClientTransactionListenerController mSplitController.clearEmbeddedActivityWindowInfoCallback(); verify(controller).unregisterActivityWindowInfoChangedListener(mActivityWindowInfoListener); // Test onActivityWindowInfoChanged triggered as no-op after clear callback. clearInvocations(mEmbeddedActivityWindowInfoCallback); mSplitController.onActivityWindowInfoChanged(mActivity.getActivityToken(), mActivityWindowInfo); verify(mEmbeddedActivityWindowInfoCallback, never()).accept(any()); } /** Creates a mock activity in the organizer process. */ private Activity createMockActivity() { return createMockActivity(TASK_ID); Loading @@ -1537,13 +1623,17 @@ public class SplitControllerTest { /** Creates a mock activity in the organizer process. */ private Activity createMockActivity(int taskId) { final Activity activity = mock(Activity.class); final ActivityThread.ActivityClientRecord activityClientRecord = mock(ActivityThread.ActivityClientRecord.class); doReturn(mActivityResources).when(activity).getResources(); final IBinder activityToken = new Binder(); doReturn(activityToken).when(activity).getActivityToken(); doReturn(activity).when(mSplitController).getActivity(activityToken); doReturn(activityClientRecord).when(mSplitController).getActivityClientRecord(activity); doReturn(taskId).when(activity).getTaskId(); doReturn(new ActivityInfo()).when(activity).getActivityInfo(); doReturn(DEFAULT_DISPLAY).when(activity).getDisplayId(); doReturn(mActivityWindowInfo).when(activityClientRecord).getActivityWindowInfo(); return activity; } Loading