diff options
| author | 2021-11-25 07:18:59 +0000 | |
|---|---|---|
| committer | 2021-11-25 07:18:59 +0000 | |
| commit | a656a4e4e4c4bdc807b4bbe6688fe2d4a1530620 (patch) | |
| tree | d17eef1bec42744449d13f1c1a187296828b4231 | |
| parent | ec0c08c77121261fcf78b9a99088b834b23d280a (diff) | |
| parent | b26f380809919a1f52b46e0ea669deec687cc0e8 (diff) | |
Merge "PiP: Show/hide enter split button based on focused task." into sc-v2-dev
8 files changed, 115 insertions, 5 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index 75bc46125324..7f370367187c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -29,6 +29,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; +import android.app.WindowConfiguration; import android.content.Context; import android.content.LocusId; import android.content.pm.ActivityInfo; @@ -122,6 +123,16 @@ public class ShellTaskOrganizer extends TaskOrganizer implements } /** + * Callbacks for events in which the focus has changed. + */ + public interface FocusListener { + /** + * Notifies when the task which is focused has changed. + */ + void onFocusTaskChanged(RunningTaskInfo taskInfo); + } + + /** * Keys map from either a task id or {@link TaskListenerType}. * @see #addListenerForTaskId * @see #addListenerForType @@ -142,6 +153,8 @@ public class ShellTaskOrganizer extends TaskOrganizer implements /** @see #addLocusIdListener */ private final ArraySet<LocusIdListener> mLocusIdListeners = new ArraySet<>(); + private final ArraySet<FocusListener> mFocusListeners = new ArraySet<>(); + private final Object mLock = new Object(); private StartingWindowController mStartingWindow; @@ -155,6 +168,9 @@ public class ShellTaskOrganizer extends TaskOrganizer implements @Nullable private final Optional<RecentTasksController> mRecentTasks; + @Nullable + private RunningTaskInfo mLastFocusedTaskInfo; + public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context) { this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */, Optional.empty() /* recentTasksController */); @@ -331,6 +347,27 @@ public class ShellTaskOrganizer extends TaskOrganizer implements } } + /** + * Adds a listener to be notified for task focus changes. + */ + public void addFocusListener(FocusListener listener) { + synchronized (mLock) { + mFocusListeners.add(listener); + if (mLastFocusedTaskInfo != null) { + listener.onFocusTaskChanged(mLastFocusedTaskInfo); + } + } + } + + /** + * Removes listener. + */ + public void removeLocusIdListener(FocusListener listener) { + synchronized (mLock) { + mFocusListeners.remove(listener); + } + } + @Override public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { if (mStartingWindow != null) { @@ -422,6 +459,18 @@ public class ShellTaskOrganizer extends TaskOrganizer implements mRecentTasks.ifPresent(recentTasks -> recentTasks.onTaskWindowingModeChanged(taskInfo)); } + // TODO (b/207687679): Remove check for HOME once bug is fixed + final boolean isFocusedOrHome = taskInfo.isFocused + || (taskInfo.topActivityType == WindowConfiguration.ACTIVITY_TYPE_HOME + && taskInfo.isVisible); + final boolean focusTaskChanged = (mLastFocusedTaskInfo == null + || mLastFocusedTaskInfo.taskId != taskInfo.taskId) && isFocusedOrHome; + if (focusTaskChanged) { + for (int i = 0; i < mFocusListeners.size(); i++) { + mFocusListeners.valueAt(i).onFocusTaskChanged(taskInfo); + } + mLastFocusedTaskInfo = taskInfo; + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 46c7b508d6e8..f562fd9cf1af 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -241,10 +241,11 @@ public class WMShellModule { static PhonePipMenuController providesPipPhoneMenuController(Context context, PipBoundsState pipBoundsState, PipMediaController pipMediaController, SystemWindows systemWindows, + Optional<SplitScreenController> splitScreenOptional, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler) { return new PhonePipMenuController(context, pipBoundsState, pipMediaController, - systemWindows, mainExecutor, mainHandler); + systemWindows, splitScreenOptional, mainExecutor, mainHandler); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java index 8d9ad4d1b96c..caa1f017082b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java @@ -90,6 +90,11 @@ public interface PipMenuController { default void updateMenuBounds(Rect destinationBounds) {} /** + * Update when the current focused task changes. + */ + default void onFocusTaskChanged(RunningTaskInfo taskInfo) {} + + /** * Returns a default LayoutParams for the PIP Menu. * @param width the PIP stack width. * @param height the PIP stack height. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index 90135f2a3c69..c2ebc3031b93 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -98,7 +98,7 @@ import java.util.function.IntConsumer; * see also {@link PipMotionHelper}. */ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, - DisplayController.OnDisplaysChangedListener { + DisplayController.OnDisplaysChangedListener, ShellTaskOrganizer.FocusListener { private static final String TAG = PipTaskOrganizer.class.getSimpleName(); private static final boolean DEBUG = false; /** @@ -286,6 +286,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, mMainExecutor.execute(() -> { mTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_PIP); }); + mTaskOrganizer.addFocusListener(this); mPipTransitionController.setPipOrganizer(this); displayController.addDisplayWindowListener(this); } @@ -772,6 +773,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, } @Override + public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) { + mPipMenuController.onFocusTaskChanged(taskInfo); + } + + @Override public boolean supportSizeCompatUI() { // PIP doesn't support size compat. return false; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java index 5687f4d62444..eb512afa644d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java @@ -19,6 +19,7 @@ package com.android.wm.shell.pip.phone; import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.RemoteAction; import android.content.Context; import android.content.pm.ParceledListSlice; @@ -43,10 +44,12 @@ import com.android.wm.shell.pip.PipBoundsState; import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipMediaController.ActionListener; import com.android.wm.shell.pip.PipMenuController; +import com.android.wm.shell.splitscreen.SplitScreenController; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.Optional; /** * Manages the PiP menu view which can show menu options or a scrim. @@ -114,6 +117,7 @@ public class PhonePipMenuController implements PipMenuController { private final ArrayList<Listener> mListeners = new ArrayList<>(); private final SystemWindows mSystemWindows; + private final Optional<SplitScreenController> mSplitScreenController; private ParceledListSlice<RemoteAction> mAppActions; private ParceledListSlice<RemoteAction> mMediaActions; private SyncRtSurfaceTransactionApplier mApplier; @@ -145,6 +149,7 @@ public class PhonePipMenuController implements PipMenuController { public PhonePipMenuController(Context context, PipBoundsState pipBoundsState, PipMediaController mediaController, SystemWindows systemWindows, + Optional<SplitScreenController> splitScreenOptional, ShellExecutor mainExecutor, Handler mainHandler) { mContext = context; mPipBoundsState = pipBoundsState; @@ -152,6 +157,7 @@ public class PhonePipMenuController implements PipMenuController { mSystemWindows = systemWindows; mMainExecutor = mainExecutor; mMainHandler = mainHandler; + mSplitScreenController = splitScreenOptional; } public boolean isMenuVisible() { @@ -180,7 +186,8 @@ public class PhonePipMenuController implements PipMenuController { if (mPipMenuView != null) { detachPipMenuView(); } - mPipMenuView = new PipMenuView(mContext, this, mMainExecutor, mMainHandler); + mPipMenuView = new PipMenuView(mContext, this, mMainExecutor, mMainHandler, + mSplitScreenController); mSystemWindows.addView(mPipMenuView, getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */), 0, SHELL_ROOT_LAYER_PIP); @@ -209,6 +216,13 @@ public class PhonePipMenuController implements PipMenuController { updateMenuLayout(destinationBounds); } + @Override + public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) { + if (mPipMenuView != null) { + mPipMenuView.onFocusTaskChanged(taskInfo); + } + } + /** * Tries to grab a surface control from {@link PipMenuView}. If this isn't available for some * reason (ie. the window isn't ready yet, thus {@link android.view.ViewRootImpl} is diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java index b209699c1a19..82e827398bb7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java @@ -16,6 +16,7 @@ package com.android.wm.shell.pip.phone; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.provider.Settings.ACTION_PICTURE_IN_PICTURE_SETTINGS; @@ -32,8 +33,10 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; +import android.app.ActivityManager; import android.app.PendingIntent.CanceledException; import android.app.RemoteAction; +import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -61,11 +64,13 @@ import com.android.wm.shell.R; import com.android.wm.shell.animation.Interpolators; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.pip.PipUtils; +import com.android.wm.shell.splitscreen.SplitScreenController; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.Optional; /** * Translucent window that gets started on top of a task in PIP to allow the user to control it. @@ -105,6 +110,7 @@ public class PipMenuView extends FrameLayout { private boolean mAllowMenuTimeout = true; private boolean mAllowTouches = true; private int mDismissFadeOutDurationMs; + private boolean mFocusedTaskAllowSplitScreen; private final List<RemoteAction> mActions = new ArrayList<>(); @@ -116,6 +122,7 @@ public class PipMenuView extends FrameLayout { private AnimatorSet mMenuContainerAnimator; private PhonePipMenuController mController; + private Optional<SplitScreenController> mSplitScreenControllerOptional; private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener = new ValueAnimator.AnimatorUpdateListener() { @@ -144,12 +151,14 @@ public class PipMenuView extends FrameLayout { protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm; public PipMenuView(Context context, PhonePipMenuController controller, - ShellExecutor mainExecutor, Handler mainHandler) { + ShellExecutor mainExecutor, Handler mainHandler, + Optional<SplitScreenController> splitScreenController) { super(context, null, 0); mContext = context; mController = controller; mMainExecutor = mainExecutor; mMainHandler = mainHandler; + mSplitScreenControllerOptional = splitScreenController; mAccessibilityManager = context.getSystemService(AccessibilityManager.class); inflate(context, R.layout.pip_menu, this); @@ -255,6 +264,15 @@ public class PipMenuView extends FrameLayout { return super.dispatchGenericMotionEvent(event); } + public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) { + final boolean isSplitScreen = mSplitScreenControllerOptional.isPresent() + && mSplitScreenControllerOptional.get().isTaskInSplitScreen(taskInfo.taskId); + mFocusedTaskAllowSplitScreen = isSplitScreen + || (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + && taskInfo.supportsSplitScreenMultiWindow + && taskInfo.topActivityType != WindowConfiguration.ACTIVITY_TYPE_HOME); + } + void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout, boolean resizeMenuOnShow, boolean withDelay, boolean showResizeHandle) { mAllowMenuTimeout = allowMenuTimeout; @@ -278,7 +296,8 @@ public class PipMenuView extends FrameLayout { ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA, mDismissButton.getAlpha(), 1f); ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA, - mEnterSplitButton.getAlpha(), ENABLE_ENTER_SPLIT ? 1f : 0f); + mEnterSplitButton.getAlpha(), + ENABLE_ENTER_SPLIT && mFocusedTaskAllowSplitScreen ? 1f : 0f); if (menuState == MENU_STATE_FULL) { mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim, enterSplitAnim); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 6b42ed775fb7..dc80813cdb2d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -183,6 +183,11 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, return mStageCoordinator.isSplitScreenVisible(); } + public boolean isTaskInSplitScreen(int taskId) { + return isSplitScreenVisible() + && mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED; + } + public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) { return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition, new WindowContainerTransaction()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index a3726d46d2a4..a390633481cd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -274,6 +274,17 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, return mSideStageListener.mVisible && mMainStageListener.mVisible; } + @SplitScreen.StageType + int getStageOfTask(int taskId) { + if (mMainStage.containsTask(taskId)) { + return STAGE_TYPE_MAIN; + } else if (mSideStage.containsTask(taskId)) { + return STAGE_TYPE_SIDE; + } + + return STAGE_TYPE_UNDEFINED; + } + boolean moveToStage(ActivityManager.RunningTaskInfo task, @SplitScreen.StageType int stageType, @SplitPosition int stagePosition, WindowContainerTransaction wct) { StageTaskListener targetStage; |