Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +15 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.content.Context; import android.os.Handler; import com.android.internal.jank.InteractionJankMonitor; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; Loading @@ -45,6 +46,7 @@ import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler; import com.android.wm.shell.pip2.phone.PhonePipMenuController; import com.android.wm.shell.pip2.phone.PipController; import com.android.wm.shell.pip2.phone.PipInteractionHandler; import com.android.wm.shell.pip2.phone.PipMotionHelper; import com.android.wm.shell.pip2.phone.PipScheduler; import com.android.wm.shell.pip2.phone.PipTaskListener; Loading Loading @@ -88,12 +90,13 @@ public abstract class Pip2Module { @NonNull PipUiStateChangeController pipUiStateChangeController, DisplayController displayController, Optional<SplitScreenController> splitScreenControllerOptional, PipDesktopState pipDesktopState) { PipDesktopState pipDesktopState, PipInteractionHandler pipInteractionHandler) { return new PipTransition(context, shellInit, shellTaskOrganizer, transitions, pipBoundsState, null, pipBoundsAlgorithm, pipTaskListener, pipScheduler, pipStackListenerController, pipDisplayLayoutState, pipUiStateChangeController, displayController, splitScreenControllerOptional, pipDesktopState); pipDesktopState, pipInteractionHandler); } @WMSingleton Loading Loading @@ -249,4 +252,14 @@ public abstract class Pip2Module { @BindsOptionalOf abstract DragToDesktopTransitionHandler optionalDragToDesktopTransitionHandler(); @WMSingleton @Provides static PipInteractionHandler providePipInteractionHandler( Context context, @ShellMainThread Handler mainHandler ) { return new PipInteractionHandler(context, mainHandler, InteractionJankMonitor.getInstance()); } } libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInteractionHandler.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.pip2.phone; import static com.android.internal.jank.Cuj.CUJ_PIP_TRANSITION; import android.annotation.IntDef; import android.content.Context; import android.os.Handler; import android.view.SurfaceControl; import com.android.internal.jank.InteractionJankMonitor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Helps track PIP CUJ interactions */ public class PipInteractionHandler { @IntDef(prefix = {"INTERACTION_"}, value = { INTERACTION_EXIT_PIP, INTERACTION_EXIT_PIP_TO_SPLIT }) @Retention(RetentionPolicy.SOURCE) public @interface Interaction {} public static final int INTERACTION_EXIT_PIP = 0; public static final int INTERACTION_EXIT_PIP_TO_SPLIT = 1; private final Context mContext; private final Handler mHandler; private final InteractionJankMonitor mInteractionJankMonitor; public PipInteractionHandler(Context context, Handler handler, InteractionJankMonitor interactionJankMonitor) { mContext = context; mHandler = handler; mInteractionJankMonitor = interactionJankMonitor; } /** * Begin tracking PIP CUJ. * * @param leash PIP leash. * @param interaction Tag for interaction. */ public void begin(SurfaceControl leash, @Interaction int interaction) { mInteractionJankMonitor.begin(leash, mContext, mHandler, CUJ_PIP_TRANSITION, pipInteractionToString(interaction)); } /** * End tracking CUJ. */ public void end() { mInteractionJankMonitor.end(CUJ_PIP_TRANSITION); } /** * Converts an interaction to a string representation used for tagging. * * @param interaction Interaction to track. * @return String representation of the interaction. */ public static String pipInteractionToString(@Interaction int interaction) { return switch (interaction) { case INTERACTION_EXIT_PIP -> "EXIT_PIP"; case INTERACTION_EXIT_PIP_TO_SPLIT -> "EXIT_PIP_TO_SPLIT"; default -> ""; }; } } libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +6 −2 Original line number Diff line number Diff line Loading @@ -113,6 +113,7 @@ public class PipTransition extends PipTransitionController implements private final DisplayController mDisplayController; private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper; private final PipDesktopState mPipDesktopState; private final PipInteractionHandler mPipInteractionHandler; // // Transition caches Loading Loading @@ -154,7 +155,8 @@ public class PipTransition extends PipTransitionController implements PipUiStateChangeController pipUiStateChangeController, DisplayController displayController, Optional<SplitScreenController> splitScreenControllerOptional, PipDesktopState pipDesktopState) { PipDesktopState pipDesktopState, PipInteractionHandler pipInteractionHandler) { super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController, pipBoundsAlgorithm); Loading @@ -168,9 +170,11 @@ public class PipTransition extends PipTransitionController implements mDisplayController = displayController; mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(mContext); mPipDesktopState = pipDesktopState; mPipInteractionHandler = pipInteractionHandler; mExpandHandler = new PipExpandHandler(mContext, pipBoundsState, pipBoundsAlgorithm, pipTransitionState, pipDisplayLayoutState, splitScreenControllerOptional); pipTransitionState, pipDisplayLayoutState, pipInteractionHandler, splitScreenControllerOptional); } @Override Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandler.java +10 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.pip2.animation.PipExpandAnimator; import com.android.wm.shell.pip2.phone.PipInteractionHandler; import com.android.wm.shell.pip2.phone.PipTransitionState; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; Loading @@ -58,6 +59,7 @@ public class PipExpandHandler implements Transitions.TransitionHandler { private final PipBoundsAlgorithm mPipBoundsAlgorithm; private final PipTransitionState mPipTransitionState; private final PipDisplayLayoutState mPipDisplayLayoutState; private final PipInteractionHandler mPipInteractionHandler; private final Optional<SplitScreenController> mSplitScreenControllerOptional; @Nullable Loading @@ -72,12 +74,14 @@ public class PipExpandHandler implements Transitions.TransitionHandler { PipBoundsAlgorithm pipBoundsAlgorithm, PipTransitionState pipTransitionState, PipDisplayLayoutState pipDisplayLayoutState, PipInteractionHandler pipInteractionHandler, Optional<SplitScreenController> splitScreenControllerOptional) { mContext = context; mPipBoundsState = pipBoundsState; mPipBoundsAlgorithm = pipBoundsAlgorithm; mPipTransitionState = pipTransitionState; mPipDisplayLayoutState = pipDisplayLayoutState; mPipInteractionHandler = pipInteractionHandler; mSplitScreenControllerOptional = splitScreenControllerOptional; mPipExpandAnimatorSupplier = PipExpandAnimator::new; Loading Loading @@ -183,6 +187,8 @@ public class PipExpandHandler implements Transitions.TransitionHandler { PipExpandAnimator animator = mPipExpandAnimatorSupplier.get(mContext, pipLeash, startTransaction, finishTransaction, endBounds, startBounds, endBounds, sourceRectHint, delta); animator.setAnimationStartCallback(() -> mPipInteractionHandler.begin(pipLeash, PipInteractionHandler.INTERACTION_EXIT_PIP)); animator.setAnimationEndCallback(() -> { if (parentBeforePip != null) { // TODO b/377362511: Animate local leash instead to also handle letterbox case. Loading @@ -190,6 +196,7 @@ public class PipExpandHandler implements Transitions.TransitionHandler { finishTransaction.setCrop(pipLeash, null); } finishTransition(); mPipInteractionHandler.end(); }); cacheAndStartTransitionAnimator(animator); saveReentryState(); Loading Loading @@ -248,6 +255,8 @@ public class PipExpandHandler implements Transitions.TransitionHandler { splitController.finishEnterSplitScreen(finishTransaction); }); animator.setAnimationStartCallback(() -> mPipInteractionHandler.begin(pipLeash, PipInteractionHandler.INTERACTION_EXIT_PIP_TO_SPLIT)); animator.setAnimationEndCallback(() -> { if (parentBeforePip == null) { // After PipExpandAnimator is done modifying finishTransaction, we need to make Loading @@ -256,6 +265,7 @@ public class PipExpandHandler implements Transitions.TransitionHandler { finishTransaction.setPosition(pipLeash, 0, 0); } finishTransition(); mPipInteractionHandler.end(); }); cacheAndStartTransitionAnimator(animator); saveReentryState(); Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipInteractionHandlerTest.java 0 → 100644 +95 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.pip2.phone; import static com.android.internal.jank.Cuj.CUJ_PIP_TRANSITION; import static com.android.wm.shell.pip2.phone.PipInteractionHandler.INTERACTION_EXIT_PIP; import static com.android.wm.shell.pip2.phone.PipInteractionHandler.INTERACTION_EXIT_PIP_TO_SPLIT; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.kotlin.VerificationKt.times; import android.content.Context; import android.os.Handler; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.SurfaceControl; import androidx.test.filters.SmallTest; import com.android.internal.jank.InteractionJankMonitor; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** * Unit test against {@link PipInteractionHandler}. */ @SmallTest @TestableLooper.RunWithLooper @RunWith(AndroidTestingRunner.class) public class PipInteractionHandlerTest { @Mock private Context mMockContext; @Mock private Handler mMockHandler; @Mock private InteractionJankMonitor mMockInteractionJankMonitor; private SurfaceControl mTestLeash; private PipInteractionHandler mPipInteractionHandler; @Before public void setUp() { MockitoAnnotations.initMocks(this); mPipInteractionHandler = new PipInteractionHandler(mMockContext, mMockHandler, mMockInteractionJankMonitor); mTestLeash = new SurfaceControl.Builder() .setContainerLayer() .setName("PipInteractionHandlerTest") .setCallsite("PipInteractionHandlerTest") .build(); } @Test public void begin_expand_startsTracking() { mPipInteractionHandler.begin(mTestLeash, INTERACTION_EXIT_PIP); verify(mMockInteractionJankMonitor, times(1)).begin(eq(mTestLeash), eq(mMockContext), eq(mMockHandler), eq(CUJ_PIP_TRANSITION), eq(PipInteractionHandler.pipInteractionToString(INTERACTION_EXIT_PIP))); } @Test public void begin_expandToSplit_startsTracking() { mPipInteractionHandler.begin(mTestLeash, INTERACTION_EXIT_PIP_TO_SPLIT); verify(mMockInteractionJankMonitor, times(1)).begin(eq(mTestLeash), eq(mMockContext), eq(mMockHandler), eq(CUJ_PIP_TRANSITION), eq(PipInteractionHandler.pipInteractionToString(INTERACTION_EXIT_PIP_TO_SPLIT))); } @Test public void end_stopsTracking() { mPipInteractionHandler.end(); verify(mMockInteractionJankMonitor, times(1)).end(CUJ_PIP_TRANSITION); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +15 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.content.Context; import android.os.Handler; import com.android.internal.jank.InteractionJankMonitor; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; Loading @@ -45,6 +46,7 @@ import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler; import com.android.wm.shell.pip2.phone.PhonePipMenuController; import com.android.wm.shell.pip2.phone.PipController; import com.android.wm.shell.pip2.phone.PipInteractionHandler; import com.android.wm.shell.pip2.phone.PipMotionHelper; import com.android.wm.shell.pip2.phone.PipScheduler; import com.android.wm.shell.pip2.phone.PipTaskListener; Loading Loading @@ -88,12 +90,13 @@ public abstract class Pip2Module { @NonNull PipUiStateChangeController pipUiStateChangeController, DisplayController displayController, Optional<SplitScreenController> splitScreenControllerOptional, PipDesktopState pipDesktopState) { PipDesktopState pipDesktopState, PipInteractionHandler pipInteractionHandler) { return new PipTransition(context, shellInit, shellTaskOrganizer, transitions, pipBoundsState, null, pipBoundsAlgorithm, pipTaskListener, pipScheduler, pipStackListenerController, pipDisplayLayoutState, pipUiStateChangeController, displayController, splitScreenControllerOptional, pipDesktopState); pipDesktopState, pipInteractionHandler); } @WMSingleton Loading Loading @@ -249,4 +252,14 @@ public abstract class Pip2Module { @BindsOptionalOf abstract DragToDesktopTransitionHandler optionalDragToDesktopTransitionHandler(); @WMSingleton @Provides static PipInteractionHandler providePipInteractionHandler( Context context, @ShellMainThread Handler mainHandler ) { return new PipInteractionHandler(context, mainHandler, InteractionJankMonitor.getInstance()); } }
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInteractionHandler.java 0 → 100644 +88 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.pip2.phone; import static com.android.internal.jank.Cuj.CUJ_PIP_TRANSITION; import android.annotation.IntDef; import android.content.Context; import android.os.Handler; import android.view.SurfaceControl; import com.android.internal.jank.InteractionJankMonitor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Helps track PIP CUJ interactions */ public class PipInteractionHandler { @IntDef(prefix = {"INTERACTION_"}, value = { INTERACTION_EXIT_PIP, INTERACTION_EXIT_PIP_TO_SPLIT }) @Retention(RetentionPolicy.SOURCE) public @interface Interaction {} public static final int INTERACTION_EXIT_PIP = 0; public static final int INTERACTION_EXIT_PIP_TO_SPLIT = 1; private final Context mContext; private final Handler mHandler; private final InteractionJankMonitor mInteractionJankMonitor; public PipInteractionHandler(Context context, Handler handler, InteractionJankMonitor interactionJankMonitor) { mContext = context; mHandler = handler; mInteractionJankMonitor = interactionJankMonitor; } /** * Begin tracking PIP CUJ. * * @param leash PIP leash. * @param interaction Tag for interaction. */ public void begin(SurfaceControl leash, @Interaction int interaction) { mInteractionJankMonitor.begin(leash, mContext, mHandler, CUJ_PIP_TRANSITION, pipInteractionToString(interaction)); } /** * End tracking CUJ. */ public void end() { mInteractionJankMonitor.end(CUJ_PIP_TRANSITION); } /** * Converts an interaction to a string representation used for tagging. * * @param interaction Interaction to track. * @return String representation of the interaction. */ public static String pipInteractionToString(@Interaction int interaction) { return switch (interaction) { case INTERACTION_EXIT_PIP -> "EXIT_PIP"; case INTERACTION_EXIT_PIP_TO_SPLIT -> "EXIT_PIP_TO_SPLIT"; default -> ""; }; } }
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +6 −2 Original line number Diff line number Diff line Loading @@ -113,6 +113,7 @@ public class PipTransition extends PipTransitionController implements private final DisplayController mDisplayController; private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper; private final PipDesktopState mPipDesktopState; private final PipInteractionHandler mPipInteractionHandler; // // Transition caches Loading Loading @@ -154,7 +155,8 @@ public class PipTransition extends PipTransitionController implements PipUiStateChangeController pipUiStateChangeController, DisplayController displayController, Optional<SplitScreenController> splitScreenControllerOptional, PipDesktopState pipDesktopState) { PipDesktopState pipDesktopState, PipInteractionHandler pipInteractionHandler) { super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController, pipBoundsAlgorithm); Loading @@ -168,9 +170,11 @@ public class PipTransition extends PipTransitionController implements mDisplayController = displayController; mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(mContext); mPipDesktopState = pipDesktopState; mPipInteractionHandler = pipInteractionHandler; mExpandHandler = new PipExpandHandler(mContext, pipBoundsState, pipBoundsAlgorithm, pipTransitionState, pipDisplayLayoutState, splitScreenControllerOptional); pipTransitionState, pipDisplayLayoutState, pipInteractionHandler, splitScreenControllerOptional); } @Override Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandler.java +10 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipDisplayLayoutState; import com.android.wm.shell.pip2.animation.PipExpandAnimator; import com.android.wm.shell.pip2.phone.PipInteractionHandler; import com.android.wm.shell.pip2.phone.PipTransitionState; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; Loading @@ -58,6 +59,7 @@ public class PipExpandHandler implements Transitions.TransitionHandler { private final PipBoundsAlgorithm mPipBoundsAlgorithm; private final PipTransitionState mPipTransitionState; private final PipDisplayLayoutState mPipDisplayLayoutState; private final PipInteractionHandler mPipInteractionHandler; private final Optional<SplitScreenController> mSplitScreenControllerOptional; @Nullable Loading @@ -72,12 +74,14 @@ public class PipExpandHandler implements Transitions.TransitionHandler { PipBoundsAlgorithm pipBoundsAlgorithm, PipTransitionState pipTransitionState, PipDisplayLayoutState pipDisplayLayoutState, PipInteractionHandler pipInteractionHandler, Optional<SplitScreenController> splitScreenControllerOptional) { mContext = context; mPipBoundsState = pipBoundsState; mPipBoundsAlgorithm = pipBoundsAlgorithm; mPipTransitionState = pipTransitionState; mPipDisplayLayoutState = pipDisplayLayoutState; mPipInteractionHandler = pipInteractionHandler; mSplitScreenControllerOptional = splitScreenControllerOptional; mPipExpandAnimatorSupplier = PipExpandAnimator::new; Loading Loading @@ -183,6 +187,8 @@ public class PipExpandHandler implements Transitions.TransitionHandler { PipExpandAnimator animator = mPipExpandAnimatorSupplier.get(mContext, pipLeash, startTransaction, finishTransaction, endBounds, startBounds, endBounds, sourceRectHint, delta); animator.setAnimationStartCallback(() -> mPipInteractionHandler.begin(pipLeash, PipInteractionHandler.INTERACTION_EXIT_PIP)); animator.setAnimationEndCallback(() -> { if (parentBeforePip != null) { // TODO b/377362511: Animate local leash instead to also handle letterbox case. Loading @@ -190,6 +196,7 @@ public class PipExpandHandler implements Transitions.TransitionHandler { finishTransaction.setCrop(pipLeash, null); } finishTransition(); mPipInteractionHandler.end(); }); cacheAndStartTransitionAnimator(animator); saveReentryState(); Loading Loading @@ -248,6 +255,8 @@ public class PipExpandHandler implements Transitions.TransitionHandler { splitController.finishEnterSplitScreen(finishTransaction); }); animator.setAnimationStartCallback(() -> mPipInteractionHandler.begin(pipLeash, PipInteractionHandler.INTERACTION_EXIT_PIP_TO_SPLIT)); animator.setAnimationEndCallback(() -> { if (parentBeforePip == null) { // After PipExpandAnimator is done modifying finishTransaction, we need to make Loading @@ -256,6 +265,7 @@ public class PipExpandHandler implements Transitions.TransitionHandler { finishTransaction.setPosition(pipLeash, 0, 0); } finishTransition(); mPipInteractionHandler.end(); }); cacheAndStartTransitionAnimator(animator); saveReentryState(); Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipInteractionHandlerTest.java 0 → 100644 +95 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.pip2.phone; import static com.android.internal.jank.Cuj.CUJ_PIP_TRANSITION; import static com.android.wm.shell.pip2.phone.PipInteractionHandler.INTERACTION_EXIT_PIP; import static com.android.wm.shell.pip2.phone.PipInteractionHandler.INTERACTION_EXIT_PIP_TO_SPLIT; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.kotlin.VerificationKt.times; import android.content.Context; import android.os.Handler; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.SurfaceControl; import androidx.test.filters.SmallTest; import com.android.internal.jank.InteractionJankMonitor; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** * Unit test against {@link PipInteractionHandler}. */ @SmallTest @TestableLooper.RunWithLooper @RunWith(AndroidTestingRunner.class) public class PipInteractionHandlerTest { @Mock private Context mMockContext; @Mock private Handler mMockHandler; @Mock private InteractionJankMonitor mMockInteractionJankMonitor; private SurfaceControl mTestLeash; private PipInteractionHandler mPipInteractionHandler; @Before public void setUp() { MockitoAnnotations.initMocks(this); mPipInteractionHandler = new PipInteractionHandler(mMockContext, mMockHandler, mMockInteractionJankMonitor); mTestLeash = new SurfaceControl.Builder() .setContainerLayer() .setName("PipInteractionHandlerTest") .setCallsite("PipInteractionHandlerTest") .build(); } @Test public void begin_expand_startsTracking() { mPipInteractionHandler.begin(mTestLeash, INTERACTION_EXIT_PIP); verify(mMockInteractionJankMonitor, times(1)).begin(eq(mTestLeash), eq(mMockContext), eq(mMockHandler), eq(CUJ_PIP_TRANSITION), eq(PipInteractionHandler.pipInteractionToString(INTERACTION_EXIT_PIP))); } @Test public void begin_expandToSplit_startsTracking() { mPipInteractionHandler.begin(mTestLeash, INTERACTION_EXIT_PIP_TO_SPLIT); verify(mMockInteractionJankMonitor, times(1)).begin(eq(mTestLeash), eq(mMockContext), eq(mMockHandler), eq(CUJ_PIP_TRANSITION), eq(PipInteractionHandler.pipInteractionToString(INTERACTION_EXIT_PIP_TO_SPLIT))); } @Test public void end_stopsTracking() { mPipInteractionHandler.end(); verify(mMockInteractionJankMonitor, times(1)).end(CUJ_PIP_TRANSITION); } }