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

Commit dd82f2ed authored by Winson Chung's avatar Winson Chung Committed by gitbuildkicker
Browse files

Workaround for input ANR, always finish PiP menu activity.

- Always finish the PiP menu activity when the interaction is complete
  (either the menu is hidden after showing, or when the user stops
  interacting with it and it was shown for the dismiss overlay)
- Fix issue with bounds animation callback not working due to the app
  window being removed and not updating the app transition that its
  animation "finished"
- Add additional logging throughout to trace PiP animation

Bug: 36877782
Test: Enter PIP, tap to show menu, wait for it to hide, and then use
      wired headset button

Change-Id: Ie88ba107d7fffdd182a4063ef4f324b58669d0ad
(cherry picked from commit 87e5d55e)
parent 80d6dced
Loading
Loading
Loading
Loading
+7 −15
Original line number Original line Diff line number Diff line
@@ -87,7 +87,9 @@ public class PipMenuActivity extends Activity {


    private boolean mMenuVisible;
    private boolean mMenuVisible;
    private boolean mAllowMenuTimeout = true;
    private boolean mAllowMenuTimeout = true;

    private final List<RemoteAction> mActions = new ArrayList<>();
    private final List<RemoteAction> mActions = new ArrayList<>();

    private View mViewRoot;
    private View mViewRoot;
    private Drawable mBackgroundDrawable;
    private Drawable mBackgroundDrawable;
    private View mMenuContainer;
    private View mMenuContainer;
@@ -266,7 +268,6 @@ public class PipMenuActivity extends Activity {
            }
            }
            notifyMenuVisibility(true);
            notifyMenuVisibility(true);
            updateExpandButtonFromBounds(stackBounds, movementBounds);
            updateExpandButtonFromBounds(stackBounds, movementBounds);
            setDecorViewVisibility(true);
            mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
            mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
                    mMenuContainer.getAlpha(), 1f);
                    mMenuContainer.getAlpha(), 1f);
            mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
            mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
@@ -311,11 +312,15 @@ public class PipMenuActivity extends Activity {
                    if (animationFinishedRunnable != null) {
                    if (animationFinishedRunnable != null) {
                        animationFinishedRunnable.run();
                        animationFinishedRunnable.run();
                    }
                    }
                    setDecorViewVisibility(false);

                    finish();
                }
                }
            });
            });
            mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
            mMenuContainerAnimator.addUpdateListener(mMenuBgUpdateListener);
            mMenuContainerAnimator.start();
            mMenuContainerAnimator.start();
        } else {
            // If the menu is not visible, just finish now
            finish();
        }
        }
    }
    }


@@ -431,7 +436,6 @@ public class PipMenuActivity extends Activity {
            alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255);
            alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255);
        }
        }
        mBackgroundDrawable.setAlpha(alpha);
        mBackgroundDrawable.setAlpha(alpha);
        setDecorViewVisibility(alpha > 0);
    }
    }


    private void notifyRegisterInputConsumer() {
    private void notifyRegisterInputConsumer() {
@@ -508,16 +512,4 @@ public class PipMenuActivity extends Activity {
        v.removeCallbacks(mFinishRunnable);
        v.removeCallbacks(mFinishRunnable);
        v.postDelayed(mFinishRunnable, delay);
        v.postDelayed(mFinishRunnable, delay);
    }
    }

    /**
     * Sets the visibility of the root view of the window to disable drawing and touches for the
     * activity.  This differs from {@link Activity#setVisible(boolean)} in that it does not set
     * the internal mVisibleFromClient state.
     */
    private void setDecorViewVisibility(boolean visible) {
        final View decorView = getWindow().getDecorView();
        if (decorView != null) {
            decorView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
        }
    }
}
}
+19 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,7 @@ import java.util.List;
public class PipMenuActivityController {
public class PipMenuActivityController {


    private static final String TAG = "PipMenuActController";
    private static final String TAG = "PipMenuActController";
    private static final boolean DEBUG = false;


