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

Commit 617e29a6 authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

Merge changes I2dfd15ff,I7507e25f

* changes:
  Support rotation on secondary displays (3/N)
  Support rotation on secondary displays (2/N)
parents e9ea3c93 5ce4bb33
Loading
Loading
Loading
Loading
+153 −883

File changed.

Preview size limit exceeded, changes collapsed.

+31 −54
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ import android.view.animation.Animation;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import com.android.server.wm.DisplayFrames;
import com.android.server.wm.DisplayRotation;
import com.android.server.wm.WindowFrames;
import com.android.server.wm.utils.WmDisplayCutout;

@@ -177,7 +178,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
    /**
     * Called when the resource overlays change.
     */
    default void onOverlayChangedLw() {}
    default void onOverlayChangedLw(DisplayContentInfo displayContentInfo) {}

    /**
     * Interface to the Window Manager state associated with a particular
@@ -638,6 +639,27 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
         * The keyguard showing state has changed
         */
        void onKeyguardShowingAndNotOccludedChanged();

        DisplayContentInfo getDefaultDisplayContentInfo();
    }

    /**
     * Provides the rotation of a device.
     *
     * @see com.android.server.policy.WindowOrientationListener
     */
    public interface RotationSource {
        int getProposedRotation();

        void setCurrentRotation(int rotation);
    }

    /**
     * Interface to get public information of a display content.
     */
    public interface DisplayContentInfo {
        DisplayRotation getDisplayRotation();
        Display getDisplay();
    }

    /** Window has been added to the screen. */
@@ -668,6 +690,11 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
     * the user. */
    public final int USER_ROTATION_LOCKED = 1;

    /**
     * Set the default display content to provide basic functions for the policy.
     */
    public void setDefaultDisplay(DisplayContentInfo displayContentInfo);

    /**
     * Perform initialization of the policy.
     *
@@ -676,17 +703,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
    public void init(Context context, IWindowManager windowManager,
            WindowManagerFuncs windowManagerFuncs);

    /**
     * @return true if com.android.internal.R.bool#config_forceDefaultOrientation is true.
     */
    public boolean isDefaultOrientationForced();

    /**
     * Called by window manager once it has the initial, default native
     * display dimensions.
     */
    public void setInitialDisplaySize(Display display, int width, int height, int density);

    /**
     * Check permissions when adding a window.
     *
@@ -1409,44 +1425,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {

    public boolean isShowingDreamLw();

    /**
     * Given an orientation constant, returns the appropriate surface rotation,
     * taking into account sensors, docking mode, rotation lock, and other factors.
     *
     * @param orientation An orientation constant, such as
     * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
     * @param lastRotation The most recently used rotation.
     * @param defaultDisplay Flag indicating whether the rotation is computed for the default
     *                       display. Currently for all non-default displays sensors, docking mode,
     *                       rotation lock and other factors are ignored.
     * @return The surface rotation to use.
     */
    public int rotationForOrientationLw(@ActivityInfo.ScreenOrientation int orientation,
            int lastRotation, boolean defaultDisplay);

    /**
     * Given an orientation constant and a rotation, returns true if the rotation
     * has compatible metrics to the requested orientation.  For example, if
     * the application requested landscape and got seascape, then the rotation
     * has compatible metrics; if the application requested portrait and got landscape,
     * then the rotation has incompatible metrics; if the application did not specify
     * a preference, then anything goes.
     *
     * @param orientation An orientation constant, such as
     * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
     * @param rotation The rotation to check.
     * @return True if the rotation is compatible with the requested orientation.
     */
    public boolean rotationHasCompatibleMetricsLw(@ActivityInfo.ScreenOrientation int orientation,
            int rotation);

    /**
     * Called by the window manager when the rotation changes.
     *
     * @param rotation The new rotation.
     */
    public void setRotationLw(int rotation);

    /**
     * Called when the system is mostly done booting to set whether
     * the system should go into safe mode.
@@ -1487,8 +1465,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
     */
    public void enableScreenAfterBoot();

    public void setCurrentOrientationLw(@ActivityInfo.ScreenOrientation int newOrientation);

    /**
     * Call from application to perform haptic feedback on its window.
     */
