Android屏幕旋转DisplayRotation - Android15

Android屏幕旋转DisplayRotation - Android15

  • 1、初始化监听WindowOrientationListener
    • [1.1 updateOrientationListenerLw状态更新](#1.1 updateOrientationListenerLw状态更新)
    • [1.2 WindowOrientationListener中SensorEventListener处理](#1.2 WindowOrientationListener中SensorEventListener处理)
  • [2、 DisplayRotation界面方向更新](#2、 DisplayRotation界面方向更新)
    • [2.1 传递给屏幕对应的`LogicalDisplay`](#2.1 传递给屏幕对应的LogicalDisplay)
    • [2.2 通过`LogicalDisplay`传递给`SurfaceComposerClient`](#2.2 通过LogicalDisplay传递给SurfaceComposerClient)
  • 3、灭屏时注销OrientationJudge监听

1、初始化监听WindowOrientationListener

Android主副屏显示-Android14 每个屏幕对应LogicalDisplay,添加对应DisplayContent,而DisplayRotationDisplayContent成员。
DisplayRotation 中初始化:

  1. OrientationListener 继承 WindowOrientationListener
  2. mSettingsObserver.observe() 中判断启用 mOrientationListener.enable()

frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java

java 复制代码
    DisplayRotation(WindowManagerService service, DisplayContent displayContent,
            DisplayAddress displayAddress, DisplayPolicy displayPolicy,
            DisplayWindowSettings displayWindowSettings, Context context, Object lock,
            @NonNull DeviceStateController deviceStateController,
            @NonNull DisplayRotationCoordinator displayRotationCoordinator) {
        //.....................
        if (isDefaultDisplay) {
            final Handler uiHandler = UiThread.getHandler();
            mOrientationListener =
                    new OrientationListener(mContext, uiHandler, defaultRotation);
            mOrientationListener.setCurrentRotation(mRotation);
            mSettingsObserver = new SettingsObserver(uiHandler);
            mSettingsObserver.observe();
            if (mSupportAutoRotation && isFoldable(mContext)) {
                mFoldController = new FoldController();
            } else {
                mFoldController = null;
            }
        } else {
            mFoldController = null;
        }
    }

1.1 updateOrientationListenerLw状态更新

屏幕关闭,如果已启用,则应始终禁用监听器。

屏幕已打开,当前app具有基于传感器的方向,如果尚未启用,请启用监听器。

屏幕已打开,当前app没有传感器方向,如果已启用,请禁用侦听器。

屏幕已打开,当前app具有基于传感器的方向,如果需要,可以启用监听器。

屏幕已打开,当前app具有基于鼻传感器的方向,什么都不做。

frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java

java 复制代码
    private void updateOrientationListenerLw() {
        if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {
            // If sensor is turned off or nonexistent for some reason.
            return;
        }

        final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();
        final boolean awake = mDisplayPolicy.isAwake();
        final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();
        final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();

        // Could have been invoked due to screen turning on or off or
        // change of the currently visible window's orientation.
        ProtoLog.v(WM_DEBUG_ORIENTATION,
                "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, "
                        + "orientationSensorEnabled=%b, keyguardDrawComplete=%b, "
                        + "windowManagerDrawComplete=%b",
                screenOnEarly, awake, mCurrentAppOrientation, mOrientationListener.mEnabled,
                keyguardDrawComplete, windowManagerDrawComplete);

        boolean disable = true;

        // If the orientation listener uses a wake sensor, keep the orientation listener on if the
        // screen is on (regardless of wake state). This allows the AoD to rotate.
        //
        // Note: We postpone the rotating of the screen until the keyguard as well as the
        // window manager have reported a draw complete or the keyguard is going away in dismiss
        // mode.
        if (screenOnEarly
                && (awake || mOrientationListener.shouldStayEnabledWhileDreaming())
                && ((keyguardDrawComplete && windowManagerDrawComplete))) {
            if (needSensorRunning()) {
                disable = false;
                // Enable listener if not already enabled.
                if (!mOrientationListener.mEnabled) {
                    mOrientationListener.enable();
                }
            }
        }
        // Check if sensors need to be disabled.
        if (disable) {
            mOrientationListener.disable();
        }
    }

1.2 WindowOrientationListener中SensorEventListener处理

1、TYPE_DEVICE_ORIENTATION 优先使用该sensor,并且优先使用该sensor的 WakeUp 类型,使用继承SensorEventListenerOrientationSensorJudge处理数据, int reportedRotation = (int) event.values[0]; 直接上方向,不需要额外处理

2、TYPE_ACCELEROMETER 默认USE_GRAVITY_SENSOR = false,所以使用该sensor,使用继承SensorEventListenerAccelSensorJudge处理数据,比较复杂,最终isTiltAngleAcceptableLocked(nearestRotation, tiltAngle) && isOrientationAngleAcceptableLocked(nearestRotation, orientationAngle) 各种角度计算后赋值给mPredictedRotation

3、最终传感器方向赋值给mProposedRotation,通过 mOrientationListener.getProposedRotation() 获取sensor方向

java 复制代码
    private WindowOrientationListener(Context context, Handler handler,
            @Surface.Rotation int defaultRotation, int rate) {
        mContext = context;
        mHandler = handler;
        mDefaultRotation = defaultRotation;
        mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
        mRate = rate;
        List<Sensor> l = mSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION);
        Sensor wakeUpDeviceOrientationSensor = null;
        Sensor nonWakeUpDeviceOrientationSensor = null;
        /**
         *  Prefer the wakeup form of the sensor if implemented.
         *  It's OK to look for just two types of this sensor and use
         *  the last found. Typical devices will only have one sensor of
         *  this type.
         */
        for (Sensor s : l) {
            if (s.isWakeUpSensor()) {
                wakeUpDeviceOrientationSensor = s;
            } else {
                nonWakeUpDeviceOrientationSensor = s;
            }
        }

        if (wakeUpDeviceOrientationSensor != null) {
            mSensor = wakeUpDeviceOrientationSensor;
        } else {
            mSensor = nonWakeUpDeviceOrientationSensor;
        }

        if (mSensor != null) {
            mOrientationJudge = new OrientationSensorJudge();
        }

        if (mOrientationJudge == null) {
            mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
                    ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
            if (mSensor != null) {
                // Create listener only if sensors do exist
                mOrientationJudge = new AccelSensorJudge(context);
            }
        }
    }

2、 DisplayRotation界面方向更新

2.1 传递给屏幕对应的LogicalDisplay

1、updateRotationUnchecked > rotationForOrientation > mRotation = rotation; 对象mRotation更新

2、通过 DisplayContentsetDisplayInfoOverride()将包含方向信息mDisplayInfo传递给LogicalDisplaymOverrideDisplayInfo

frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java

java 复制代码
    int rotationForOrientation(@ScreenOrientation int orientation,
            @Surface.Rotation int lastRotation) {
        ProtoLog.v(WM_DEBUG_ORIENTATION,
                "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s",
                ActivityInfo.screenOrientationToString(orientation), orientation,
                Surface.rotationToString(lastRotation), lastRotation,
                Surface.rotationToString(mUserRotation), mUserRotation,
                mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
                        ? "USER_ROTATION_LOCKED" : "");

        if (isFixedToUserRotation()) {
            return mUserRotation;
        }

        @Surface.Rotation
        int sensorRotation = mOrientationListener != null
                ? mOrientationListener.getProposedRotation() // may be -1
                : -1;
        if (mFoldController != null && mFoldController.shouldIgnoreSensorRotation()) {
            sensorRotation = -1;
        }
        if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis(mDisplayContent)) {
            sensorRotation = RotationUtils.reverseRotationDirectionAroundZAxis(sensorRotation);
        }
        mLastSensorRotation = sensorRotation;
        if (sensorRotation < 0) {
            sensorRotation = lastRotation;
        }

        final int lidState = mDisplayPolicy.getLidState();
        final int dockMode = mDisplayPolicy.getDockMode();
        final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
        final boolean carDockEnablesAccelerometer =
                mDisplayPolicy.isCarDockEnablesAccelerometer();
        final boolean deskDockEnablesAccelerometer =
                mDisplayPolicy.isDeskDockEnablesAccelerometer();

        @Surface.Rotation
        final int preferredRotation;
        if (!isDefaultDisplay) {
            // For secondary displays we ignore things like displays sensors, docking mode and
            // rotation lock, and always prefer user rotation.
            preferredRotation = mUserRotation;
        } else if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
            // Ignore sensor when lid switch is open and rotation is forced.
            preferredRotation = mLidOpenRotation;
        } else if (dockMode == Intent.EXTRA_DOCK_STATE_CAR
                && (carDockEnablesAccelerometer || mCarDockRotation >= 0)) {
            // Ignore sensor when in car dock unless explicitly enabled.
            // This case can override the behavior of NOSENSOR, and can also
            // enable 180 degree rotation while docked.
            preferredRotation = carDockEnablesAccelerometer ? sensorRotation : mCarDockRotation;
        } else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
                || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
                || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
                && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)
                && !(orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED
                        || orientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)) {
            // Ignore sensor when in desk dock unless explicitly enabled.
            // This case can enable 180 degree rotation while docked.
            preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation;
        } else if (hdmiPlugged && mDemoHdmiRotationLock) {
            // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
            // Note that the dock orientation overrides the HDMI orientation.
            preferredRotation = mDemoHdmiRotation;
        } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
                && mUndockedHdmiRotation >= 0) {
            // Ignore sensor when plugged into HDMI and an undocked orientation has
            // been specified in the configuration (only for legacy devices without
            // full multi-display support).
            // Note that the dock orientation overrides the HDMI orientation.
            preferredRotation = mUndockedHdmiRotation;
        } else if (mDemoRotationLock) {
            // Ignore sensor when demo rotation lock is enabled.
            // Note that the dock orientation and HDMI rotation lock override this.
            preferredRotation = mDemoRotation;
        } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
            // While in VR, apps always prefer a portrait rotation. This does not change
            // any apps that explicitly set landscape, but does cause sensors be ignored,
            // and ignored any orientation lock that the user has set (this conditional
            // should remain above the ORIENTATION_LOCKED conditional below).
            preferredRotation = mPortraitRotation;
        } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
            // Application just wants to remain locked in the last rotation.
            preferredRotation = lastRotation;
        } else if (!mSupportAutoRotation) {
            if (mFixedToUserRotation == IWindowManager.FIXED_TO_USER_ROTATION_IF_NO_AUTO_ROTATION) {
                preferredRotation = mUserRotation;
            } else {
                // If we don't support auto-rotation then bail out here and ignore
                // the sensor and any rotation lock settings.
                preferredRotation = -1;
            }
        } else if (((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
                            || isTabletopAutoRotateOverrideEnabled())
                        && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
                                || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
                                || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
                                || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
                                || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))
                || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
                || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
                || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
                || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
            // Otherwise, use sensor only if requested by the application or enabled
            // by default for USER or UNSPECIFIED modes.  Does not apply to NOSENSOR.
            if (sensorRotation != Surface.ROTATION_180
                    || getAllowAllRotations() == ALLOW_ALL_ROTATIONS_ENABLED
                    || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
                    || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
                preferredRotation = sensorRotation;
            } else {
                preferredRotation = lastRotation;
            }
        } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
                && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
                && orientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
                && orientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
                && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
                && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {
            // Apply rotation lock. Does not apply to NOSENSOR or specific rotations.
            // The idea is that the user rotation expresses a weak preference for the direction
            // of gravity and as NOSENSOR is never affected by gravity, then neither should
            // NOSENSOR be affected by rotation lock (although it will be affected by docks).
            // Also avoid setting user rotation when app has preference over one particular rotation
            // to avoid leaving the rotation to the reverse of it which has the compatible
            // orientation, but isn't what app wants, when the user rotation is the reverse of the
            // preferred rotation.
            preferredRotation = mUserRotation;
        } else {
            // No overriding preference.
            // We will do exactly what the application asked us to do.
            preferredRotation = -1;
        }

        switch (orientation) {
            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
                // Return portrait unless overridden.
                if (isAnyPortrait(preferredRotation)) {
                    return preferredRotation;
                }
                return mPortraitRotation;

            case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
                // Return landscape unless overridden.
                if (isLandscapeOrSeascape(preferredRotation)) {
                    return preferredRotation;
                }
                return mLandscapeRotation;

            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
                // Return reverse portrait unless overridden.
                if (isAnyPortrait(preferredRotation)) {
                    return preferredRotation;
                }
                return mUpsideDownRotation;

            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
                // Return seascape unless overridden.
                if (isLandscapeOrSeascape(preferredRotation)) {
                    return preferredRotation;
                }
                return mSeascapeRotation;

            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
            case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
                // Return either landscape rotation.
                if (isLandscapeOrSeascape(preferredRotation)) {
                    return preferredRotation;
                }
                if (isLandscapeOrSeascape(lastRotation)) {
                    return lastRotation;
                }
                return mLandscapeRotation;

            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
            case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
                // Return either portrait rotation.
                if (isAnyPortrait(preferredRotation)) {
                    return preferredRotation;
                }
                if (isAnyPortrait(lastRotation)) {
                    return lastRotation;
                }
                return mPortraitRotation;

            default:
                // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
                // just return the preferred orientation we already calculated.
                if (preferredRotation >= 0) {
                    return preferredRotation;
                }
                return Surface.ROTATION_0;
        }
    }

frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

java 复制代码
    private void setDisplayInfoOverride() {
        mWmService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(mDisplayId,
                mDisplayInfo);

        if (mLastDisplayInfoOverride == null) {
            mLastDisplayInfoOverride = new DisplayInfo();
        }

        mLastDisplayInfoOverride.copyFrom(mDisplayInfo);
    }
 
   private DisplayInfo updateDisplayAndOrientation(Configuration outConfig) {
        // Use the effective "visual" dimensions based on current rotation
        final int rotation = getRotation();
        final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
        final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
        final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;

        // Update application display metrics.
        final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
        final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
        final DisplayShape displayShape = calculateDisplayShapeForRotation(rotation);

        final Rect appFrame = mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
        mDisplayInfo.rotation = rotation;
        mDisplayInfo.logicalWidth = dw;
        mDisplayInfo.logicalHeight = dh;
        mDisplayInfo.logicalDensityDpi = mBaseDisplayDensity;
        mDisplayInfo.physicalXDpi = mBaseDisplayPhysicalXDpi;
        mDisplayInfo.physicalYDpi = mBaseDisplayPhysicalYDpi;
        mDisplayInfo.appWidth = appFrame.width();
        mDisplayInfo.appHeight = appFrame.height();
        if (isDefaultDisplay) {
            mDisplayInfo.getLogicalMetrics(mRealDisplayMetrics,
                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
        }
        mDisplayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout;
        mDisplayInfo.roundedCorners = roundedCorners;
        mDisplayInfo.displayShape = displayShape;
        mDisplayInfo.getAppMetrics(mDisplayMetrics);
        if (mDisplayScalingDisabled) {
            mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
        } else {
            mDisplayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
        }

        computeSizeRanges(mDisplayInfo, rotated, dw, dh, mDisplayMetrics.density, outConfig,
                false /* overrideConfig */);

        setDisplayInfoOverride();

        if (isDefaultDisplay) {
            mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
                    mCompatDisplayMetrics);
        }

        onDisplayInfoChanged();

        return mDisplayInfo;
    }

