
本文实例讲述了AndroID6.0开发中屏幕旋转原理与流程。分享给大家供大家参考,具体如下:
从AndroID 系统开发开始,这里写下AndroID 6.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,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类
@OverrIDepublic 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方法
@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);}// 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,animation in progress."); return false; } if (!mdisplayEnabled) { // No point choosing a rotation if the display is not enabled. if (DEBUG_ORIENTATION) Slog.v(TAG,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(),1); } /** * 关闭重力感应,即设置屏幕不可旋转 * @param context */ public static voID closeSensor(Context context){ Settings.System.putInt(context.getContentResolver(),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; }}更多关于AndroID相关内容感兴趣的读者可查看本站专题:《Android开发入门与进阶教程》、《Android视图View技巧总结》、《Android编程之activity *** 作技巧总结》、《Android文件 *** 作技巧汇总》、《Android资源 *** 作技巧汇总》及《Android控件用法总结》
希望本文所述对大家AndroID程序设计有所帮助。
总结以上是内存溢出为你收集整理的Android6.0开发中屏幕旋转原理与流程分析全部内容,希望文章能够帮你解决Android6.0开发中屏幕旋转原理与流程分析所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)