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

Commit 69cace40 authored by Evan Rosky's avatar Evan Rosky
Browse files

Give SystemUI a chance to participate in display rotation

This adds support for registering a single DisplayRotationController
to WMS. It gives a chance for the controller to suggest some
task changes to be executed along with a display rotation. There
is only one because it's a 2-way communication and there is only
intended to be one client for now.

This allows us to move Split and PiP presentation/layout logic out
of WM into systemui because WM no-longer needs to be the one
calculating the new bounds of everything during rotation.

This uses the windowcontainer transaction because all the
configuration changes and the display rotation need to happen
synchronously; otherwise, relayouts can occur after the display
is rotated, but before the configuration changes are applied.
When this happens, apps get incorrect bounds/insets which can
trigger erroneous lifecycle events in the app.

The flow is like this:
1. DisplayContent/Rotation freezes screen
2. DisplayRotationController is notified of a rotation and provided a
   callback.
3. The Controller then evaluates/queues some task changes in
   a transaction and, when done, fires the provided callback.
4. The callback applies the config change transaction and continues
   the rest of the rotation synchronously.

The DisplayWindowController is sys-ui piece that serves as an
interface between system-ui components and display-related wm
logic. For now it just facilitates the rotation calculation, but
in the future it will have more general utility for display logic
like inset/bounds calculation.

Bug: 124011688
Bug: 133381284
Test: Added some wmtests and coretests.
Change-Id: If10695f44fa076725ba17746842f6fbd64da5d20
parent b66ea478
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 android.view;

/**
 * Interface to listen for changes to display window-containers.
 *
 * This differs from DisplayManager's DisplayListener:
 *  - onDisplayAdded is always called after the display is actually added to the WM hierarchy.
 *    This corresponds to the DisplayContent and not the raw Dislay from DisplayManager.
 *
 * @hide
 */
oneway interface IDisplayWindowListener {

    /**
     * Called when a display is added to the WM hierarchy.
     */
    void onDisplayAdded(int displayId);

    /**
     * Called when a display is removed from the hierarchy.
     */
    void onDisplayRemoved(int displayId);

}
+29 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 android.view;

import android.view.WindowContainerTransaction;

/**
 * Interface to be invoked by the controller when it has finished preparing for a display rotation.
 *
 * @see IDisplayWindowRotationController
 * @hide
 */
interface IDisplayWindowRotationCallback {
    void continueRotateDisplay(int targetRotation, in WindowContainerTransaction t);
}
+52 −0
Original line number Diff line number Diff line
/**
 * Copyright (C) 2019 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 android.view;

import android.view.IDisplayWindowRotationCallback;

/**
 * Singular controller of a "remote" display rotation. When a display rotation is started, WM
 * freezes the screen. It will then call into this controller and wait for a response via the
 * callback.
 *
 * This needs to provide configuration changes because those changes need to be applied in sync
 * with the actual display rotation to prevent relayouts with mismatched information.
 *
 * The flow is like this:
 *  1. DisplayContent/Rotation freezes the screen
 *  2. This controller is notified of a rotation and provided a callback.
 *  3. This controller is responsible for collecting a set of configuration changes to go along with
 *     the rotation.
 *  4. The callback is fired which tells DisplayContent/Rotation to apply the provided configuration
 *     changes and continue the rotation.
 *
 * @hide
 */
oneway interface IDisplayWindowRotationController {

    /**
     * Called when WM needs to know how to update tasks in response to a display rotation.
     * If this isn't called, a timeout will continue the rotation in WM.
     *
     * @param displayId the display that is rotating.
     * @param fromRotation the rotation the display is rotating from.
     * @param toRotation the rotation the display is rotating to.
     * @param callback A callback to be called when this has calculated updated configs.
     */
    void onRotateDisplay(int displayId, int fromRotation, int toRotation,
            in IDisplayWindowRotationCallback callback);
}
+19 −0
Original line number Diff line number Diff line
@@ -35,7 +35,9 @@ import android.os.ParcelFileDescriptor;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
import android.view.IDisplayWindowListener;
import android.view.IDisplayFoldListener;
import android.view.IDisplayWindowRotationController;
import android.view.IOnKeyguardExitResult;
import android.view.IPinnedStackListener;
import android.view.RemoteAnimationAdapter;
@@ -96,6 +98,13 @@ interface IWindowManager
    void removeWindowToken(IBinder token, int displayId);
    void prepareAppTransition(int transit, boolean alwaysKeepCurrent);

    /**
     * Sets a singular remote controller of display rotations. There can only be one. The
     * controller is called after the display has "frozen" for a rotation and display rotation will
     * only continue once the controller has finished calculating associated configurations.
     */
    void setDisplayWindowRotationController(IDisplayWindowRotationController controller);

    /**
     * Like overridePendingAppTransitionMultiThumb, but uses a future to supply the specs. This is
     * used for recents, where generating the thumbnails of the specs takes a non-trivial amount of
@@ -475,6 +484,16 @@ interface IWindowManager
     */
    void unregisterDisplayFoldListener(IDisplayFoldListener listener);

    /**
     * Registers an IDisplayContainerListener
     */
    void registerDisplayWindowListener(IDisplayWindowListener listener);

    /**
     * Unregisters an IDisplayContainerListener.
     */
    void unregisterDisplayWindowListener(IDisplayWindowListener listener);

    /**
     * Starts a window trace.
     */
+3 −0
Original line number Diff line number Diff line
@@ -125,6 +125,7 @@ import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.leak.LeakReporter;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.wm.DisplayWindowController;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -332,6 +333,7 @@ public class Dependency {
    @Inject Lazy<CommandQueue> mCommandQueue;
    @Inject Lazy<Recents> mRecents;
    @Inject Lazy<StatusBar> mStatusBar;
    @Inject Lazy<DisplayWindowController> mDisplayWindowController;

    @Inject
    public Dependency() {
@@ -523,6 +525,7 @@ public class Dependency {
        mProviders.put(CommandQueue.class, mCommandQueue::get);
        mProviders.put(Recents.class, mRecents::get);
        mProviders.put(StatusBar.class, mStatusBar::get);
        mProviders.put(DisplayWindowController.class, mDisplayWindowController::get);

        // TODO(b/118592525): to support multi-display , we start to add something which is
        //                    per-display, while others may be global. I think it's time to add
Loading