diff options
4 files changed, 216 insertions, 10 deletions
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl new file mode 100644 index 000000000000..e5ced3ec3dc2 --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISplitScreenListener.aidl @@ -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); +}
\ No newline at end of file diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 388eeb6cd706..e38cf237d36b 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -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; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 760ebadf1b99..a9f76f61c537 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java index b63274ba246a..451c78fd1202 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java @@ -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)); } |