软件编程
位置:首页>> 软件编程>> Android编程>> Android6.0开发中屏幕旋转原理与流程分析

Android6.0开发中屏幕旋转原理与流程分析

作者:未来薇妮她爹  发布时间:2023-06-22 19:21:23 

标签:Android6.0,屏幕旋转

本文实例讲述了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, 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;
 }
}

希望本文所述对大家Android程序设计有所帮助。

来源:http://blog.csdn.net/xyyjxa/article/details/53939739

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com