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

Commit 637cd489 authored by Mady Mellor's avatar Mady Mellor
Browse files

Show x for short period of time when activity is PIP'd

- Moves dismiss view out of menu container layout and manages the alpha
  for it separately (i.e. when animating menu in / out or modifying the
  alpha when dragging to dismiss)
- Shows the dismiss view when PIP mode is entered, fades out after
  menu time out, on interaction the timeout is reset

Test: Enter PIP, note 'x' that is displayed, tap on it to dismiss the PIP
      or don't tap on it and it goes away
Bug: 36900043
Change-Id: Ia596ee60cd9c0d744e459564586ba6a0a9c23d5d
parent 4a306894
Loading
Loading
Loading
Loading
+11 −10
Original line number Diff line number Diff line
@@ -26,16 +26,6 @@
      android:layout_height="match_parent"
      android:forceHasOverlappingRendering="false">

      <ImageView
          android:id="@+id/dismiss"
          android:layout_width="@dimen/pip_action_size"
          android:layout_height="@dimen/pip_action_size"
          android:layout_gravity="top|end"
          android:padding="@dimen/pip_action_padding"
          android:contentDescription="@string/pip_phone_close"
          android:src="@drawable/ic_close_white"
          android:background="?android:selectableItemBackgroundBorderless" />

      <!-- The margins for this container is calculated in the code depending on whether the
           actions_container is visible. -->
      <FrameLayout
@@ -67,4 +57,15 @@
              android:showDividers="middle" />
      </FrameLayout>
  </FrameLayout>

  <ImageView
      android:id="@+id/dismiss"
      android:layout_width="@dimen/pip_action_size"
      android:layout_height="@dimen/pip_action_size"
      android:layout_gravity="top|end"
      android:padding="@dimen/pip_action_padding"
      android:contentDescription="@string/pip_phone_close"
      android:src="@drawable/ic_close_white"
      android:background="?android:selectableItemBackgroundBorderless" />

</FrameLayout>
+64 −26
Original line number Diff line number Diff line
@@ -21,11 +21,16 @@ import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ALL
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_DISMISS_FRACTION;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MOVEMENT_BOUNDS;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_SHOW_MENU;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MENU_STATE;
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_STACK_BOUNDS;

