Loading packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java 0 → 100644 +123 −0 Original line number Diff line number Diff line /* * 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)); } } packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +8 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -68,6 +69,7 @@ public class PipManager implements BasePipManager { } mTouchHandler.onActivityPinned(); mMediaController.onActivityPinned(); mMenuController.onActivityPinned(); } @Override Loading Loading @@ -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); } /** Loading @@ -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); } Loading packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +29 −12 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -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 Loading @@ -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); } Loading Loading @@ -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(); if (notifyMenuVisibility) { notifyMenuVisibility(false); } mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA, mMenuContainer.getAlpha(), 0f); mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT); Loading Loading @@ -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(); Loading @@ -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() { Loading @@ -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) { Loading packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +46 −16 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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. Loading @@ -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() { Loading @@ -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: { Loading @@ -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; } Loading @@ -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(); } } /** Loading Loading @@ -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. */ Loading Loading @@ -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. Loading @@ -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()); } } packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +38 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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) { 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); mBoundsAnimator = createAnimationToBounds(mBounds, normalBounds, SHRINK_STACK_FROM_MENU_DURATION, FAST_OUT_SLOW_IN, mUpdateBoundsListener); mBoundsAnimator.start(); } else { animateToClosestSnapTarget(normalMovementBounds); if (minimized) { normalBounds = getClosestMinimizedBounds(normalBounds, normalMovementBounds); } resizeAndAnimatePipUnchecked(normalBounds, SHRINK_STACK_FROM_MENU_DURATION); } /** Loading Loading @@ -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); } }); } Loading Loading
packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java 0 → 100644 +123 −0 Original line number Diff line number Diff line /* * 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)); } }
packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +8 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -68,6 +69,7 @@ public class PipManager implements BasePipManager { } mTouchHandler.onActivityPinned(); mMediaController.onActivityPinned(); mMenuController.onActivityPinned(); } @Override Loading Loading @@ -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); } /** Loading @@ -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); } Loading
packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +29 −12 Original line number Diff line number Diff line Loading @@ -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(); Loading @@ -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 Loading @@ -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); } Loading Loading @@ -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(); if (notifyMenuVisibility) { notifyMenuVisibility(false); } mMenuContainerAnimator = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA, mMenuContainer.getAlpha(), 0f); mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT); Loading Loading @@ -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(); Loading @@ -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() { Loading @@ -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) { Loading
packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +46 −16 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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. Loading @@ -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() { Loading @@ -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: { Loading @@ -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; } Loading @@ -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(); } } /** Loading Loading @@ -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. */ Loading Loading @@ -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. Loading @@ -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()); } }
packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +38 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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) { 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); mBoundsAnimator = createAnimationToBounds(mBounds, normalBounds, SHRINK_STACK_FROM_MENU_DURATION, FAST_OUT_SLOW_IN, mUpdateBoundsListener); mBoundsAnimator.start(); } else { animateToClosestSnapTarget(normalMovementBounds); if (minimized) { normalBounds = getClosestMinimizedBounds(normalBounds, normalMovementBounds); } resizeAndAnimatePipUnchecked(normalBounds, SHRINK_STACK_FROM_MENU_DURATION); } /** Loading Loading @@ -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); } }); } Loading