frameworks/base/services/core/java/com/android/server/display/LogicalDisplay.java

java 复制代码
    public boolean setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo info) {
        if (info != null) {
            if (mOverrideDisplayInfo == null) {
                mOverrideDisplayInfo = new DisplayInfo(info);
                mInfo.set(null);
                return true;
            } else if (!mOverrideDisplayInfo.equals(info)) {
                mOverrideDisplayInfo.copyFrom(info);
                mInfo.set(null);
                return true;
            }
        } else if (mOverrideDisplayInfo != null) {
            mOverrideDisplayInfo = null;
            mInfo.set(null);
            return true;
        }
        return false;
    }

2.2 通过LogicalDisplay传递给SurfaceComposerClient

  1. Android主副屏显示-Android14configureDisplayLocked刷新获取 displayInfo = getDisplayInfoLocked(); , 新增DisplayInfoOverrides.java单独处理
  2. device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect) :最终更新到 sfSurfaceComposerClient::Transaction::setDisplayProjection
  3. 内置屏幕才包含FLAG_ROTATES_WITH_CONTENT,跟随逻辑屏旋转orientation = displayInfo.rotation;

frameworks/base/services/core/java/com/android/server/wm/utils/DisplayInfoOverrides.java

java 复制代码
    /**
     * Set of DisplayInfo fields that are overridden in DisplayManager using values from
     * WindowManager
     */
    public static final DisplayInfoFieldsUpdater WM_OVERRIDE_FIELDS = (out, source) -> {
        out.appWidth = source.appWidth;
        out.appHeight = source.appHeight;
        out.smallestNominalAppWidth = source.smallestNominalAppWidth;
        out.smallestNominalAppHeight = source.smallestNominalAppHeight;
        out.largestNominalAppWidth = source.largestNominalAppWidth;
        out.largestNominalAppHeight = source.largestNominalAppHeight;
        out.logicalWidth = source.logicalWidth;
        out.logicalHeight = source.logicalHeight;
        out.physicalXDpi = source.physicalXDpi;
        out.physicalYDpi = source.physicalYDpi;
        out.rotation = source.rotation;
        out.displayCutout = source.displayCutout;
        out.logicalDensityDpi = source.logicalDensityDpi;
        out.roundedCorners = source.roundedCorners;
        out.displayShape = source.displayShape;
    };

    /**
     * Gets {@param base} DisplayInfo, overrides WindowManager-specific overrides using
     * {@param override} and writes the result to {@param out}
     */
    public static void copyDisplayInfoFields(@NonNull DisplayInfo out,
            @NonNull DisplayInfo base,
            @Nullable DisplayInfo override,
            @NonNull DisplayInfoFieldsUpdater fields) {
        out.copyFrom(base);

        if (override != null) {
            fields.setFields(out, override);
        }
    }

frameworks/base/services/core/java/com/android/server/display/LogicalDisplay.java

java 复制代码
    public void configureDisplayLocked(SurfaceControl.Transaction t,
            DisplayDevice device,
            boolean isBlanked) {
        // Set the layer stack.
        device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack, mDisplayId);
        // Also inform whether the device is the same one sent to inputflinger for its layerstack.
        // Prevent displays that are disabled from receiving input.
        // TODO(b/188914255): Remove once input can dispatch against device vs layerstack.
        device.setDisplayFlagsLocked(t,
                (isEnabledLocked() && device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE)
                        ? SurfaceControl.DISPLAY_RECEIVES_INPUT
                        : 0);

        // Set the color mode and allowed display mode.
        if (device == mPrimaryDisplayDevice) {
            device.setDesiredDisplayModeSpecsLocked(mDesiredDisplayModeSpecs);
            device.setRequestedColorModeLocked(mRequestedColorMode);
        } else {
            // Reset to default for non primary displays
            device.setDesiredDisplayModeSpecsLocked(
                    new DisplayModeDirector.DesiredDisplayModeSpecs());
            device.setRequestedColorModeLocked(0);
        }

        device.setAutoLowLatencyModeLocked(mRequestedMinimalPostProcessing);
        device.setGameContentTypeLocked(mRequestedMinimalPostProcessing);

        // Only grab the display info now as it may have been changed based on the requests above.
        final DisplayInfo displayInfo = getDisplayInfoLocked();
        final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();

        // Set the viewport.
        // This is the area of the logical display that we intend to show on the
        // display device.  For now, it is always the full size of the logical display.
        mTempLayerStackRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);

        // Set the orientation.
        // The orientation specifies how the physical coordinate system of the display
        // is rotated when the contents of the logical display are rendered.
        int orientation = Surface.ROTATION_0;

        // FLAG_ROTATES_WITH_CONTENT is now handled in DisplayContent. When the flag
        // mAlwaysRotateDisplayDeviceEnabled is removed, we should also remove this check for
        // ROTATES_WITH_CONTENT here and always set the orientation.
        if ((displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0
                    || mAlwaysRotateDisplayDeviceEnabled) {
            orientation = displayInfo.rotation;
        }

        // Apply the physical rotation of the display device itself.
        orientation = (orientation + displayDeviceInfo.rotation) % 4;

        // Set the frame.
        // The frame specifies the rotated physical coordinates into which the viewport
        // is mapped.  We need to take care to preserve the aspect ratio of the viewport.
        // Currently we maximize the area to fill the display, but we could try to be
        // more clever and match resolutions.
        boolean rotated = (orientation == Surface.ROTATION_90
                || orientation == Surface.ROTATION_270);
        int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
        int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;

        Rect maskingInsets = getMaskingInsets(displayDeviceInfo);
        InsetUtils.rotateInsets(maskingInsets, orientation);
        // Don't consider the masked area as available when calculating the scaling below.
        physWidth -= maskingInsets.left + maskingInsets.right;
        physHeight -= maskingInsets.top + maskingInsets.bottom;

        var displayLogicalWidth = displayInfo.logicalWidth;
        var displayLogicalHeight = displayInfo.logicalHeight;

        if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.type == Display.TYPE_EXTERNAL
                    && displayDeviceInfo.xDpi > 0 && displayDeviceInfo.yDpi > 0) {
            if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * DisplayDevice.MAX_ANISOTROPY) {
                var scalingFactor = displayDeviceInfo.yDpi / displayDeviceInfo.xDpi;
                if (rotated) {
                    displayLogicalWidth = (int) ((float) displayLogicalWidth * scalingFactor + 0.5);
                } else {
                    displayLogicalHeight = (int) ((float) displayLogicalHeight * scalingFactor
                                                          + 0.5);
                }
            } else if (displayDeviceInfo.xDpi * DisplayDevice.MAX_ANISOTROPY
                               < displayDeviceInfo.yDpi) {
                var scalingFactor = displayDeviceInfo.xDpi / displayDeviceInfo.yDpi;
                if (rotated) {
                    displayLogicalHeight = (int) ((float) displayLogicalHeight * scalingFactor
                                                          + 0.5);
                } else {
                    displayLogicalWidth = (int) ((float) displayLogicalWidth * scalingFactor + 0.5);
                }
            }
        }

        // Determine whether the width or height is more constrained to be scaled.
        //    physWidth / displayInfo.logicalWidth    => letter box
        // or physHeight / displayInfo.logicalHeight  => pillar box
        //
        // We avoid a division (and possible floating point imprecision) here by
        // multiplying the fractions by the product of their denominators before
        // comparing them.
        int displayRectWidth, displayRectHeight;
        if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0 || mDisplayScalingDisabled) {
            displayRectWidth = displayLogicalWidth;
            displayRectHeight = displayLogicalHeight;
        } else if (physWidth * displayLogicalHeight
                < physHeight * displayLogicalWidth) {
            // Letter box.
            displayRectWidth = physWidth;
            displayRectHeight = displayLogicalHeight * physWidth / displayLogicalWidth;
        } else {
            // Pillar box.
            displayRectWidth = displayLogicalWidth * physHeight / displayLogicalHeight;
            displayRectHeight = physHeight;
        }
        int displayRectTop = (physHeight - displayRectHeight) / 2;
        int displayRectLeft = (physWidth - displayRectWidth) / 2;
        mTempDisplayRect.set(displayRectLeft, displayRectTop,
                displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);

        // Now add back the offset for the masked area.
        mTempDisplayRect.offset(maskingInsets.left, maskingInsets.top);

        if (orientation == Surface.ROTATION_0) {
            mTempDisplayRect.offset(mDisplayOffsetX, mDisplayOffsetY);
        } else if (orientation == Surface.ROTATION_90) {
            mTempDisplayRect.offset(mDisplayOffsetY, -mDisplayOffsetX);
        } else if (orientation == Surface.ROTATION_180) {
            mTempDisplayRect.offset(-mDisplayOffsetX, -mDisplayOffsetY);
        } else {  // Surface.ROTATION_270
            mTempDisplayRect.offset(-mDisplayOffsetY, mDisplayOffsetX);
        }

        mDisplayPosition.set(mTempDisplayRect.left, mTempDisplayRect.top);
        device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect);
    }

3、灭屏时注销OrientationJudge监听

DisplayRotation更新时灭屏状态screenOnEarly = mDisplayPolicy.isScreenOnEarly(),注销sensor监听,尤其是使用wake sensor

java 复制代码
    private void updateOrientationListenerLw() {
        if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {
            // If sensor is turned off or nonexistent for some reason.
            return;
        }

        final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();
        final boolean awake = mDisplayPolicy.isAwake();
        final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();
        final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();

        // Could have been invoked due to screen turning on or off or
        // change of the currently visible window's orientation.
        ProtoLog.v(WM_DEBUG_ORIENTATION,
                "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, "
                        + "orientationSensorEnabled=%b, keyguardDrawComplete=%b, "
                        + "windowManagerDrawComplete=%b",
                screenOnEarly, awake, mCurrentAppOrientation, mOrientationListener.mEnabled,
                keyguardDrawComplete, windowManagerDrawComplete);

        boolean disable = true;

        // If the orientation listener uses a wake sensor, keep the orientation listener on if the
        // screen is on (regardless of wake state). This allows the AoD to rotate.
        //
        // Note: We postpone the rotating of the screen until the keyguard as well as the
        // window manager have reported a draw complete or the keyguard is going away in dismiss
        // mode.
        if (screenOnEarly
                && (awake || mOrientationListener.shouldStayEnabledWhileDreaming())
                && ((keyguardDrawComplete && windowManagerDrawComplete))) {
            if (needSensorRunning()) {
                disable = false;
                // Enable listener if not already enabled.
                if (!mOrientationListener.mEnabled) {
                    mOrientationListener.enable();
                }
            }
        }
        // Check if sensors need to be disabled.
        if (disable) {
            mOrientationListener.disable();
        }
    }
相关推荐
小脑斧12316 分钟前
安卓专属|青禾去水印 APP 免费无广告 多媒体素材处理工具
android
菜鸟国国2 小时前
一步到位学 Compose + Paging3:从 0 到 1 实现分页加载(超详细新手教程)
android
TO_ZRG2 小时前
Android Service基础
android
ECT-OS-JiuHuaShan3 小时前
功夫不负匠心人,渡劫代谢舞沧桑
android·开发语言·人工智能·算法·机器学习·kotlin·拓扑学
ZC跨境爬虫4 小时前
移动端爬虫工具Fiddler完整配置流程:PC+安卓模拟器全覆盖,零基础一次配置成功
android·前端·爬虫·测试工具·fiddler
巴德鸟4 小时前
DaVinci 常用技巧 关键帧 自动字幕 追踪 音频 冻结帧 快捷键 多轨道字幕 扩充边缘
android·编辑器·音视频·视频·davinci·davin
学习使我健康5 小时前
Android 广播介绍详情
android·开发语言·kotlin
dalancon6 小时前
AudioTrack Start 执行流程分析
android
众少成多积小致巨6 小时前
Android 初始化语言入门
android·linux·c++