Merge "Expose methods to invoke split screen."

This commit is contained in:
TreeHugger Robot
2017-11-27 20:42:32 +00:00
committed by Android (Google) Code Review
6 changed files with 114 additions and 84 deletions

View File

@@ -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.

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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.
*/

View File

@@ -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) {

View File

@@ -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();