@@ -1702,9 +1678,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
    /**
     * Called when the configuration has changed, and it's safe to load new values from resources.
     */
    public void onConfigurationChanged();
    public void onConfigurationChanged(DisplayContentInfo displayContentInfo);

    public boolean shouldRotateSeamlessly(int oldRotation, int newRotation);
    public boolean shouldRotateSeamlessly(DisplayRotation displayRotation,
            int oldRotation, int newRotation);

    /**
     * Called when System UI has been started.
+4 −0
Original line number Diff line number Diff line
@@ -204,6 +204,10 @@ public abstract class WindowOrientationListener {
        }
    }

    public Handler getHandler() {
        return mHandler;
    }

    /**
     * Sets the current rotation.
     *
+92 −17
Original line number Diff line number Diff line
@@ -173,7 +173,8 @@ import java.util.function.Predicate;
 * IMPORTANT: No method from this class should ever be used without holding
 * WindowManagerService.mWindowMap.
 */
class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer> {
class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>
        implements WindowManagerPolicy.DisplayContentInfo {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;

    /** Unique identifier of this stack. */
@@ -234,6 +235,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    private final DisplayInfo mDisplayInfo = new DisplayInfo();
    private final Display mDisplay;
    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
    private final DisplayPolicy mDisplayPolicy;
    private DisplayRotation mDisplayRotation;
    DisplayFrames mDisplayFrames;

    /**
@@ -304,8 +307,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    private boolean mLayoutNeeded;
    int pendingLayoutChanges;
    int mDeferredRotationPauseCount;

    // TODO(multi-display): remove some of the usages.
    @VisibleForTesting
    boolean isDefaultDisplay;

    /**
     * Flag indicating whether WindowManager should override info for this display in
     * DisplayManager.
@@ -762,6 +768,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo,
                calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
        initializeDisplayBaseInfo();
        mDisplayPolicy = new DisplayPolicy(service);
        mDisplayRotation = new DisplayRotation(service, this);
        if (isDefaultDisplay) {
            // The policy may be invoked right after here, so it requires the necessary default
            // fields of this display content.
            mService.mPolicy.setDefaultDisplay(this);
        }
        mDividerControllerLocked = new DockedStackDividerController(service, this);
        mPinnedStackControllerLocked = new PinnedStackController(service, this);

@@ -907,7 +920,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        appToken.onRemovedFromDisplay();
    }

    Display getDisplay() {
    @Override
    public Display getDisplay() {
        return mDisplay;
    }

@@ -919,6 +933,20 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        return mDisplayMetrics;
    }

    DisplayPolicy getDisplayPolicy() {
        return mDisplayPolicy;
    }

    @Override
    public DisplayRotation getDisplayRotation() {
        return mDisplayRotation;
    }

    @VisibleForTesting
    void setDisplayRotation(DisplayRotation displayRotation) {
        mDisplayRotation = displayRotation;
    }

    int getRotation() {
        return mRotation;
    }
@@ -926,6 +954,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    @VisibleForTesting
    void setRotation(int newRotation) {
        mRotation = newRotation;
        mDisplayRotation.setRotation(newRotation);
    }

    int getLastOrientation() {
@@ -971,11 +1000,42 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo

        mDeferredRotationPauseCount--;
        if (mDeferredRotationPauseCount == 0) {
            final boolean changed = updateRotationUnchecked();
            updateRotationAndSendNewConfigIfNeeded();
        }
    }

    /**
     * If this is true we have updated our desired orientation, but not yet changed the real
     * orientation our applied our screen rotation animation. For example, because a previous
     * screen rotation was in progress.
     *
     * @return {@code true} if the there is an ongoing rotation change.
     */
    boolean rotationNeedsUpdate() {
        final int lastOrientation = getLastOrientation();
        final int oldRotation = getRotation();
        final boolean oldAltOrientation = getAltOrientation();

        final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
        final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics(
                lastOrientation, rotation);
        if (oldRotation == rotation && oldAltOrientation == altOrientation) {
            return false;
        }
        return true;
    }

    /**
     * Update rotation of the display and send configuration if the rotation is changed.
     *
     * @return {@code true} if the rotation has been changed and the new config is sent.
     */
    boolean updateRotationAndSendNewConfigIfNeeded() {
        final boolean changed = updateRotationUnchecked(false /* forceUpdate */);
        if (changed) {
            mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mDisplayId).sendToTarget();
        }
        }
        return changed;
    }

    /**
@@ -1036,13 +1096,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        final int oldRotation = mRotation;
        final int lastOrientation = mLastOrientation;
        final boolean oldAltOrientation = mAltOrientation;
        final int rotation = mService.mPolicy.rotationForOrientationLw(lastOrientation, oldRotation,
                isDefaultDisplay);
        final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id="
                + mDisplayId + " based on lastOrientation=" + lastOrientation
                + " and oldRotation=" + oldRotation);
        boolean mayRotateSeamlessly = mService.mPolicy.shouldRotateSeamlessly(oldRotation,
                rotation);
        boolean mayRotateSeamlessly = mService.mPolicy.shouldRotateSeamlessly(mDisplayRotation,
                oldRotation, rotation);

        if (mayRotateSeamlessly) {
            final WindowState seamlessRotated = getWindow((w) -> w.mSeamlesslyRotated);
@@ -1073,7 +1132,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        //       an orientation that has different metrics than it expected.
        //       eg. Portrait instead of Landscape.

        final boolean altOrientation = !mService.mPolicy.rotationHasCompatibleMetricsLw(
        final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics(
                lastOrientation, rotation);

        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
@@ -1095,11 +1154,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
            mService.mWaitingForConfig = true;
        }

        mRotation = rotation;
        setRotation(rotation);
        mAltOrientation = altOrientation;
        if (isDefaultDisplay) {
            mService.mPolicy.setRotationLw(rotation);
        }

        mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
        mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
@@ -1193,8 +1249,23 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    }

    void configureDisplayPolicy() {
        mService.mPolicy.setInitialDisplaySize(getDisplay(),
                mBaseDisplayWidth, mBaseDisplayHeight, mBaseDisplayDensity);
        final int width = mBaseDisplayWidth;
        final int height = mBaseDisplayHeight;
        final int shortSize;
        final int longSize;
        if (width > height) {
            shortSize = height;
            longSize = width;
        } else {
            shortSize = width;
            longSize = height;
        }

        final int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity;
        final int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity;

        mDisplayRotation.configure(width, height, shortSizeDp, longSizeDp);
        mDisplayPolicy.configure(width, height, shortSizeDp);

        mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
                calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
@@ -2369,6 +2440,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        pw.println();
        mDisplayFrames.dump(prefix, pw);
        pw.println();
        mDisplayPolicy.dump(prefix, pw);
        pw.println();
        mDisplayRotation.dump(prefix, pw);
        pw.println();
        mInputMonitor.dump(pw, "  ");
    }

+260 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.server.wm;

import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;

import android.content.Intent;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.Slog;

import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;

import java.io.PrintWriter;

/**
 * The policy that provides the basic behaviors and states of a display to show UI.
 */
