Android6.0开发中屏幕旋转原理与流程分析
本文实例讲述了Android6.0开发中屏幕旋转原理与流程。分享给大家供大家参考,具体如下:
从Android系统开发开始,这里写下Android6.0屏幕旋转系统分析。
第一部分
Kenel
Android系统屏幕旋转得以实现,是靠从底层驱动gsensor中获取数据,从而判断屏幕方向的。kernelsensor的驱动先就不在这里赘述,简单介绍下,gsensor驱动注册input事件在/dev/input/下,可以通过adbgetevent-p可以查看系统所有的输入事件。
gsensor提供X/Y/Z三个方向的加速度数据,一旦注册到系统,hardware层打开设备之后,sensor就开始上报数据。注意这里很关键,sensor驱动加载完成之后,并不会立即激活,需要hardware层打开设备激活设备,设备才开始工作。
第二部分
Hardware
在hardware层,通过注册android标准modules之后,设备就打开激活,在Android系统就注册了
{.name=“Gravitysensor”,
.vendor=“TheAndroidOpenSourceProject”,
.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数据;
//Configurerotationlock.
intuserRotation=Settings.System.getIntForUser(resolver,
Settings.System.USER_ROTATION,Surface.ROTATION_0,
UserHandle.USER_CURRENT);
if(mUserRotation!=userRotation){
mUserRotation=userRotation;
updateRotation=true;
}
intuserRotationMode=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的监听
voidupdateOrientationListenerLp(){
if(!mOrientationListener.canDetectOrientation()){
//Ifsensoristurnedoffornonexistentforsomereason
return;
}
//Couldhavebeeninvokedduetoscreenturningonoroffor
//changeofthecurrentlyvisiblewindow'sorientation.
if(localLOGV)Slog.v(TAG,"mScreenOnEarly="+mScreenOnEarly
+",mAwake="+mAwake+",mCurrentAppOrientation="+mCurrentAppOrientation
+",mOrientationSensorEnabled="+mOrientationSensorEnabled
+",mKeyguardDrawComplete="+mKeyguardDrawComplete
+",mWindowManagerDrawComplete="+mWindowManagerDrawComplete);
booleandisable=true;
//Note:Wepostponetherotatingofthescreenuntilthekeyguardaswellasthe
//windowmanagerhavereportedadrawcomplete.
if(mScreenOnEarly&&mAwake&&
mKeyguardDrawComplete&&mWindowManagerDrawComplete){
if(needSensorRunningLp()){
disable=false;
//enablelistenerifnotalreadyenabled
if(!mOrientationSensorEnabled){
mOrientationListener.enable();
if(localLOGV)Slog.v(TAG,"Enablinglisteners");
mOrientationSensorEnabled=true;
}
}
}
//checkifsensorsneedtobedisabled
if(disable&&mOrientationSensorEnabled){
mOrientationListener.disable();
if(localLOGV)Slog.v(TAG,"Disablinglisteners");
mOrientationSensorEnabled=false;
}
}
/**
*EnablestheWindowOrientationListenersoitwillmonitorthesensorandcall
*{@link#onProposedRotationChanged(int)}whenthedeviceorientationchanges.
*/
publicvoidenable(){
synchronized(mLock){
if(mSensor==null){
Slog.w(TAG,"Cannotdetectsensors.Notenabled");
return;
}
if(mEnabled==false){
if(LOG){
Slog.d(TAG,"WindowOrientationListenerenabled");
}
mOrientationJudge.resetLocked();
mSensorManager.registerListener(mOrientationJudge,mSensor,mRate,mHandler);
mEnabled=true;
}
}
}
mOrientationJudge类型为OrientationJudge,其中onSensorChanged方法提供了通过gsensor各个方向的加速度数据计算方向的方法。一旦计算出屏幕方向发送变化则调用onProposedRotationChanged接口通知前面的Listener。而onProposedRotationChanged是一个抽象方法,由子类实现也PhoneWindowManger中的MyOrientationListener类
@Override
publicvoidonProposedRotationChanged(introtation){
if(localLOGV)Slog.v(TAG,"onProposedRotationChanged,rotation="+rotation);
mHandler.post(mUpdateRotationRunnable);
}
privatefinalRunnablemUpdateRotationRunnable=newRunnable(){
@Override
publicvoidrun(){
//sendinteractionhinttoimproveredrawperformance
mPowerManagerInternal.powerHint(PowerManagerInternal.POWER_HINT_INTERACTION,0);
updateRotation(false);
}
};
voidupdateRotation(booleanalwaysSendConfiguration){
try{
//setorientationonWindowManager
mWindowManager.updateRotation(alwaysSendConfiguration,false);
}catch(RemoteExceptione){
//Ignore
}
}
调用windowManagerService中的updateRotation方法
@Override
publicvoidupdateRotation(booleanalwaysSendConfiguration,booleanforceRelayout){
updateRotationUnchecked(alwaysSendConfiguration,forceRelayout);
}
publicvoidupdateRotationUnchecked(booleanalwaysSendConfiguration,booleanforceRelayout){
if(DEBUG_ORIENTATION)Slog.v(TAG,"updateRotationUnchecked("
+"alwaysSendConfiguration="+alwaysSendConfiguration+")");
longorigId=Binder.clearCallingIdentity();
booleanchanged;
synchronized(mWindowMap){
changed=updateRotationUncheckedLocked(false);
if(!changed||forceRelayout){
getDefaultDisplayContentLocked().layoutNeeded=true;
performLayoutAndPlaceSurfacesLocked();
}
}
if(changed||alwaysSendConfiguration){
sendNewConfiguration();
}
Binder.restoreCallingIdentity(origId);
}
//TODO(multidisplay):Rotateanydisplay?
/**
*Updatesthecurrentrotation.
*
*Returnstrueiftherotationhasbeenchanged.InthiscaseYOU
*MUSTCALLsendNewConfiguration()TOUNFREEZETHESCREEN.
*/
publicbooleanupdateRotationUncheckedLocked(booleaninTransaction){
if(mDeferredRotationPauseCount>0){
//Rotationupdateshavebeenpausedtemporarily.Defertheupdateuntil
//updateshavebeenresumed.
if(DEBUG_ORIENTATION)Slog.v(TAG,"Deferringrotation,rotationispaused.");
returnfalse;
}
ScreenRotationAnimationscreenRotationAnimation=
mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
if(screenRotationAnimation!=null&&screenRotationAnimation.isAnimating()){
//Rotationupdatescannotbeperformedwhilethepreviousrotationchange
//animationisstillinprogress.Skipthisupdate.Wewilltryupdating
//againaftertheanimationisfinishedandthedisplayisunfrozen.
if(DEBUG_ORIENTATION)Slog.v(TAG,"Deferringrotation,animationinprogress.");
returnfalse;
}
if(!mDisplayEnabled){
//Nopointchoosingarotationifthedisplayisnotenabled.
if(DEBUG_ORIENTATION)Slog.v(TAG,"Deferringrotation,displayisnotenabled.");
returnfalse;
}
//TODO:Implementforcedrotationchanges.
//SetmAltOrientationtoindicatethattheapplicationisreceiving
//anorientationthathasdifferentmetricsthanitexpected.
//eg.PortraitinsteadofLandscape.
introtation=mPolicy.rotationForOrientationLw(mForcedAppOrientation,mRotation);
booleanaltOrientation=!mPolicy.rotationHasCompatibleMetricsLw(
mForcedAppOrientation,rotation);
if(DEBUG_ORIENTATION){
Slog.v(TAG,"Applicationrequestedorientation"
+mForcedAppOrientation+",gotrotation"+rotation
+"whichhas"+(altOrientation?"incompatible":"compatible")
+"metrics");
}
if(mRotateOnBoot){
mRotation=Surface.ROTATION_0;
rotation=Surface.ROTATION_90;
}
/*displayportrait,forceandroidrotationaccordingto90*/
if("true".equals(SystemProperties.get("persist.display.portrait","false"))){
rotation=Surface.ROTATION_90;
}
/*displayportraitend*/
//if("vr".equals(SystemProperties.get("ro.target.product","tablet")))
//rotation=Surface.ROTATION_0;
if(mRotation==rotation&&mAltOrientation==altOrientation){
//Nochange.
returnfalse;
}
resetWindowState();
if(DEBUG_ORIENTATION){
Slog.v(TAG,
"Rotationchangedto"+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;
finalDisplayContentdisplayContent=getDefaultDisplayContentLocked();
displayContent.layoutNeeded=true;
finalint[]anim=newint[2];
if(displayContent.isDimming()){
anim[0]=anim[1]=0;
}else{
mPolicy.selectRotationAnimationLw(anim);
}
startFreezingDisplayLocked(inTransaction,anim[0],anim[1]);
//startFreezingDisplayLockedcanresettheScreenRotationAnimation.
screenRotationAnimation=
mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
booleanisDelay=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{
IBindersurfaceFlinger=ServiceManager.getService("SurfaceFlinger");
if(surfaceFlinger!=null){
Slog.i(TAG,"*******TELLINGSURFACEFLINGERWEAREBOOTED!!!!!");
Parceldata=Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
data,null,0);
data.recycle();
}
}catch(RemoteExceptionex){
Slog.e(TAG,"Bootcompleted:SurfaceFlingerisdead!");
}
}
//Weneedtoupdateourscreensizeinformationtomatchthenewrotation.Iftherotation
//hasactuallychangedthenthismethodwillreturntrueand,accordingtothecommentat
//thetopofthemethod,thecallerisobligatedtocallcomputeNewConfigurationLocked().
//ByupdatingtheDisplayinfohereitwillbeavailableto
//computeScreenConfigurationLockedlater.
updateDisplayAndOrientationLocked();
finalDisplayInfodisplayInfo=displayContent.getDisplayInfo();
if(!inTransaction){
if(SHOW_TRANSACTIONS){
Slog.i(TAG,">>>OPENTRANSACTIONsetRotationUnchecked");
}
SurfaceControl.openTransaction();
}
try{
//NOTE:Wedisabletherotationintheemulatorbecause
//itdoesn'tsupporthardwareOpenGLemulationyet.
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,"<<=0;i--){
WindowStatew=windows.get(i);
if(w.mHasSurface){
if(DEBUG_ORIENTATION)Slog.v(TAG,"SetmOrientationChangingof"+w);
w.mOrientationChanging=true;
mInnerFields.mOrientationChangeComplete=false;
}
w.mLastFreezeDuration=0;
}
for(inti=mRotationWatchers.size()-1;i>=0;i--){
try{
mRotationWatchers.get(i).watcher.onRotationChanged(rotation);
}catch(RemoteExceptione){
}
}
//TODO(multidisplay):Magnificationissupportedonlyforthedefaultdisplay.
//Announcerotationonlyifwewillnotanimateaswealreadyhavethe
//windowsinfinalstate.Otherwise,wemakethiscallattherotation`这里写代码片`end.
if(screenRotationAnimation==null&&mAccessibilityController!=null
&&displayContent.getDisplayId()==Display.DEFAULT_DISPLAY){
mAccessibilityController.onRotationChangedLocked(getDefaultDisplayContentLocked(),
rotation);
}
returntrue;
}
附:Android动态禁用或开启屏幕旋转的方法
packagecom.gwtsz.gts2.util;
importandroid.content.Context;
importandroid.provider.Settings;
importandroid.provider.Settings.SettingNotFoundException;
/**
*重力感应器开关
*围绕手机屏幕旋转的设置功能编写的方法
*@authorWilson
*/
publicclassSensorUtil{
/**
*打开重力感应,即设置屏幕可旋转
*@paramcontext
*/
publicstaticvoidopenSensor(Contextcontext){
Settings.System.putInt(context.getContentResolver(),Settings.System.ACCELEROMETER_ROTATION,1);
}
/**
*关闭重力感应,即设置屏幕不可旋转
*@paramcontext
*/
publicstaticvoidcloseSensor(Contextcontext){
Settings.System.putInt(context.getContentResolver(),Settings.System.ACCELEROMETER_ROTATION,0);
}
/**
*获取屏幕旋转功能开启状态
*@paramcontext
*@return
*/
publicstaticintgetSensorState(Contextcontext){
intsensorState=0;
try{
sensorState=Settings.System.getInt(context.getContentResolver(),Settings.System.ACCELEROMETER_ROTATION);
returnsensorState;
}catch(SettingNotFoundExceptione){
e.printStackTrace();
}
returnsensorState;
}
/**
*判断屏幕旋转功能是否开启
*/
publicstaticbooleanisOpenSensor(Contextcontext){
booleanisOpen=false;
if(getSensorState(context)==1){
isOpen=true;
}elseif(getSensorState(context)==0){
isOpen=false;
}
returnisOpen;
}
}
更多关于Android相关内容感兴趣的读者可查看本站专题:《Android开发入门与进阶教程》、《Android视图View技巧总结》、《Android编程之activity操作技巧总结》、《Android文件操作技巧汇总》、《Android资源操作技巧汇总》及《Android控件用法总结》
希望本文所述对大家Android程序设计有所帮助。