(1)疑问
(1)settings put system user_rotation 1是什么意思?
答:设置用户期望的屏幕转向,0代表:Surface.ROTATION_0竖屏;1代表:Surface.ROTATION_90横屏;
(2)设置user_rotation和GSensor哪个优先级更高,比如user_rotation = 0期待竖屏,但是打开屏幕旋转且处于横屏时,应该是横屏还是竖屏?
答:此时GSensor优先级更高,横屏显示,具体原因看第三个问题。
(3)SystemUI中的"自动旋转"按钮影响的是哪个数据和系统的值?
答:会影响Settings.System.ACCELEROMETER_ROTATION和DisplayRotation.userRotationMode的值。
java
// When not otherwise specified by the activity's screenOrientation, rotation should be determined by the system (that is, using sensors).
public final int USER_ROTATION_FREE = 0;
//When not otherwise specified by the activity's screenOrientation, rotation is set by the user.
public final int USER_ROTATION_LOCKED = 1;
USER_ROTATION_FREE :如果应用不指定屏幕方向,sensor传感器决定
USER_ROTATION_LOCKED:如果应用不指定屏幕方向,user决定方向,即user_rotation数据库值
打开自动旋转时候设置的是Settings.System.ACCELEROMETER_ROTATION的值,并且为1,否则设置成0,这个值会直接影响DisplayRotation.userRotationMode的值。
java
final int userRotationMode = Settings.System.getIntForUser(resolver,
Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) !=0
? WindowManagerPolicy.USER_ROTATION_FREE
: WindowManagerPolicy.USER_ROTATION_LOCKED;
也就说如果打开了自动旋转,userRotationMode = USER_ROTATION_FREE,代表通过sensor决定;
否则设置成USER_ROTATION_LOCKED,由user_rotation决定。
(2)屏幕旋转流程
在Framework中,屏幕旋转功能主要是由WMS模块中的DisplayRotation对象来完成,在启动WindowManagerService过程中,创建DisplayContent对象时,会创建一个对应的DisplayRotation负责屏幕旋转逻辑,一个DisiplayContent对象对应一个DisplayRotation对象,或者说DisplayContent对象中持有一个DisplayRotation对象。
在DisplayRotation中,将获取Sensor数据并转换成具体方向旋转角度值的逻辑交给了OrientationListener对象来负责。
总结如下:DisplayContent负责控制,DisplayRotation负责执行,OrientationListener负责获取数据。
(A)DisplayRotation的初始化
java
//frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
DisplayRotation(WindowManagerService service, DisplayContent displayContent,
DisplayPolicy displayPolicy, DisplayWindowSettings displayWindowSettings,
Context context, Object lock) {
// 是否支持自动旋转
mSupportAutoRotation =
mContext.getResources().getBoolean(R.bool.config_supportAutoRotation);
// lid open 时指定的旋转角度
mLidOpenRotation = readRotation(R.integer.config_lidOpenRotation);
// 放在car dock时指定的旋转角度
mCarDockRotation = readRotation(R.integer.config_carDockRotation);
// 放在desk dock时指定的旋转角度
mDeskDockRotation = readRotation(R.integer.config_deskDockRotation);
// Hdmi连接时指定的旋转角度
mUndockedHdmiRotation = readRotation(R.integer.config_undockedHdmiRotation);
if (isDefaultDisplay) {
final Handler uiHandler = UiThread.getHandler();
// 创建OrientationListener对象
mOrientationListener = new OrientationListener(mContext, uiHandler);
// 初始化
mOrientationListener.setCurrentRotation(mRotation);
// 监听SettingsProvider中的变化
mSettingsObserver = new SettingsObserver(uiHandler);
mSettingsObserver.observe();
}
}
屏幕旋转离不开Sensor的监听,具体是由OrientationListener来负责,它会获取Sensor对象、监听Sensor数据、将Sensor的数据转换成旋转角度,并通知WindowManagerService更新方向。
(B)OrientationListener监听Gsensor数据
java
//frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
private class OrientationListener extends WindowOrientationListener implements Runnable {
transient boolean mEnabled;
OrientationListener(Context context, Handler handler,
@Surface.Rotation int defaultRotation) {
super(context, handler, defaultRotation);
}
@Override
public void onProposedRotationChanged(@Surface.Rotation int rotation) {
ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation);
// Send interaction power boost to improve redraw performance.
mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0);
dispatchProposedRotation(rotation);
if (isRotationChoiceAllowed(rotation)) {
mRotationChoiceShownToUserForConfirmation = rotation;
final boolean isValid = isValidRotationChoice(rotation);
sendProposedRotationChangeToStatusBarInternal(rotation, isValid);
} else {
mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED;
mService.updateRotation(false /* alwaysSendConfiguration */,
false /* forceRelayout */);
}
}
@Override
public void enable() {
mEnabled = true;
getHandler().post(this);
ProtoLog.v(WM_DEBUG_ORIENTATION, "Enabling listeners");
}
@Override
public void disable() {
mEnabled = false;
getHandler().post(this);
ProtoLog.v(WM_DEBUG_ORIENTATION, "Disabling listeners");
}
@Override
public void run() {
if (mEnabled) {
super.enable();
} else {
super.disable();
}
}
}
我们看一下它的父类WindowOrientationListener相关。
java
//frameworks/base/services/core/java/com/android/server/wm/WindowOrientationListener.java
public abstract class WindowOrientationListener {
public WindowOrientationListener(Context context, Handler handler,
@Surface.Rotation int defaultRotation) {
this(context, handler, defaultRotation, SensorManager.SENSOR_DELAY_UI);
}
private WindowOrientationListener(Context context, Handler handler,
@Surface.Rotation int defaultRotation, int rate) {
mContext = context;
mHandler = handler;
mDefaultRotation = defaultRotation;
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mRate = rate;
List<Sensor> l = mSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION);
Sensor wakeUpDeviceOrientationSensor = null;
Sensor nonWakeUpDeviceOrientationSensor = null;
for (Sensor s : l) {
if (s.isWakeUpSensor()) {
wakeUpDeviceOrientationSensor = s;
} else {
nonWakeUpDeviceOrientationSensor = s;
}
}
if (wakeUpDeviceOrientationSensor != null) {
mSensor = wakeUpDeviceOrientationSensor;
} else {
mSensor = nonWakeUpDeviceOrientationSensor;
}
if (mSensor != null) {
//优先使用此种Sensor监听
mOrientationJudge = new OrientationSensorJudge();
}
if (mOrientationJudge == null) {
mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
if (mSensor != null) {
// Create listener only if sensors do exist
//还有另外一种选择
mOrientationJudge = new AccelSensorJudge(context);
}
}
}
abstract boolean isRotationResolverEnabled();
public abstract void onProposedRotationChanged(int rotation);
}
OrientationSensorJudge和AccelSensorJudge都是继承自OrientationJudge,而OrientationJudge类作为SensorEventListener的实现类来接收Sensor事件,根据不同的Sensor会有不同的OrientationJudge对象与之匹配,之所以这样做是因为不同的Sensor上报的原始数据不同,因此需要做不同的转换才能获得最终的旋转角度值。
java
//frameworks/base/services/core/java/com/android/server/wm/WindowOrientationListener.java
abstract class OrientationJudge implements SensorEventListener {
//...
@Override
public abstract void onAccuracyChanged(Sensor sensor, int accuracy);
@Override
public abstract void onSensorChanged(SensorEvent event);
}
java
final class OrientationSensorJudge extends OrientationJudge {
public void onSensorChanged(SensorEvent event) {
int reportedRotation = (int) event.values[0];
if (reportedRotation < 0 || reportedRotation > 3) {
return;
}
//...
finalizeRotation(reportedRotation);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
}
private void finalizeRotation(int reportedRotation) {
int newRotation;
synchronized (mLock) {
mDesiredRotation = reportedRotation;
newRotation = evaluateRotationChangeLocked();
}
if (newRotation >= 0) {
mLastRotationResolution = newRotation;
mLastRotationResolutionTimeStamp = SystemClock.uptimeMillis();
//最终回调子类实现的onProposedRotationChanged函数
onProposedRotationChanged(newRotation);
}
}
最终调用到OrientationListener的onProposedRotationChanged函数。
java
//frameworks/base/services/core/java/com/android/server/wm/WindowOrientationListener.java
final class AccelSensorJudge extends OrientationJudge {
public void onSensorChanged(SensorEvent event) {
float x = event.values[ACCELEROMETER_DATA_X];
float y = event.values[ACCELEROMETER_DATA_Y];
float z = event.values[ACCELEROMETER_DATA_Z];
final long now = event.timestamp;
final long then = mLastFilteredTimestampNanos;
final float timeDeltaMS = (now - then) * 0.000001f;
//各种计算函数
// Determine new proposed rotation.
oldProposedRotation = mProposedRotation;
if (mPredictedRotation < 0 || isPredictedRotationAcceptableLocked(now)) {
mProposedRotation = mPredictedRotation;
}
proposedRotation = mProposedRotation;
// Tell the listener.
if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {
//最终回调子类实现的onProposedRotationChanged函数
onProposedRotationChanged(proposedRotation);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
//判断当前的方向改变是否需要更新到系统
private boolean isPredictedRotationAcceptableLocked(long now) {
// The predicted rotation must have settled long enough.
//当前角度需要保持40ms以上
if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) {
return false;
}
// The last flat state (time since picked up) must have been sufficiently long ago.
//从手机平放着拿起需要500ms才会转屏
if (now < mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) {
return false;
}
// The last swing state (time since last movement to put down) must have been sufficiently long ago.
//晃动后300ms内都不能转屏
if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) {
return false;
}
// The last acceleration state must have been sufficiently long ago.
//加速转动的时候500ms都不能转屏
if (now < mAccelerationTimestampNanos
+ PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) {
return false;
}
// The last touch must have ended sufficiently long ago.
//手没有触摸屏幕500ms才能转屏
if (mTouched || now < mTouchEndedTimestampNanos
+ PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS) {
return false;
}
// Looks good!
return true;
}
}
可以看出以上二种实现,最终都会调用子类的onProposedRotationChanged函数来更新屏幕方向。
(C)监听SettingsProvider字段
另外在涉及到方向旋转功能上,DisplayRotation中还监听了以下四个SettingsProvider中的字段:
java
//frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
private class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
}
void observe() {
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.ACCELEROMETER_ROTATION), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.USER_ROTATION), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.CAMERA_AUTOROTATE), false, this,
UserHandle.USER_ALL);
updateSettings();
}
@Override
public void onChange(boolean selfChange) {
if (updateSettings()) {
mService.updateRotation(true /* alwaysSendConfiguration */,
false /* forceRelayout */);
}
}
}
- Settings.System.ACCELEROMETER_ROTATION:该字段表示屏幕旋转模式,是否使用加速度传感器控制屏幕的方向旋转,开启时表示自由模式,关闭表示锁定模式;
- Settings.System.USER_ROTATION:用户设置的屏幕旋转方向值,当没有使用加速度传感器,且顶层Activity没有指定旋转方向时作为默认值使用;
java
//frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
private boolean updateSettings() {
final ContentResolver resolver = mContext.getContentResolver();
// 是否更新旋转方向值
boolean shouldUpdateRotation = false;
synchronized (mLock) {
// 是否更新旋转方向监听
boolean shouldUpdateOrientationListener = false;
// Configure rotation suggestions.
final int showRotationSuggestions =
ActivityManager.isLowRamDeviceStatic()
? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED
: Settings.Secure.getIntForUser(resolver,
Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
UserHandle.USER_CURRENT);
if (mShowRotationSuggestions != showRotationSuggestions) {
mShowRotationSuggestions = showRotationSuggestions;
shouldUpdateOrientationListener = true;
}
// Configure rotation lock.
final int userRotation = Settings.System.getIntForUser(resolver,
Settings.System.USER_ROTATION, Surface.ROTATION_0,
UserHandle.USER_CURRENT);
if (mUserRotation != userRotation) {
mUserRotation = userRotation;
shouldUpdateRotation = true;
}
final 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;
shouldUpdateOrientationListener = true;
shouldUpdateRotation = true;
}
// 更新方向旋转监听状态
if (shouldUpdateOrientationListener) {
updateOrientationListenerLw(); // Enable or disable the orientation listener.
}
final int cameraRotationMode = Settings.Secure.getIntForUser(resolver,
Settings.Secure.CAMERA_AUTOROTATE, 0,
UserHandle.USER_CURRENT);
if (mCameraRotationMode != cameraRotationMode) {
mCameraRotationMode = cameraRotationMode;
shouldUpdateRotation = true;
}
}
return shouldUpdateRotation;
}
- shouldUpdateRotation = true表示需要更新旋转角度;
- shouldUpdateOrientationListener = true表示要更新旋转方向的监听状态;
- mUserRotationMode表示当前的方向旋转模式;
(D)方向旋转Sensor监听的注册与解除
旋转角度监听状态的更新在DisplayRotation.updateOrientationListenerLw()方法中,这里会进行旋转角度相关Sensor的注册和解除流程。
查看代码发现,在亮灭屏流程中,当keyguard绘制状态、window状态发生变化后,也都会通过DisplayRotation.updateOrientationListener()方法更新方向旋转Sensor的监听状态。
java
public void updateOrientationListener() {
synchronized (mLock) {
updateOrientationListenerLw();
}
}
下面就来看一下,系统在什么场景下需要监听相关Sensor来进行方向旋转,什么情况下不需要监听。
java
private void updateOrientationListenerLw() {
if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {
// If sensor is turned off or nonexistent for some reason.
return;
}
// 是否正在进行点亮屏幕的操作
final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();
// 是否唤醒系统
final boolean awake = mDisplayPolicy.isAwake();
// keyguard绘制是否完成
final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();
// 窗口绘制是否完成
final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();
boolean disable = true;
// 只有在屏幕唤醒状态,且keyguard和窗口全部绘制完成的情况下,才会有资格注册sensor监听
if (screenOnEarly
&& (awake || mOrientationListener.shouldStayEnabledWhileDreaming())
&& ((keyguardDrawComplete && windowManagerDrawComplete))) {
if (needSensorRunning()) {
disable = false;
// Enable listener if not already enabled.
if (!mOrientationListener.mEnabled) {
mOrientationListener.enable();
}
}
}
// Check if sensors need to be disabled.
if (disable) {
mOrientationListener.disable();
}
}
对于旋转角度Sensor的注册/解除,会有多个因素决定,如是否亮屏、Keyguard绘制是否完成等。其规则是,在屏幕唤醒状态,且keyguard和窗口全部绘制完成的情况下,如果needSensorRunning()方法返回true,就会注册Sensor去监听方向旋转。