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

Commit 42ce900d authored by Winson Chung's avatar Winson Chung
Browse files

Expose methods to invoke split screen.



- Also remove duplicate code in shortcut key dispatcher.

Bug: 67510855
Test: Drag and dock in Recents
Change-Id: I46634ab0585d29edd2068a6149cffa928f729d33
Signed-off-by: default avatarWinson Chung <winsonc@google.com>
parent 15176cd9
Loading
Loading
Loading
Loading
+25 −18
Original line number Original line Diff line number Diff line
@@ -319,30 +319,37 @@ public class ActivityManagerWrapper {
        mBackgroundExecutor.submit(new Runnable() {
        mBackgroundExecutor.submit(new Runnable() {
            @Override
            @Override
            public void run() {
            public void run() {
                boolean result = false;
                try {
                try {
                    ActivityManager.getService().startActivityFromRecents(taskKey.id,
                    result = startActivityFromRecents(taskKey.id, finalOptions);
                            finalOptions == null ? null : finalOptions.toBundle());
                } catch (Exception e) {
                    // Fall through
                }
                final boolean finalResult = result;
                if (resultCallback != null) {
                if (resultCallback != null) {
                    resultCallbackHandler.post(new Runnable() {
                    resultCallbackHandler.post(new Runnable() {
                        @Override
                        @Override
                        public void run() {
                        public void run() {
                                resultCallback.accept(true);
                            resultCallback.accept(finalResult);
                        }
                        }
                    });
                    });
                }
                }
                } catch (Exception e) {
                    if (resultCallback != null) {
                        resultCallbackHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                resultCallback.accept(false);
            }
            }
        });
        });
    }
    }

    /**
     * Starts a task from Recents synchronously.
     */
    public boolean startActivityFromRecents(int taskId, ActivityOptions options) {
        try {
            Bundle optsBundle = options == null ? null : options.toBundle();
            ActivityManager.getService().startActivityFromRecents(taskId, optsBundle);
            return true;
        } catch (Exception e) {
            return false;
        }
        }
    }
    }
        });
    }


    /**
    /**
     * Registers a task stack listener with the system.
     * Registers a task stack listener with the system.
+41 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 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.systemui.shared.system;

import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;

import android.app.ActivityOptions;

/**
 * Wrapper around internal ActivityOptions creation.
 */
public abstract class ActivityOptionsCompat {

    /**
     * @return ActivityOptions for starting a task in split screen.
     */
    public static ActivityOptions makeSplitScreenOptions(boolean dockTopLeft) {
        final ActivityOptions options = ActivityOptions.makeBasic();
        options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
        options.setSplitScreenCreateMode(dockTopLeft
                ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
                : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
        return options;
    }
}
+25 −2
Original line number Original line Diff line number Diff line
@@ -19,8 +19,15 @@ package com.android.systemui.shared.system;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY;


import android.graphics.Rect;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.util.Log;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerGlobal;


import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;

public class WindowManagerWrapper {
public class WindowManagerWrapper {


    private static final String TAG = "WindowManagerWrapper";
    private static final String TAG = "WindowManagerWrapper";
@@ -38,8 +45,24 @@ public class WindowManagerWrapper {
        try {
        try {
            WindowManagerGlobal.getWindowManagerService().getStableInsets(DEFAULT_DISPLAY,
            WindowManagerGlobal.getWindowManagerService().getStableInsets(DEFAULT_DISPLAY,
                    outStableInsets);
                    outStableInsets);
        } catch (Exception e) {
        } catch (RemoteException e) {
            e.printStackTrace();
            Log.e(TAG, "Failed to get stable insets", e);
        }
    }

    /**
     * Overrides a pending app transition.
     */
    public void overridePendingAppTransitionMultiThumbFuture(
            AppTransitionAnimationSpecsFuture animationSpecFuture,
            Runnable animStartedCallback, Handler animStartedCallbackHandler, boolean scaleUp) {
        try {
            WindowManagerGlobal.getWindowManagerService()
                    .overridePendingAppTransitionMultiThumbFuture(animationSpecFuture.getFuture(),
                            RecentsTransition.wrapStartedListener(animStartedCallbackHandler,
                                    animStartedCallback), scaleUp);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to override pending app transition (multi-thumbnail future): ", e);
        }
        }
    }
    }
}
}
+0 −35
Original line number Original line Diff line number Diff line
@@ -21,12 +21,10 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;


import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
@@ -49,9 +47,6 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.SystemProperties;
@@ -63,7 +58,6 @@ import android.service.dreams.IDreamManager;
import android.util.Log;
import android.util.Log;
import android.util.MutableBoolean;
import android.util.MutableBoolean;
import android.view.Display;
import android.view.Display;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
import android.view.IDockedStackListener;
import android.view.IWindowManager;
import android.view.IWindowManager;
import android.view.WindowManager;
import android.view.WindowManager;
@@ -78,12 +72,9 @@ import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserInfoController;


