Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e0f5d8a authored by Tracy Zhou's avatar Tracy Zhou
Browse files

Implement split from workspace to workspace

parent 3ccbba3e
Loading
Loading
Loading
Loading
+52 −6
Original line number Diff line number Diff line
@@ -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;
        }
    }
+15 −4
Original line number Diff line number Diff line
@@ -96,6 +96,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;
    }
+28 −0
Original line number Diff line number Diff line
@@ -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) {
+9 −5
Original line number Diff line number Diff line
@@ -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;
    }
+66 −0
Original line number Diff line number Diff line
/*
 * 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;
    }
}
Loading