Migrate from PipMenuActivity -> PipMenuView.
Bug: 161710689 Test: Build and run Change-Id: I879502085daefd3dbfbe437410a29c3353c5cf1a
This commit is contained in:
@@ -22,8 +22,6 @@ import android.view.IWindowManager;
|
||||
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.pip.phone.PipMenuActivity;
|
||||
import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
|
||||
import com.android.systemui.wm.DisplaySystemBarsController;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.DisplayImeController;
|
||||
@@ -43,12 +41,4 @@ public class CarWMShellModule {
|
||||
return new DisplaySystemBarsController(context, wmService, displayController,
|
||||
mainHandler, transactionPool);
|
||||
}
|
||||
|
||||
/** TODO(b/150319024): PipMenuActivity will move to a Window */
|
||||
@SysUISingleton
|
||||
@PipMenuActivityClass
|
||||
@Provides
|
||||
Class<?> providePipMenuActivityClass() {
|
||||
return PipMenuActivity.class;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,20 +530,6 @@
|
||||
androidprv:alwaysFocusable="true"
|
||||
android:excludeFromRecents="true" />
|
||||
|
||||
<activity
|
||||
android:name=".pip.phone.PipMenuActivity"
|
||||
android:permission="com.android.systemui.permission.SELF"
|
||||
android:theme="@style/PipPhoneOverlayControlTheme"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="false"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:stateNotNeeded="true"
|
||||
android:taskAffinity=""
|
||||
android:launchMode="singleTop"
|
||||
androidprv:alwaysFocusable="true" />
|
||||
|
||||
<!-- started from SliceProvider -->
|
||||
<activity android:name=".SlicePermissionActivity"
|
||||
android:theme="@style/Theme.SystemUI.Dialog.Alert"
|
||||
|
||||
@@ -49,6 +49,9 @@ import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.Size;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceControlViewHost;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.window.TaskOrganizer;
|
||||
import android.window.WindowContainerToken;
|
||||
import android.window.WindowContainerTransaction;
|
||||
@@ -57,6 +60,7 @@ import android.window.WindowOrganizer;
|
||||
|
||||
import com.android.internal.os.SomeArgs;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.pip.phone.PipMenuActivityController;
|
||||
import com.android.systemui.pip.phone.PipUpdateThread;
|
||||
import com.android.systemui.stackdivider.SplitScreen;
|
||||
import com.android.wm.shell.R;
|
||||
@@ -95,6 +99,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
|
||||
private static final int MSG_FINISH_RESIZE = 4;
|
||||
private static final int MSG_RESIZE_USER = 5;
|
||||
|
||||
private final Context mContext;
|
||||
private final Handler mMainHandler;
|
||||
private final Handler mUpdateHandler;
|
||||
private final PipBoundsHandler mPipBoundsHandler;
|
||||
@@ -107,6 +112,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
|
||||
private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
|
||||
private final Optional<SplitScreen> mSplitScreenOptional;
|
||||
protected final ShellTaskOrganizer mTaskOrganizer;
|
||||
private SurfaceControlViewHost mPipViewHost;
|
||||
private SurfaceControl mPipMenuSurface;
|
||||
|
||||
// These callbacks are called on the update thread
|
||||
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
|
||||
@@ -212,6 +219,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
|
||||
@NonNull DisplayController displayController,
|
||||
@NonNull PipUiEventLogger pipUiEventLogger,
|
||||
@NonNull ShellTaskOrganizer shellTaskOrganizer) {
|
||||
mContext = context;
|
||||
mMainHandler = new Handler(Looper.getMainLooper());
|
||||
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
|
||||
mPipBoundsHandler = boundsHandler;
|
||||
@@ -503,6 +511,45 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the ViewHost and attach the provided menu view to the ViewHost.
|
||||
*/
|
||||
public void attachPipMenuViewHost(View menuView, WindowManager.LayoutParams lp) {
|
||||
if (mPipMenuSurface != null) {
|
||||
Log.e(TAG, "PIP Menu View already created and attached.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Looper.getMainLooper() != Looper.myLooper()) {
|
||||
throw new RuntimeException("PipMenuView needs to be attached on the main thread.");
|
||||
}
|
||||
|
||||
mPipViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(),
|
||||
(android.os.Binder) null);
|
||||
mPipMenuSurface = mPipViewHost.getSurfacePackage().getSurfaceControl();
|
||||
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
|
||||
transaction.reparent(mPipMenuSurface, mLeash);
|
||||
transaction.show(mPipMenuSurface);
|
||||
transaction.setRelativeLayer(mPipMenuSurface, mLeash, 1);
|
||||
transaction.apply();
|
||||
mPipViewHost.setView(menuView, lp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Releases the PIP Menu's View host, remove it from PIP task surface.
|
||||
*/
|
||||
public void detachPipMenuViewHost() {
|
||||
if (mPipMenuSurface != null) {
|
||||
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
|
||||
transaction.remove(mPipMenuSurface);
|
||||
transaction.apply();
|
||||
mPipMenuSurface = null;
|
||||
mPipViewHost = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note that dismissing PiP is now originated from SystemUI, see {@link #exitPip(int)}.
|
||||
* Meanwhile this callback is invoked whenever the task is removed. For instance:
|
||||
@@ -838,6 +885,12 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
|
||||
WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
prepareFinishResizeTransaction(destinationBounds, direction, tx, wct);
|
||||
applyFinishBoundsResize(wct, direction);
|
||||
runOnMainHandler(() -> {
|
||||
if (mPipViewHost != null) {
|
||||
mPipViewHost.relayout(PipMenuActivityController.getPipMenuLayoutParams(
|
||||
destinationBounds.width(), destinationBounds.height()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void prepareFinishResizeTransaction(Rect destinationBounds,
|
||||
|
||||
@@ -49,7 +49,6 @@ import com.android.systemui.pip.PipBoundsHandler;
|
||||
import com.android.systemui.pip.PipSurfaceTransactionHelper;
|
||||
import com.android.systemui.pip.PipTaskOrganizer;
|
||||
import com.android.systemui.pip.PipUiEventLogger;
|
||||
import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
|
||||
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.InputConsumerController;
|
||||
@@ -267,7 +266,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
|
||||
|
||||
@Inject
|
||||
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
|
||||
@PipMenuActivityClass Class<?> pipMenuActivityClass,
|
||||
ConfigurationController configController,
|
||||
DeviceConfigProxy deviceConfig,
|
||||
DisplayController displayController,
|
||||
@@ -296,8 +294,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
|
||||
mPipTaskOrganizer.registerPipTransitionCallback(this);
|
||||
mInputConsumerController = InputConsumerController.getPipInputConsumer();
|
||||
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
|
||||
mMenuController = new PipMenuActivityController(context, pipMenuActivityClass,
|
||||
mMediaController, mInputConsumerController);
|
||||
mMenuController = new PipMenuActivityController(context,
|
||||
mMediaController, mInputConsumerController, mPipTaskOrganizer);
|
||||
mTouchHandler = new PipTouchHandler(context, mActivityManager,
|
||||
mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
|
||||
floatingContentCoordinator, deviceConfig, sysUiState, pipUiEventLogger);
|
||||
|
||||
@@ -19,27 +19,20 @@ package com.android.systemui.pip.phone;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager.StackInfo;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.RemoteAction;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.os.Debug;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.systemui.pip.PipTaskOrganizer;
|
||||
import com.android.systemui.pip.phone.PipMediaController.ActionListener;
|
||||
import com.android.systemui.shared.system.InputConsumerController;
|
||||
|
||||
@@ -58,30 +51,10 @@ public class PipMenuActivityController {
|
||||
private static final String TAG = "PipMenuActController";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
public static final String EXTRA_CONTROLLER_MESSENGER = "messenger";
|
||||
public static final String EXTRA_ACTIONS = "actions";
|
||||
public static final String EXTRA_STACK_BOUNDS = "stack_bounds";
|
||||
public static final String EXTRA_ALLOW_TIMEOUT = "allow_timeout";
|
||||
public static final String EXTRA_WILL_RESIZE_MENU = "resize_menu_on_show";
|
||||
public static final String EXTRA_DISMISS_FRACTION = "dismiss_fraction";
|
||||
public static final String EXTRA_MENU_STATE = "menu_state";
|
||||
public static final String EXTRA_SHOW_MENU_WITH_DELAY = "show_menu_with_delay";
|
||||
public static final String EXTRA_SHOW_RESIZE_HANDLE = "show_resize_handle";
|
||||
public static final String EXTRA_MESSAGE_CALLBACK_WHAT = "message_callback_what";
|
||||
|
||||
public static final int MESSAGE_MENU_STATE_CHANGED = 100;
|
||||
public static final int MESSAGE_EXPAND_PIP = 101;
|
||||
public static final int MESSAGE_DISMISS_PIP = 103;
|
||||
public static final int MESSAGE_UPDATE_ACTIVITY_CALLBACK = 104;
|
||||
public static final int MESSAGE_SHOW_MENU = 107;
|
||||
|
||||
public static final int MENU_STATE_NONE = 0;
|
||||
public static final int MENU_STATE_CLOSE = 1;
|
||||
public static final int MENU_STATE_FULL = 2;
|
||||
|
||||
// The duration to wait before we consider the start activity as having timed out
|
||||
private static final long START_ACTIVITY_REQUEST_TIMEOUT_MS = 300;
|
||||
|
||||
/**
|
||||
* A listener interface to receive notification on changes in PIP.
|
||||
*/
|
||||
@@ -110,9 +83,8 @@ public class PipMenuActivityController {
|
||||
void onPipShowMenu();
|
||||
}
|
||||
|
||||
/** TODO(b/150319024): PipMenuActivity will move to a Window */
|
||||
private Class<?> mPipMenuActivityClass;
|
||||
private Context mContext;
|
||||
private PipTaskOrganizer mPipTaskOrganizer;
|
||||
private PipMediaController mMediaController;
|
||||
private InputConsumerController mInputConsumerController;
|
||||
|
||||
@@ -121,63 +93,7 @@ public class PipMenuActivityController {
|
||||
private ParceledListSlice<RemoteAction> mMediaActions;
|
||||
private int mMenuState;
|
||||
|
||||
// The dismiss fraction update is sent frequently, so use a temporary bundle for the message
|
||||
private Bundle mTmpDismissFractionData = new Bundle();
|
||||
|
||||
private Runnable mOnAnimationEndRunnable;
|
||||
private boolean mStartActivityRequested;
|
||||
private long mStartActivityRequestedTime;
|
||||
private Messenger mToActivityMessenger;
|
||||
private Handler mHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MESSAGE_MENU_STATE_CHANGED: {
|
||||
final int menuState = msg.arg1;
|
||||
final boolean resize = msg.arg2 != 0;
|
||||
onMenuStateChanged(menuState, resize,
|
||||
getMenuStateChangeFinishedCallback(msg.replyTo, (Bundle) msg.obj));
|
||||
break;
|
||||
}
|
||||
case MESSAGE_EXPAND_PIP: {
|
||||
mListeners.forEach(Listener::onPipExpand);
|
||||
break;
|
||||
}
|
||||
case MESSAGE_DISMISS_PIP: {
|
||||
mListeners.forEach(Listener::onPipDismiss);
|
||||
break;
|
||||
}
|
||||
case MESSAGE_SHOW_MENU: {
|
||||
mListeners.forEach(Listener::onPipShowMenu);
|
||||
break;
|
||||
}
|
||||
case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
|
||||
mToActivityMessenger = msg.replyTo;
|
||||
setStartActivityRequested(false);
|
||||
if (mOnAnimationEndRunnable != null) {
|
||||
mOnAnimationEndRunnable.run();
|
||||
mOnAnimationEndRunnable = null;
|
||||
}
|
||||
// Mark the menu as invisible once the activity finishes as well
|
||||
if (mToActivityMessenger == null) {
|
||||
final boolean resize = msg.arg1 != 0;
|
||||
onMenuStateChanged(MENU_STATE_NONE, resize, null /* callback */);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
private Messenger mMessenger = new Messenger(mHandler);
|
||||
|
||||
private Runnable mStartActivityRequestedTimeoutRunnable = () -> {
|
||||
setStartActivityRequested(false);
|
||||
if (mOnAnimationEndRunnable != null) {
|
||||
mOnAnimationEndRunnable.run();
|
||||
mOnAnimationEndRunnable = null;
|
||||
}
|
||||
Log.e(TAG, "Expected start menu activity request timed out");
|
||||
};
|
||||
private PipMenuView mPipMenuView;
|
||||
|
||||
private ActionListener mMediaActionListener = new ActionListener() {
|
||||
@Override
|
||||
@@ -187,39 +103,40 @@ public class PipMenuActivityController {
|
||||
}
|
||||
};
|
||||
|
||||
public PipMenuActivityController(Context context, Class<?> pipMenuActivityClass,
|
||||
PipMediaController mediaController, InputConsumerController inputConsumerController
|
||||
public PipMenuActivityController(Context context,
|
||||
PipMediaController mediaController, InputConsumerController inputConsumerController,
|
||||
PipTaskOrganizer pipTaskOrganizer
|
||||
) {
|
||||
mContext = context;
|
||||
mMediaController = mediaController;
|
||||
mInputConsumerController = inputConsumerController;
|
||||
mPipMenuActivityClass = pipMenuActivityClass;
|
||||
mPipTaskOrganizer = pipTaskOrganizer;
|
||||
}
|
||||
|
||||
public boolean isMenuActivityVisible() {
|
||||
return mToActivityMessenger != null;
|
||||
public boolean isMenuVisible() {
|
||||
return mPipMenuView != null && mMenuState != MENU_STATE_NONE;
|
||||
}
|
||||
|
||||
public void onActivityPinned() {
|
||||
if (mPipMenuView == null) {
|
||||
WindowManager.LayoutParams lp =
|
||||
getPipMenuLayoutParams(0, 0);
|
||||
mPipMenuView = new PipMenuView(mContext, this);
|
||||
mPipTaskOrganizer.attachPipMenuViewHost(mPipMenuView, lp);
|
||||
}
|
||||
mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
|
||||
}
|
||||
|
||||
public void onActivityUnpinned() {
|
||||
hideMenu();
|
||||
mInputConsumerController.unregisterInputConsumer();
|
||||
setStartActivityRequested(false);
|
||||
mPipTaskOrganizer.detachPipMenuViewHost();
|
||||
mPipMenuView = null;
|
||||
}
|
||||
|
||||
public void onPinnedStackAnimationEnded() {
|
||||
// Note: Only active menu activities care about this event
|
||||
if (mToActivityMessenger != null) {
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivity.MESSAGE_ANIMATION_ENDED;
|
||||
try {
|
||||
mToActivityMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not notify menu pinned animation ended", e);
|
||||
}
|
||||
if (isMenuVisible()) {
|
||||
mPipMenuView.onPipAnimationEnded();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,27 +153,13 @@ public class PipMenuActivityController {
|
||||
* Updates the appearance of the menu and scrim on top of the PiP while dismissing.
|
||||
*/
|
||||
public void setDismissFraction(float fraction) {
|
||||
final boolean isMenuVisible = isMenuVisible();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "setDismissFraction() hasActivity=" + (mToActivityMessenger != null)
|
||||
Log.d(TAG, "setDismissFraction() isMenuVisible=" + isMenuVisible
|
||||
+ " fraction=" + fraction);
|
||||
}
|
||||
if (mToActivityMessenger != null) {
|
||||
mTmpDismissFractionData.clear();
|
||||
mTmpDismissFractionData.putFloat(EXTRA_DISMISS_FRACTION, fraction);
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivity.MESSAGE_UPDATE_DISMISS_FRACTION;
|
||||
m.obj = mTmpDismissFractionData;
|
||||
try {
|
||||
mToActivityMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not notify menu to update dismiss fraction", e);
|
||||
}
|
||||
} else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
|
||||
// If we haven't requested the start activity, or if it previously took too long to
|
||||
// start, then start it
|
||||
startMenuActivity(MENU_STATE_NONE, null /* stackBounds */,
|
||||
false /* allowMenuTimeout */, false /* resizeMenuOnShow */,
|
||||
false /* withDelay */, false /* showResizeHandle */);
|
||||
if (isMenuVisible) {
|
||||
mPipMenuView.updateDismissFraction(fraction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,27 +185,11 @@ public class PipMenuActivityController {
|
||||
false /* withDelay */, showResizeHandle);
|
||||
}
|
||||
|
||||
private Runnable getMenuStateChangeFinishedCallback(@Nullable Messenger replyTo,
|
||||
@Nullable Bundle data) {
|
||||
if (replyTo == null || data == null) {
|
||||
return null;
|
||||
}
|
||||
return () -> {
|
||||
try {
|
||||
final Message m = Message.obtain();
|
||||
m.what = data.getInt(EXTRA_MESSAGE_CALLBACK_WHAT);
|
||||
replyTo.send(m);
|
||||
} catch (RemoteException e) {
|
||||
// ignored
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void showMenuInternal(int menuState, Rect stackBounds, boolean allowMenuTimeout,
|
||||
boolean willResizeMenu, boolean withDelay, boolean showResizeHandle) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "showMenu() state=" + menuState
|
||||
+ " hasActivity=" + (mToActivityMessenger != null)
|
||||
+ " isMenuVisible=" + isMenuVisible()
|
||||
+ " allowMenuTimeout=" + allowMenuTimeout
|
||||
+ " willResizeMenu=" + willResizeMenu
|
||||
+ " withDelay=" + withDelay
|
||||
@@ -310,64 +197,34 @@ public class PipMenuActivityController {
|
||||
+ " callers=\n" + Debug.getCallers(5, " "));
|
||||
}
|
||||
|
||||
if (mToActivityMessenger != null) {
|
||||
Bundle data = new Bundle();
|
||||
data.putInt(EXTRA_MENU_STATE, menuState);
|
||||
if (stackBounds != null) {
|
||||
data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
|
||||
}
|
||||
data.putBoolean(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
|
||||
data.putBoolean(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
|
||||
data.putBoolean(EXTRA_SHOW_MENU_WITH_DELAY, withDelay);
|
||||
data.putBoolean(EXTRA_SHOW_RESIZE_HANDLE, showResizeHandle);
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivity.MESSAGE_SHOW_MENU;
|
||||
m.obj = data;
|
||||
try {
|
||||
mToActivityMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not notify menu to show", e);
|
||||
}
|
||||
} else if (!mStartActivityRequested || isStartActivityRequestedElapsed()) {
|
||||
// If we haven't requested the start activity, or if it previously took too long to
|
||||
// start, then start it
|
||||
startMenuActivity(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
|
||||
showResizeHandle);
|
||||
if (mPipMenuView == null) {
|
||||
Log.e(TAG, "PipMenu has not been attached yet.");
|
||||
return;
|
||||
}
|
||||
mPipMenuView.showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
|
||||
showResizeHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pokes the menu, indicating that the user is interacting with it.
|
||||
*/
|
||||
public void pokeMenu() {
|
||||
final boolean isMenuVisible = isMenuVisible();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "pokeMenu() hasActivity=" + (mToActivityMessenger != null));
|
||||
Log.d(TAG, "pokeMenu() isMenuVisible=" + isMenuVisible);
|
||||
}
|
||||
if (mToActivityMessenger != null) {
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivity.MESSAGE_POKE_MENU;
|
||||
try {
|
||||
mToActivityMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not notify poke menu", e);
|
||||
}
|
||||
if (isMenuVisible) {
|
||||
mPipMenuView.pokeMenu();
|
||||
}
|
||||
}
|
||||
|
||||
private void fadeOutMenu() {
|
||||
final boolean isMenuVisible = isMenuVisible();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "fadeOutMenu() state=" + mMenuState
|
||||
+ " hasActivity=" + (mToActivityMessenger != null)
|
||||
+ " callers=\n" + Debug.getCallers(5, " "));
|
||||
Log.d(TAG, "fadeOutMenu() isMenuVisible=" + isMenuVisible);
|
||||
}
|
||||
if (mToActivityMessenger != null) {
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivity.MESSAGE_FADE_OUT_MENU;
|
||||
try {
|
||||
mToActivityMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not notify menu to fade out", e);
|
||||
}
|
||||
if (isMenuVisible) {
|
||||
mPipMenuView.fadeOutMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,19 +232,14 @@ public class PipMenuActivityController {
|
||||
* Hides the menu activity.
|
||||
*/
|
||||
public void hideMenu() {
|
||||
final boolean isMenuVisible = isMenuVisible();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "hideMenu() state=" + mMenuState
|
||||
+ " hasActivity=" + (mToActivityMessenger != null)
|
||||
+ " isMenuVisible=" + isMenuVisible
|
||||
+ " callers=\n" + Debug.getCallers(5, " "));
|
||||
}
|
||||
if (mToActivityMessenger != null) {
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
|
||||
try {
|
||||
mToActivityMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not notify menu to hide", e);
|
||||
}
|
||||
if (isMenuVisible) {
|
||||
mPipMenuView.hideMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,29 +247,11 @@ public class PipMenuActivityController {
|
||||
* Hides the menu activity.
|
||||
*/
|
||||
public void hideMenu(Runnable onStartCallback, Runnable onEndCallback) {
|
||||
if (mStartActivityRequested) {
|
||||
// If the menu has been start-requested, but not actually started, then we defer the
|
||||
// trigger callback until the menu has started and called back to the controller.
|
||||
mOnAnimationEndRunnable = onEndCallback;
|
||||
onStartCallback.run();
|
||||
|
||||
// Fallback for b/63752800, we have started the PipMenuActivity but it has not made any
|
||||
// callbacks. Don't continue to wait for the menu to show past some timeout.
|
||||
mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
|
||||
mHandler.postDelayed(mStartActivityRequestedTimeoutRunnable,
|
||||
START_ACTIVITY_REQUEST_TIMEOUT_MS);
|
||||
} else if (mMenuState != MENU_STATE_NONE && mToActivityMessenger != null) {
|
||||
if (isMenuVisible()) {
|
||||
// If the menu is visible in either the closed or full state, then hide the menu and
|
||||
// trigger the animation trigger afterwards
|
||||
onStartCallback.run();
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivity.MESSAGE_HIDE_MENU;
|
||||
m.obj = onEndCallback;
|
||||
try {
|
||||
mToActivityMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not notify hide menu", e);
|
||||
}
|
||||
mPipMenuView.hideMenu(onEndCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,6 +272,18 @@ public class PipMenuActivityController {
|
||||
updateMenuActions();
|
||||
}
|
||||
|
||||
void onPipExpand() {
|
||||
mListeners.forEach(Listener::onPipExpand);
|
||||
}
|
||||
|
||||
void onPipDismiss() {
|
||||
mListeners.forEach(Listener::onPipDismiss);
|
||||
}
|
||||
|
||||
void onPipShowMenu() {
|
||||
mListeners.forEach(Listener::onPipShowMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the best set of actions to show in the PiP menu.
|
||||
*/
|
||||
@@ -449,47 +295,20 @@ public class PipMenuActivityController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the menu activity on the top task of the pinned stack.
|
||||
* Returns a default LayoutParams for the PIP Menu.
|
||||
* @param width the PIP stack width.
|
||||
* @param height the PIP stack height.
|
||||
*/
|
||||
private void startMenuActivity(int menuState, Rect stackBounds, boolean allowMenuTimeout,
|
||||
boolean willResizeMenu, boolean withDelay, boolean showResizeHandle) {
|
||||
try {
|
||||
StackInfo pinnedStackInfo = ActivityTaskManager.getService().getStackInfo(
|
||||
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
|
||||
if (pinnedStackInfo != null && pinnedStackInfo.taskIds != null &&
|
||||
pinnedStackInfo.taskIds.length > 0) {
|
||||
Intent intent = new Intent(mContext, mPipMenuActivityClass);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.putExtra(EXTRA_CONTROLLER_MESSENGER, mMessenger);
|
||||
intent.putExtra(EXTRA_ACTIONS, resolveMenuActions());
|
||||
if (stackBounds != null) {
|
||||
intent.putExtra(EXTRA_STACK_BOUNDS, stackBounds);
|
||||
}
|
||||
intent.putExtra(EXTRA_MENU_STATE, menuState);
|
||||
intent.putExtra(EXTRA_ALLOW_TIMEOUT, allowMenuTimeout);
|
||||
intent.putExtra(EXTRA_WILL_RESIZE_MENU, willResizeMenu);
|
||||
intent.putExtra(EXTRA_SHOW_MENU_WITH_DELAY, withDelay);
|
||||
intent.putExtra(EXTRA_SHOW_RESIZE_HANDLE, showResizeHandle);
|
||||
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
|
||||
options.setLaunchTaskId(
|
||||
pinnedStackInfo.taskIds[pinnedStackInfo.taskIds.length - 1]);
|
||||
options.setTaskOverlay(true, true /* canResume */);
|
||||
mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
|
||||
setStartActivityRequested(true);
|
||||
} else {
|
||||
Log.e(TAG, "No PIP tasks found");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
setStartActivityRequested(false);
|
||||
Log.e(TAG, "Error showing PIP menu activity", e);
|
||||
}
|
||||
public static WindowManager.LayoutParams getPipMenuLayoutParams(int width, int height) {
|
||||
return new WindowManager.LayoutParams(width, height,
|
||||
WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSLUCENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the PiP menu activity with the best set of actions provided.
|
||||
* Updates the PiP menu with the best set of actions provided.
|
||||
*/
|
||||
private void updateMenuActions() {
|
||||
if (mToActivityMessenger != null) {
|
||||
if (isMenuVisible()) {
|
||||
// Fetch the pinned stack bounds
|
||||
Rect stackBounds = null;
|
||||
try {
|
||||
@@ -499,20 +318,10 @@ public class PipMenuActivityController {
|
||||
stackBounds = pinnedStackInfo.bounds;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error showing PIP menu activity", e);
|
||||
Log.e(TAG, "Error showing PIP menu", e);
|
||||
}
|
||||
|
||||
Bundle data = new Bundle();
|
||||
data.putParcelable(EXTRA_STACK_BOUNDS, stackBounds);
|
||||
data.putParcelable(EXTRA_ACTIONS, resolveMenuActions());
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivity.MESSAGE_UPDATE_ACTIONS;
|
||||
m.obj = data;
|
||||
try {
|
||||
mToActivityMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not notify menu activity to update actions", e);
|
||||
}
|
||||
mPipMenuView.setActions(stackBounds, resolveMenuActions().getList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,18 +332,10 @@ public class PipMenuActivityController {
|
||||
return actions != null && actions.getList().size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the time of the activity request has exceeded the timeout.
|
||||
*/
|
||||
private boolean isStartActivityRequestedElapsed() {
|
||||
return (SystemClock.uptimeMillis() - mStartActivityRequestedTime)
|
||||
>= START_ACTIVITY_REQUEST_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changes in menu visibility.
|
||||
*/
|
||||
private void onMenuStateChanged(int menuState, boolean resize, Runnable callback) {
|
||||
void onMenuStateChanged(int menuState, boolean resize, Runnable callback) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onMenuStateChanged() mMenuState=" + mMenuState
|
||||
+ " menuState=" + menuState + " resize=" + resize
|
||||
@@ -556,25 +357,14 @@ public class PipMenuActivityController {
|
||||
mMenuState = menuState;
|
||||
}
|
||||
|
||||
private void setStartActivityRequested(boolean requested) {
|
||||
mHandler.removeCallbacks(mStartActivityRequestedTimeoutRunnable);
|
||||
mStartActivityRequested = requested;
|
||||
mStartActivityRequestedTime = requested ? SystemClock.uptimeMillis() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a pointer event sent from pip input consumer.
|
||||
*/
|
||||
void handlePointerEvent(MotionEvent ev) {
|
||||
if (mToActivityMessenger != null) {
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivity.MESSAGE_POINTER_EVENT;
|
||||
m.obj = ev;
|
||||
try {
|
||||
mToActivityMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not dispatch touch event", e);
|
||||
}
|
||||
if (ev.isTouchEvent()) {
|
||||
mPipMenuView.dispatchTouchEvent(ev);
|
||||
} else {
|
||||
mPipMenuView.dispatchGenericMotionEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,15 +372,14 @@ public class PipMenuActivityController {
|
||||
* Tell the PIP Menu to recalculate its layout given its current position on the display.
|
||||
*/
|
||||
public void updateMenuLayout(Rect bounds) {
|
||||
if (mToActivityMessenger != null) {
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivity.MESSAGE_UPDATE_MENU_LAYOUT;
|
||||
m.obj = bounds;
|
||||
try {
|
||||
mToActivityMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not dispatch touch event", e);
|
||||
}
|
||||
final boolean isMenuVisible = isMenuVisible();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "updateMenuLayout() state=" + mMenuState
|
||||
+ " isMenuVisible=" + isMenuVisible
|
||||
+ " callers=\n" + Debug.getCallers(5, " "));
|
||||
}
|
||||
if (isMenuVisible) {
|
||||
mPipMenuView.updateMenuLayout(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,9 +387,7 @@ public class PipMenuActivityController {
|
||||
final String innerPrefix = prefix + " ";
|
||||
pw.println(prefix + TAG);
|
||||
pw.println(innerPrefix + "mMenuState=" + mMenuState);
|
||||
pw.println(innerPrefix + "mToActivityMessenger=" + mToActivityMessenger);
|
||||
pw.println(innerPrefix + "mPipMenuView=" + mPipMenuView);
|
||||
pw.println(innerPrefix + "mListeners=" + mListeners.size());
|
||||
pw.println(innerPrefix + "mStartActivityRequested=" + mStartActivityRequested);
|
||||
pw.println(innerPrefix + "mStartActivityRequestedTime=" + mStartActivityRequestedTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
* Copyright (C) 2020 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.
|
||||
@@ -11,7 +11,7 @@
|
||||
* 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
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.pip.phone;
|
||||
@@ -23,15 +23,6 @@ import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTR
|
||||
import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
|
||||
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
|
||||
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ACTIONS;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_ALLOW_TIMEOUT;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_CONTROLLER_MESSENGER;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_DISMISS_FRACTION;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_MENU_STATE;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_SHOW_MENU_WITH_DELAY;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_SHOW_RESIZE_HANDLE;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_STACK_BOUNDS;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.EXTRA_WILL_RESIZE_MENU;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
|
||||
import static com.android.systemui.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
|
||||
@@ -41,14 +32,12 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.PendingIntent.CanceledException;
|
||||
import android.app.RemoteAction;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
@@ -56,10 +45,6 @@ import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
@@ -68,7 +53,6 @@ import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -76,32 +60,20 @@ import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.systemui.Interpolators;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.systemui.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Translucent activity that gets started on top of a task in PIP to allow the user to control it.
|
||||
* TODO(b/150319024): PipMenuActivity will move to a Window
|
||||
* Translucent window that gets started on top of a task in PIP to allow the user to control it.
|
||||
*/
|
||||
public class PipMenuActivity extends Activity {
|
||||
public class PipMenuView extends FrameLayout {
|
||||
|
||||
private static final String TAG = "PipMenuActivity";
|
||||
private static final String TAG = "PipMenuView";
|
||||
|
||||
private static final int MESSAGE_INVALID_TYPE = -1;
|
||||
|
||||
public static final int MESSAGE_SHOW_MENU = 1;
|
||||
public static final int MESSAGE_POKE_MENU = 2;
|
||||
public static final int MESSAGE_HIDE_MENU = 3;
|
||||
public static final int MESSAGE_UPDATE_ACTIONS = 4;
|
||||
public static final int MESSAGE_UPDATE_DISMISS_FRACTION = 5;
|
||||
public static final int MESSAGE_ANIMATION_ENDED = 6;
|
||||
public static final int MESSAGE_POINTER_EVENT = 7;
|
||||
public static final int MESSAGE_MENU_EXPANDED = 8;
|
||||
public static final int MESSAGE_FADE_OUT_MENU = 9;
|
||||
public static final int MESSAGE_UPDATE_MENU_LAYOUT = 10;
|
||||
|
||||
private static final int INITIAL_DISMISS_DELAY = 3500;
|
||||
private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
|
||||
@@ -130,85 +102,20 @@ public class PipMenuActivity extends Activity {
|
||||
private int mBetweenActionPaddingLand;
|
||||
|
||||
private AnimatorSet mMenuContainerAnimator;
|
||||
private PipMenuActivityController mController;
|
||||
|
||||
private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
|
||||
new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
final float alpha = (float) animation.getAnimatedValue();
|
||||
mBackgroundDrawable.setAlpha((int) (MENU_BACKGROUND_ALPHA*alpha*255));
|
||||
mBackgroundDrawable.setAlpha((int) (MENU_BACKGROUND_ALPHA * alpha * 255));
|
||||
}
|
||||
};
|
||||
|
||||
private Handler mHandler = new Handler(Looper.getMainLooper()) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MESSAGE_SHOW_MENU: {
|
||||
final Bundle data = (Bundle) msg.obj;
|
||||
showMenu(data.getInt(EXTRA_MENU_STATE),
|
||||
data.getParcelable(EXTRA_STACK_BOUNDS),
|
||||
data.getBoolean(EXTRA_ALLOW_TIMEOUT),
|
||||
data.getBoolean(EXTRA_WILL_RESIZE_MENU),
|
||||
data.getBoolean(EXTRA_SHOW_MENU_WITH_DELAY),
|
||||
data.getBoolean(EXTRA_SHOW_RESIZE_HANDLE));
|
||||
break;
|
||||
}
|
||||
case MESSAGE_POKE_MENU:
|
||||
cancelDelayedFinish();
|
||||
break;
|
||||
case MESSAGE_HIDE_MENU:
|
||||
hideMenu((Runnable) msg.obj);
|
||||
break;
|
||||
case MESSAGE_UPDATE_ACTIONS: {
|
||||
final Bundle data = (Bundle) msg.obj;
|
||||
final ParceledListSlice<RemoteAction> actions = data.getParcelable(
|
||||
EXTRA_ACTIONS);
|
||||
setActions(data.getParcelable(EXTRA_STACK_BOUNDS), actions != null
|
||||
? actions.getList() : Collections.emptyList());
|
||||
break;
|
||||
}
|
||||
case MESSAGE_UPDATE_DISMISS_FRACTION: {
|
||||
final Bundle data = (Bundle) msg.obj;
|
||||
updateDismissFraction(data.getFloat(EXTRA_DISMISS_FRACTION));
|
||||
break;
|
||||
}
|
||||
case MESSAGE_ANIMATION_ENDED: {
|
||||
mAllowTouches = true;
|
||||
break;
|
||||
}
|
||||
case MESSAGE_POINTER_EVENT: {
|
||||
final MotionEvent ev = (MotionEvent) msg.obj;
|
||||
dispatchPointerEvent(ev);
|
||||
break;
|
||||
}
|
||||
case MESSAGE_MENU_EXPANDED : {
|
||||
if (mMenuContainerAnimator == null) {
|
||||
return;
|
||||
}
|
||||
mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
|
||||
mMenuContainerAnimator.start();
|
||||
break;
|
||||
}
|
||||
case MESSAGE_FADE_OUT_MENU: {
|
||||
fadeOutMenu();
|
||||
break;
|
||||
}
|
||||
case MESSAGE_UPDATE_MENU_LAYOUT: {
|
||||
if (mPipMenuIconsAlgorithm == null) {
|
||||
return;
|
||||
}
|
||||
final Rect bounds = (Rect) msg.obj;
|
||||
mPipMenuIconsAlgorithm.onBoundsChanged(bounds);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
private Messenger mToControllerMessenger;
|
||||
private Messenger mMessenger = new Messenger(mHandler);
|
||||
private Handler mHandler = new Handler();
|
||||
|
||||
private final Runnable mFinishRunnable = this::hideMenu;
|
||||
private final Runnable mHideMenuRunnable = this::hideMenu;
|
||||
|
||||
protected View mViewRoot;
|
||||
protected View mSettingsButton;
|
||||
@@ -217,17 +124,14 @@ public class PipMenuActivity extends Activity {
|
||||
protected View mTopEndContainer;
|
||||
protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
// Set the flags to allow us to watch for outside touches and also hide the menu and start
|
||||
// manipulating the PIP in the same touch gesture
|
||||
getWindow().addFlags(LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
|
||||
public PipMenuView(Context context, PipMenuActivityController controller) {
|
||||
super(context, null, 0);
|
||||
mContext = context;
|
||||
mController = controller;
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
|
||||
inflate(context, R.layout.pip_menu, this);
|
||||
|
||||
setContentView(R.layout.pip_menu_activity);
|
||||
|
||||
mAccessibilityManager = getSystemService(AccessibilityManager.class);
|
||||
mBackgroundDrawable = new ColorDrawable(Color.BLACK);
|
||||
mBackgroundDrawable.setAlpha(0);
|
||||
mViewRoot = findViewById(R.id.background);
|
||||
@@ -250,26 +154,25 @@ public class PipMenuActivity extends Activity {
|
||||
expandPip();
|
||||
}
|
||||
});
|
||||
// TODO (b/161710689): Remove this once focusability for Windowless window is working
|
||||
findViewById(R.id.expand_button).setFocusable(false);
|
||||
mDismissButton.setFocusable(false);
|
||||
mSettingsButton.setFocusable(false);
|
||||
|
||||
mResizeHandle = findViewById(R.id.resize_handle);
|
||||
mResizeHandle.setAlpha(0);
|
||||
mActionsGroup = findViewById(R.id.actions_group);
|
||||
mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
|
||||
R.dimen.pip_between_action_padding_land);
|
||||
mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(this.getApplicationContext());
|
||||
mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(mContext);
|
||||
mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
|
||||
mResizeHandle, mSettingsButton, mDismissButton);
|
||||
updateFromIntent(getIntent());
|
||||
setTitle(R.string.pip_menu_title);
|
||||
setDisablePreviewScreenshots(true);
|
||||
|
||||
// Hide without an animation.
|
||||
getWindow().setExitTransition(null);
|
||||
|
||||
initAccessibility();
|
||||
}
|
||||
|
||||
private void initAccessibility() {
|
||||
getWindow().getDecorView().setAccessibilityDelegate(new View.AccessibilityDelegate() {
|
||||
this.setAccessibilityDelegate(new View.AccessibilityDelegate() {
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||
@@ -280,9 +183,7 @@ public class PipMenuActivity extends Activity {
|
||||
@Override
|
||||
public boolean performAccessibilityAction(View host, int action, Bundle args) {
|
||||
if (action == ACTION_CLICK && mMenuState == MENU_STATE_CLOSE) {
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivityController.MESSAGE_SHOW_MENU;
|
||||
sendMessage(m, "Could not notify controller to show PIP menu");
|
||||
mController.onPipShowMenu();
|
||||
}
|
||||
return super.performAccessibilityAction(host, action, args);
|
||||
}
|
||||
@@ -298,109 +199,38 @@ public class PipMenuActivity extends Activity {
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
updateFromIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserInteraction() {
|
||||
if (mAllowMenuTimeout) {
|
||||
repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUserLeaveHint() {
|
||||
super.onUserLeaveHint();
|
||||
|
||||
// If another task is starting on top of the menu, then hide and finish it so that it can be
|
||||
// recreated on the top next time it starts
|
||||
hideMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
|
||||
super.onTopResumedActivityChanged(isTopResumedActivity);
|
||||
if (!isTopResumedActivity && mMenuState != MENU_STATE_NONE) {
|
||||
hideMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
|
||||
// In cases such as device lock, hide and finish it so that it can be recreated on the top
|
||||
// next time it starts, see also {@link #onUserLeaveHint}
|
||||
hideMenu();
|
||||
cancelDelayedFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
// Fallback, if we are destroyed for any other reason (like when the task is being reset),
|
||||
// also reset the callback.
|
||||
notifyActivityCallback(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
|
||||
if (!isInPictureInPictureMode) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a pointer event from {@link PipTouchHandler}.
|
||||
*/
|
||||
private void dispatchPointerEvent(MotionEvent event) {
|
||||
if (event.isTouchEvent()) {
|
||||
dispatchTouchEvent(event);
|
||||
} else {
|
||||
dispatchGenericMotionEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (!mAllowTouches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// On the first action outside the window, hide the menu
|
||||
switch (ev.getAction()) {
|
||||
case MotionEvent.ACTION_OUTSIDE:
|
||||
hideMenu();
|
||||
return true;
|
||||
if (mAllowMenuTimeout) {
|
||||
repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
|
||||
}
|
||||
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
notifyActivityCallback(null);
|
||||
super.finish();
|
||||
public boolean dispatchGenericMotionEvent(MotionEvent event) {
|
||||
if (mAllowMenuTimeout) {
|
||||
repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
|
||||
}
|
||||
|
||||
return super.dispatchGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
private void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
|
||||
void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
|
||||
boolean resizeMenuOnShow, boolean withDelay, boolean showResizeHandle) {
|
||||
mAllowMenuTimeout = allowMenuTimeout;
|
||||
if (mMenuState != menuState) {
|
||||
// Disallow touches if the menu needs to resize while showing, and we are transitioning
|
||||
// to/from a full menu state.
|
||||
boolean disallowTouchesUntilAnimationEnd = resizeMenuOnShow &&
|
||||
(mMenuState == MENU_STATE_FULL || menuState == MENU_STATE_FULL);
|
||||
boolean disallowTouchesUntilAnimationEnd = resizeMenuOnShow
|
||||
&& (mMenuState == MENU_STATE_FULL || menuState == MENU_STATE_FULL);
|
||||
mAllowTouches = !disallowTouchesUntilAnimationEnd;
|
||||
cancelDelayedFinish();
|
||||
cancelDelayedHide();
|
||||
updateActionViews(stackBounds);
|
||||
if (mMenuContainerAnimator != null) {
|
||||
mMenuContainerAnimator.cancel();
|
||||
@@ -431,22 +261,28 @@ public class PipMenuActivity extends Activity {
|
||||
mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
repostDelayedFinish(INITIAL_DISMISS_DELAY);
|
||||
repostDelayedHide(INITIAL_DISMISS_DELAY);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (withDelay) {
|
||||
// starts the menu container animation after window expansion is completed
|
||||
notifyMenuStateChange(menuState, resizeMenuOnShow, MESSAGE_MENU_EXPANDED);
|
||||
notifyMenuStateChange(menuState, resizeMenuOnShow, () -> {
|
||||
if (mMenuContainerAnimator == null) {
|
||||
return;
|
||||
}
|
||||
mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
|
||||
mMenuContainerAnimator.start();
|
||||
});
|
||||
} else {
|
||||
notifyMenuStateChange(menuState, resizeMenuOnShow, MESSAGE_INVALID_TYPE);
|
||||
notifyMenuStateChange(menuState, resizeMenuOnShow, null);
|
||||
mMenuContainerAnimator.start();
|
||||
}
|
||||
} else {
|
||||
// If we are already visible, then just start the delayed dismiss and unregister any
|
||||
// existing input consumers from the previous drag
|
||||
if (allowMenuTimeout) {
|
||||
repostDelayedFinish(POST_INTERACTION_DISMISS_DELAY);
|
||||
repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -456,28 +292,39 @@ public class PipMenuActivity extends Activity {
|
||||
* and instead, it fades out the controls by setting the alpha to 0 directly without menu
|
||||
* visibility callbacks invoked.
|
||||
*/
|
||||
private void fadeOutMenu() {
|
||||
void fadeOutMenu() {
|
||||
mMenuContainer.setAlpha(0f);
|
||||
mSettingsButton.setAlpha(0f);
|
||||
mDismissButton.setAlpha(0f);
|
||||
mResizeHandle.setAlpha(0f);
|
||||
}
|
||||
|
||||
private void hideMenu() {
|
||||
void pokeMenu() {
|
||||
cancelDelayedHide();
|
||||
}
|
||||
|
||||
void onPipAnimationEnded() {
|
||||
mAllowTouches = true;
|
||||
}
|
||||
|
||||
void updateMenuLayout(Rect bounds) {
|
||||
mPipMenuIconsAlgorithm.onBoundsChanged(bounds);
|
||||
}
|
||||
|
||||
void hideMenu() {
|
||||
hideMenu(null);
|
||||
}
|
||||
|
||||
private void hideMenu(Runnable animationEndCallback) {
|
||||
hideMenu(animationEndCallback, true /* notifyMenuVisibility */, false /* isDismissing */,
|
||||
true /* animate */);
|
||||
void hideMenu(Runnable animationEndCallback) {
|
||||
hideMenu(animationEndCallback, true /* notifyMenuVisibility */, false);
|
||||
}
|
||||
|
||||
private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
|
||||
boolean isDismissing, boolean animate) {
|
||||
boolean animate) {
|
||||
if (mMenuState != MENU_STATE_NONE) {
|
||||
cancelDelayedFinish();
|
||||
cancelDelayedHide();
|
||||
if (notifyMenuVisibility) {
|
||||
notifyMenuStateChange(MENU_STATE_NONE, mResize, MESSAGE_INVALID_TYPE);
|
||||
notifyMenuStateChange(MENU_STATE_NONE, mResize, null);
|
||||
}
|
||||
mMenuContainerAnimator = new AnimatorSet();
|
||||
ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
|
||||
@@ -498,49 +345,13 @@ public class PipMenuActivity extends Activity {
|
||||
if (animationFinishedRunnable != null) {
|
||||
animationFinishedRunnable.run();
|
||||
}
|
||||
|
||||
if (!isDismissing) {
|
||||
// If we are dismissing the PiP, then don't try to pre-emptively finish the
|
||||
// menu activity
|
||||
finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
mMenuContainerAnimator.start();
|
||||
} else {
|
||||
// If the menu is not visible, just finish now
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFromIntent(Intent intent) {
|
||||
mToControllerMessenger = intent.getParcelableExtra(EXTRA_CONTROLLER_MESSENGER);
|
||||
if (mToControllerMessenger == null) {
|
||||
Log.w(TAG, "Controller messenger is null. Stopping.");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
notifyActivityCallback(mMessenger);
|
||||
|
||||
ParceledListSlice<RemoteAction> actions = intent.getParcelableExtra(EXTRA_ACTIONS);
|
||||
if (actions != null) {
|
||||
mActions.clear();
|
||||
mActions.addAll(actions.getList());
|
||||
}
|
||||
|
||||
final int menuState = intent.getIntExtra(EXTRA_MENU_STATE, MENU_STATE_NONE);
|
||||
if (menuState != MENU_STATE_NONE) {
|
||||
Rect stackBounds = intent.getParcelableExtra(EXTRA_STACK_BOUNDS);
|
||||
boolean allowMenuTimeout = intent.getBooleanExtra(EXTRA_ALLOW_TIMEOUT, true);
|
||||
boolean willResizeMenu = intent.getBooleanExtra(EXTRA_WILL_RESIZE_MENU, false);
|
||||
boolean withDelay = intent.getBooleanExtra(EXTRA_SHOW_MENU_WITH_DELAY, false);
|
||||
boolean showResizeHandle = intent.getBooleanExtra(EXTRA_SHOW_RESIZE_HANDLE, false);
|
||||
showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
|
||||
showResizeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
private void setActions(Rect stackBounds, List<RemoteAction> actions) {
|
||||
void setActions(Rect stackBounds, List<RemoteAction> actions) {
|
||||
mActions.clear();
|
||||
mActions.addAll(actions);
|
||||
updateActionViews(stackBounds);
|
||||
@@ -560,7 +371,7 @@ public class PipMenuActivity extends Activity {
|
||||
actionsContainer.setVisibility(View.VISIBLE);
|
||||
if (mActionsGroup != null) {
|
||||
// Ensure we have as many buttons as actions
|
||||
final LayoutInflater inflater = LayoutInflater.from(this);
|
||||
final LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
while (mActionsGroup.getChildCount() < mActions.size()) {
|
||||
final ImageButton actionView = (ImageButton) inflater.inflate(
|
||||
R.layout.pip_menu_action, mActionsGroup, false);
|
||||
@@ -575,14 +386,14 @@ public class PipMenuActivity extends Activity {
|
||||
}
|
||||
|
||||
// Recreate the layout
|
||||
final boolean isLandscapePip = stackBounds != null &&
|
||||
(stackBounds.width() > stackBounds.height());
|
||||
final boolean isLandscapePip = stackBounds != null
|
||||
&& (stackBounds.width() > stackBounds.height());
|
||||
for (int i = 0; i < mActions.size(); i++) {
|
||||
final RemoteAction action = mActions.get(i);
|
||||
final ImageButton actionView = (ImageButton) mActionsGroup.getChildAt(i);
|
||||
|
||||
// TODO: Check if the action drawable has changed before we reload it
|
||||
action.getIcon().loadDrawableAsync(this, d -> {
|
||||
action.getIcon().loadDrawableAsync(mContext, d -> {
|
||||
d.setTint(Color.WHITE);
|
||||
actionView.setImageDrawable(d);
|
||||
}, mHandler);
|
||||
@@ -620,7 +431,7 @@ public class PipMenuActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDismissFraction(float fraction) {
|
||||
void updateDismissFraction(float fraction) {
|
||||
int alpha;
|
||||
final float menuAlpha = 1 - fraction;
|
||||
if (mMenuState == MENU_STATE_FULL) {
|
||||
@@ -639,31 +450,15 @@ public class PipMenuActivity extends Activity {
|
||||
mBackgroundDrawable.setAlpha(alpha);
|
||||
}
|
||||
|
||||
private void notifyMenuStateChange(int menuState, boolean resize, int callbackWhat) {
|
||||
private void notifyMenuStateChange(int menuState, boolean resize, Runnable callback) {
|
||||
mMenuState = menuState;
|
||||
mResize = resize;
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivityController.MESSAGE_MENU_STATE_CHANGED;
|
||||
m.arg1 = menuState;
|
||||
m.arg2 = resize ? 1 : 0;
|
||||
if (callbackWhat != MESSAGE_INVALID_TYPE) {
|
||||
// This message could be sent across processes when in secondary user.
|
||||
// Make the receiver end sending back via our own Messenger
|
||||
m.replyTo = mMessenger;
|
||||
final Bundle data = new Bundle(1);
|
||||
data.putInt(PipMenuActivityController.EXTRA_MESSAGE_CALLBACK_WHAT, callbackWhat);
|
||||
m.obj = data;
|
||||
}
|
||||
sendMessage(m, "Could not notify controller of PIP menu visibility");
|
||||
mController.onMenuStateChanged(menuState, resize, callback);
|
||||
}
|
||||
|
||||
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 */, false /* isDismissing */, true /* animate */);
|
||||
hideMenu(mController::onPipExpand, false /* notifyMenuVisibility */, true /* animate */);
|
||||
}
|
||||
|
||||
private void dismissPip() {
|
||||
@@ -673,58 +468,30 @@ public class PipMenuActivity extends Activity {
|
||||
final boolean animate = mMenuState != MENU_STATE_CLOSE;
|
||||
// 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 */, true /* isDismissing */, animate);
|
||||
hideMenu(mController::onPipDismiss, false /* notifyMenuVisibility */, animate);
|
||||
}
|
||||
|
||||
private void showSettings() {
|
||||
final Pair<ComponentName, Integer> topPipActivityInfo =
|
||||
PipUtils.getTopPipActivity(this, ActivityManager.getService());
|
||||
PipUtils.getTopPipActivity(mContext, ActivityManager.getService());
|
||||
if (topPipActivityInfo.first != null) {
|
||||
final UserHandle user = UserHandle.of(topPipActivityInfo.second);
|
||||
final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
|
||||
Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null));
|
||||
settingsIntent.putExtra(Intent.EXTRA_USER_HANDLE, user);
|
||||
settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(settingsIntent);
|
||||
mContext.startActivity(settingsIntent);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyActivityCallback(Messenger callback) {
|
||||
Message m = Message.obtain();
|
||||
m.what = PipMenuActivityController.MESSAGE_UPDATE_ACTIVITY_CALLBACK;
|
||||
m.replyTo = callback;
|
||||
m.arg1 = mResize ? 1 : 0;
|
||||
sendMessage(m, "Could not notify controller of activity finished");
|
||||
private void cancelDelayedHide() {
|
||||
mHandler.removeCallbacks(mHideMenuRunnable);
|
||||
}
|
||||
|
||||
private void sendEmptyMessage(int what, String errorMsg) {
|
||||
Message m = Message.obtain();
|
||||
m.what = what;
|
||||
sendMessage(m, errorMsg);
|
||||
}
|
||||
|
||||
private void sendMessage(Message m, String errorMsg) {
|
||||
if (mToControllerMessenger == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mToControllerMessenger.send(m);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, errorMsg, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelDelayedFinish() {
|
||||
mHandler.removeCallbacks(mFinishRunnable);
|
||||
}
|
||||
|
||||
private void repostDelayedFinish(int delay) {
|
||||
private void repostDelayedHide(int delay) {
|
||||
int recommendedTimeout = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
|
||||
FLAG_CONTENT_ICONS | FLAG_CONTENT_CONTROLS);
|
||||
mHandler.removeCallbacks(mFinishRunnable);
|
||||
mHandler.postDelayed(mFinishRunnable, recommendedTimeout);
|
||||
mHandler.removeCallbacks(mHideMenuRunnable);
|
||||
mHandler.postDelayed(mHideMenuRunnable, recommendedTimeout);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,8 @@ import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Debug;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.Choreographer;
|
||||
|
||||
@@ -66,6 +68,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
private PipMenuActivityController mMenuController;
|
||||
private PipSnapAlgorithm mSnapAlgorithm;
|
||||
|
||||
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
/** PIP's current bounds on the screen. */
|
||||
private final Rect mBounds = new Rect();
|
||||
|
||||
@@ -128,8 +132,10 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
|
||||
|
||||
private final Consumer<Rect> mUpdateBoundsCallback = (Rect newBounds) -> {
|
||||
mMenuController.updateMenuLayout(newBounds);
|
||||
mBounds.set(newBounds);
|
||||
mMainHandler.post(() -> {
|
||||
mMenuController.updateMenuLayout(newBounds);
|
||||
mBounds.set(newBounds);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -253,7 +259,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
mTemporaryBounds.set(toBounds);
|
||||
mPipTaskOrganizer.scheduleUserResizePip(mBounds, mTemporaryBounds,
|
||||
(Rect newBounds) -> {
|
||||
mMenuController.updateMenuLayout(newBounds);
|
||||
mMainHandler.post(() -> {
|
||||
mMenuController.updateMenuLayout(newBounds);
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -111,6 +111,7 @@ public class PipResizeGestureHandler {
|
||||
private InputMonitor mInputMonitor;
|
||||
private InputEventReceiver mInputEventReceiver;
|
||||
private PipTaskOrganizer mPipTaskOrganizer;
|
||||
private PipMenuActivityController mPipMenuActivityController;
|
||||
private PipUiEventLogger mPipUiEventLogger;
|
||||
|
||||
private int mCtrlType;
|
||||
@@ -119,7 +120,7 @@ public class PipResizeGestureHandler {
|
||||
PipMotionHelper motionHelper, DeviceConfigProxy deviceConfig,
|
||||
PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier,
|
||||
Runnable updateMovementBoundsRunnable, SysUiState sysUiState,
|
||||
PipUiEventLogger pipUiEventLogger) {
|
||||
PipUiEventLogger pipUiEventLogger, PipMenuActivityController menuActivityController) {
|
||||
mContext = context;
|
||||
mDisplayId = context.getDisplayId();
|
||||
mMainExecutor = context.getMainExecutor();
|
||||
@@ -129,6 +130,7 @@ public class PipResizeGestureHandler {
|
||||
mMovementBoundsSupplier = movementBoundsSupplier;
|
||||
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
|
||||
mSysUiState = sysUiState;
|
||||
mPipMenuActivityController = menuActivityController;
|
||||
mPipUiEventLogger = pipUiEventLogger;
|
||||
|
||||
context.getDisplay().getRealSize(mMaxSize);
|
||||
@@ -298,6 +300,7 @@ public class PipResizeGestureHandler {
|
||||
float x = ev.getX();
|
||||
float y = ev.getY();
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
final Rect currentPipBounds = mMotionHelper.getBounds();
|
||||
mLastResizeBounds.setEmpty();
|
||||
mAllowGesture = isInValidSysUiState() && isWithinTouchRegion((int) x, (int) y);
|
||||
if (mAllowGesture) {
|
||||
@@ -305,6 +308,10 @@ public class PipResizeGestureHandler {
|
||||
mDownPoint.set(x, y);
|
||||
mLastDownBounds.set(mMotionHelper.getBounds());
|
||||
}
|
||||
if (!currentPipBounds.contains((int) ev.getX(), (int) ev.getY())
|
||||
&& mPipMenuActivityController.isMenuVisible()) {
|
||||
mPipMenuActivityController.hideMenu();
|
||||
}
|
||||
|
||||
} else if (mAllowGesture) {
|
||||
switch (action) {
|
||||
|
||||
@@ -230,7 +230,7 @@ public class PipTouchHandler {
|
||||
mPipResizeGestureHandler =
|
||||
new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
|
||||
deviceConfig, pipTaskOrganizer, this::getMovementBounds,
|
||||
this::updateMovementBounds, sysUiState, pipUiEventLogger);
|
||||
this::updateMovementBounds, sysUiState, pipUiEventLogger, menuController);
|
||||
mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler,
|
||||
() -> mMenuController.showMenuWithDelay(MENU_STATE_FULL, mMotionHelper.getBounds(),
|
||||
true /* allowMenuTimeout */, willResizeMenu(), shouldShowResizeHandle()),
|
||||
@@ -773,10 +773,7 @@ public class PipTouchHandler {
|
||||
* Updates the appearance of the menu and scrim on top of the PiP while dismissing.
|
||||
*/
|
||||
private void updateDismissFraction() {
|
||||
// Skip updating the dismiss fraction when the IME is showing. This is to work around an
|
||||
// issue where starting the menu activity for the dismiss overlay will steal the window
|
||||
// focus, which closes the IME.
|
||||
if (mMenuController != null && !mIsImeShowing) {
|
||||
if (mMenuController != null) {
|
||||
Rect bounds = mMotionHelper.getBounds();
|
||||
final float target = mInsetBounds.bottom;
|
||||
float fraction = 0f;
|
||||
@@ -784,7 +781,7 @@ public class PipTouchHandler {
|
||||
final float distance = bounds.bottom - target;
|
||||
fraction = Math.min(distance / bounds.height(), 1f);
|
||||
}
|
||||
if (Float.compare(fraction, 0f) != 0 || mMenuController.isMenuActivityVisible()) {
|
||||
if (Float.compare(fraction, 0f) != 0 || mMenuController.isMenuVisible()) {
|
||||
// Update if the fraction > 0, or if fraction == 0 and the menu was already visible
|
||||
mMenuController.setDismissFraction(fraction);
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.dagger;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
|
||||
@Qualifier
|
||||
@Documented
|
||||
@Retention(RUNTIME)
|
||||
public @interface PipMenuActivityClass {
|
||||
}
|
||||
@@ -22,8 +22,6 @@ import android.view.IWindowManager;
|
||||
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.pip.phone.PipMenuActivity;
|
||||
import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
|
||||
import com.android.systemui.stackdivider.SplitScreen;
|
||||
import com.android.systemui.stackdivider.SplitScreenController;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
@@ -50,14 +48,6 @@ public class WMShellModule {
|
||||
return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
|
||||
}
|
||||
|
||||
/** TODO(b/150319024): PipMenuActivity will move to a Window */
|
||||
@SysUISingleton
|
||||
@PipMenuActivityClass
|
||||
@Provides
|
||||
static Class<?> providePipMenuActivityClass() {
|
||||
return PipMenuActivity.class;
|
||||
}
|
||||
|
||||
@SysUISingleton
|
||||
@Provides
|
||||
static SplitScreen provideSplitScreen(Context context,
|
||||
|
||||
Reference in New Issue
Block a user