Android8.0 屏幕旋转180度

一般手机只能旋转3个方向,这里将介绍如何让手机可以旋转180度,也就是上下颠倒。

1.静态方法
frameworks/base/core/res/res/values/config.xml
config_allowAllRotations通过这个来设置。

    <!-- Auto-rotation behavior -->

    <!-- If true, enables auto-rotation features using the accelerometer.
         Otherwise, auto-rotation is disabled.  Applications may still request
         to use specific orientations but the sensor is ignored and sensor-based
         orientations are not available.  Furthermore, all auto-rotation related
         settings are omitted from the system UI.  In certain situations we may
         still use the accelerometer to determine the orientation, such as when
         docked if the dock is configured to enable the accelerometer. -->
    <bool name="config_supportAutoRotation">true</bool>

    <!-- If true, the screen can be rotated via the accelerometer in all 4
         rotations as the default behavior. -->
    <bool name="config_allowAllRotations">true</bool>

2.动态方法
在手机确认要旋转后,就会走PhoneWindowManager.java的onProposedRotationChanged。

    class MyOrientationListener extends WindowOrientationListener {
        private final Runnable mUpdateRotationRunnable = new Runnable() {
            @Override
            public void run() {
                // send interaction hint to improve redraw performance
                mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
                updateRotation(false);
            }
        };

        MyOrientationListener(Context context, Handler handler) {
            super(context, handler);
        }

        @Override
        public void onProposedRotationChanged(int rotation) {
            if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
            mHandler.post(mUpdateRotationRunnable);
        }
    }

然后走

    void updateRotation(boolean alwaysSendConfiguration) {
        try {
            //set orientation on WindowManager
            mWindowManager.updateRotation(alwaysSendConfiguration, false);
        } catch (RemoteException e) {
            // Ignore
        }
    }

再走WindowManagerService.java的updateRotation。

    /**
     * Recalculate the current rotation.
     *
     * Called by the window manager policy whenever the state of the system changes
     * such that the current rotation might need to be updated, such as when the
     * device is docked or rotated into a new posture.
     */
    @Override
    public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
        updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
    }

再走

    private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
        if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked:"
                + " alwaysSendConfiguration=" + alwaysSendConfiguration
                + " forceRelayout=" + forceRelayout);

        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation");

        long origId = Binder.clearCallingIdentity();

        try {
            // TODO(multi-display): Update rotation for different displays separately.
            final boolean rotationChanged;
            final int displayId;
            synchronized (mWindowMap) {
                final DisplayContent displayContent = getDefaultDisplayContentLocked();
                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: display");
                rotationChanged = displayContent.updateRotationUnchecked(
                        false /* inTransaction */);
                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                if (!rotationChanged || forceRelayout) {
                    displayContent.setLayoutNeeded();
                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
                            "updateRotation: performSurfacePlacement");
                    mWindowPlacerLocked.performSurfacePlacement();
                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                }
                displayId = displayContent.getDisplayId();
            }

            if (rotationChanged || alwaysSendConfiguration) {
                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: sendNewConfiguration");
                sendNewConfiguration(displayId);
                Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

再走DisplayContent.java的updateRotationUnchecked


    /**
     * Update rotation of the display.
     *
     * Returns true if the rotation has been changed.  In this case YOU MUST CALL
     * {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
     */
    boolean updateRotationUnchecked(boolean inTransaction) {
        if (mService.mDeferredRotationPauseCount > 0) {
            // Rotation updates have been paused temporarily.  Defer the update until
            // updates have been resumed.
            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
            return false;
        }

        ScreenRotationAnimation screenRotationAnimation =
                mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
            // Rotation updates cannot be performed while the previous rotation change
            // animation is still in progress.  Skip this update.  We will try updating
            // again after the animation is finished and the display is unfrozen.
            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
            return false;
        }
        if (mService.mDisplayFrozen) {
            // Even if the screen rotation animation has finished (e.g. isAnimating
            // returns false), there is still some time where we haven't yet unfrozen
            // the display. We also need to abort rotation here.
            if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
                    "Deferring rotation, still finishing previous rotation");
            return false;
        }

        if (!mService.mDisplayEnabled) {
            // No point choosing a rotation if the display is not enabled.
            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled.");
            return false;
        }

        final int oldRotation = mRotation;
        final int lastOrientation = mLastOrientation;
        final boolean oldAltOrientation = mAltOrientation;
        int rotation = mService.mPolicy.rotationForOrientationLw(lastOrientation, oldRotation);
        final boolean rotateSeamlessly = mService.mPolicy.shouldRotateSeamlessly(oldRotation,
                rotation);

        if (rotateSeamlessly) {
            final WindowState seamlessRotated = getWindow((w) -> w.mSeamlesslyRotated);
            if (seamlessRotated != null) {
                // We can't rotate (seamlessly or not) while waiting for the last seamless rotation
                // to complete (that is, waiting for windows to redraw). It's tempting to check
                // w.mSeamlessRotationCount but that could be incorrect in the case of
                // window-removal.
                return false;
            }
        }
        。。。。。。
}

