Merge "Expose methods to invoke split screen."
This commit is contained in:
committed by
Android (Google) Code Review
commit
e4cf6bf474
@@ -319,31 +319,38 @@ public class ActivityManagerWrapper {
|
||||
mBackgroundExecutor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
boolean result = false;
|
||||
try {
|
||||
ActivityManager.getService().startActivityFromRecents(taskKey.id,
|
||||
finalOptions == null ? null : finalOptions.toBundle());
|
||||
if (resultCallback != null) {
|
||||
resultCallbackHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultCallback.accept(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
result = startActivityFromRecents(taskKey.id, finalOptions);
|
||||
} catch (Exception e) {
|
||||
if (resultCallback != null) {
|
||||
resultCallbackHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultCallback.accept(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Fall through
|
||||
}
|
||||
final boolean finalResult = result;
|
||||
if (resultCallback != null) {
|
||||
resultCallbackHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
resultCallback.accept(finalResult);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* This should be called on the main thread.
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,15 @@ package com.android.systemui.shared.system;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
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 com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
|
||||
import com.android.systemui.shared.recents.view.RecentsTransition;
|
||||
|
||||
public class WindowManagerWrapper {
|
||||
|
||||
private static final String TAG = "WindowManagerWrapper";
|
||||
@@ -38,8 +45,24 @@ public class WindowManagerWrapper {
|
||||
try {
|
||||
WindowManagerGlobal.getWindowManagerService().getStableInsets(DEFAULT_DISPLAY,
|
||||
outStableInsets);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} catch (RemoteException e) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_UNDEFINED;
|
||||
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_SECONDARY;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManager.StackInfo;
|
||||
import android.app.ActivityOptions;
|
||||
@@ -49,9 +47,6 @@ import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.os.IRemoteCallback;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
@@ -63,7 +58,6 @@ import android.service.dreams.IDreamManager;
|
||||
import android.util.Log;
|
||||
import android.util.MutableBoolean;
|
||||
import android.view.Display;
|
||||
import android.view.IAppTransitionAnimationSpecsFuture;
|
||||
import android.view.IDockedStackListener;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.WindowManager;
|
||||
@@ -78,12 +72,9 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.UiOffloadThread;
|
||||
import com.android.systemui.recents.Recents;
|
||||
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 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
|
||||
@@ -268,22 +259,6 @@ public class SystemServicesProxy {
|
||||
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. */
|
||||
public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
|
||||
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 android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.ActivityOptions.OnAnimationStartedListener;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Canvas;
|
||||
@@ -33,11 +34,11 @@ import android.graphics.Rect;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.os.IRemoteCallback;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.view.AppTransitionAnimationSpec;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
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.misc.ReferenceCountedTrigger;
|
||||
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.TaskStack;
|
||||
import com.android.systemui.shared.recents.utilities.Utilities;
|
||||
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
|
||||
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
|
||||
import com.android.systemui.shared.recents.view.RecentsTransition;
|
||||
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.statusbar.FlingAnimationUtils;
|
||||
import com.android.systemui.statusbar.phone.ScrimController;
|
||||
@@ -608,16 +611,17 @@ public class RecentsView extends FrameLayout {
|
||||
// rect to its final layout-space rect
|
||||
Utilities.setViewFrameFromTranslation(event.taskView);
|
||||
|
||||
// Dock the task and launch it
|
||||
SystemServicesProxy ssp = Recents.getSystemServices();
|
||||
if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) {
|
||||
final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions(
|
||||
dockState.createMode == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
|
||||
if (ActivityManagerWrapper.getInstance().startActivityFromRecents(event.task.key.id,
|
||||
options)) {
|
||||
final Runnable animStartedListener = () -> {
|
||||
EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
|
||||
// Remove the task and don't bother relaying out, as all the tasks will be
|
||||
// relaid out when the stack changes on the multiwindow change event
|
||||
// Remove the task and don't bother relaying out, as all the tasks
|
||||
// will be relaid out when the stack changes on the multiwindow
|
||||
// change event
|
||||
getStack().removeTask(event.task, null, true /* fromDockGesture */);
|
||||
};
|
||||
|
||||
final Rect taskRect = getTaskRect(event.taskView);
|
||||
AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture(
|
||||
getHandler()) {
|
||||
@@ -626,10 +630,8 @@ public class RecentsView extends FrameLayout {
|
||||
return mTransitionHelper.composeDockAnimationSpec(event.taskView, taskRect);
|
||||
}
|
||||
};
|
||||
ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(),
|
||||
RecentsTransition.wrapStartedListener(getHandler(), animStartedListener),
|
||||
true /* scaleUp */);
|
||||
|
||||
WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
|
||||
future, animStartedListener, getHandler(), true /* scaleUp */);
|
||||
MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
|
||||
event.task.getTopComponent().flattenToShortString());
|
||||
} else {
|
||||
@@ -1032,11 +1034,9 @@ public class RecentsView extends FrameLayout {
|
||||
if (taskIndex > -1) {
|
||||
taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
|
||||
}
|
||||
EventBus.getDefault().send(new LaunchTaskSucceededEvent(
|
||||
taskIndexFromFront));
|
||||
EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
|
||||
} else {
|
||||
Log.e(TAG, mContext.getString(R.string.recents_launch_error_message,
|
||||
task.title));
|
||||
Log.e(TAG, mContext.getString(R.string.recents_launch_error_message, task.title));
|
||||
|
||||
// Dismiss the task if we fail to launch it
|
||||
if (taskView != null) {
|
||||
|
||||
@@ -20,6 +20,8 @@ import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIG
|
||||
import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
|
||||
import static android.os.UserHandle.USER_CURRENT;
|
||||
|
||||
import static com.android.systemui.statusbar.phone.NavigationBarGestureHelper.DRAG_MODE_NONE;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.RemoteException;
|
||||
@@ -36,6 +38,7 @@ import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
import com.android.systemui.stackdivider.Divider;
|
||||
import com.android.systemui.stackdivider.DividerView;
|
||||
import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -89,20 +92,11 @@ public class ShortcutKeyDispatcher extends SystemUI
|
||||
try {
|
||||
int dockSide = mWindowManagerService.getDockedStackSide();
|
||||
if (dockSide == WindowManager.DOCKED_INVALID) {
|
||||
// If there is no window docked, we dock the top-most window.
|
||||
// Split the screen
|
||||
Recents recents = getComponent(Recents.class);
|
||||
int dockMode = (shortcutCode == SC_DOCK_LEFT)
|
||||
recents.splitPrimaryTask(DRAG_MODE_NONE, (shortcutCode == SC_DOCK_LEFT)
|
||||
? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
|
||||
: SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
|
||||
List<ActivityManager.RecentTaskInfo> taskList =
|
||||
ActivityManagerWrapper.getInstance().getRecentTasks(1, USER_CURRENT);
|
||||
recents.showRecentApps(
|
||||
false /* triggeredFromAltTab */,
|
||||
false /* fromHome */);
|
||||
if (!taskList.isEmpty()) {
|
||||
SystemServicesProxy.getInstance(mContext).startTaskInDockedMode(
|
||||
taskList.get(0).id, dockMode);
|
||||
}
|
||||
: SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
|
||||
} else {
|
||||
// If there is already a docked window, we respond by resizing the docking pane.
|
||||
DividerView dividerView = getComponent(Divider.class).getView();
|
||||
|
||||
Reference in New Issue
Block a user