summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Winson Chung <winsonc@google.com> 2017-02-28 11:40:41 -0800
committer Winson Chung <winsonc@google.com> 2017-03-06 13:41:48 -0800
commitd2d909778c3dd67ccbccd5134ef7624059994ca9 (patch)
tree09c6c64ef00a1cd85d833ef5a5cdbc32f515fd62
parenta2f8f4970ef852d4b0caf40d7828376e4a4890c2 (diff)
Initial changes to support expanded PiP
- Prior to this CL, the input consumer and size of the PiP was tightly coupled with the visibility of the menu, but with the expanded state, the PiP should still move while the menu is visible. Bug: 35358488 Test: Click on the PiP to expand it Change-Id: If52208f19af516b2455bde26855c80f44bc9021a
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java123
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java163
6 files changed, 298 insertions, 161 deletions
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 000000000000..7a1849ed741e
--- /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 714b263e40cc..4c5d8a12a872 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 4e28061dc21b..f67241ef178a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -139,6 +139,11 @@ public class PipMenuActivity extends Activity {
}
@Override
+ public void onUserInteraction() {
+ repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
+ }
+
+ @Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
@@ -164,11 +169,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
switch (ev.getAction()) {
@@ -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 91115d034671..76c3caf9f454 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<Listener> 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();
+ }
}
/**
@@ -207,6 +225,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.
*/
public void setAppActions(ParceledListSlice appActions) {
@@ -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 ed0a37fed52d..a26fd4aafd1f 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 4100b66b07b6..54b15aa17e69 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;
@@ -106,36 +97,12 @@ public class PipTouchHandler {
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);