diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java new file mode 100644 index 0000000000000..7a1849ed741ec --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2017 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.systemui.pip.phone; + +import static android.view.WindowManager.INPUT_CONSUMER_PIP; + +import android.os.Looper; +import android.os.RemoteException; +import android.util.Log; +import android.view.InputChannel; +import android.view.InputEvent; +import android.view.InputEventReceiver; +import android.view.IWindowManager; +import android.view.MotionEvent; + +import java.io.PrintWriter; + +/** + * Manages the input consumer that allows the SystemUI to control the PiP. + */ +public class InputConsumerController { + + private static final String TAG = InputConsumerController.class.getSimpleName(); + + /** + * Listener interface for callers to subscribe to touch events. + */ + public interface TouchListener { + boolean onTouchEvent(MotionEvent ev); + } + + /** + * Input handler used for the PiP input consumer. + */ + private final class PipInputEventReceiver extends InputEventReceiver { + + public PipInputEventReceiver(InputChannel inputChannel, Looper looper) { + super(inputChannel, looper); + } + + @Override + public void onInputEvent(InputEvent event) { + boolean handled = true; + try { + // To be implemented for input handling over Pip windows + if (mListener != null && event instanceof MotionEvent) { + MotionEvent ev = (MotionEvent) event; + handled = mListener.onTouchEvent(ev); + } + } finally { + finishInputEvent(event, handled); + } + } + } + + private IWindowManager mWindowManager; + + private PipInputEventReceiver mInputEventReceiver; + private TouchListener mListener; + + public InputConsumerController(IWindowManager windowManager) { + mWindowManager = windowManager; + registerInputConsumer(); + } + + /** + * Sets the touch listener. + */ + public void setTouchListener(TouchListener listener) { + mListener = listener; + } + + /** + * Registers the input consumer. + */ + public void registerInputConsumer() { + if (mInputEventReceiver == null) { + final InputChannel inputChannel = new InputChannel(); + try { + mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP); + mWindowManager.createInputConsumer(INPUT_CONSUMER_PIP, inputChannel); + } catch (RemoteException e) { + Log.e(TAG, "Failed to create PIP input consumer", e); + } + mInputEventReceiver = new PipInputEventReceiver(inputChannel, Looper.myLooper()); + } + } + + /** + * Unregisters the input consumer. + */ + public void unregisterInputConsumer() { + if (mInputEventReceiver != null) { + try { + mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP); + } catch (RemoteException e) { + Log.e(TAG, "Failed to destroy PIP input consumer", e); + } + mInputEventReceiver.dispose(); + mInputEventReceiver = null; + } + } + + public void dump(PrintWriter pw, String prefix) { + final String innerPrefix = prefix + " "; + pw.println(prefix + TAG); + pw.println(innerPrefix + "registered=" + (mInputEventReceiver != null)); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 714b263e40cc1..4c5d8a12a8721 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -53,6 +53,7 @@ public class PipManager implements BasePipManager { private final PinnedStackListener mPinnedStackListener = new PinnedStackListener(); + private InputConsumerController mInputConsumerController; private PipMenuActivityController mMenuController; private PipMediaController mMediaController; private PipTouchHandler mTouchHandler; @@ -68,6 +69,7 @@ public class PipManager implements BasePipManager { } mTouchHandler.onActivityPinned(); mMediaController.onActivityPinned(); + mMenuController.onActivityPinned(); } @Override @@ -151,11 +153,12 @@ public class PipManager implements BasePipManager { } SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener); + mInputConsumerController = new InputConsumerController(mWindowManager); mMediaController = new PipMediaController(context, mActivityManager); - mMenuController = new PipMenuActivityController(context, mActivityManager, mWindowManager, - mMediaController); - mTouchHandler = new PipTouchHandler(context, mMenuController, mActivityManager, - mWindowManager); + mMenuController = new PipMenuActivityController(context, mActivityManager, mMediaController, + mInputConsumerController); + mTouchHandler = new PipTouchHandler(context, mActivityManager, mMenuController, + mInputConsumerController); } /** @@ -178,6 +181,7 @@ public class PipManager implements BasePipManager { public void dump(PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG); + mInputConsumerController.dump(pw, innerPrefix); mMenuController.dump(pw, innerPrefix); mTouchHandler.dump(pw, innerPrefix); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index 4e28061dc21b7..f67241ef178ad 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -138,6 +138,11 @@ public class PipMenuActivity extends Activity { showMenu(); } + @Override + public void onUserInteraction() { + repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY); + } + @Override protected void onUserLeaveHint() { super.onUserLeaveHint(); @@ -163,11 +168,6 @@ public class PipMenuActivity extends Activity { } } - @Override - public void onUserInteraction() { - repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY); - } - @Override public boolean dispatchTouchEvent(MotionEvent ev) { // On the first action outside the window, hide the menu @@ -177,13 +177,16 @@ public class PipMenuActivity extends Activity { break; case MotionEvent.ACTION_DOWN: mDownPosition.set(ev.getX(), ev.getY()); + mDownDelta.set(0f, 0f); break; case MotionEvent.ACTION_MOVE: mDownDelta.set(ev.getX() - mDownPosition.x, ev.getY() - mDownPosition.y); if (mDownDelta.length() > mViewConfig.getScaledTouchSlop() && mMenuVisible) { - hideMenu(); - mMenuVisible = false; + // Restore the input consumer and let that drive the movement of this menu + notifyRegisterInputConsumer(); + cancelDelayedFinish(); } + break; } return super.dispatchTouchEvent(ev); } @@ -219,17 +222,21 @@ public class PipMenuActivity extends Activity { } }); mMenuContainerAnimator.start(); + } else { + repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY); } } private void hideMenu() { - hideMenu(null /* animationFinishedRunnable */); + hideMenu(null /* animationFinishedRunnable */, true /* notifyMenuVisibility */); } - private void hideMenu(final Runnable animationFinishedRunnable) { + private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility) { if (mMenuVisible) { cancelDelayedFinish(); - notifyMenuVisibility(false); + if (notifyMenuVisibility) { + notifyMenuVisibility(false); + } mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA, mMenuContainer.getAlpha(), 0f); mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT); @@ -291,6 +298,12 @@ public class PipMenuActivity extends Activity { } } + private void notifyRegisterInputConsumer() { + Message m = Message.obtain(); + m.what = PipMenuActivityController.MESSAGE_REGISTER_INPUT_CONSUMER; + sendMessage(m, "Could not notify controller to register input consumer"); + } + private void notifyMenuVisibility(boolean visible) { mMenuVisible = visible; Message m = Message.obtain(); @@ -300,10 +313,12 @@ public class PipMenuActivity extends Activity { } private void expandPip() { + // Do not notify menu visibility when hiding the menu, the controller will do this when it + // handles the message hideMenu(() -> { sendEmptyMessage(PipMenuActivityController.MESSAGE_EXPAND_PIP, "Could not notify controller to expand PIP"); - }); + }, false /* notifyMenuVisibility */); } private void minimizePip() { @@ -312,10 +327,12 @@ public class PipMenuActivity extends Activity { } private void dismissPip() { + // Do not notify menu visibility when hiding the menu, the controller will do this when it + // handles the message hideMenu(() -> { sendEmptyMessage(PipMenuActivityController.MESSAGE_DISMISS_PIP, "Could not notify controller to dismiss PIP"); - }); + }, false /* notifyMenuVisibility */); } private void notifyActivityCallback(Messenger callback) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java index 91115d0346713..76c3caf9f454e 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java @@ -57,6 +57,7 @@ public class PipMenuActivityController { 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; /** * A listener interface to receive notification on changes in PIP. @@ -64,8 +65,11 @@ public class PipMenuActivityController { public interface Listener { /** * 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 */ - void onPipMenuVisibilityChanged(boolean visible); + void onPipMenuVisibilityChanged(boolean menuVisible, boolean resize); /** * Called when the PIP requested to be expanded. @@ -85,13 +89,13 @@ public class PipMenuActivityController { private Context mContext; private IActivityManager mActivityManager; - private IWindowManager mWindowManager; private PipMediaController mMediaController; + private InputConsumerController mInputConsumerController; private ArrayList mListeners = new ArrayList<>(); private ParceledListSlice mAppActions; private ParceledListSlice mMediaActions; - private boolean mVisible; + private boolean mMenuVisible; private Messenger mToActivityMessenger; private Messenger mMessenger = new Messenger(new Handler() { @@ -100,13 +104,14 @@ public class PipMenuActivityController { switch (msg.what) { case MESSAGE_MENU_VISIBILITY_CHANGED: { boolean visible = msg.arg1 > 0; - onMenuVisibilityChanged(visible); + onMenuVisibilityChanged(visible, true /* resize */); break; } case MESSAGE_EXPAND_PIP: { mListeners.forEach(l -> l.onPipExpand()); - // Preemptively mark the menu as invisible once we expand the PiP - onMenuVisibilityChanged(false); + // 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 */); break; } case MESSAGE_MINIMIZE_PIP: { @@ -115,15 +120,20 @@ public class PipMenuActivityController { } case MESSAGE_DISMISS_PIP: { mListeners.forEach(l -> l.onPipDismiss()); - // Preemptively mark the menu as invisible once we dismiss the PiP - onMenuVisibilityChanged(false); + // 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 */); + break; + } + case MESSAGE_REGISTER_INPUT_CONSUMER: { + mInputConsumerController.registerInputConsumer(); break; } case MESSAGE_UPDATE_ACTIVITY_CALLBACK: { mToActivityMessenger = msg.replyTo; // Mark the menu as invisible once the activity finishes as well if (mToActivityMessenger == null) { - onMenuVisibilityChanged(false); + onMenuVisibilityChanged(false, true /* resize */); } break; } @@ -140,11 +150,19 @@ public class PipMenuActivityController { }; public PipMenuActivityController(Context context, IActivityManager activityManager, - IWindowManager windowManager, PipMediaController mediaController) { + PipMediaController mediaController, InputConsumerController inputConsumerController) { mContext = context; mActivityManager = activityManager; - mWindowManager = windowManager; mMediaController = mediaController; + mInputConsumerController = inputConsumerController; + } + + public void onActivityPinned() { + if (!mMenuVisible) { + // If the menu is not visible, then re-register the input consumer if it is not already + // registered + mInputConsumerController.registerInputConsumer(); + } } /** @@ -206,6 +224,13 @@ public class PipMenuActivityController { } } + /** + * @return whether the menu is currently visible. + */ + public boolean isMenuVisible() { + return mMenuVisible; + } + /** * Sets the menu actions to the actions provided by the current PiP activity. */ @@ -250,9 +275,14 @@ public class PipMenuActivityController { /** * Handles changes in menu visibility. */ - private void onMenuVisibilityChanged(boolean visible) { - mListeners.forEach(l -> l.onPipMenuVisibilityChanged(visible)); - if (visible != mVisible) { + private void onMenuVisibilityChanged(boolean visible, boolean resize) { + if (visible) { + mInputConsumerController.unregisterInputConsumer(); + } else { + mInputConsumerController.registerInputConsumer(); + } + if (visible != mMenuVisible) { + mListeners.forEach(l -> l.onPipMenuVisibilityChanged(visible, resize)); if (visible) { // Once visible, start listening for media action changes. This call will trigger // the menu actions to be updated again. @@ -263,13 +293,13 @@ public class PipMenuActivityController { mMediaController.removeListener(mMediaActionListener); } } - mVisible = visible; + mMenuVisible = visible; } public void dump(PrintWriter pw, String prefix) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); - pw.println(innerPrefix + "mVisible=" + mVisible); + pw.println(innerPrefix + "mMenuVisible=" + mMenuVisible); pw.println(innerPrefix + "mListeners=" + mListeners.size()); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index ed0a37fed52df..a26fd4aafd1f2 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -217,19 +217,12 @@ public class PipMotionHelper { /** * Animates the PiP to the minimized state, slightly offscreen. */ - Rect animateToClosestMinimizedState(Rect movementBounds, - final PipMenuActivityController menuController) { + Rect animateToClosestMinimizedState(Rect movementBounds) { cancelAnimations(); Rect toBounds = getClosestMinimizedBounds(mBounds, movementBounds); if (!mBounds.equals(toBounds)) { mBoundsAnimator = createAnimationToBounds(mBounds, toBounds, MINIMIZE_STACK_MAX_DURATION, LINEAR_OUT_SLOW_IN, mUpdateBoundsListener); - mBoundsAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - menuController.hideMenu(); - } - }); mBoundsAnimator.start(); } return toBounds; @@ -274,9 +267,7 @@ public class PipMotionHelper { Rect expandedMovementBounds) { float savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(mBounds), movementBounds); mSnapAlgorithm.applySnapFraction(expandedBounds, expandedMovementBounds, savedSnapFraction); - mBoundsAnimator = createAnimationToBounds(mBounds, expandedBounds, - EXPAND_STACK_TO_MENU_DURATION, FAST_OUT_SLOW_IN, mUpdateBoundsListener); - mBoundsAnimator.start(); + resizeAndAnimatePipUnchecked(expandedBounds, EXPAND_STACK_TO_MENU_DURATION); return savedSnapFraction; } @@ -284,15 +275,17 @@ public class PipMotionHelper { * Animates the PiP from the expanded state to the normal state after the menu is hidden. */ void animateToUnexpandedState(Rect normalBounds, float savedSnapFraction, - Rect normalMovementBounds) { - if (savedSnapFraction >= 0f) { - mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction); - mBoundsAnimator = createAnimationToBounds(mBounds, normalBounds, - SHRINK_STACK_FROM_MENU_DURATION, FAST_OUT_SLOW_IN, mUpdateBoundsListener); - mBoundsAnimator.start(); - } else { - animateToClosestSnapTarget(normalMovementBounds); + Rect normalMovementBounds, Rect currentMovementBounds, boolean minimized) { + if (savedSnapFraction < 0f) { + // If there are no saved snap fractions, then just use the current bounds + savedSnapFraction = mSnapAlgorithm.getSnapFraction(new Rect(mBounds), + currentMovementBounds); } + mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction); + if (minimized) { + normalBounds = getClosestMinimizedBounds(normalBounds, normalMovementBounds); + } + resizeAndAnimatePipUnchecked(normalBounds, SHRINK_STACK_FROM_MENU_DURATION); } /** @@ -365,7 +358,32 @@ public class PipMotionHelper { mActivityManager.resizePinnedStack(toBounds, null /* tempPinnedTaskBounds */); mBounds.set(toBounds); } catch (RemoteException e) { - Log.e(TAG, "Could not move pinned stack to bounds: " + toBounds, e); + Log.e(TAG, "Could not resize pinned stack to bounds: " + toBounds, e); + } + }); + } + } + + /** + * Directly resizes the PiP to the given {@param bounds}. + */ + private void resizeAndAnimatePipUnchecked(Rect toBounds, int duration) { + if (!toBounds.equals(mBounds)) { + mHandler.post(() -> { + try { + StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID); + if (stackInfo == null) { + // In the case where we've already re-expanded or dismissed the PiP, then + // just skip the resize + return; + } + + mActivityManager.resizeStack(PINNED_STACK_ID, toBounds, + false /* allowResizeInDockedMode */, true /* preserveWindows */, + true /* animate */, duration); + mBounds.set(toBounds); + } catch (RemoteException e) { + Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e); } }); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 4100b66b07b64..54b15aa17e691 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -16,21 +16,15 @@ package com.android.systemui.pip.phone; -import static android.view.WindowManager.INPUT_CONSUMER_PIP; - import android.app.IActivityManager; import android.content.Context; import android.graphics.PointF; import android.graphics.Rect; import android.os.Handler; -import android.os.Looper; import android.os.RemoteException; import android.util.Log; import android.view.IPinnedStackController; import android.view.IWindowManager; -import android.view.InputChannel; -import android.view.InputEvent; -import android.view.InputEventReceiver; import android.view.MotionEvent; import android.view.ViewConfiguration; @@ -59,12 +53,10 @@ public class PipTouchHandler { private final Context mContext; private final IActivityManager mActivityManager; - private final IWindowManager mWindowManager; private final ViewConfiguration mViewConfig; private final PipMenuListener mMenuListener = new PipMenuListener(); private IPinnedStackController mPinnedStackController; - private PipInputEventReceiver mInputEventReceiver; private final PipMenuActivityController mMenuController; private final PipDismissViewController mDismissViewController; private final PipSnapAlgorithm mSnapAlgorithm; @@ -89,9 +81,8 @@ public class PipTouchHandler { }; // Behaviour states - private boolean mIsTappingThrough; - private boolean mIsMinimized; private boolean mIsMenuVisible; + private boolean mIsMinimized; private boolean mIsImeShowing; private int mImeHeight; private float mSavedSnapFraction = -1f; @@ -105,37 +96,13 @@ public class PipTouchHandler { // Temp vars private final Rect mTmpBounds = new Rect(); - /** - * Input handler used for Pip windows. - */ - private final class PipInputEventReceiver extends InputEventReceiver { - - public PipInputEventReceiver(InputChannel inputChannel, Looper looper) { - super(inputChannel, looper); - } - - @Override - public void onInputEvent(InputEvent event) { - boolean handled = true; - try { - // To be implemented for input handling over Pip windows - if (event instanceof MotionEvent) { - MotionEvent ev = (MotionEvent) event; - handled = handleTouchEvent(ev); - } - } finally { - finishInputEvent(event, handled); - } - } - } - /** * A listener for the PIP menu activity. */ private class PipMenuListener implements PipMenuActivityController.Listener { @Override - public void onPipMenuVisibilityChanged(boolean visible) { - setMenuVisibilityState(visible); + public void onPipMenuVisibilityChanged(boolean menuVisible, boolean resize) { + setMenuVisibilityState(menuVisible, resize); } @Override @@ -148,7 +115,7 @@ public class PipTouchHandler { @Override public void onPipMinimize() { setMinimizedStateInternal(true); - mMotionHelper.animateToClosestMinimizedState(mMovementBounds, mMenuController); + mMotionHelper.animateToClosestMinimizedState(mMovementBounds); } @Override @@ -159,13 +126,13 @@ public class PipTouchHandler { } } - public PipTouchHandler(Context context, PipMenuActivityController menuController, - IActivityManager activityManager, IWindowManager windowManager) { + public PipTouchHandler(Context context, IActivityManager activityManager, + PipMenuActivityController menuController, + InputConsumerController inputConsumerController) { // Initialize the Pip input consumer mContext = context; mActivityManager = activityManager; - mWindowManager = windowManager; mViewConfig = ViewConfiguration.get(context); mMenuController = menuController; mMenuController.addListener(mMenuListener); @@ -178,7 +145,9 @@ public class PipTouchHandler { }; mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mSnapAlgorithm, mFlingAnimationUtils); - registerInputConsumer(); + + // Register the listener for input consumer touch events + inputConsumerController.setTouchListener(this::handleTouchEvent); } public void setTouchEnabled(boolean enabled) { @@ -187,9 +156,8 @@ public class PipTouchHandler { public void onActivityPinned() { // Reset some states once we are pinned - if (mIsTappingThrough) { - mIsTappingThrough = false; - registerInputConsumer(); + if (mIsMenuVisible) { + mIsMenuVisible = false; } if (mIsMinimized) { setMinimizedStateInternal(false); @@ -255,7 +223,7 @@ public class PipTouchHandler { // above mNormalMovementBounds = normalMovementBounds; mExpandedMovementBounds = expandedMovementBounds; - updateMovementBounds(); + updateMovementBounds(mIsMenuVisible); } private boolean handleTouchEvent(MotionEvent ev) { @@ -287,7 +255,7 @@ public class PipTouchHandler { case MotionEvent.ACTION_UP: { // Update the movement bounds again if the state has changed since the user started // dragging (ie. when the IME shows) - updateMovementBounds(); + updateMovementBounds(mIsMenuVisible); for (PipTouchGesture gesture : mGestures) { if (gesture.onUp(mTouchState)) { @@ -302,38 +270,7 @@ public class PipTouchHandler { break; } } - return !mIsTappingThrough; - } - - /** - * Registers the input consumer. - */ - private void registerInputConsumer() { - if (mInputEventReceiver == null) { - final InputChannel inputChannel = new InputChannel(); - try { - mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP); - mWindowManager.createInputConsumer(INPUT_CONSUMER_PIP, inputChannel); - } catch (RemoteException e) { - Log.e(TAG, "Failed to create PIP input consumer", e); - } - mInputEventReceiver = new PipInputEventReceiver(inputChannel, Looper.myLooper()); - } - } - - /** - * Unregisters the input consumer. - */ - private void unregisterInputConsumer() { - if (mInputEventReceiver != null) { - try { - mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP); - } catch (RemoteException e) { - Log.e(TAG, "Failed to destroy PIP input consumer", e); - } - mInputEventReceiver.dispose(); - mInputEventReceiver = null; - } + return !mIsMenuVisible; } /** @@ -379,34 +316,30 @@ public class PipTouchHandler { /** * Sets the menu visibility. */ - void setMenuVisibilityState(boolean isMenuVisible) { - if (!isMenuVisible) { - mIsTappingThrough = false; - registerInputConsumer(); - } else { - unregisterInputConsumer(); - } - MetricsLogger.visibility(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU, - isMenuVisible); - - if (isMenuVisible != mIsMenuVisible) { - if (isMenuVisible) { - // Save the current snap fraction and if we do not drag or move the PiP, then - // we store back to this snap fraction. Otherwise, we'll reset the snap - // fraction and snap to the closest edge - Rect expandedBounds = new Rect(mExpandedBounds); + void setMenuVisibilityState(boolean menuVisible, boolean resize) { + if (menuVisible) { + // Save the current snap fraction and if we do not drag or move the PiP, then + // we store back to this snap fraction. Otherwise, we'll reset the snap + // fraction and snap to the closest edge + Rect expandedBounds = new Rect(mExpandedBounds); + if (resize) { mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds, mMovementBounds, mExpandedMovementBounds); - } else { - // Try and restore the PiP to the closest edge, using the saved snap fraction - // if possible + } + } else { + // Try and restore the PiP to the closest edge, using the saved snap fraction + // if possible + if (resize) { Rect normalBounds = new Rect(mNormalBounds); mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction, - mNormalMovementBounds); + mNormalMovementBounds, mMovementBounds, mIsMinimized); } - mIsMenuVisible = isMenuVisible; - updateMovementBounds(); + mSavedSnapFraction = -1f; } + mIsMenuVisible = menuVisible; + updateMovementBounds(menuVisible); + MetricsLogger.visibility(mContext, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU, + menuVisible); } /** @@ -495,21 +428,35 @@ public class PipTouchHandler { } finally { mDismissViewController.destroyDismissTarget(); } + if (touchState.isDragging()) { PointF vel = mTouchState.getVelocity(); if (!mIsMinimized && (mMotionHelper.shouldMinimizePip() || isHorizontalFlingTowardsCurrentEdge(vel))) { // Pip should be minimized setMinimizedStateInternal(true); - mMotionHelper.animateToClosestMinimizedState(mMovementBounds, mMenuController); + if (mMenuController.isMenuVisible()) { + // If the user dragged the expanded PiP to the edge, then hiding the menu + // will trigger the PiP to be scaled back to the normal size with the + // minimize offset adjusted + mMenuController.hideMenu(); + } else { + mMotionHelper.animateToClosestMinimizedState(mMovementBounds); + } return true; } if (mIsMinimized) { - // If we're dragging and it wasn't a minimize gesture - // then we shouldn't be minimized. + // If we're dragging and it wasn't a minimize gesture then we shouldn't be + // minimized. setMinimizedStateInternal(false); } + // 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 + if (mMenuController.isMenuVisible()) { + mMenuController.showMenu(); + } + final float velocity = PointF.length(vel.x, vel.y); if (velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond()) { mMotionHelper.flingToSnapTarget(velocity, vel.x, vel.y, mMovementBounds); @@ -520,9 +467,8 @@ public class PipTouchHandler { // This was a tap, so no longer minimized mMotionHelper.animateToClosestSnapTarget(mMovementBounds); setMinimizedStateInternal(false); - } else if (!mIsTappingThrough) { + } else if (!mIsMenuVisible) { mMenuController.showMenu(); - mIsTappingThrough = true; } else { mMotionHelper.expandPip(); } @@ -559,8 +505,8 @@ public class PipTouchHandler { /** * Updates the current movement bounds based on whether the menu is currently visible. */ - private void updateMovementBounds() { - mMovementBounds = mIsMenuVisible + private void updateMovementBounds(boolean isExpanded) { + mMovementBounds = isExpanded ? mExpandedMovementBounds : mNormalMovementBounds; } @@ -573,9 +519,8 @@ public class PipTouchHandler { pw.println(innerPrefix + "mNormalMovementBounds=" + mNormalMovementBounds); pw.println(innerPrefix + "mExpandedBounds=" + mExpandedBounds); pw.println(innerPrefix + "mExpandedMovementBounds=" + mExpandedMovementBounds); - pw.println(innerPrefix + "mIsTappingThrough=" + mIsTappingThrough); - pw.println(innerPrefix + "mIsMinimized=" + mIsMinimized); pw.println(innerPrefix + "mIsMenuVisible=" + mIsMenuVisible); + pw.println(innerPrefix + "mIsMinimized=" + mIsMinimized); pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing); pw.println(innerPrefix + "mImeHeight=" + mImeHeight); pw.println(innerPrefix + "mSavedSnapFraction=" + mSavedSnapFraction);