最后走PhoneWindowManager.java的rotationForOrientationLw

    @Override
    public int rotationForOrientationLw(int orientation, int lastRotation) {
        if (false) {
            Slog.v(TAG, "rotationForOrientationLw(orient="
                        + orientation + ", last=" + lastRotation
                        + "); user=" + mUserRotation + " "
                        + ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED)
                            ? "USER_ROTATION_LOCKED" : "")
                        );

        //Aaron add
        mAllowAllRotations = -1;

        if (mForceDefaultOrientation) {
            return Surface.ROTATION_0;
        }

        synchronized (mLock) {
            int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1
            if (sensorRotation < 0) {
                sensorRotation = lastRotation;
            }

            final int preferredRotation;
            if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {
                // Ignore sensor when lid switch is open and rotation is forced.
                preferredRotation = mLidOpenRotation;
            } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR
                    && (mCarDockEnablesAccelerometer || 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 = mCarDockEnablesAccelerometer
                        ? sensorRotation : mCarDockRotation;
            } else if ((mDockMode == Intent.EXTRA_DOCK_STATE_DESK
                    || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
                    || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
                    && (mDeskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
                // Ignore sensor when in desk dock unless explicitly enabled.
                // This case can override the behavior of NOSENSOR, and can also
                // enable 180 degree rotation while docked.
                preferredRotation = mDeskDockEnablesAccelerometer
                        ? sensorRotation : mDeskDockRotation;
            } else if ((mHdmiPlugged || mWifiDisplayConnected) && 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 (mWifiDisplayConnected && (mWifiDisplayCustomRotation > -1)) {
                // Ignore sensor when WFD is active and UIBC rotation is enabled
                 preferredRotation = mWifiDisplayCustomRotation;
            } else if (mHdmiPlugged && mDockMode == 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 (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
                // Application just wants to remain locked in the last rotation.
                preferredRotation = lastRotation;
            } else if (!mSupportAutoRotation) {
                // 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
                            && (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 (mAllowAllRotations < 0) {
                    // Can't read this during init() because the context doesn't
                    // have display metrics at that time so we cannot determine
                    // tablet vs. phone then.

                    //这里注释掉原来的 添加自己修改的
                    //Aaron change
                    /*mAllowAllRotations = mContext.getResources().getBoolean(
                            com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;*/
                    mAllowAllRotations = Global.getInt(mContext.getContentResolver(), Global.ALLOW_ALL_ROTATION_ON,0);
                    int enable = Global.getInt(mContext.getContentResolver(), Global.AUTO_ROTATION, 0);
                    if (enable != 1)
                        mAllowAllRotations = -1;
                }
                if (sensorRotation != Surface.ROTATION_180
                        || mAllowAllRotations == 1
                        || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
                        || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
                    // In VrMode, we report the sensor as always being in default orientation so:
                    // 1) The orientation doesn't change as the user moves their head.
                    // 2) 2D apps within VR show in the device's default orientation.
                    // This only overwrites the sensor-provided orientation and does not affect any
                    // explicit orientation preferences specified by any activities.
                    preferredRotation =
                            mPersistentVrModeEnabled ? Surface.ROTATION_0 : sensorRotation;
                } else {
                    preferredRotation = lastRotation;
                }
            } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
                    && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
                // Apply rotation lock.  Does not apply to NOSENSOR.
                // 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).
                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;
            }
        }
    }

这里主要就是修改mAllowAllRotations的值,虽然每次旋转都要走这个判断要不要选择180度,但是实际上就判断一次,因为mAllowAllRotations这个值变了之后就不会再走赋值的地方了,可以看代码。所以我们要每次都要去根据要不要选择180度来改变这个值,所以每次进来先mAllowAllRotations=-1,然后就会走到赋值的那个里面,进行赋值。

是否要旋转180度的数据库。

mAllowAllRotations = Global.getInt(mContext.getContentResolver(), Global.ALLOW_ALL_ROTATION_ON,0);

注意:如果先把180度关闭,打开自动选择,把手机选择180度,然后再打开180度开关,这时候屏幕不会选择180度,正确的,但是当你再关闭自动旋转的时候,屏幕会先选择180度,然后再旋转回来。有问题,所以多加了个判断。

当自动旋转打开的时候才能旋转180。数据库自己加的。

                    int enable = Global.getInt(mContext.getContentResolver(), Global.AUTO_ROTATION, 0);
                    if (enable != 1)
                        mAllowAllRotations = -1;
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值