import java.util.List;
import java.util.List;
import java.util.function.Consumer;


/**
/**
 * Acts as a shim around the real system services that we need to access data from, and provides
 * Acts as a shim around the real system services that we need to access data from, and provides
@@ -268,22 +259,6 @@ public class SystemServicesProxy {
        return mIsSafeMode;
        return mIsSafeMode;
    }
    }


    /** Docks a task to the side of the screen and starts it. */
    public boolean startTaskInDockedMode(int taskId, int createMode) {
        if (mIam == null) return false;

        try {
            final ActivityOptions options = ActivityOptions.makeBasic();
            options.setSplitScreenCreateMode(createMode);
            options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
            mIam.startActivityFromRecents(taskId, options.toBundle());
            return true;
        } catch (Exception e) {
            Log.e(TAG, "Failed to dock task: " + taskId + " with createMode: " + createMode, e);
        }
        return false;
    }

    /** Moves an already resumed task to the side of the screen to initiate split screen. */
    /** Moves an already resumed task to the side of the screen to initiate split screen. */
    public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
    public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
            Rect initialBounds) {
            Rect initialBounds) {
@@ -540,16 +515,6 @@ public class SystemServicesProxy {
        }
        }
    }
    }


    public void overridePendingAppTransitionMultiThumbFuture(
            IAppTransitionAnimationSpecsFuture future, IRemoteCallback animStartedListener,
            boolean scaleUp) {
        try {
            mIwm.overridePendingAppTransitionMultiThumbFuture(future, animStartedListener, scaleUp);
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to override transition: " + e);
        }
    }

    /**
    /**
     * Updates the visibility of recents.
     * Updates the visibility of recents.
     */
     */
+17 −17
Original line number Original line Diff line number Diff line
@@ -16,13 +16,14 @@


package com.android.systemui.recents.views;
package com.android.systemui.recents.views;


import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;

import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;


import android.animation.ValueAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.ActivityOptions;
import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.Context;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Canvas;
@@ -33,11 +34,11 @@ import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.util.ArraySet;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Log;
import android.util.MathUtils;
import android.util.MathUtils;
import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View;
@@ -86,13 +87,15 @@ import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -608,16 +611,17 @@ public class RecentsView extends FrameLayout {
            // rect to its final layout-space rect
            // rect to its final layout-space rect
            Utilities.setViewFrameFromTranslation(event.taskView);
            Utilities.setViewFrameFromTranslation(event.taskView);


            // Dock the task and launch it
            final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions(
            SystemServicesProxy ssp = Recents.getSystemServices();
                    dockState.createMode == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
            if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) {
            if (ActivityManagerWrapper.getInstance().startActivityFromRecents(event.task.key.id,
                    options)) {
                final Runnable animStartedListener = () -> {
                final Runnable animStartedListener = () -> {
                    EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
                    EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
                    // Remove the task and don't bother relaying out, as all the tasks will be
                    // Remove the task and don't bother relaying out, as all the tasks
                    // relaid out when the stack changes on the multiwindow change event
                    // will be relaid out when the stack changes on the multiwindow
                    // change event
                    getStack().removeTask(event.task, null, true /* fromDockGesture */);
                    getStack().removeTask(event.task, null, true /* fromDockGesture */);
                };
                };

                final Rect taskRect = getTaskRect(event.taskView);
                final Rect taskRect = getTaskRect(event.taskView);
                AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture(
                AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture(
                        getHandler()) {
                        getHandler()) {
@@ -626,10 +630,8 @@ public class RecentsView extends FrameLayout {
                        return mTransitionHelper.composeDockAnimationSpec(event.taskView, taskRect);
                        return mTransitionHelper.composeDockAnimationSpec(event.taskView, taskRect);
                    }
                    }
                };
                };
                ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(),
                WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
                        RecentsTransition.wrapStartedListener(getHandler(), animStartedListener),
                        future, animStartedListener, getHandler(), true /* scaleUp */);
                        true /* scaleUp */);

                MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
                MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
                        event.task.getTopComponent().flattenToShortString());
                        event.task.getTopComponent().flattenToShortString());
            } else {
            } else {
@@ -1032,11 +1034,9 @@ public class RecentsView extends FrameLayout {
                if (taskIndex > -1) {
                if (taskIndex > -1) {
                    taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
                    taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
                }
                }
                EventBus.getDefault().send(new LaunchTaskSucceededEvent(
                EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
                        taskIndexFromFront));
            } else {
            } else {
                Log.e(TAG, mContext.getString(R.string.recents_launch_error_message,
                Log.e(TAG, mContext.getString(R.string.recents_launch_error_message, task.title));
                        task.title));


                // Dismiss the task if we fail to launch it
                // Dismiss the task if we fail to launch it
                if (taskView != null) {
                if (taskView != null) {
Loading