    public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
    public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
    public static final String EXTRA_ACTIONS = "actions";
    public static final String EXTRA_ACTIONS = "actions";
@@ -195,6 +196,10 @@ public class PipMenuActivityController {
     * Updates the appearance of the menu and scrim on top of the PiP while dismissing.
     * Updates the appearance of the menu and scrim on top of the PiP while dismissing.
     */
     */
    public void setDismissFraction(float fraction) {
    public void setDismissFraction(float fraction) {
        if (DEBUG) {
            Log.d(TAG, "setDismissFraction() hasActivity=" + (mToActivityMessenger != null)
                    + " fraction=" + fraction);
        }
        if (mToActivityMessenger != null) {
        if (mToActivityMessenger != null) {
            mTmpDismissFractionData.clear();
            mTmpDismissFractionData.clear();
            mTmpDismissFractionData.putFloat(EXTRA_DISMISS_FRACTION, fraction);
            mTmpDismissFractionData.putFloat(EXTRA_DISMISS_FRACTION, fraction);
@@ -216,6 +221,9 @@ public class PipMenuActivityController {
     * Shows the menu activity.
     * Shows the menu activity.
     */
     */
    public void showMenu(Rect stackBounds, Rect movementBounds, boolean allowMenuTimeout) {
    public void showMenu(Rect stackBounds, Rect movementBounds, boolean allowMenuTimeout) {
        if (DEBUG) {
            Log.d(TAG, "showMenu() hasActivity=" + (mToActivityMessenger != null));
        }
        if (mToActivityMessenger != null) {
        if (mToActivityMessenger != null) {
            Bundle data = new Bundle();
            Bundle data = new Bundle();
            data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
            data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
@@ -238,6 +246,9 @@ public class PipMenuActivityController {
     * Pokes the menu, indicating that the user is interacting with it.
     * Pokes the menu, indicating that the user is interacting with it.
     */
     */
    public void pokeMenu() {
    public void pokeMenu() {
        if (DEBUG) {
            Log.d(TAG, "pokeMenu() hasActivity=" + (mToActivityMessenger != null));
        }
        if (mToActivityMessenger != null) {
        if (mToActivityMessenger != null) {
            Message m = Message.obtain();
            Message m = Message.obtain();
            m.what = PipMenuActivity.MESSAGE_POKE_MENU;
            m.what = PipMenuActivity.MESSAGE_POKE_MENU;
@@ -253,6 +264,9 @@ public class PipMenuActivityController {
     * Hides the menu activity.
     * Hides the menu activity.
     */
     */
    public void hideMenu() {
    public void hideMenu() {
        if (DEBUG) {
            Log.d(TAG, "hideMenu() hasActivity=" + (mToActivityMessenger != null));
        }
        if (mToActivityMessenger != null) {
        if (mToActivityMessenger != null) {
            Message m = Message.obtain();
            Message m = Message.obtain();
            m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
            m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
@@ -365,6 +379,10 @@ public class PipMenuActivityController {
     * Handles changes in menu visibility.
     * Handles changes in menu visibility.
     */
     */
    private void onMenuVisibilityChanged(boolean visible, boolean resize) {
    private void onMenuVisibilityChanged(boolean visible, boolean resize) {
        if (DEBUG) {
            Log.d(TAG, "onMenuVisibilityChanged() mMenuVisible=" + mMenuVisible
                    + " menuVisible=" + visible + " resize=" + resize);
        }
        if (visible) {
        if (visible) {
            mInputConsumerController.unregisterInputConsumer();
            mInputConsumerController.unregisterInputConsumer();
        } else {
        } else {
@@ -389,6 +407,7 @@ public class PipMenuActivityController {
        final String innerPrefix = prefix + "  ";
        final String innerPrefix = prefix + "  ";
        pw.println(prefix + TAG);
        pw.println(prefix + TAG);
        pw.println(innerPrefix + "mMenuVisible=" + mMenuVisible);
        pw.println(innerPrefix + "mMenuVisible=" + mMenuVisible);
        pw.println(innerPrefix + "mToActivityMessenger=" + mToActivityMessenger);
        pw.println(innerPrefix + "mListeners=" + mListeners.size());
        pw.println(innerPrefix + "mListeners=" + mListeners.size());
    }
    }
}
}
+14 −6
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;
import static com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN;


import android.animation.Animator;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorListenerAdapter;
import android.animation.RectEvaluator;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator;
@@ -253,7 +254,7 @@ public class PipMotionHelper {
     * Flings the PiP to the closest snap target.
     * Flings the PiP to the closest snap target.
     */
     */
    Rect flingToSnapTarget(float velocity, float velocityX, float velocityY, Rect movementBounds,
    Rect flingToSnapTarget(float velocity, float velocityX, float velocityY, Rect movementBounds,
            AnimatorUpdateListener listener) {
            AnimatorUpdateListener updateListener, AnimatorListener listener) {
        cancelAnimations();
        cancelAnimations();
        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds,
                velocityX, velocityY);
                velocityX, velocityY);
@@ -263,8 +264,11 @@ public class PipMotionHelper {
            mFlingAnimationUtils.apply(mBoundsAnimator, 0,
            mFlingAnimationUtils.apply(mBoundsAnimator, 0,
                    distanceBetweenRectOffsets(mBounds, toBounds),
                    distanceBetweenRectOffsets(mBounds, toBounds),
                    velocity);
                    velocity);
            if (updateListener != null) {
                mBoundsAnimator.addUpdateListener(updateListener);
            }
            if (listener != null){
            if (listener != null){
                mBoundsAnimator.addUpdateListener(listener);
                mBoundsAnimator.addListener(listener);
            }
            }
            mBoundsAnimator.start();
            mBoundsAnimator.start();
        }
        }
@@ -274,14 +278,18 @@ public class PipMotionHelper {
    /**
    /**
     * Animates the PiP to the closest snap target.
     * Animates the PiP to the closest snap target.
     */
     */
    Rect animateToClosestSnapTarget(Rect movementBounds, AnimatorUpdateListener listener) {
    Rect animateToClosestSnapTarget(Rect movementBounds, AnimatorUpdateListener updateListener,
            AnimatorListener listener) {
        cancelAnimations();
        cancelAnimations();
        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds);
        Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds);
        if (!mBounds.equals(toBounds)) {
        if (!mBounds.equals(toBounds)) {
            mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, SNAP_STACK_DURATION,
            mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, SNAP_STACK_DURATION,
                    FAST_OUT_SLOW_IN, mUpdateBoundsListener);
                    FAST_OUT_SLOW_IN, mUpdateBoundsListener);
            if (updateListener != null) {
                mBoundsAnimator.addUpdateListener(updateListener);
            }
            if (listener != null){
            if (listener != null){
                mBoundsAnimator.addUpdateListener(listener);
                mBoundsAnimator.addListener(listener);
            }
            }
            mBoundsAnimator.start();
            mBoundsAnimator.start();
        }
        }
+23 −6
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@


package com.android.systemui.pip.phone;
package com.android.systemui.pip.phone;


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.IActivityManager;
import android.app.IActivityManager;
@@ -391,9 +393,12 @@ public class PipTouchHandler implements TunerService.Tunable {
                final float distance = bounds.bottom - target;
                final float distance = bounds.bottom - target;
                fraction = Math.min(distance / bounds.height(), 1f);
                fraction = Math.min(distance / bounds.height(), 1f);
            }
            }
            if (Float.compare(fraction, 0f) != 0 || mMenuController.isMenuVisible()) {
                // Update if the fraction > 0, or if fraction == 0 and the menu was already visible
                mMenuController.setDismissFraction(fraction);
                mMenuController.setDismissFraction(fraction);
            }
            }
        }
        }
    }


    /**
    /**
     * Sets the controller to update the system of changes from user interaction.
     * Sets the controller to update the system of changes from user interaction.
@@ -611,22 +616,34 @@ public class PipTouchHandler implements TunerService.Tunable {
                    setMinimizedStateInternal(false);
                    setMinimizedStateInternal(false);
                }
                }


                // If the menu is still visible, and we aren't minimized, then just poke the menu
                AnimatorListenerAdapter postAnimationCallback = null;
                // so that it will timeout after the user stops touching it
                if (mMenuController.isMenuVisible()) {
                if (mMenuController.isMenuVisible()) {
                    // If the menu is still visible, and we aren't minimized, then just poke the
                    // menu so that it will timeout after the user stops touching it
                    mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds,
                    mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds,
                            true /* allowMenuTimeout */);
                            true /* allowMenuTimeout */);
                } else {
                    // If the menu is not visible, then we can still be showing the activity for the
                    // dismiss overlay, so just finish it after the animation completes
                    postAnimationCallback = new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            mMenuController.hideMenu();
                        }
                    };
                }
                }


                if (isFling) {
                if (isFling) {
                    mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds,
                    mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds,
                            mUpdateScrimListener);
                            mUpdateScrimListener, postAnimationCallback);
                } else {
                } else {
                    mMotionHelper.animateToClosestSnapTarget(mMovementBounds, mUpdateScrimListener);
                    mMotionHelper.animateToClosestSnapTarget(mMovementBounds, mUpdateScrimListener,
                            postAnimationCallback);
                }
                }
            } else if (mIsMinimized) {
            } else if (mIsMinimized) {
                // This was a tap, so no longer minimized
                // This was a tap, so no longer minimized
                mMotionHelper.animateToClosestSnapTarget(mMovementBounds, null /* listener */);
                mMotionHelper.animateToClosestSnapTarget(mMovementBounds, null /* updateListener */,
                        null /* animatorListener */);
                setMinimizedStateInternal(false);
                setMinimizedStateInternal(false);
            } else if (!mIsMenuVisible) {
            } else if (!mIsMenuVisible) {
                mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds,
                mMenuController.showMenu(mMotionHelper.getBounds(), mMovementBounds,
+7 −0
Original line number Original line Diff line number Diff line
@@ -505,6 +505,13 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
            getController().removeStartingWindow();
            getController().removeStartingWindow();
        }
        }


        // If this window was animating, then we need to ensure that the app transition notifies
        // that animations have completed in WMS.handleAnimatingStoppedAndTransitionLocked(), so
        // add to that list now
        if (mAppAnimator.animating) {
            mService.mNoAnimationNotifyOnTransitionFinished.add(token);
        }

        final TaskStack stack = getTask().mStack;
        final TaskStack stack = getTask().mStack;
        if (delayed && !isEmpty()) {
        if (delayed && !isEmpty()) {
            // set the token aside because it has an active animation to be finished
            // set the token aside because it has an active animation to be finished
Loading