mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-03-01 00:06:47 +00:00
Merge "Allow split select transition from desktop mode." into udc-qpr-dev am: aad3a8e34f
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/23922245 Change-Id: Id221e4a600c38e1a62b009c507d7a588573eb9c1 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -33,6 +33,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
|
||||
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
|
||||
import static com.android.launcher3.config.FeatureFlags.RECEIVE_UNFOLD_EVENTS_FROM_SYSUI;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
|
||||
@@ -261,6 +262,7 @@ public class QuickstepLauncher extends Launcher {
|
||||
mDesktopVisibilityController = new DesktopVisibilityController(this);
|
||||
if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
|
||||
mDesktopVisibilityController.registerSystemUiListener();
|
||||
mSplitSelectStateController.initSplitFromDesktopController(this);
|
||||
}
|
||||
mHotseatPredictionController = new HotseatPredictionController(this);
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ import com.android.wm.shell.recents.IRecentTasks;
|
||||
import com.android.wm.shell.recents.IRecentTasksListener;
|
||||
import com.android.wm.shell.splitscreen.ISplitScreen;
|
||||
import com.android.wm.shell.splitscreen.ISplitScreenListener;
|
||||
import com.android.wm.shell.splitscreen.ISplitSelectListener;
|
||||
import com.android.wm.shell.startingsurface.IStartingWindow;
|
||||
import com.android.wm.shell.startingsurface.IStartingWindowListener;
|
||||
import com.android.wm.shell.transition.IShellTransitions;
|
||||
@@ -128,6 +129,7 @@ public class SystemUiProxy implements ISystemUiProxy {
|
||||
private IPipAnimationListener mPipAnimationListener;
|
||||
private IBubblesListener mBubblesListener;
|
||||
private ISplitScreenListener mSplitScreenListener;
|
||||
private ISplitSelectListener mSplitSelectListener;
|
||||
private IStartingWindowListener mStartingWindowListener;
|
||||
private ILauncherUnlockAnimationController mLauncherUnlockAnimationController;
|
||||
private IRecentTasksListener mRecentTasksListener;
|
||||
@@ -239,6 +241,7 @@ public class SystemUiProxy implements ISystemUiProxy {
|
||||
setPipAnimationListener(mPipAnimationListener);
|
||||
setBubblesListener(mBubblesListener);
|
||||
registerSplitScreenListener(mSplitScreenListener);
|
||||
registerSplitSelectListener(mSplitSelectListener);
|
||||
setStartingWindowListener(mStartingWindowListener);
|
||||
setLauncherUnlockAnimationController(mLauncherUnlockAnimationController);
|
||||
new LinkedHashMap<>(mRemoteTransitions).forEach(this::registerRemoteTransition);
|
||||
@@ -740,6 +743,28 @@ public class SystemUiProxy implements ISystemUiProxy {
|
||||
mSplitScreenListener = null;
|
||||
}
|
||||
|
||||
public void registerSplitSelectListener(ISplitSelectListener listener) {
|
||||
if (mSplitScreen != null) {
|
||||
try {
|
||||
mSplitScreen.registerSplitSelectListener(listener);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed call registerSplitSelectListener");
|
||||
}
|
||||
}
|
||||
mSplitSelectListener = listener;
|
||||
}
|
||||
|
||||
public void unregisterSplitSelectListener(ISplitSelectListener listener) {
|
||||
if (mSplitScreen != null) {
|
||||
try {
|
||||
mSplitScreen.unregisterSplitSelectListener(listener);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed call unregisterSplitSelectListener");
|
||||
}
|
||||
}
|
||||
mSplitSelectListener = null;
|
||||
}
|
||||
|
||||
/** Start multiple tasks in split-screen simultaneously. */
|
||||
public void startTasks(int taskId1, Bundle options1, int taskId2, Bundle options2,
|
||||
@SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio,
|
||||
@@ -1281,6 +1306,17 @@ public class SystemUiProxy implements ISystemUiProxy {
|
||||
}
|
||||
}
|
||||
|
||||
/** Perform cleanup transactions after animation to split select is complete */
|
||||
public void onDesktopSplitSelectAnimComplete(ActivityManager.RunningTaskInfo taskInfo) {
|
||||
if (mDesktopMode != null) {
|
||||
try {
|
||||
mDesktopMode.onDesktopSplitSelectAnimComplete(taskInfo);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed call onDesktopSplitSelectAnimComplete", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Unfold transition
|
||||
//
|
||||
|
||||
@@ -17,10 +17,14 @@
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.Utilities.postAsyncCallback;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM;
|
||||
import static com.android.launcher3.testing.shared.TestProtocol.LAUNCH_SPLIT_PAIR;
|
||||
import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
|
||||
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
|
||||
import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_PENDINGINTENT_PENDINGINTENT;
|
||||
import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_PENDINGINTENT_TASK;
|
||||
import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_SHORTCUT_TASK;
|
||||
@@ -31,6 +35,8 @@ import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_PENDIN
|
||||
import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_SHORTCUT;
|
||||
import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_TASK;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityOptions;
|
||||
@@ -38,11 +44,16 @@ import android.app.ActivityThread;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
@@ -57,7 +68,11 @@ import android.window.TransitionInfo;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.internal.logging.InstanceId;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.icons.IconProvider;
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
@@ -66,6 +81,11 @@ import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.shared.TestProtocol;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
|
||||
import com.android.quickstep.OverviewComponentObserver;
|
||||
import com.android.quickstep.RecentsAnimationCallbacks;
|
||||
import com.android.quickstep.RecentsAnimationController;
|
||||
import com.android.quickstep.RecentsAnimationDeviceState;
|
||||
import com.android.quickstep.RecentsAnimationTargets;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.SplitSelectionListener;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
@@ -74,8 +94,11 @@ import com.android.quickstep.TaskViewUtils;
|
||||
import com.android.quickstep.views.FloatingTaskView;
|
||||
import com.android.quickstep.views.GroupedTaskView;
|
||||
import com.android.quickstep.views.SplitInstructionsView;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
|
||||
import com.android.wm.shell.splitscreen.ISplitSelectListener;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -99,6 +122,7 @@ public class SplitSelectStateController {
|
||||
private final StatsLogManager mStatsLogManager;
|
||||
private final SystemUiProxy mSystemUiProxy;
|
||||
private final StateManager mStateManager;
|
||||
private SplitFromDesktopController mSplitFromDesktopController;
|
||||
@Nullable
|
||||
private DepthController mDepthController;
|
||||
private boolean mRecentsAnimationRunning;
|
||||
@@ -476,6 +500,14 @@ public class SplitSelectStateController {
|
||||
}
|
||||
}
|
||||
|
||||
public void initSplitFromDesktopController(Launcher launcher) {
|
||||
mSplitFromDesktopController = new SplitFromDesktopController(launcher);
|
||||
}
|
||||
|
||||
public void enterSplitFromDesktop(ActivityManager.RunningTaskInfo taskInfo) {
|
||||
mSplitFromDesktopController.enterSplitSelect(taskInfo);
|
||||
}
|
||||
|
||||
private RemoteTransition getShellRemoteTransition(int firstTaskId, int secondTaskId,
|
||||
@Nullable Consumer<Boolean> callback, String transitionName) {
|
||||
final RemoteSplitLaunchTransitionRunner animationRunner =
|
||||
@@ -686,4 +718,114 @@ public class SplitSelectStateController {
|
||||
mSplitSelectDataHolder.dump(prefix, writer);
|
||||
}
|
||||
}
|
||||
|
||||
public class SplitFromDesktopController {
|
||||
private static final String TAG = "SplitFromDesktopController";
|
||||
|
||||
private final Launcher mLauncher;
|
||||
private final OverviewComponentObserver mOverviewComponentObserver;
|
||||
private final int mSplitPlaceholderSize;
|
||||
private final int mSplitPlaceholderInset;
|
||||
private ActivityManager.RunningTaskInfo mTaskInfo;
|
||||
private ISplitSelectListener mSplitSelectListener;
|
||||
private Drawable mAppIcon;
|
||||
|
||||
public SplitFromDesktopController(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(
|
||||
launcher.getApplicationContext());
|
||||
mOverviewComponentObserver =
|
||||
new OverviewComponentObserver(launcher.getApplicationContext(), deviceState);
|
||||
mSplitPlaceholderSize = mLauncher.getResources().getDimensionPixelSize(
|
||||
R.dimen.split_placeholder_size);
|
||||
mSplitPlaceholderInset = mLauncher.getResources().getDimensionPixelSize(
|
||||
R.dimen.split_placeholder_inset);
|
||||
mSplitSelectListener = new ISplitSelectListener.Stub() {
|
||||
@Override
|
||||
public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo) {
|
||||
if (!ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE.get()) return false;
|
||||
MAIN_EXECUTOR.execute(() -> enterSplitSelect(taskInfo));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
SystemUiProxy.INSTANCE.get(mLauncher).registerSplitSelectListener(mSplitSelectListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter split select from desktop mode.
|
||||
* @param taskInfo the desktop task to move to split stage
|
||||
*/
|
||||
public void enterSplitSelect(ActivityManager.RunningTaskInfo taskInfo) {
|
||||
mTaskInfo = taskInfo;
|
||||
String packageName = mTaskInfo.realActivity.getPackageName();
|
||||
PackageManager pm = mLauncher.getApplicationContext().getPackageManager();
|
||||
IconProvider provider = new IconProvider(mLauncher.getApplicationContext());
|
||||
try {
|
||||
mAppIcon = provider.getIcon(pm.getActivityInfo(mTaskInfo.baseActivity,
|
||||
PackageManager.ComponentInfoFlags.of(0)));
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.w(TAG, "Package not found: " + packageName, e);
|
||||
}
|
||||
RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
|
||||
SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()),
|
||||
false /* allowMinimizeSplitScreen */);
|
||||
|
||||
DesktopSplitRecentsAnimationListener listener =
|
||||
new DesktopSplitRecentsAnimationListener();
|
||||
|
||||
MAIN_EXECUTOR.execute(() -> {
|
||||
callbacks.addListener(listener);
|
||||
UI_HELPER_EXECUTOR.execute(
|
||||
// Transition from app to enter stage split in launcher with
|
||||
// recents animation.
|
||||
() -> ActivityManagerWrapper.getInstance().startRecentsActivity(
|
||||
mOverviewComponentObserver.getOverviewIntent(),
|
||||
SystemClock.uptimeMillis(), callbacks, null, null));
|
||||
});
|
||||
}
|
||||
|
||||
private class DesktopSplitRecentsAnimationListener implements
|
||||
RecentsAnimationCallbacks.RecentsAnimationListener {
|
||||
private final Rect mTempRect = new Rect();
|
||||
|
||||
@Override
|
||||
public void onRecentsAnimationStart(RecentsAnimationController controller,
|
||||
RecentsAnimationTargets targets) {
|
||||
setInitialTaskSelect(mTaskInfo, STAGE_POSITION_BOTTOM_OR_RIGHT,
|
||||
null, LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM);
|
||||
|
||||
RecentsView recentsView = mLauncher.getOverviewPanel();
|
||||
recentsView.getPagedOrientationHandler().getInitialSplitPlaceholderBounds(
|
||||
mSplitPlaceholderSize, mSplitPlaceholderInset,
|
||||
mLauncher.getDeviceProfile(), getActiveSplitStagePosition(), mTempRect);
|
||||
|
||||
PendingAnimation anim = new PendingAnimation(
|
||||
SplitAnimationTimings.TABLET_HOME_TO_SPLIT.getDuration());
|
||||
RectF startingTaskRect = new RectF(mTaskInfo.configuration.windowConfiguration
|
||||
.getBounds());
|
||||
final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(
|
||||
mLauncher, mLauncher.getDragLayer(),
|
||||
null /* thumbnail */,
|
||||
mAppIcon, new RectF());
|
||||
floatingTaskView.setAlpha(1);
|
||||
floatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
|
||||
false /* fadeWithThumbnail */, true /* isStagedTask */);
|
||||
setFirstFloatingTaskView(floatingTaskView);
|
||||
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
controller.finish(true /* toRecents */, null /* onFinishComplete */,
|
||||
false /* sendUserLeaveHint */);
|
||||
}
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext())
|
||||
.onDesktopSplitSelectAnimComplete(mTaskInfo);
|
||||
}
|
||||
});
|
||||
anim.buildAnim().start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
|
||||
|
||||
@@ -178,7 +179,8 @@ public class SplitToWorkspaceController {
|
||||
|
||||
private boolean shouldIgnoreSecondSplitLaunch() {
|
||||
return (!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()
|
||||
&& !ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get())
|
||||
&& !ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()
|
||||
&& !ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE.get())
|
||||
|| !mController.isSplitSelectActive();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,6 +370,10 @@ public final class FeatureFlags {
|
||||
270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", TEAMFOOD,
|
||||
"Enable initiating split screen from workspace to workspace.");
|
||||
|
||||
public static final BooleanFlag ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE = getDebugFlag(
|
||||
279586624, "ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE", DISABLED,
|
||||
"Enable initiating split screen from desktop mode to workspace.");
|
||||
|
||||
public static final BooleanFlag ENABLE_TRACKPAD_GESTURE = getDebugFlag(271010401,
|
||||
"ENABLE_TRACKPAD_GESTURE", ENABLED, "Enables trackpad gesture.");
|
||||
|
||||
|
||||
@@ -621,6 +621,9 @@ public class StatsLogManager implements ResourceBasedOverride {
|
||||
@UiEvent(doc = "User has invoked split to left half with a keyboard shortcut.")
|
||||
LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP(1233),
|
||||
|
||||
@UiEvent(doc = "User has invoked split to right half with desktop mode app icon")
|
||||
LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM(1412),
|
||||
|
||||
@UiEvent(doc = "User has collapsed the work FAB button by scrolling down in the all apps"
|
||||
+ " work A-Z list.")
|
||||
LAUNCHER_WORK_FAB_BUTTON_COLLAPSE(1276),
|
||||
|
||||
Reference in New Issue
Block a user