import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_FULL;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
@@ -85,7 +90,7 @@ public class PipMenuActivity extends Activity {

    private static final float DISABLED_ACTION_ALPHA = 0.54f;

    private boolean mMenuVisible;
    private int mMenuState;
    private boolean mAllowMenuTimeout = true;

    private final List<RemoteAction> mActions = new ArrayList<>();
@@ -98,7 +103,8 @@ public class PipMenuActivity extends Activity {
    private ImageView mExpandButton;
    private int mBetweenActionPaddingLand;

    private ObjectAnimator mMenuContainerAnimator;
    private AnimatorSet mMenuContainerAnimator;

    private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
            new ValueAnimator.AnimatorUpdateListener() {
                @Override
@@ -119,7 +125,8 @@ public class PipMenuActivity extends Activity {
            switch (msg.what) {
                case MESSAGE_SHOW_MENU: {
                    final Bundle data = (Bundle) msg.obj;
                    showMenu(data.getParcelable(EXTRA_STACK_BOUNDS),
                    showMenu(data.getInt(EXTRA_MENU_STATE),
                            data.getParcelable(EXTRA_STACK_BOUNDS),
                            data.getParcelable(EXTRA_MOVEMENT_BOUNDS),
                            data.getBoolean(EXTRA_ALLOW_TIMEOUT));
                    break;
@@ -170,9 +177,14 @@ public class PipMenuActivity extends Activity {
        mMenuContainer = findViewById(R.id.menu_container);
        mMenuContainer.setAlpha(0);
        mMenuContainer.setOnClickListener((v) -> {
            if (mMenuState == MENU_STATE_CLOSE) {
                showPipMenu();
            } else {
                expandPip();
            }
        });
        mDismissButton = findViewById(R.id.dismiss);
        mDismissButton.setAlpha(0);
        mDismissButton.setOnClickListener((v) -> {
            dismissPip();
        });
@@ -236,7 +248,8 @@ public class PipMenuActivity extends Activity {
                break;
            case MotionEvent.ACTION_MOVE:
                mDownDelta.set(ev.getX() - mDownPosition.x, ev.getY() - mDownPosition.y);
                if (mDownDelta.length() > mViewConfig.getScaledTouchSlop() && mMenuVisible) {
                if (mDownDelta.length() > mViewConfig.getScaledTouchSlop()
                        && mMenuState != MENU_STATE_NONE) {
                    // Restore the input consumer and let that drive the movement of this menu
                    notifyRegisterInputConsumer();
                    cancelDelayedFinish();
@@ -259,17 +272,28 @@ public class PipMenuActivity extends Activity {
        // Do nothing
    }

    private void showMenu(Rect stackBounds, Rect movementBounds, boolean allowMenuTimeout) {
    private void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
            boolean allowMenuTimeout) {
        mAllowMenuTimeout = allowMenuTimeout;
        if (!mMenuVisible) {
        if (mMenuState != menuState) {
            cancelDelayedFinish();
            updateActionViews(stackBounds);
            if (mMenuContainerAnimator != null) {
                mMenuContainerAnimator.cancel();
            }
            notifyMenuVisibility(true);
            notifyMenuStateChange(menuState);
            updateExpandButtonFromBounds(stackBounds, movementBounds);
            mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
            mMenuContainerAnimator = new AnimatorSet();
            ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
                    mMenuContainer.getAlpha(), 1f);
            menuAnim.addUpdateListener(mMenuBgUpdateListener);
            ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
                    mDismissButton.getAlpha(), 1f);
            if (menuState == MENU_STATE_FULL) {
                mMenuContainerAnimator.playTogether(menuAnim, dismissAnim);
            } else {
                mMenuContainerAnimator.play(dismissAnim);
            }
            mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
            mMenuContainerAnimator.setDuration(MENU_FADE_DURATION);
            if (allowMenuTimeout) {
@@ -280,7 +304,6 @@ public class PipMenuActivity extends Activity {
                    }
                });
            }
            mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
            mMenuContainerAnimator.start();
        } else {
            // If we are already visible, then just start the delayed dismiss and unregister any
@@ -297,13 +320,18 @@ public class PipMenuActivity extends Activity {
    }

    private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility) {
        if (mMenuVisible) {
        if (mMenuState != MENU_STATE_NONE) {
            cancelDelayedFinish();
            if (notifyMenuVisibility) {
                notifyMenuVisibility(false);
                notifyMenuStateChange(MENU_STATE_NONE);
            }
            mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
            mMenuContainerAnimator = new AnimatorSet();
            ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
                    mMenuContainer.getAlpha(), 0f);
            menuAnim.addUpdateListener(mMenuBgUpdateListener);
            ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
                    mDismissButton.getAlpha(), 0f);
            mMenuContainerAnimator.playTogether(menuAnim, dismissAnim);
            mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
            mMenuContainerAnimator.setDuration(MENU_FADE_DURATION);
            mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
@@ -312,11 +340,9 @@ public class PipMenuActivity extends Activity {
                    if (animationFinishedRunnable != null) {
                        animationFinishedRunnable.run();
                    }

                    finish();
                }
            });
            mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
            mMenuContainerAnimator.start();
        } else {
            // If the menu is not visible, just finish now
@@ -332,11 +358,12 @@ public class PipMenuActivity extends Activity {
            mActions.clear();
            mActions.addAll(actions.getList());
        }
        if (intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
        final int menuState = intent.getIntExtra(EXTRA_MENU_STATE, MENU_STATE_NONE);
        if (menuState != MENU_STATE_NONE) {
            Rect stackBounds = intent.getParcelableExtra(EXTRA_STACK_BOUNDS);
            Rect movementBounds = intent.getParcelableExtra(EXTRA_MOVEMENT_BOUNDS);
            boolean allowMenuTimeout = intent.getBooleanExtra(EXTRA_ALLOW_TIMEOUT, true);
            showMenu(stackBounds, movementBounds, allowMenuTimeout);
            showMenu(menuState, stackBounds, movementBounds, allowMenuTimeout);
        }
    }

@@ -372,7 +399,7 @@ public class PipMenuActivity extends Activity {
            return true;
        });

        if (mActions.isEmpty()) {
        if (mActions.isEmpty() || mMenuState == MENU_STATE_CLOSE) {
            actionsContainer.setVisibility(View.INVISIBLE);
        } else {
            actionsContainer.setVisibility(View.VISIBLE);
@@ -427,12 +454,17 @@ public class PipMenuActivity extends Activity {

    private void updateDismissFraction(float fraction) {
        int alpha;
        if (mMenuVisible) {
            mMenuContainer.setAlpha(1 - fraction);
        final float menuAlpha = 1 - fraction;
        if (mMenuState == MENU_STATE_FULL) {
            mMenuContainer.setAlpha(menuAlpha);
            mDismissButton.setAlpha(menuAlpha);
            final float interpolatedAlpha =
                    MENU_BACKGROUND_ALPHA * (1.0f - fraction) + DISMISS_BACKGROUND_ALPHA * fraction;
                    MENU_BACKGROUND_ALPHA * menuAlpha + DISMISS_BACKGROUND_ALPHA * fraction;
            alpha = (int) (interpolatedAlpha * 255);
        } else {
            if (mMenuState == MENU_STATE_CLOSE) {
                mDismissButton.setAlpha(menuAlpha);
            }
            alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255);
        }
        mBackgroundDrawable.setAlpha(alpha);
@@ -450,11 +482,11 @@ public class PipMenuActivity extends Activity {
        sendMessage(m, "Could not notify controller to unregister input consumer");
    }

    private void notifyMenuVisibility(boolean visible) {
        mMenuVisible = visible;
    private void notifyMenuStateChange(int menuState) {
        mMenuState = menuState;
        Message m = Message.obtain();
        m.what = PipMenuActivityController.MESSAGE_MENU_VISIBILITY_CHANGED;
        m.arg1 = visible ? 1 : 0;
        m.what = PipMenuActivityController.MESSAGE_MENU_STATE_CHANGED;
        m.arg1 = menuState;
        sendMessage(m, "Could not notify controller of PIP menu visibility");
    }

@@ -481,6 +513,12 @@ public class PipMenuActivity extends Activity {
        }, false /* notifyMenuVisibility */);
    }

    private void showPipMenu() {
        Message m = Message.obtain();
        m.what = PipMenuActivityController.MESSAGE_SHOW_MENU;
        sendMessage(m, "Could not notify controller to show PIP menu");
    }

    private void notifyActivityCallback(Messenger callback) {
        Message m = Message.obtain();
        m.what = PipMenuActivityController.MESSAGE_UPDATE_ACTIVITY_CALLBACK;
+50 −34
Original line number Diff line number Diff line
@@ -57,16 +57,21 @@ public class PipMenuActivityController {
    public static final String EXTRA_STACK_BOUNDS = "stack_bounds";
    public static final String EXTRA_MOVEMENT_BOUNDS = "movement_bounds";
    public static final String EXTRA_ALLOW_TIMEOUT = "allow_timeout";
    public static final String EXTRA_SHOW_MENU = "show_menu";
    public static final String EXTRA_DISMISS_FRACTION = "dismiss_fraction";
    public static final String EXTRA_MENU_STATE = "menu_state";

    public static final int MESSAGE_MENU_VISIBILITY_CHANGED = 100;
    public static final int MESSAGE_MENU_STATE_CHANGED = 100;
    public static final int MESSAGE_EXPAND_PIP = 101;
    public static final int MESSAGE_MINIMIZE_PIP = 102;
    public static final int MESSAGE_DISMISS_PIP = 103;
    public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104;
    public static final int MESSAGE_REGISTER_INPUT_CONSUMER = 105;
    public static final int MESSAGE_UNREGISTER_INPUT_CONSUMER = 106;
    public static final int MESSAGE_SHOW_MENU = 107;

    public static final int MENU_STATE_NONE = 0;
    public static final int MENU_STATE_CLOSE = 1;
    public static final int MENU_STATE_FULL = 2;

    /**
     * A listener interface to receive notification on changes in PIP.
@@ -75,10 +80,10 @@ public class PipMenuActivityController {
        /**
         * Called when the PIP menu visibility changes.
         *
         * @param menuVisible whether or not the menu is visible
         * @param resize whether or not to resize the PiP with the visibility change
         * @param menuState the current state of the menu
         * @param resize whether or not to resize the PiP with the state change
         */
        void onPipMenuVisibilityChanged(boolean menuVisible, boolean resize);
        void onPipMenuStateChanged(int menuState, boolean resize);

        /**
         * Called when the PIP requested to be expanded.
@@ -94,6 +99,11 @@ public class PipMenuActivityController {
         * Called when the PIP requested to be dismissed.
         */
        void onPipDismiss();

        /**
         * Called when the PIP requested to show the menu.
         */
        void onPipShowMenu();
    }

    private Context mContext;
@@ -104,7 +114,7 @@ public class PipMenuActivityController {
    private ArrayList<Listener> mListeners = new ArrayList<>();
    private ParceledListSlice mAppActions;
    private ParceledListSlice mMediaActions;
    private boolean mMenuVisible;
    private int mMenuState;

    // The dismiss fraction update is sent frequently, so use a temporary bundle for the message
    private Bundle mTmpDismissFractionData = new Bundle();
@@ -115,16 +125,16 @@ public class PipMenuActivityController {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_MENU_VISIBILITY_CHANGED: {
                    boolean visible = msg.arg1 > 0;
                    onMenuVisibilityChanged(visible, true /* resize */);
                case MESSAGE_MENU_STATE_CHANGED: {
                    int menuState = msg.arg1;
                    onMenuStateChanged(menuState, true /* resize */);
                    break;
                }
                case MESSAGE_EXPAND_PIP: {
                    mListeners.forEach(l -> l.onPipExpand());
                    // Preemptively mark the menu as invisible once we expand the PiP, but don't
                    // resize as we will be animating the stack
                    onMenuVisibilityChanged(false, false /* resize */);
                    onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
                    break;
                }
                case MESSAGE_MINIMIZE_PIP: {
@@ -135,7 +145,11 @@ public class PipMenuActivityController {
                    mListeners.forEach(l -> l.onPipDismiss());
                    // Preemptively mark the menu as invisible once we dismiss the PiP, but don't
                    // resize as we'll be removing the stack in place
                    onMenuVisibilityChanged(false, false /* resize */);
                    onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
                    break;
                }
                case MESSAGE_SHOW_MENU: {
                    mListeners.forEach(l -> l.onPipShowMenu());
                    break;
                }
                case MESSAGE_REGISTER_INPUT_CONSUMER: {
@@ -151,7 +165,7 @@ public class PipMenuActivityController {
                    mStartActivityRequested = false;
                    // Mark the menu as invisible once the activity finishes as well
                    if (mToActivityMessenger == null) {
                        onMenuVisibilityChanged(false, true /* resize */);
                        onMenuStateChanged(MENU_STATE_NONE, true /* resize */);
                    }
                    break;
                }
@@ -176,7 +190,7 @@ public class PipMenuActivityController {
    }

    public void onActivityPinned() {
        if (!mMenuVisible) {
        if (mMenuState == MENU_STATE_NONE) {
            // If the menu is not visible, then re-register the input consumer if it is not already
            // registered
            mInputConsumerController.registerInputConsumer();
@@ -209,23 +223,25 @@ public class PipMenuActivityController {
            try {
                mToActivityMessenger.send(m);
            } catch (RemoteException e) {
                Log.e(TAG, "Could not notify menu to show", e);
                Log.e(TAG, "Could not notify menu to update dismiss fraction", e);
            }
        } else if (!mStartActivityRequested) {
            startMenuActivity(null /* stackBounds */, null /* movementBounds */,
                    false /* showMenu */, false /* allowMenuTimeout */);
            startMenuActivity(MENU_STATE_NONE, null /* stackBounds */,
                    null /* movementBounds */, false /* allowMenuTimeout */);
        }
    }

    /**
     * Shows the menu activity.
     */
    public void showMenu(Rect stackBounds, Rect movementBounds, boolean allowMenuTimeout) {
    public void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
            boolean allowMenuTimeout) {
        if (DEBUG) {
            Log.d(TAG, "showMenu() hasActivity=" + (mToActivityMessenger != null));
        }
        if (mToActivityMessenger != null) {
            Bundle data = new Bundle();
            data.putInt(EXTRA_MENU_STATE, menuState);
            data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
            data.putParcelable(EXTRA_MOVEMENT_BOUNDS, movementBounds);
            data.putBoolean(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
@@ -238,7 +254,7 @@ public class PipMenuActivityController {
                Log.e(TAG, "Could not notify menu to show", e);
            }
        } else if (!mStartActivityRequested) {
            startMenuActivity(stackBounds, movementBounds, true /* showMenu */, allowMenuTimeout);
            startMenuActivity(menuState, stackBounds, movementBounds, allowMenuTimeout);
        }
    }

@@ -279,10 +295,10 @@ public class PipMenuActivityController {
    }

    /**
     * @return whether the menu is currently visible.
     * @return the current menu state.
     */
    public boolean isMenuVisible() {
        return mMenuVisible;
    public int getMenuState() {
        return mMenuState;
    }

    /**
@@ -306,7 +322,7 @@ public class PipMenuActivityController {
    /**
     * Starts the menu activity on the top task of the pinned stack.
     */
    private void startMenuActivity(Rect stackBounds, Rect movementBounds, boolean showMenu,
    private void startMenuActivity(int menuState, Rect stackBounds, Rect movementBounds,
            boolean allowMenuTimeout) {
        try {
            StackInfo pinnedStackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
@@ -321,7 +337,7 @@ public class PipMenuActivityController {
                if (movementBounds != null) {
                    intent.putExtra(EXTRA_MOVEMENT_BOUNDS, movementBounds);
                }
                intent.putExtra(EXTRA_SHOW_MENU, showMenu);
                intent.putExtra(EXTRA_MENU_STATE, menuState);
                intent.putExtra(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
                ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
                options.setLaunchTaskId(
@@ -378,19 +394,19 @@ public class PipMenuActivityController {
    /**
     * Handles changes in menu visibility.
     */
    private void onMenuVisibilityChanged(boolean visible, boolean resize) {
    private void onMenuStateChanged(int menuState, boolean resize) {
        if (DEBUG) {
            Log.d(TAG, "onMenuVisibilityChanged() mMenuVisible=" + mMenuVisible
                    + " menuVisible=" + visible + " resize=" + resize);
            Log.d(TAG, "onMenuStateChanged() mMenuState=" + mMenuState
                    + " menuState=" + menuState + " resize=" + resize);
        }
        if (visible) {
            mInputConsumerController.unregisterInputConsumer();
        } else {
        if (menuState == MENU_STATE_NONE) {
            mInputConsumerController.registerInputConsumer();
        } else {
            mInputConsumerController.unregisterInputConsumer();
        }
        if (visible != mMenuVisible) {
            mListeners.forEach(l -> l.onPipMenuVisibilityChanged(visible, resize));
            if (visible) {
        if (menuState != mMenuState) {
            mListeners.forEach(l -> l.onPipMenuStateChanged(menuState, resize));
            if (menuState == MENU_STATE_FULL) {
                // Once visible, start listening for media action changes. This call will trigger
                // the menu actions to be updated again.
                mMediaController.addListener(mMediaActionListener);
@@ -400,13 +416,13 @@ public class PipMenuActivityController {
                mMediaController.removeListener(mMediaActionListener);
            }
        }
        mMenuVisible = visible;
        mMenuState = menuState;
    }

    public void dump(PrintWriter pw, String prefix) {
        final String innerPrefix = prefix + "  ";
        pw.println(prefix + TAG);
        pw.println(innerPrefix + "mMenuVisible=" + mMenuVisible);
        pw.println(innerPrefix + "mMenuState=" + mMenuState);
        pw.println(innerPrefix + "mToActivityMessenger=" + mToActivityMessenger);
        pw.println(innerPrefix + "mListeners=" + mListeners.size());
    }
+46 −33

File changed.

Preview size limit exceeded, changes collapsed.