public class DisplayPolicy {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;

    private final WindowManagerService mService;
    private final Object mLock;

    private final boolean mCarDockEnablesAccelerometer;
    private final boolean mDeskDockEnablesAccelerometer;

    private volatile int mLidState = LID_ABSENT;
    private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
    private volatile boolean mHdmiPlugged;

    private volatile boolean mHasNavigationBar;
    // Can the navigation bar ever move to the side?
    private volatile boolean mNavigationBarCanMove;

    // Written by vr manager thread, only read in this class.
    private volatile boolean mPersistentVrModeEnabled;

    private volatile boolean mAwake;
    private volatile boolean mScreenOnEarly;
    private volatile boolean mScreenOnFully;
    private volatile ScreenOnListener mScreenOnListener;

    private volatile boolean mKeyguardDrawComplete;
    private volatile boolean mWindowManagerDrawComplete;

    DisplayPolicy(WindowManagerService service) {
        mService = service;
        mLock = service.getWindowManagerLock();
        mCarDockEnablesAccelerometer = service.mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_carDockEnablesAccelerometer);
        mDeskDockEnablesAccelerometer = service.mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_deskDockEnablesAccelerometer);
    }

    void configure(int width, int height, int shortSizeDp) {
        // Allow the navigation bar to move on non-square small devices (phones).
        mNavigationBarCanMove = width != height && shortSizeDp < 600;

        mHasNavigationBar = mService.mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_showNavigationBar);

        // Allow a system property to override this. Used by the emulator.
        // See also hasNavigationBar().
        String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
        if ("1".equals(navBarOverride)) {
            mHasNavigationBar = false;
        } else if ("0".equals(navBarOverride)) {
            mHasNavigationBar = true;
        }
    }

    public void setHdmiPlugged(boolean plugged) {
        setHdmiPlugged(plugged, false /* force */);
    }

    public void setHdmiPlugged(boolean plugged, boolean force) {
        if (force || mHdmiPlugged != plugged) {
            mHdmiPlugged = plugged;
            mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
            final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
            intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
            mService.mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
        }
    }

    boolean isHdmiPlugged() {
        return mHdmiPlugged;
    }

    boolean isCarDockEnablesAccelerometer() {
        return mCarDockEnablesAccelerometer;
    }

    boolean isDeskDockEnablesAccelerometer() {
        return mDeskDockEnablesAccelerometer;
    }

    public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
        mPersistentVrModeEnabled = persistentVrModeEnabled;
    }

    public boolean isPersistentVrModeEnabled() {
        return mPersistentVrModeEnabled;
    }

    public void setDockMode(int dockMode) {
        mDockMode = dockMode;
    }

    public int getDockMode() {
        return mDockMode;
    }

    public boolean hasNavigationBar() {
        return mHasNavigationBar;
    }

    public boolean navigationBarCanMove() {
        return mNavigationBarCanMove;
    }

    public void setLidState(int lidState) {
        mLidState = lidState;
    }

    public int getLidState() {
        return mLidState;
    }

    public void setAwake(boolean awake) {
        mAwake = awake;
    }

    public boolean isAwake() {
        return mAwake;
    }

    public boolean isScreenOnEarly() {
        return mScreenOnEarly;
    }

    public boolean isScreenOnFully() {
        return mScreenOnFully;
    }

    public boolean isKeyguardDrawComplete() {
        return mKeyguardDrawComplete;
    }

    public boolean isWindowManagerDrawComplete() {
        return mWindowManagerDrawComplete;
    }

    public ScreenOnListener getScreenOnListener() {
        return mScreenOnListener;
    }

    public void screenTurnedOn(ScreenOnListener screenOnListener) {
        synchronized (mLock) {
            mScreenOnEarly = true;
            mScreenOnFully = false;
            mKeyguardDrawComplete = false;
            mWindowManagerDrawComplete = false;
            mScreenOnListener = screenOnListener;
        }
    }

    public void screenTurnedOff() {
        synchronized (mLock) {
            mScreenOnEarly = false;
            mScreenOnFully = false;
            mKeyguardDrawComplete = false;
            mWindowManagerDrawComplete = false;
            mScreenOnListener = null;
        }
    }

    /** Return false if we are not awake yet or we have already informed of this event. */
    public boolean finishKeyguardDrawn() {
        synchronized (mLock) {
            if (!mScreenOnEarly || mKeyguardDrawComplete) {
                return false;
            }

            mKeyguardDrawComplete = true;
            mWindowManagerDrawComplete = false;
        }
        return true;
    }

    /** Return false if screen is not turned on or we did already handle this case earlier. */
    public boolean finishWindowsDrawn() {
        synchronized (mLock) {
            if (!mScreenOnEarly || mWindowManagerDrawComplete) {
                return false;
            }

            mWindowManagerDrawComplete = true;
        }
        return true;
    }

    /** Return false if it is not ready to turn on. */
    public boolean finishScreenTurningOn() {
        synchronized (mLock) {
            if (DEBUG_SCREEN_ON) Slog.d(TAG,
                    "finishScreenTurningOn: mAwake=" + mAwake
                            + ", mScreenOnEarly=" + mScreenOnEarly
                            + ", mScreenOnFully=" + mScreenOnFully
                            + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
                            + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);

            if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
                    || (mAwake && !mKeyguardDrawComplete)) {
                return false;
            }

            if (DEBUG_SCREEN_ON) Slog.i(TAG, "Finished screen turning on...");
            mScreenOnListener = null;
            mScreenOnFully = true;
        }
        return true;
    }

    void dump(String prefix, PrintWriter pw) {
        pw.println(prefix + "DisplayPolicy");
        pw.print(prefix + "  mCarDockEnablesAccelerometer=" + mCarDockEnablesAccelerometer);
        pw.println(" mDeskDockEnablesAccelerometer=" + mDeskDockEnablesAccelerometer);
        pw.print(prefix + "  mDockMode=" + Intent.dockStateToString(mDockMode));
        pw.println(" mLidState=" + WindowManagerFuncs.lidStateToString(mLidState));
        pw.print(prefix + "  mAwake=" + mAwake);
        pw.print(" mScreenOnEarly=" + mScreenOnEarly);
        pw.println(" mScreenOnFully=" + mScreenOnFully);
        pw.print(prefix + "  mKeyguardDrawComplete=" + mKeyguardDrawComplete);
        pw.println(" mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
        pw.println(prefix + "  mHdmiPlugged=" + mHdmiPlugged);
    }
}
Loading