屏幕横竖屏切换的设置是在packages/apps/Settings下的DisplaySettings.java中定义的,代码如下:
在frameworks/base/policy/src/com/android/internal/policy/impl/phonewindowmanager.java中,定义了一个Observer,用来观察Setting数据库的改动,代码如下:
mFancyRotationAnimation);的实现类是windowmanagerservice.java:
到这里,屏幕的横竖屏切换大概就分析完了,如有错误疏漏的地方敬请指正!
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
if (preference == mAccelerometer) {
Settings.System.putInt(getContentResolver(),
Settings.System.ACCELEROMETER_ROTATION,
mAccelerometer.isChecked() ? 1 : 0);
}
else if (preference instanceof PreferenceScreen) {
final String key = preference.getKey();
if (KEY_SENSORLEVELCALIBRATION.equals(key)) {
Intent intent = new Intent(this, SensorLevelCalibration.class);
startActivity(intent);
}
}
return true;
}
通过跟踪代码,发现最后跑到了frameworks/base/core/java/android/provider/settings.java中,代码如下:
protected static boolean putString(ContentResolver resolver, Uri uri,
String name, String value) {
// The database will take care of replacing duplicates.
try {
ContentValues values = new ContentValues();
values.put(NAME, name);
values.put(VALUE, value);
resolver.insert(uri, values);
return true;
} catch (SQLException e) {
Log.w(TAG, "Can't set key " + name + " in " + uri, e);
return false;
}
}
即将值插入到了setting的数据库中,开关设置到这里就算完成了,下面来分析后续的动作。
在frameworks/base/policy/src/com/android/internal/policy/impl/phonewindowmanager.java中,定义了一个Observer,用来观察Setting数据库的改动,代码如下:
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
}
//设置观察对象
void observe() {
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.END_BUTTON_BEHAVIOR), false, this);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.ACCELEROMETER_ROTATION), false, this);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_OFF_TIMEOUT), false, this);
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.POINTER_LOCATION), false, this);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
resolver.registerContentObserver(Settings.System.getUriFor(
"fancy_rotation_anim"), false, this);
updateSettings();
}
//当观察对象改变时,回调
@Override public void onChange(boolean selfChange) {
updateSettings();
try {
mWindowManager.setRotation(USE_LAST_ROTATION, false,
mFancyRotationAnimation);
} catch (RemoteException e) {
// Ignore
}
}
}
从上面代码可以看出,当setting数据库中被注册了的几个值发生改变时,就会调用onChange()函数,下面先分析updateSettings():
public void updateSettings() {
ContentResolver resolver = mContext.getContentResolver();
.
.
int accelerometerDefault = Settings.System.getInt(resolver,
Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION);
if (mAccelerometerDefault != accelerometerDefault) {
mAccelerometerDefault = accelerometerDefault;
updateOrientationListenerLp(); //进行更改
}
.
.
}
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) Log.v(TAG, "Screen status="+mScreenOn+
", current orientation="+mCurrentAppOrientation+
", SensorEnabled="+mOrientationSensorEnabled);
boolean disable = true;
if (mScreenOn) { //当屏幕是开启状态时,才能进行屏幕旋转
if (needSensorRunningLp()) { //根据当前sensor的反馈信息和当前屏幕状态检查是否需要循环转屏幕
disable = false;
//enable listener if not already enabled
if (!mOrientationSensorEnabled) { //如果mOrientationListener状态是disable的
mOrientationListener.enable();
if(localLOGV) Log.v(TAG, "Enabling listeners");
mOrientationSensorEnabled = true;
}
}
}
}
mOrientationListener.enable()的实现方法在frameworks/base/core/java/android/view/windoworientationlistener.java中:
public void enable() {
if (mSensor == null) {
Log.w(TAG, "Cannot detect sensors. Not enabled");
return;
}
if (mEnabled == false) {
if (localLOGV) Log.d(TAG, "WindowOrientationListener enabled");
mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
mEnabled = true;
}
}
可以看到,在enable()方法中,在mSensorManager中注册了一个mSensorEventListener,下面就要分析下在mSensorEventListener中做了什么事情,mSensorEventListener是SensorEventListenerImpl的一个对象,在SensorEventListenerImpl的实现中,其实现了onSensorChanged()方法,这个方法就是当传感器发生数据变化时接收数据,并进行计算的地方了。
下面再继续分析Observer的onChange()方法:mWindowManager.setRotation(USE_LAST_ROTATION, false,mFancyRotationAnimation);的实现类是windowmanagerservice.java:
public void setRotation(int rotation,
boolean alwaysSendConfiguration, int animFlags) {
if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
"setRotation()")) {
throw new SecurityException("Requires SET_ORIENTATION permission");
}
setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags);
}
继续跟进:
public void setRotationUnchecked(int rotation,
boolean alwaysSendConfiguration, int animFlags) {
if(DEBUG_ORIENTATION) Slog.v(TAG,
"alwaysSendConfiguration set to "+alwaysSendConfiguration);
long origId = Binder.clearCallingIdentity();
boolean changed;
synchronized(mWindowMap) {
changed = setRotationUncheckedLocked(rotation, animFlags); //
}
if (changed || alwaysSendConfiguration) {
sendNewConfiguration();
}
Binder.restoreCallingIdentity(origId);
}
setRotationUncheckedLocked()的官方说法是:Apply a new rotation to the screen, respecting the requests of applications. Use WindowManagerPolicy.USE_LAST_ROTATION to simply re-evaluate the desired rotation.大概就是重新计算要旋转的方向吧。下一步如果要旋转的话,则调用sendNewConfiguration():
void sendNewConfiguration() {
try {
mActivityManager.updateConfiguration(null);
} catch (RemoteException e) {
}
}
即通知窗口管理器要重画窗口了,后续的就是一个Activity的oncreate()等一系列过程。
到这里,屏幕的横竖屏切换大概就分析完了,如有错误疏漏的地方敬请指正!