安卓系统强制旋转屏幕实现横竖屏切换
我們要實現開機強制系統橫屏或者豎屏,并且可以再系統中實時切換橫豎屏,首先分析代碼找到
WindowManagerService.java
@Overridepublic int getRotation() {return mRotation;}查看WindowManagerService.java代碼發現我們獲取當前屏幕參數時返回的是mRotation參數,繼續查看mRotation初始化調用
/** All DisplayContents in the world, kept here */SparseArray<DisplayContent> mDisplayContents = new SparseArray<>(2);int mRotation = 0; //初始化int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(mForcedAppOrientation, rotation);if (DEBUG_ORIENTATION) {Slog.v(TAG, "Application requested orientation "+ mForcedAppOrientation + ", got rotation " + rotation+ " which has " + (altOrientation ? "incompatible" : "compatible")+ " metrics");}if (mRotation == rotation && mAltOrientation == altOrientation) {// No change.return false;}if (DEBUG_ORIENTATION) {Slog.v(TAG,"Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")+ " from " + mRotation + (mAltOrientation ? " (alt)" : "")+ ", forceApp=" + mForcedAppOrientation);}mRotation = rotation;//代碼中唯一一次賦值發現代碼中只有一次賦值,我們先嘗試初始化時直接修改我這里為0 顯示是橫屏,修改為1,編譯后發現開機剛進去時豎了過來,但是馬上又橫了過來,說明有別的地方重新設置了參數,查看log發現是上述代碼修改了參數
int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(mForcedAppOrientation, rotation);if (DEBUG_ORIENTATION) {Slog.v(TAG, "Application requested orientation "+ mForcedAppOrientation + ", got rotation " + rotation+ " which has " + (altOrientation ? "incompatible" : "compatible")+ " metrics");}if (mRotation == rotation && mAltOrientation == altOrientation) {// No change.return false;}if (DEBUG_ORIENTATION) {Slog.v(TAG,"Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")+ " from " + mRotation + (mAltOrientation ? " (alt)" : "")+ ", forceApp=" + mForcedAppOrientation);}mRotation = rotation;mAltOrientation = altOrientation;mPolicy.setRotationLw(mRotation);根據mPolicy.rotationForOrientationLw查看發現
PhoneWindowManager.java
@Overridepublic 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" : ""));}if (mForceDefaultOrientation) {return Surface.ROTATION_0;}synchronized (mLock) {int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1if (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 && 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 (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.mAllowAllRotations = mContext.getResources().getBoolean(com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;}if (sensorRotation != Surface.ROTATION_180|| mAllowAllRotations == 1|| 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) {// 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;}}}發現是這個方法修改了屏幕方向參數,由于我們這邊直接強制修改,不需要動態判斷所以實行簡單粗暴的方法直接在最上面return我們想要的參數,寫上我們自己修改屏幕方向的參數。
這里我們實現了修改參數后重新開機實現橫豎屏切換,但是我們要實現開機時動態修改橫豎屏并實時顯示,
/*** 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.*/@Overridepublic void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);}//public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked("+ "alwaysSendConfiguration=" + alwaysSendConfiguration + ")");long origId = Binder.clearCallingIdentity();boolean changed;synchronized(mWindowMap) {changed = updateRotationUncheckedLocked(false);if (!changed || forceRelayout) {getDefaultDisplayContentLocked().layoutNeeded = true;performLayoutAndPlaceSurfacesLocked();}}if (changed || alwaysSendConfiguration) {sendNewConfiguration();}Binder.restoreCallingIdentity(origId);}查看上述代碼發現是此處刷新,我們可以再此刷新我們的參數,然后在應用界面設置的旋轉參數,然后通過系統服務調用updateRotation方法進行刷新
try {IWindowManager mWm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));mWm.updateRotation(true, true);} catch (SecurityException e) {// expected} catch (RemoteException e) {}此時旋轉成功,但是發現在豎屏時有的軟件是寫了強制橫屏的參數的話會出現顯示異常的情況,參考mstar設置強制橫屏屬性mstar.forcelandscape
// MStar Android Patch Beginpublic int screenOrientation = (1 == SystemProperties.getInt("mstar.forcelandscape", 0) ?ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);// MStar Android Patch End//查看activityinfo文件/** @hide */@IntDef({SCREEN_ORIENTATION_UNSPECIFIED,SCREEN_ORIENTATION_LANDSCAPE,SCREEN_ORIENTATION_PORTRAIT,SCREEN_ORIENTATION_USER,SCREEN_ORIENTATION_BEHIND,SCREEN_ORIENTATION_SENSOR,SCREEN_ORIENTATION_NOSENSOR,SCREEN_ORIENTATION_SENSOR_LANDSCAPE,SCREEN_ORIENTATION_SENSOR_PORTRAIT,SCREEN_ORIENTATION_REVERSE_LANDSCAPE,SCREEN_ORIENTATION_REVERSE_PORTRAIT,SCREEN_ORIENTATION_FULL_SENSOR,SCREEN_ORIENTATION_USER_LANDSCAPE,SCREEN_ORIENTATION_USER_PORTRAIT,SCREEN_ORIENTATION_FULL_USER,SCREEN_ORIENTATION_LOCKED})這里強制豎屏我們用到SCREEN_ORIENTATION_PORTRAIT,所以修改系統中mstar所有mstar.forcelandscape屬性判斷操作的
SCREEN_ORIENTATION_UNSPECIFIED 為 SCREEN_ORIENTATION_PORTRAIT
開機動畫修改為豎屏
BootAnimation.cpp
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),forcelandscape ? dinfo.h : dinfo.w,forcelandscape ? dinfo.w : dinfo.h,?
總結
以上是生活随笔為你收集整理的安卓系统强制旋转屏幕实现横竖屏切换的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【bzoj3698】【XWW的难题】【有
- 下一篇: 【人工智能】深度学习思维导图、人工智能思