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

Commit a8e90de6 authored by Hongwei Wang's avatar Hongwei Wang Committed by Android (Google) Code Review
Browse files

Merge "Reset PiP params on PiP component change" into main

parents 41752e79 6a213e98
Loading
Loading
Loading
Loading
+43 −8
Original line number Diff line number Diff line
@@ -143,6 +143,9 @@ public class PipBoundsState {
     */
    public final Rect mCachedLauncherShelfHeightKeepClearArea = new Rect();

    private final List<OnPipComponentChangedListener> mOnPipComponentChangedListeners =
            new ArrayList<>();

    // the size of the current bounds relative to the max size spec
    private float mBoundsScale;

@@ -156,9 +159,7 @@ public class PipBoundsState {
        // Update the relative proportion of the bounds compared to max possible size. Max size
        // spec takes the aspect ratio of the bounds into account, so both width and height
        // scale by the same factor.
        addPipExclusionBoundsChangeCallback((bounds) -> {
            updateBoundsScale();
        });
        addPipExclusionBoundsChangeCallback((bounds) -> updateBoundsScale());
    }

    /** Reloads the resources. */
@@ -341,11 +342,14 @@ public class PipBoundsState {
    /** Set the last {@link ComponentName} to enter PIP mode. */
    public void setLastPipComponentName(@Nullable ComponentName lastPipComponentName) {
        final boolean changed = !Objects.equals(mLastPipComponentName, lastPipComponentName);
        mLastPipComponentName = lastPipComponentName;
        if (changed) {
        if (!changed) return;
        clearReentryState();
        setHasUserResizedPip(false);
        setHasUserMovedPip(false);
        final ComponentName oldComponentName = mLastPipComponentName;
        mLastPipComponentName = lastPipComponentName;
        for (OnPipComponentChangedListener listener : mOnPipComponentChangedListeners) {
            listener.onPipComponentChanged(oldComponentName, mLastPipComponentName);
        }
    }

@@ -616,6 +620,21 @@ public class PipBoundsState {
        }
    }

    /** Adds callback to listen on component change. */
    public void addOnPipComponentChangedListener(@NonNull OnPipComponentChangedListener listener) {
        if (!mOnPipComponentChangedListeners.contains(listener)) {
            mOnPipComponentChangedListeners.add(listener);
        }
    }

    /** Removes callback to listen on component change. */
    public void removeOnPipComponentChangedListener(
            @NonNull OnPipComponentChangedListener listener) {
        if (mOnPipComponentChangedListeners.contains(listener)) {
            mOnPipComponentChangedListeners.remove(listener);
        }
    }

    public LauncherState getLauncherState() {
        return mLauncherState;
    }
@@ -695,7 +714,7 @@ public class PipBoundsState {
     * Represents the state of pip to potentially restore upon reentry.
     */
    @VisibleForTesting
    public static final class PipReentryState {
    static final class PipReentryState {
        private static final String TAG = PipReentryState.class.getSimpleName();

        private final float mSnapFraction;
@@ -722,6 +741,22 @@ public class PipBoundsState {
        }
    }

    /**
     * Listener interface for PiP component change, i.e. the app in pip mode changes
     * TODO: Move this out of PipBoundsState once pip1 is deprecated.
     */
    public interface OnPipComponentChangedListener {
        /**
         * Callback when the component in pip mode changes.
         * @param oldPipComponent previous component in pip mode,
         *                        {@code null} if this is the very first time PiP appears.
         * @param newPipComponent new component that enters pip mode.
         */
        void onPipComponentChanged(
                @Nullable ComponentName oldPipComponent,
                @NonNull ComponentName newPipComponent);
    }

    /** Dumps internal state. */
    public void dump(PrintWriter pw, String prefix) {
        final String innerPrefix = prefix + "  ";
+6 −1
Original line number Diff line number Diff line
@@ -153,7 +153,12 @@ public class PhonePipMenuController implements PipMenuController,
        mPipUiEventLogger = pipUiEventLogger;

        mPipTransitionState.addPipTransitionStateChangedListener(this);

        // Clear actions after exit PiP. Otherwise, next PiP could accidentally inherit the
        // actions provided by the previous app in PiP mode.
        mPipBoundsState.addOnPipComponentChangedListener(((oldPipComponent, newPipComponent) -> {
            if (mAppActions != null) mAppActions.clear();
            mCloseAction = null;
        }));
        mPipTaskListener.addParamsChangedListener(new PipTaskListener.PipParamsChangedCallback() {
            @Override
            public void onActionsChanged(List<RemoteAction> actions, RemoteAction closeAction) {
+8 −4
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ public class PipTaskListener implements ShellTaskOrganizer.TaskListener,
    private final PipBoundsState mPipBoundsState;
    private final PipBoundsAlgorithm mPipBoundsAlgorithm;
    private final ShellExecutor mMainExecutor;
    private final PictureInPictureParams mPictureInPictureParams =
    private PictureInPictureParams mPictureInPictureParams =
            new PictureInPictureParams.Builder().build();

    private boolean mWaitingForAspectRatioChange = false;
@@ -92,6 +92,11 @@ public class PipTaskListener implements ShellTaskOrganizer.TaskListener,
        }
        mPipResizeAnimatorSupplier = PipResizeAnimator::new;
        mPipScheduler.setPipParamsSupplier(this::getPictureInPictureParams);
        // Reset {@link #mPictureInPictureParams} after exiting PiP. For instance, next Activity
        // with null aspect ratio would accidentally inherit the aspect ratio from a previous
        // PiP Activity.
        mPipBoundsState.addOnPipComponentChangedListener(((oldPipComponent, newPipComponent) ->
                mPictureInPictureParams = new PictureInPictureParams.Builder().build()));
    }

    void setPictureInPictureParams(@Nullable PictureInPictureParams params) {
@@ -138,9 +143,8 @@ public class PipTaskListener implements ShellTaskOrganizer.TaskListener,
        if (mPictureInPictureParams.hasSetAspectRatio()
                && mPipBoundsAlgorithm.isValidPictureInPictureAspectRatio(newAspectRatio)
                && PipUtils.aspectRatioChanged(newAspectRatio, mPipBoundsState.getAspectRatio())) {
            mPipTransitionState.setOnIdlePipTransitionStateRunnable(() -> {
                onAspectRatioChanged(newAspectRatio);
            });
            mPipTransitionState.setOnIdlePipTransitionStateRunnable(
                    () -> onAspectRatioChanged(newAspectRatio));
        }
    }

+27 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.wm.shell.common.pip;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -127,6 +129,31 @@ public class PipBoundsStateTest extends ShellTestCase {
        assertNull(mPipBoundsState.getReentryState());
    }

    @Test
    public void setLastPipComponentName_notChanged_doesNotCallbackComponentChangedListener() {
        mPipBoundsState.setLastPipComponentName(mTestComponentName1);
        PipBoundsState.OnPipComponentChangedListener mockListener =
                mock(PipBoundsState.OnPipComponentChangedListener.class);

        mPipBoundsState.addOnPipComponentChangedListener(mockListener);
        mPipBoundsState.setLastPipComponentName(mTestComponentName1);

        verify(mockListener, never()).onPipComponentChanged(any(), any());
    }

    @Test
    public void setLastPipComponentName_changed_callbackComponentChangedListener() {
        mPipBoundsState.setLastPipComponentName(mTestComponentName1);
        PipBoundsState.OnPipComponentChangedListener mockListener =
                mock(PipBoundsState.OnPipComponentChangedListener.class);

        mPipBoundsState.addOnPipComponentChangedListener(mockListener);
        mPipBoundsState.setLastPipComponentName(mTestComponentName2);

        verify(mockListener).onPipComponentChanged(
                eq(mTestComponentName1), eq(mTestComponentName2));
    }

    @Test
    public void testSetLastPipComponentName_notChanged_doesNotClearReentryState() {
        mPipBoundsState.setLastPipComponentName(mTestComponentName1);
+35 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.kotlin.MatchersKt.eq;
import static org.mockito.kotlin.VerificationKt.clearInvocations;
@@ -35,7 +36,9 @@ import android.app.ActivityManager;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -48,8 +51,10 @@ import androidx.test.filters.SmallTest;

import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
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.PipResizeAnimator;

import org.junit.Before;
@@ -106,6 +111,16 @@ public class PipTaskListenerTest {
        verify(mMockPipTransitionState).addPipTransitionStateChangedListener(eq(mPipTaskListener));
    }

    @Test
    public void constructor_addOnPipComponentChangedListener() {
        mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer,
                mMockPipTransitionState, mMockPipScheduler, mMockPipBoundsState,
                mMockPipBoundsAlgorithm, mMockShellExecutor);

        verify(mMockPipBoundsState).addOnPipComponentChangedListener(
                any(PipBoundsState.OnPipComponentChangedListener.class));
    }

    @Test
    public void setPictureInPictureParams_updatePictureInPictureParams() {
        mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer,
@@ -359,6 +374,26 @@ public class PipTaskListenerTest {
        verify(mMockPipResizeAnimator, times(0)).start();
    }

    @Test
    public void onPipComponentChanged_clearPictureInPictureParams() {
        when(mMockContext.getResources()).thenReturn(mock(Resources.class));
        PipBoundsState pipBoundsState = new PipBoundsState(mMockContext,
                mock(PhoneSizeSpecSource.class), mock(PipDisplayLayoutState.class));
        pipBoundsState.setLastPipComponentName(new ComponentName("org.test", "test1"));

        mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer,
                mMockPipTransitionState, mMockPipScheduler, pipBoundsState,
                mMockPipBoundsAlgorithm, mMockShellExecutor);
        Rational aspectRatio = new Rational(4, 3);
        String action1 = "action1";
        mPipTaskListener.setPictureInPictureParams(getPictureInPictureParams(
                aspectRatio, action1));

        pipBoundsState.setLastPipComponentName(new ComponentName("org.test", "test2"));

        assertTrue(mPipTaskListener.getPictureInPictureParams().empty());
    }

    private PictureInPictureParams getPictureInPictureParams(Rational aspectRatio,
            String... actions) {
        final PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder();