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();
        }
    }
相关推荐
alexhilton2 小时前
使用LoRA微调Gemma实现移动端推理
android·kotlin·android jetpack
冬奇Lab2 小时前
Zygote进程孵化与应用启动机制:从fork到SystemServer的完整旅程
android·源码阅读
姜行运4 小时前
【Linux】基础指令2
android·linux·服务器
大模型玩家七七5 小时前
技术抉择:微调还是 RAG?——以春节祝福生成为例
android·java·大数据·开发语言·人工智能·算法·安全
低调小一5 小时前
Fresco 图片加载全链路解析:从 SimpleDraweeView 到 Producer 责任链
android·开发语言·fresco
Asmewill5 小时前
Kotlin高阶函数
android
我命由我123456 小时前
Android Studio - 在 Android Studio 中直观查看 Git 代码的更改
android·java·开发语言·git·java-ee·android studio·android jetpack
hewence16 小时前
Kotlin协程启动方式详解
android·开发语言·kotlin
城东米粉儿6 小时前
Android EventHub的Epoll原理 笔记
android