Android 系统设置中显示设置之屏幕旋转和字体设置篇
继上一篇学习了android系统设置的UI内容后,今天学习android设置中有关显示设置的内容。
当我们点击系统设置的显示选项的时候,会跳转到有关系统显示设置的页面,该页面便是DisplaySettings.java,这个类的继承关系为:
原来它也是PreferenceFragment的子类,至于PreferenceFragment怎么使用,请详见:http://blog.csdn.net/zwq1457/article/details/8490004
我们看到在DisplaySettings的oncreate方法中addPreferencesFromResource(R.xml.display_settings)将我们所看到的界面加载进来,界面的内容就是display_settings.xml,具体定义如下:

1 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" 2 android:title="@string/display_settings" 3 xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"> 4 5 <com.android.settings.BrightnessPreference 6 android:title="@string/brightness" 7 android:persistent="false"/> 8 9 <PreferenceScreen 10 android:key="wallpaper" 11 android:title="@string/wallpaper_settings_title" 12 android:fragment="com.android.settings.WallpaperTypeSettings" /> 13 14 <CheckBoxPreference 15 android:key="accelerometer" 16 android:title="@string/accelerometer_title"/> 17 18 <ListPreference 19 android:key="screen_timeout" 20 android:title="@string/screen_timeout" 21 android:summary="@string/screen_timeout_summary" 22 android:persistent="false" 23 android:entries="@array/screen_timeout_entries" 24 android:entryValues="@array/screen_timeout_values" /> 25 26 <PreferenceScreen 27 android:key="screensaver" 28 android:title="@string/screensaver_settings_title" 29 android:fragment="com.android.settings.DreamSettings" /> 30 31 <com.android.settings.WarnedListPreference 32 android:key="font_size" 33 android:title="@string/title_font_size" 34 android:summary="@string/summary_font_size" 35 android:entries="@array/entries_font_size" 36 android:entryValues="@array/entryvalues_font_size" 37 android:dialogTitle="@string/dialog_title_font_size" /> 38 39 <CheckBoxPreference 40 android:key="notification_pulse" 41 android:title="@string/notification_pulse_title" 42 android:persistent="false" /> 43 44 <PreferenceScreen 45 android:key="wifi_display" 46 android:title="@string/wifi_display_settings_title" 47 android:fragment="com.android.settings.wfd.WifiDisplaySettings" /> 48 49 </PreferenceScreen>
设置界面说完了,我们就来看看具体代码是如何设置的。
1. 首先了解一下自动旋转的设置
从界面读取该preference并判断是否进行显示
1 @Override 2 public void onCreate(Bundle savedInstanceState) { 3 super.onCreate(savedInstanceState); 4 ContentResolver resolver = getActivity().getContentResolver(); 5 6 addPreferencesFromResource(R.xml.display_settings); 7 8 //从界面中找到设置旋转的preference 9 mAccelerometer = (CheckBoxPreference) findPreference(KEY_ACCELEROMETER); 10 mAccelerometer.setPersistent(false); 11 //判断设备是否支持旋转和设置 12 if (!RotationPolicy.isRotationSupported(getActivity()) 13 || RotationPolicy.isRotationLockToggleSupported(getActivity())) { 14 // If rotation lock is supported, then we do not provide this option in 15 // Display settings. However, is still available in Accessibility settings, 16 // if the device supports rotation. 17 getPreferenceScreen().removePreference(mAccelerometer); 18 }
接下来我们看看如何判断设备是否支持旋转:

1 /** 2 * Gets whether the device supports rotation. In general such a 3 * device has an accelerometer and has the portrait and landscape 4 * features. 5 * //这里判断设备是否支持旋转,通常情况下设备都支持加速和横竖屏属性 6 * @param context Context for accessing system resources. 7 * @return Whether the device supports rotation. 8 */ 9 public static boolean isRotationSupported(Context context) { 10 PackageManager pm = context.getPackageManager(); 11 return pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER) 12 && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT) 13 && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE); 14 } 15 16 /** 17 * Returns true if the device supports the rotation-lock toggle feature 18 * in the system UI or system bar. 19 * //这里的意思是讲设备是否支持快捷方式设置旋转 20 * When the rotation-lock toggle is supported, the "auto-rotate screen" option in 21 * Display settings should be hidden, but it should remain available in Accessibility 22 * settings. 23 */ 24 public static boolean isRotationLockToggleSupported(Context context) { 25 return isRotationSupported(context) 26 && context.getResources().getConfiguration().smallestScreenWidthDp >= 600; 27 }
以上的代码通过RotationPolicy类判断设备是否支持旋转和是否支持快捷设置了。那设备是如何获取设备的状态又将将修改的内容设置到哪里去了呢?
1 /** 2 * 更新该preference的状态,从RotationPolicy.isRotationLocked中读取 3 */ 4 private void updateAccelerometerRotationCheckbox() { 5 if (getActivity() == null) return; 6 7 mAccelerometer.setChecked(!RotationPolicy.isRotationLocked(getActivity())); 8 }
1 /** 2 * Returns true if rotation lock is enabled. 3 * 如果旋转旋转锁可用就返回true,调用的地方取反在界面上显示就是没有选中。 4 * 其中我们也看到我们的旋转属性是从Settings.System中获取。 5 */ 6 public static boolean isRotationLocked(Context context) { 7 return Settings.System.getIntForUser(context.getContentResolver(), 8 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0; 9 }
Settings.system中的Settings是专门用来存储和对于属性的类,它的实现用的是ContentProvider进行存储和读取的。具体的我们查看在framework中找到SettingsProvider.java和Settings.java,他们都存储在framework/base/core/java/android/provider/中,具体的实现请百度。
说完了读取,我们接下来学习下如何设置旋转:
1 @Override 2 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { 3 if (preference == mAccelerometer) { 4 //如果当前的preference是设置旋转的preference,调用RotationPolicy的setRotationLockForAccessibility函数进行设置 5 RotationPolicy.setRotationLockForAccessibility( 6 getActivity(), !mAccelerometer.isChecked()); 7 } else if (preference == mNotificationPulse) { 8 boolean value = mNotificationPulse.isChecked(); 9 Settings.System.putInt(getContentResolver(), Settings.System.NOTIFICATION_LIGHT_PULSE, 10 value ? 1 : 0); 11 return true; 12 } 13 return super.onPreferenceTreeClick(preferenceScreen, preference); 14 }

1 /** 2 * Enables or disables rotation lock and adjusts whether the rotation lock toggle 3 * should be hidden for accessibility purposes. 4 * 5 * Should be used by Display settings and Accessibility settings. 6 */ 7 public static void setRotationLockForAccessibility(Context context, final boolean enabled) { 8 //将用户设置的内容设置到Settings.system中 9 Settings.System.putIntForUser(context.getContentResolver(), 10 Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, enabled ? 1 : 0, 11 UserHandle.USER_CURRENT); 12 13 AsyncTask.execute(new Runnable() { 14 @Override 15 public void run() { 16 try { 17 IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); 18 if (enabled) { 19 //不允许旋转,Surface.ROTATION_0--->旋转角度为0 20 wm.freezeRotation(Surface.ROTATION_0); 21 } else { 22 //允许进行自动旋转 23 wm.thawRotation(); 24 } 25 } catch (RemoteException exc) { 26 Log.w(TAG, "Unable to save auto-rotate setting"); 27 } 28 } 29 }); 30 }
以上的代码的作用是点击该preference,修改对应的状态并根据修改后的状态设置快捷设置中旋转的开关状态。其中我们发现了IwindowManager通过调用freezeRotation和thawRotation控制屏幕是否旋转等。
详情也可以参考:http://blog.csdn.net/siobhan/article/details/8526006
2. 字体大小的读取与设置
- 字体大小的读取操作
1 /** 2 * 读取系统字体的大小,这里主要用到Configuration类,这个类中包含了字体大小的属性fontScale 3 * 至于ActivityManagerNative.getDefault()的使用请百度或者参考: 4 * http://www.cnblogs.com/bastard/archive/2012/05/25/2517522.html 5 */ 6 public void readFontSizePreference(ListPreference pref) { 7 try { 8 mCurConfig.updateFrom(ActivityManagerNative.getDefault().getConfiguration()); 9 } catch (RemoteException e) { 10 Log.w(TAG, "Unable to retrieve font size"); 11 } 12 13 // mark the appropriate item in the preferences list 14 int index = floatToIndex(mCurConfig.fontScale); 15 pref.setValueIndex(index); 16 17 // report the current size in the summary text 18 final Resources res = getResources(); 19 String[] fontSizeNames = res.getStringArray(R.array.entries_font_size); 20 pref.setSummary(String.format(res.getString(R.string.summary_font_size), 21 fontSizeNames[index])); 22 }
- 字体的写入过程
在DisplaySettings.java中对字体的设置涉及到了几个地方,首先:
1 @Override 2 public boolean onPreferenceClick(Preference preference) { 3 if (preference == mFontSizePref) { 4 //首先判断系统是否是多用户模式,如果是则弹出提示框提示是否进行字体的修改 5 if (Utils.hasMultipleUsers(getActivity())) { 6 showDialog(DLG_GLOBAL_CHANGE_WARNING); 7 return true; 8 } else { 9 //preference消失,然后调转到onPreferenceChange进行处理 10 mFontSizePref.click(); 11 } 12 } 13 return false; 14 }

1 public boolean onPreferenceChange(Preference preference, Object objValue) { 2 final String key = preference.getKey(); 3 if (KEY_SCREEN_TIMEOUT.equals(key)) { 4 int value = Integer.parseInt((String) objValue); 5 try { 6 Settings.System.putInt(getContentResolver(), SCREEN_OFF_TIMEOUT, value); 7 updateTimeoutPreferenceDescription(value); 8 } catch (NumberFormatException e) { 9 Log.e(TAG, "could not persist screen timeout setting", e); 10 } 11 } 12 if (KEY_FONT_SIZE.equals(key)) { 13 //该函数对字体进行设置 14 writeFontSizePreference(objValue); 15 } 16 17 return true; 18 }
1 public void writeFontSizePreference(Object objValue) { 2 try { 3 //对fontScale进行修改,然后调用updatePersistentConfiguration进行设置 4 mCurConfig.fontScale = Float.parseFloat(objValue.toString()); 5 ActivityManagerNative.getDefault().updatePersistentConfiguration(mCurConfig); 6 } catch (RemoteException e) { 7 Log.w(TAG, "Unable to save font size"); 8 } 9 }
我们默认的字体大小有哪些呢?

1 <string-array name="entries_font_size"> 2 <item msgid="6490061470416867723">Small</item> 3 <item msgid="3579015730662088893">Normal</item> 4 <item msgid="1678068858001018666">Large</item> 5 <item msgid="490158884605093126">Huge</item> 6 </string-array> 7 8 <string-array name="entryvalues_font_size" translatable="false"> 9 <item>0.85</item> 10 <item>1.0</item> 11 <item>1.15</item> 12 <item>1.30</item> 13 </string-array>
通过以上分析,我们了解到android系统对字体大小的修改主要用到了ActivityManagerNative.getDefault().getConfiguration()得到Configuration对象,而该对象中正好保存了字体大小的属性fontScale。当我们修改字体大小的时候,只要修改Configuration中的fontScale,并调用updatePersistentConfiguration函数就可以了。
今天先到这里吧!后续会把其他的显示设置加进来。你的支持是我不懈的动力,当然不喜勿喷!2014-07-28 16:51:03