Added shared lib APIs for Launcher to use split-screen APIs.

Bug: 179176511
Test: presubmits!
Change-Id: I782fbd50d2fadf730072d0ffc3657280217d8d86
This commit is contained in:
Wale Ogunwale
2021-02-02 17:35:35 -08:00
parent e3956ba87a
commit a5f9ba6cb1
4 changed files with 216 additions and 10 deletions

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2021 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.recents;
/**
* Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
*/
oneway interface ISplitScreenListener {
void onStagePositionChanged(int stage, int position);
void onTaskStageChanged(int taskId, int stage);
}

View File

@@ -16,6 +16,7 @@
package com.android.systemui.shared.recents;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
@@ -23,9 +24,11 @@ import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
import android.view.MotionEvent;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.ISplitScreenListener;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteTransitionCompat;
@@ -202,4 +205,49 @@ interface ISystemUiProxy {
/** Unegisters a RemoteTransitionCompat that will handle transitions. */
void unregisterRemoteTransition(in RemoteTransitionCompat remoteTransition) = 33;
// SplitScreen APIs...copied from SplitScreen.java
/**
* Stage position isn't specified normally meaning to use what ever it is currently set to.
*/
//int STAGE_POSITION_UNDEFINED = -1;
/**
* Specifies that a stage is positioned at the top half of the screen if
* in portrait mode or at the left half of the screen if in landscape mode.
*/
//int STAGE_POSITION_TOP_OR_LEFT = 0;
/**
* Specifies that a stage is positioned at the bottom half of the screen if
* in portrait mode or at the right half of the screen if in landscape mode.
*/
//int STAGE_POSITION_BOTTOM_OR_RIGHT = 1;
/**
* Stage type isn't specified normally meaning to use what ever the default is.
* E.g. exit split-screen and launch the app in fullscreen.
*/
//int STAGE_TYPE_UNDEFINED = -1;
/**
* The main stage type.
* @see MainStage
*/
//int STAGE_TYPE_MAIN = 0;
/**
* The side stage type.
* @see SideStage
*/
//int STAGE_TYPE_SIDE = 1;
void registerSplitScreenListener(in ISplitScreenListener listener) = 34;
void unregisterSplitScreenListener(in ISplitScreenListener listener) = 35;
/** Hides the side-stage if it is currently visible. */
void setSideStageVisibility(in boolean visible) = 36;
/** Removes the split-screen stages. */
void exitSplitScreen() = 37;
void startTask(in int taskId, in int stage, in int position, in Bundle options) = 38;
void startShortcut(in String packageName, in String shortcutId, in int stage, in int position,
in Bundle options, in UserHandle user) = 39;
void startIntent(
in PendingIntent intent, in int stage, in int position, in Bundle options) = 40;
}

View File

