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

Commit a71d353f authored by Tracy Zhou's avatar Tracy Zhou Committed by Android (Google) Code Review
Browse files

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

parents c480c268 7e0f5d8a
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
@@ -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;
    }
+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