Merge "Implement split from workspace to workspace" into tm-qpr-dev

This commit is contained in:
Tracy Zhou
2022-11-17 07:04:48 +00:00
committed by Android (Google) Code Review
8 changed files with 175 additions and 43 deletions

View File

@@ -15,20 +15,29 @@
*/
package com.android.launcher3.popup;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.R;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.views.FloatingTaskView;
import com.android.quickstep.views.RecentsView;
public interface QuickstepSystemShortcut {
@@ -44,6 +53,10 @@ public interface QuickstepSystemShortcut {
class SplitSelectSystemShortcut extends SystemShortcut<QuickstepLauncher> {
private final int mSplitPlaceholderSize;
private final int mSplitPlaceholderInset;
private final Rect mTempRect = new Rect();
private final SplitPositionOption mPosition;
public SplitSelectSystemShortcut(QuickstepLauncher launcher, ItemInfo itemInfo,
@@ -51,6 +64,11 @@ public interface QuickstepSystemShortcut {
super(position.iconResId, position.textResId, launcher, itemInfo, originalView);
mPosition = position;
mSplitPlaceholderSize = launcher.getResources().getDimensionPixelSize(
R.dimen.split_placeholder_size);
mSplitPlaceholderInset = launcher.getResources().getDimensionPixelSize(
R.dimen.split_placeholder_inset);
}
@Override
@@ -72,11 +90,39 @@ public interface QuickstepSystemShortcut {
return;
}
RecentsView recentsView = mTarget.getOverviewPanel();
StatsLogManager.EventEnum splitEvent = getLogEventForPosition(mPosition.stagePosition);
recentsView.initiateSplitSelect(
new SplitSelectSource(mOriginalView, new BitmapDrawable(bitmap), intent,
mPosition, mItemInfo, splitEvent));
SplitSelectSource source = new SplitSelectSource(mOriginalView,
new BitmapDrawable(bitmap), intent, mPosition, mItemInfo, splitEvent);
if (ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
startSplitToHome(source);
} else {
RecentsView recentsView = mTarget.getOverviewPanel();
recentsView.initiateSplitSelect(source);
}
}
private void startSplitToHome(SplitSelectSource source) {
AbstractFloatingView.closeAllOpenViews(mTarget);
SplitSelectStateController controller = mTarget.getSplitSelectStateController();
controller.setInitialTaskSelect(source.intent, source.position.stagePosition,
source.itemInfo, source.splitEvent);
RecentsView recentsView = mTarget.getOverviewPanel();
recentsView.getPagedOrientationHandler().getInitialSplitPlaceholderBounds(
mSplitPlaceholderSize, mSplitPlaceholderInset, mTarget.getDeviceProfile(),
controller.getActiveSplitStagePosition(), mTempRect);
PendingAnimation anim = new PendingAnimation(TABLET_HOME_TO_SPLIT.getDuration());
RectF startingTaskRect = new RectF();
FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(mTarget,
source.view, null /* thumbnail */,
source.drawable, startingTaskRect);
floatingTaskView.setAlpha(1);
floatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect,
false /* fadeWithThumbnail */, true /* isStagedTask */);
controller.setFirstFloatingTaskView(floatingTaskView);
anim.buildAnim().start();
}
}
@@ -86,7 +132,7 @@ public interface QuickstepSystemShortcut {
public final Drawable drawable;
public final Intent intent;
public final SplitPositionOption position;
public final ItemInfo mItemInfo;
public final ItemInfo itemInfo;
public final StatsLogManager.EventEnum splitEvent;
public SplitSelectSource(View view, Drawable drawable, Intent intent,
@@ -96,7 +142,7 @@ public interface QuickstepSystemShortcut {
this.drawable = drawable;
this.intent = intent;
this.position = position;
this.mItemInfo = itemInfo;
this.itemInfo = itemInfo;
this.splitEvent = splitEvent;
}
}

View File

@@ -95,6 +95,7 @@ import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.proxy.ProxyActivityStarter;
import com.android.launcher3.proxy.StartActivityParams;
@@ -136,6 +137,7 @@ import com.android.quickstep.util.QuickstepOnboardingPrefs;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.SplitToWorkspaceController;
import com.android.quickstep.util.SplitWithKeyboardShortcutController;
import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.OverviewActionsView;
@@ -182,7 +184,10 @@ public class QuickstepLauncher extends Launcher {
private @Nullable RotationChangeProvider mRotationChangeProvider;
private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController;
private SplitSelectStateController mSplitSelectStateController;
private SplitWithKeyboardShortcutController mSplitWithKeyboardShortcutController;
private SplitToWorkspaceController mSplitToWorkspaceController;
/**
* If Launcher restarted while in the middle of an Overview split select, it needs this data to
* recover. In all other cases this will remain null.
@@ -199,12 +204,14 @@ public class QuickstepLauncher extends Launcher {
mActionsView = findViewById(R.id.overview_actions_view);
RecentsView overviewPanel = getOverviewPanel();
SplitSelectStateController controller =
mSplitSelectStateController =
new SplitSelectStateController(this, mHandler, getStateManager(),
getDepthController(), getStatsLogManager());
overviewPanel.init(mActionsView, controller);
overviewPanel.init(mActionsView, mSplitSelectStateController);
mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController(this,
controller);
mSplitSelectStateController);
mSplitToWorkspaceController = new SplitToWorkspaceController(this,
mSplitSelectStateController);
mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize());
mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this));
@@ -330,7 +337,7 @@ public class QuickstepLauncher extends Launcher {
}
protected void onItemClicked(View view) {
if (!mSplitWithKeyboardShortcutController.handleSecondAppSelectionForSplit(view)) {
if (!mSplitToWorkspaceController.handleSecondAppSelectionForSplit(view)) {
QuickstepLauncher.super.getItemOnClickListener().onClick(view);
}
}
@@ -724,6 +731,10 @@ public class QuickstepLauncher extends Launcher {
return mTaskbarUIController;
}
public SplitSelectStateController getSplitSelectStateController() {
return mSplitSelectStateController;
}
public <T extends OverviewActionsView> T getActionsView() {
return (T) mActionsView;
}

View File

@@ -561,6 +561,20 @@ public class SystemUiProxy implements ISystemUiProxy {
}
}
public void startIntents(PendingIntent pendingIntent1, Bundle options1,
PendingIntent pendingIntent2, Bundle options2,
@SplitConfigurationOptions.StagePosition int splitPosition,
float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
if (mSystemUiProxy != null) {
try {
mSplitScreen.startIntents(pendingIntent1, options1, pendingIntent2, options2,
splitPosition, splitRatio, remoteTransition, instanceId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntents");
}
}
}
public void startShortcutAndTask(ShortcutInfo shortcutInfo, Bundle options1, int taskId,
Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
@@ -617,6 +631,20 @@ public class SystemUiProxy implements ISystemUiProxy {
}
}
public void startIntentsWithLegacyTransition(PendingIntent pendingIntent1, Bundle options1,
PendingIntent pendingIntent2, Bundle options2,
@SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio,
RemoteAnimationAdapter adapter, InstanceId instanceId) {
if (mSystemUiProxy != null) {
try {
mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, options1,
pendingIntent2, options2, sidePosition, splitRatio, adapter, instanceId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntentsWithLegacyTransition");
}
}
}
public void startShortcut(String packageName, String shortcutId, int position,
Bundle options, UserHandle user, InstanceId instanceId) {
if (mSplitScreen != null) {

View File

@@ -37,6 +37,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.RemoteAnimationAdapter;
@@ -207,8 +208,8 @@ public class SplitSelectStateController {
* fill in intent with a taskId2 are set.
* @param intent1 is null when split is initiated from Overview
* @param stagePosition representing location of task1
* @param shellInstanceId loggingId to be used by shell, will be non-null for actions that create
* a split instance, null for cases that bring existing instaces to the
* @param shellInstanceId loggingId to be used by shell, will be non-null for actions that
* create a split instance, null for cases that bring existing instaces to the
* foreground (quickswitch, launching previous pairs from overview)
*/
public void launchTasks(int taskId1, @Nullable Intent intent1, int taskId2,
@@ -238,7 +239,9 @@ public class SplitSelectStateController {
getOppositeStagePosition(stagePosition), splitRatio, remoteTransition,
shellInstanceId);
} else {
// TODO: the case when both split apps are started from an intent.
mSystemUiProxy.startIntents(getPendingIntent(intent1), options1.toBundle(),
getPendingIntent(intent2), null /* options2 */, stagePosition,
splitRatio, remoteTransition, shellInstanceId);
}
} else {
final RemoteSplitLaunchAnimationRunner animationRunner =
@@ -259,7 +262,9 @@ public class SplitSelectStateController {
getOppositeStagePosition(stagePosition), splitRatio, adapter,
shellInstanceId);
} else {
// TODO: the case when both split apps are started from an intent.
mSystemUiProxy.startIntentsWithLegacyTransition(getPendingIntent(intent1),
options1.toBundle(), getPendingIntent(intent2), null /* options2 */,
stagePosition, splitRatio, adapter, shellInstanceId);
}
}
}
@@ -305,7 +310,6 @@ public class SplitSelectStateController {
: PendingIntent.getActivity(mContext, 0, intent, FLAG_MUTABLE));
}
public @StagePosition int getActiveSplitStagePosition() {
return mStagePosition;
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2022 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.quickstep.util;
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;
import android.content.Intent;
import android.view.View;
import com.android.launcher3.Launcher;
import com.android.launcher3.model.data.WorkspaceItemInfo;
/** Handles when the stage split lands on the home screen. */
public class SplitToWorkspaceController {
private final Launcher mLauncher;
private final SplitSelectStateController mController;
public SplitToWorkspaceController(Launcher launcher, SplitSelectStateController controller) {
mLauncher = launcher;
mController = controller;
}
/**
* Handles second app selection from stage split. If the item can't be opened in split or
* it's not in stage split state, we pass it onto Launcher's default item click handler.
*/
public boolean handleSecondAppSelectionForSplit(View view) {
if ((!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()
&& !ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get())
|| !mController.isSplitSelectActive()) {
return false;
}
Object tag = view.getTag();
Intent intent;
if (tag instanceof WorkspaceItemInfo) {
final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) tag;
intent = workspaceItemInfo.intent;
} else if (tag instanceof com.android.launcher3.model.data.AppInfo) {
final com.android.launcher3.model.data.AppInfo appInfo =
(com.android.launcher3.model.data.AppInfo) tag;
intent = appInfo.intent;
} else {
return false;
}
mController.setSecondTask(intent);
mController.launchSplitTasks(aBoolean -> mLauncher.getDragLayer().removeView(
mController.getFirstFloatingTaskView()));
return true;
}
}