@@ -35,6 +35,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_T
import android.annotation.FloatRange;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -83,6 +84,7 @@ import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.ISplitScreenListener;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -98,6 +100,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.transition.Transitions;
import java.io.FileDescriptor;
@@ -133,7 +136,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final Context mContext;
private final Optional<Pip> mPipOptional;
private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
private final Optional<LegacySplitScreen> mSplitScreenOptional;
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
private final Optional<SplitScreen> mSplitScreenOptional;
private SysUiState mSysUiState;
private final Handler mHandler;
private final Lazy<NavigationBarController> mNavBarControllerLazy;
@@ -263,7 +267,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
final long token = Binder.clearCallingIdentity();
try {
return mSplitScreenOptional.map(splitScreen ->
return mLegacySplitScreenOptional.map(splitScreen ->
splitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds())
.orElse(null);
} finally {
@@ -401,7 +405,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void setSplitScreenMinimized(boolean minimized) {
mSplitScreenOptional.ifPresent(
mLegacySplitScreenOptional.ifPresent(
splitScreen -> splitScreen.setMinimized(minimized));
}
@@ -559,6 +563,105 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
}
@Override
public void registerSplitScreenListener(ISplitScreenListener listener) {
if (!verifyCaller("registerSplitScreenListener")) {
return;
}
mISplitScreenListener = listener;
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(
s -> s.registerSplitScreenListener(mSplitScreenListener));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
if (!verifyCaller("unregisterSplitScreenListener")) {
return;
}
mISplitScreenListener = null;
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(
s -> s.unregisterSplitScreenListener(mSplitScreenListener));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void setSideStageVisibility(boolean visible) {
if (!verifyCaller("setSideStageVisibility")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(s -> s.setSideStageVisibility(visible));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void exitSplitScreen() {
if (!verifyCaller("exitSplitScreen")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(s -> s.exitSplitScreen());
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void startTask(int taskId, int stage, int position, Bundle options) {
if (!verifyCaller("startTask")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(
s -> s.startTask(taskId, stage, position, options));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void startShortcut(String packageName, String shortcutId, int stage, int position,
Bundle options, UserHandle user) {
if (!verifyCaller("startShortcut")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(s ->
s.startShortcut(packageName, shortcutId, stage, position, options, user));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void startIntent(PendingIntent intent, int stage, int position, Bundle options) {
if (!verifyCaller("startIntent")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(s ->
s.startIntent(intent, stage, position, options));
} finally {
Binder.restoreCallingIdentity(token);
}
}
private boolean verifyCaller(String reason) {
final int callerId = Binder.getCallingUserHandle().getIdentifier();
if (callerId != mCurrentBoundedUserId) {
@@ -658,6 +761,32 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
= this::cleanupAfterDeath;
private ISplitScreenListener mISplitScreenListener;
private final SplitScreen.SplitScreenListener mSplitScreenListener =
new SplitScreen.SplitScreenListener() {
@Override
public void onStagePositionChanged(int stage, int position) {
try {
if (mISplitScreenListener != null) {
mISplitScreenListener.onStagePositionChanged(stage, position);
}
} catch (RemoteException e) {
Log.e(TAG_OPS, "onStagePositionChanged", e);
}
}
@Override
public void onTaskStageChanged(int taskId, int stage) {
try {
if (mISplitScreenListener != null) {
mISplitScreenListener.onTaskStageChanged(taskId, stage);
}
} catch (RemoteException e) {
Log.e(TAG_OPS, "onTaskStageChanged", e);
}
}
};
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
@@ -665,7 +794,8 @@ public class OverviewProxyService extends CurrentUserTracker implements
NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
Optional<Pip> pipOptional,
Optional<LegacySplitScreen> splitScreenOptional,
Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional,
Optional<Lazy<StatusBar>> statusBarOptionalLazy,
Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher,
@@ -718,9 +848,10 @@ public class OverviewProxyService extends CurrentUserTracker implements
});
mCommandQueue = commandQueue;
splitScreenOptional.ifPresent(splitScreen ->
splitScreen.registerBoundsChangeListener(mSplitScreenBoundsChangeListener));
mSplitScreenOptional = splitScreenOptional;
legacySplitScreenOptional.ifPresent(splitScreen ->
splitScreen.registerBoundsChangeListener(mSplitScreenBoundsChangeListener));
mLegacySplitScreenOptional = legacySplitScreenOptional;
// Listen for user setup
startTracking();
@@ -835,7 +966,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
startConnectionToCurrentUser();
// Clean up the minimized state if launcher dies
mSplitScreenOptional.ifPresent(
mLegacySplitScreenOptional.ifPresent(
splitScreen -> splitScreen.setMinimized(false));
// Clean up any registered remote transitions

View File

@@ -42,6 +42,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
@@ -71,7 +72,8 @@ public class OverviewProxyServiceTest extends SysuiTestCase {
@Mock private NavigationModeController mMockNavModeController;
@Mock private NotificationShadeWindowController mMockStatusBarWinController;
@Mock private Optional<Pip> mMockPipOptional;
@Mock private Optional<LegacySplitScreen> mMockSplitScreenOptional;
@Mock private Optional<LegacySplitScreen> mMockLegacySplitScreenOptional;
@Mock private Optional<SplitScreen> mMockSplitScreenOptional;
@Mock private Optional<Lazy<StatusBar>> mMockStatusBarOptionalLazy;
@Mock private Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional;
@Mock private PackageManager mPackageManager;
@@ -89,8 +91,8 @@ public class OverviewProxyServiceTest extends SysuiTestCase {
mSpiedOverviewProxyService = spy(new OverviewProxyService(mSpiedContext, mMockCommandQueue,
mMockNavBarControllerLazy, mMockNavModeController, mMockStatusBarWinController,
mMockSysUiState, mMockPipOptional, mMockSplitScreenOptional,
mMockStatusBarOptionalLazy, mMockOneHandedOptional,
mMockSysUiState, mMockPipOptional, mMockLegacySplitScreenOptional,
mMockSplitScreenOptional, mMockStatusBarOptionalLazy, mMockOneHandedOptional,
mMockBroadcastDispatcher, mMockTransitions));
}