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

Commit a5f9ba6c authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

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

Bug: 179176511
Test: presubmits!
Change-Id: I782fbd50d2fadf730072d0ffc3657280217d8d86
parent e3956ba8
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
/*
 * 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
+48 −0
Original line number Diff line number Diff line
@@ -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;
}
+138 −7
Original line number Diff line number Diff line
@@ -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
+5 −3
Original line number Diff line number Diff line
@@ -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));
    }