View File

@@ -101,33 +101,6 @@ public class SplitWithKeyboardShortcutController {
});
}
/**
* Handles second app selection from stage split. If the item can't be opened in split or
* it's not in stage split state, we pass it onto Launcher's default item click handler.
*/
public boolean handleSecondAppSelectionForSplit(View view) {
if (!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()
|| !mController.isSplitSelectActive()) {
return false;
}
Object tag = view.getTag();
Intent intent;
if (tag instanceof WorkspaceItemInfo) {
final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) tag;
intent = workspaceItemInfo.intent;
} else if (tag instanceof com.android.launcher3.model.data.AppInfo) {
final com.android.launcher3.model.data.AppInfo appInfo =
(com.android.launcher3.model.data.AppInfo) tag;
intent = appInfo.intent;
} else {
return false;
}
mController.setSecondTask(intent);
mController.launchSplitTasks(aBoolean -> mLauncher.getDragLayer().removeView(
mController.getFirstFloatingTaskView()));
return true;
}
public void onDestroy() {
mOverviewComponentObserver.onDestroy();
}

View File

@@ -4265,7 +4265,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
public void initiateSplitSelect(QuickstepSystemShortcut.SplitSelectSource splitSelectSource) {
mSplitSelectSource = splitSelectSource;
mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
splitSelectSource.position.stagePosition, splitSelectSource.mItemInfo,
splitSelectSource.position.stagePosition, splitSelectSource.itemInfo,
splitSelectSource.splitEvent);
}

View File

@@ -258,6 +258,10 @@ public final class FeatureFlags {
getDebugFlag("ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", false,
"Enable splitting from fullscreen app with keyboard shortcuts");
public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag(
"ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", false,
"Enable initiating split screen from workspace to workspace.");
public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(
"ENABLE_NEW_MIGRATION_LOGIC", true,
"Enable the new grid migration logic, keeping pages when src < dest");