您好,登錄后才能下訂單哦!
這篇文章給大家介紹Android6.0中屏幕旋轉的原理是什么,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
第一部分
Kenel
Android 系統屏幕旋轉得以實現,是靠從底層驅動gsensor 中獲取數據,從而判斷屏幕方向的。kernel sensor的驅動先就不在這里贅述,簡單介紹下,gsensor 驅動注冊input 事件 在/dev/input/下,可以通過adb getevent -p 可以查看系統所有的輸入事件。
gsensor 提供X/Y/Z 三個方向的加速度數據,一旦注冊到系統,hardware 層打開設備之后,sensor 就開始上報數據。注意這里很關鍵,sensor 驅動加載完成之后,并不會立即激活,需要hardware 層打開設備激活設備,設備才開始工作。
第二部分
Hardware
在hardware層,通過注冊android 標準modules之后,設備就打開激活,在Android 系統就注冊了
{ .name = “Gravity sensor”, .vendor = “The Android Open Source Project”, .version = 1, .handle = SENSORS_HANDLE_BASE+ID_A, .type = SENSOR_TYPE_ACCELEROMETER, .maxRange = 4.0f*9.81f, .resolution = (4.0f*9.81f)/256.0f, .power = 0.2f, .minDelay = 5000, .reserved = {} },
第三部分
framework
PhoneWindownManager.java中的updateSettings()
中讀取系統中屏幕的設置方式,一旦開啟自動旋轉就調用updateOrientationListenerLp()
開啟讀取sensor 數據;
// Configure rotation lock. int userRotation = Settings.System.getIntForUser(resolver, Settings.System.USER_ROTATION, Surface.ROTATION_0, UserHandle.USER_CURRENT); if (mUserRotation != userRotation) { mUserRotation = userRotation; updateRotation = true; } int userRotationMode = Settings.System.getIntForUser(resolver, Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ? WindowManagerPolicy.USER_ROTATION_FREE : WindowManagerPolicy.USER_ROTATION_LOCKED; if (mUserRotationMode != userRotationMode) { mUserRotationMode = userRotationMode; updateRotation = true; updateOrientationListenerLp(); }
updateOrientationListenerLp中調用mOrientationListener.enable();
調用到WindowOrientationListener.java中enable 注冊gsensor的監聽
void updateOrientationListenerLp() { if (!mOrientationListener.canDetectOrientation()) { // If sensor is turned off or nonexistent for some reason return; } // Could have been invoked due to screen turning on or off or // change of the currently visible window's orientation. if (localLOGV) Slog.v(TAG, "mScreenOnEarly=" + mScreenOnEarly + ", mAwake=" + mAwake + ", mCurrentAppOrientation=" + mCurrentAppOrientation + ", mOrientationSensorEnabled=" + mOrientationSensorEnabled + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete); boolean disable = true; // Note: We postpone the rotating of the screen until the keyguard as well as the // window manager have reported a draw complete. if (mScreenOnEarly && mAwake && mKeyguardDrawComplete && mWindowManagerDrawComplete) { if (needSensorRunningLp()) { disable = false; //enable listener if not already enabled if (!mOrientationSensorEnabled) { mOrientationListener.enable(); if(localLOGV) Slog.v(TAG, "Enabling listeners"); mOrientationSensorEnabled = true; } } } //check if sensors need to be disabled if (disable && mOrientationSensorEnabled) { mOrientationListener.disable(); if(localLOGV) Slog.v(TAG, "Disabling listeners"); mOrientationSensorEnabled = false; } } /** * Enables the WindowOrientationListener so it will monitor the sensor and call * {@link #onProposedRotationChanged(int)} when the device orientation changes. */ public void enable() { synchronized (mLock) { if (mSensor == null) { Slog.w(TAG, "Cannot detect sensors. Not enabled"); return; } if (mEnabled == false) { if (LOG) { Slog.d(TAG, "WindowOrientationListener enabled"); } mOrientationJudge.resetLocked(); mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler); mEnabled = true; } } }
mOrientationJudge 類型為OrientationJudge ,其中onSensorChanged方法提供了通過gsensor 各個方向的加速度數據計算方向的方法。一旦計算出屏幕方向發送變化則調用onProposedRotationChanged接口通知前面的Listener。而onProposedRotationChanged是一個抽象方法,由子類實現也PhoneWindowManger 中的MyOrientationListener類
@Override public void onProposedRotationChanged(int rotation) { if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation); mHandler.post(mUpdateRotationRunnable); } private final Runnable mUpdateRotationRunnable = new Runnable() { @Override public void run() { // send interaction hint to improve redraw performance mPowerManagerInternal.powerHint(PowerManagerInternal.POWER_HINT_INTERACTION, 0); updateRotation(false); } }; void updateRotation(boolean alwaysSendConfiguration) { try { //set orientation on WindowManager mWindowManager.updateRotation(alwaysSendConfiguration, false); } catch (RemoteException e) { // Ignore } }
調用windowManagerService中的updateRotation方法
@Override public 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); } // TODO(multidisplay): Rotate any display? /** * Updates the current rotation. * * Returns true if the rotation has been changed. In this case YOU * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN. */ public boolean updateRotationUncheckedLocked(boolean inTransaction) { if (mDeferredRotationPauseCount > 0) { // Rotation updates have been paused temporarily. Defer the update until // updates have been resumed. if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused."); return false; } ScreenRotationAnimation screenRotationAnimation = mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY); 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, "Deferring rotation, animation in progress."); return false; } if (!mDisplayEnabled) { // No point choosing a rotation if the display is not enabled. if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled."); return false; } // TODO: Implement forced rotation changes. // Set mAltOrientation to indicate that the application is receiving // an orientation that has different metrics than it expected. // eg. Portrait instead of Landscape. 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 (mRotateOnBoot) { mRotation = Surface.ROTATION_0; rotation = Surface.ROTATION_90; } /* display portrait, force android rotation according to 90 */ if("true".equals(SystemProperties.get("persist.display.portrait","false"))){ rotation = Surface.ROTATION_90; } /* display portrait end */ // if("vr".equals(SystemProperties.get("ro.target.product","tablet"))) // rotation = Surface.ROTATION_0; if (mRotation == rotation && mAltOrientation == altOrientation) { // No change. return false; } resetWindowState(); 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); ThumbModeHelper.getInstance().setRotation(mRotation); mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE; mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); if (mFirstRotate) { mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, 5000); mFirstRotate = false; } else { mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION); } mWaitingForConfig = true; final DisplayContent displayContent = getDefaultDisplayContentLocked(); displayContent.layoutNeeded = true; final int[] anim = new int[2]; if (displayContent.isDimming()) { anim[0] = anim[1] = 0; } else { mPolicy.selectRotationAnimationLw(anim); } startFreezingDisplayLocked(inTransaction, anim[0], anim[1]); // startFreezingDisplayLocked can reset the ScreenRotationAnimation. screenRotationAnimation = mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY); boolean isDelay = true; /*(("true".equals(SystemProperties.get("ro.config.low_ram", "false"))) ||("true".equals(SystemProperties.get("ro.mem_optimise.enable", "false")))) && (!"true".equals(SystemProperties.get("sys.cts_gts.status", "false")));*/ if (mRotateOnBoot) { try { IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger"); if (surfaceFlinger != null) { Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED !!!!!"); Parcel data = Parcel.obtain(); data.writeInterfaceToken("android.ui.ISurfaceComposer"); surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, data, null, 0); data.recycle(); } } catch (RemoteException ex) { Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!"); } } // We need to update our screen size information to match the new rotation. If the rotation // has actually changed then this method will return true and, according to the comment at // the top of the method, the caller is obligated to call computeNewConfigurationLocked(). // By updating the Display info here it will be available to // computeScreenConfigurationLocked later. updateDisplayAndOrientationLocked(); final DisplayInfo displayInfo = displayContent.getDisplayInfo(); if (!inTransaction) { if (SHOW_TRANSACTIONS) { Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked"); } SurfaceControl.openTransaction(); } try { // NOTE: We disable the rotation in the emulator because // it doesn't support hardware OpenGL emulation yet. if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()) { if (screenRotationAnimation.setRotationInTransaction( rotation, mFxSession, MAX_ANIMATION_DURATION, getTransitionAnimationScaleLocked(), displayInfo.logicalWidth, displayInfo.logicalHeight)) { scheduleAnimationLocked(); } } mDisplayManagerInternal.performTraversalInTransactionFromWindowManager(); } finally { if (!inTransaction) { SurfaceControl.closeTransaction(); if (SHOW_LIGHT_TRANSACTIONS) { Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked"); } } } final WindowList windows = displayContent.getWindowList(); for (int i = windows.size() - 1; i >= 0; i--) { WindowState w = windows.get(i); if (w.mHasSurface) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w); w.mOrientationChanging = true; mInnerFields.mOrientationChangeComplete = false; } w.mLastFreezeDuration = 0; } for (int i=mRotationWatchers.size()-1; i>=0; i--) { try { mRotationWatchers.get(i).watcher.onRotationChanged(rotation); } catch (RemoteException e) { } } //TODO (multidisplay): Magnification is supported only for the default display. // Announce rotation only if we will not animate as we already have the // windows in final state. Otherwise, we make this call at the rotation`這里寫代碼片` end. if (screenRotationAnimation == null && mAccessibilityController != null && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) { mAccessibilityController.onRotationChangedLocked(getDefaultDisplayContentLocked(), rotation); } return true; }
附:Android動態禁用或開啟屏幕旋轉的方法
package com.gwtsz.gts2.util; import android.content.Context; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; /** * 重力感應器開關 * 圍繞手機屏幕旋轉的設置功能編寫的方法 * @author Wilson */ public class SensorUtil { /** * 打開重力感應,即設置屏幕可旋轉 * @param context */ public static void openSensor(Context context){ Settings.System.putInt(context.getContentResolver(),Settings.System.ACCELEROMETER_ROTATION, 1); } /** * 關閉重力感應,即設置屏幕不可旋轉 * @param context */ public static void closeSensor(Context context){ Settings.System.putInt(context.getContentResolver(),Settings.System.ACCELEROMETER_ROTATION, 0); } /** * 獲取屏幕旋轉功能開啟狀態 * @param context * @return */ public static int getSensorState(Context context){ int sensorState = 0; try { sensorState = Settings.System.getInt(context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION); return sensorState; } catch (SettingNotFoundException e) { e.printStackTrace(); } return sensorState; } /** * 判斷屏幕旋轉功能是否開啟 */ public static boolean isOpenSensor(Context context){ boolean isOpen = false; if(getSensorState(context) == 1){ isOpen = true; }else if(getSensorState(context) == 0){ isOpen = false; } return isOpen; } }
關于Android6.0中屏幕旋轉的原理是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。