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

Commit b8540a09 authored by Evan Rosky's avatar Evan Rosky
Browse files

Fix crash on devices that don't support multiwindow

Only initializes split-screen organizer if device supports it.

Also added some graceful degredation for when organizer binding
fails. Needed to clean-up some things for this though since
now unregistering task-organizers needs to work.

Previously, registering one task-org for multiple windowing
modes worked, but unregistering only cleaned-up one windowing-mode.
So this reworks some of the data-structures to support that
use-case.

Bug: 152401027
Test: Use device that doesn't support split-screen multiwindow.
Change-Id: I7d417721b7b51b20b0c054d9a25f62c443837670
parent d6f32126
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static android.window.WindowOrganizer.TaskOrganizer;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -32,11 +33,11 @@ import android.os.Handler;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Slog;
import android.window.IWindowContainer;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
import android.window.IWindowContainer;
import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;

@@ -112,6 +113,9 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,

    private DisplayChangeController.OnDisplayChangingListener mRotationController =
            (display, fromRotation, toRotation, t) -> {
                if (!mSplits.isSplitScreenSupported()) {
                    return;
                }
                DisplayLayout displayLayout =
                        new DisplayLayout(mDisplayController.getDisplayLayout(display));
                SplitDisplayLayout sdl = new SplitDisplayLayout(mContext, displayLayout, mSplits);
@@ -472,6 +476,10 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
                mDisplayController.getDisplayLayout(displayId), mSplits);
        mImeController.addPositionProcessor(mImePositionProcessor);
        mDisplayController.addDisplayChangingController(mRotationController);
        if (!ActivityTaskManager.supportsSplitScreenMultiWindow(mContext)) {
            removeDivider();
            return;
        }
        try {
            mSplits.init(mSurfaceSession);
            // Set starting tile bounds based on middle target
@@ -481,13 +489,15 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
            WindowOrganizer.applyTransaction(tct);
        } catch (Exception e) {
            Slog.e(TAG, "Failed to register docked stack listener", e);
            removeDivider();
            return;
        }
        update(mDisplayController.getDisplayContext(displayId).getResources().getConfiguration());
    }

    @Override
    public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
        if (displayId != DEFAULT_DISPLAY) {
        if (displayId != DEFAULT_DISPLAY || !mSplits.isSplitScreenSupported()) {
            return;
        }
        mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
+0 −9
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -130,7 +129,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,

    private int mDividerInsets;
    private final Display mDefaultDisplay;
    private boolean mSupportSplitScreenMultiWindow;

    private int mDividerSize;
    private int mTouchElevation;
@@ -284,8 +282,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
        final DisplayManager displayManager =
                (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
        mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
        mSupportSplitScreenMultiWindow =
                ActivityTaskManager.supportsSplitScreenMultiWindow(mContext);
    }

    @Override
@@ -358,11 +354,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (!mSupportSplitScreenMultiWindow) {
            super.onLayout(changed, left, top, right, bottom);
            return;
        }

        if (mFirstLayout) {
            // Wait for first layout so that the ViewRootImpl surface has been created.
            initializeSurfaceState();
+18 −6
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub {
    ArrayList<SurfaceControl> mHomeAndRecentsSurfaces = new ArrayList<>();
    Rect mHomeBounds = new Rect();
    final Divider mDivider;
    private boolean mSplitScreenSupported = false;

    SplitScreenTaskOrganizer(Divider divider) {
        mDivider = divider;
@@ -57,12 +58,19 @@ class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub {
    void init(SurfaceSession session) throws RemoteException {
        TaskOrganizer.registerOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
        TaskOrganizer.registerOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
        try {
            mPrimary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY,
                    WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
            mSecondary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY,
                    WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
            mPrimarySurface = mPrimary.token.getLeash();
            mSecondarySurface = mSecondary.token.getLeash();
        } catch (RemoteException e) {
            // teardown to prevent callbacks
            TaskOrganizer.unregisterOrganizer(this);
            throw e;
        }
        mSplitScreenSupported = true;

        // Initialize dim surfaces:
        mPrimaryDim = new SurfaceControl.Builder(session).setParent(mPrimarySurface)
@@ -78,6 +86,10 @@ class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub {
        releaseTransaction(t);
    }

    boolean isSplitScreenSupported() {
        return mSplitScreenSupported;
    }

    SurfaceControl.Transaction getTransaction() {
        return mDivider.mTransactionPool.acquire();
    }
+41 −29
Original line number Diff line number Diff line
@@ -20,14 +20,13 @@ import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
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 com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS;
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;

import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Binder;
@@ -53,7 +52,7 @@ import java.util.WeakHashMap;
 */
class TaskOrganizerController extends ITaskOrganizerController.Stub {
    private static final String TAG = "TaskOrganizerController";
    private static final LinkedList<TaskOrganizerState> EMPTY_LIST = new LinkedList<>();
    private static final LinkedList<IBinder> EMPTY_LIST = new LinkedList<>();

    /**
     * Masks specifying which configurations are important to report back to an organizer when
@@ -65,12 +64,10 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
    private final WindowManagerGlobalLock mGlobalLock;

    private class DeathRecipient implements IBinder.DeathRecipient {
        int mWindowingMode;
        ITaskOrganizer mTaskOrganizer;

        DeathRecipient(ITaskOrganizer organizer, int windowingMode) {
        DeathRecipient(ITaskOrganizer organizer) {
            mTaskOrganizer = organizer;
            mWindowingMode = windowingMode;
        }

        @Override
@@ -86,18 +83,16 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
    private class TaskOrganizerState {
        private final ITaskOrganizer mOrganizer;
        private final DeathRecipient mDeathRecipient;
        private final int mWindowingMode;
        private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();

        TaskOrganizerState(ITaskOrganizer organizer, int windowingMode) {
        TaskOrganizerState(ITaskOrganizer organizer) {
            mOrganizer = organizer;
            mDeathRecipient = new DeathRecipient(organizer, windowingMode);
            mDeathRecipient = new DeathRecipient(organizer);
            try {
                organizer.asBinder().linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
                Slog.e(TAG, "TaskOrganizer failed to register death recipient");
            }
            mWindowingMode = windowingMode;
        }

        void addTask(Task t) {
@@ -120,7 +115,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {

        void dispose() {
            releaseTasks();
            mTaskOrganizersForWindowingMode.get(mWindowingMode).remove(this);
            for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) {
                mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.asBinder());
            }
        }

        private void releaseTasks() {
@@ -136,7 +133,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
        }
    }

    private final SparseArray<LinkedList<TaskOrganizerState>> mTaskOrganizersForWindowingMode =
    private final SparseArray<LinkedList<IBinder>> mTaskOrganizersForWindowingMode =
            new SparseArray<>();
    private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
    private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
@@ -162,10 +159,22 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
     */
    @Override
    public void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
        if (windowingMode != WINDOWING_MODE_PINNED
                && windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
                && windowingMode != WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                && windowingMode != WINDOWING_MODE_MULTI_WINDOW) {
        if (windowingMode == WINDOWING_MODE_PINNED) {
            if (!mService.mSupportsPictureInPicture) {
                throw new UnsupportedOperationException("Picture in picture is not supported on "
                        + "this device");
            }
        } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
            if (!mService.mSupportsSplitScreenMultiWindow) {
                throw new UnsupportedOperationException("Split-screen is not supported on this "
                        + "device");
            }
        } else if (windowingMode == WINDOWING_MODE_MULTI_WINDOW) {
            if (!mService.mSupportsMultiWindow) {
                throw new UnsupportedOperationException("Multi-window is not supported on this "
                        + "device");
            }
        } else {
            throw new UnsupportedOperationException("As of now only Pinned/Split/Multiwindow"
                    + " windowing modes are supported for registerTaskOrganizer");
        }
@@ -178,19 +187,18 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
                            + windowingMode);
                }

                LinkedList<TaskOrganizerState> states;
                if (mTaskOrganizersForWindowingMode.contains(windowingMode)) {
                    states = mTaskOrganizersForWindowingMode.get(windowingMode);
                } else {
                    states = new LinkedList<>();
                    mTaskOrganizersForWindowingMode.put(windowingMode, states);
                LinkedList<IBinder> orgs = mTaskOrganizersForWindowingMode.get(windowingMode);
                if (orgs == null) {
                    orgs = new LinkedList<>();
                    mTaskOrganizersForWindowingMode.put(windowingMode, orgs);
                }
                orgs.add(organizer.asBinder());
                if (!mTaskOrganizerStates.containsKey(organizer.asBinder())) {
                    mTaskOrganizerStates.put(organizer.asBinder(),
                            new TaskOrganizerState(organizer));
                }
                final TaskOrganizerState previousState = states.peekLast();
                final TaskOrganizerState state = new TaskOrganizerState(organizer, windowingMode);
                states.add(state);
                mTaskOrganizerStates.put(organizer.asBinder(), state);

                if (previousState == null) {
                if (orgs.size() == 1) {
                    // Only in the case where this is the root task organizer for the given
                    // windowing mode, we add report all existing tasks in that mode to the new
                    // task organizer.
@@ -214,8 +222,12 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
    }

    ITaskOrganizer getTaskOrganizer(int windowingMode) {
        final TaskOrganizerState state = mTaskOrganizersForWindowingMode.get(windowingMode,
                EMPTY_LIST).peekLast();
        final IBinder organizer =
                mTaskOrganizersForWindowingMode.get(windowingMode, EMPTY_LIST).peekLast();
        if (organizer == null) {
            return null;
        }
        final TaskOrganizerState state = mTaskOrganizerStates.get(organizer);
        if (state == null) {
            return null;
        }