目录
1.1.2.1.从AndroidManifest.xml开始 6
3.2.2.updateRotationPreferenceDescription方法的构建 22
前言
本文档是在全志A33平台 Android 系统中,关于屏幕旋转方面的技术调研。
李瀚
2015年4月14日
1.关于
决定屏幕方向有两个层面,一个是 Linux 内核层的 FB 方向(这里暂不深入),驱动上做的修改,另一个是 Android OS 上的修改。
在 Linux 内核初始化以后,init进程启动,紧接着启动了Zygote。Zygote让Dalvik虚拟机共享代码、低内存占用以及最小的启动时间成为可能。Zygote是一个虚拟器进程,正如我们在前一个步骤所说的在系统引 导的时候启动。Zygote预加载以及初始化核心库类。通常,这些核心类一般是只读的,也是Android SDK或者核心框架的一部分。在Java虚拟机中,每一个实例都有它自己的核心库类文件和堆对象的拷贝。
如上图,Zygote启动以后,初始化了 System.Settings,开始了SystemUI 和 Settings 的进程、监听屏幕旋转机制和传感器管理器。当来自 SystemUI 或者 Settings 对 System.Settings 数据库的设置生效,监听屏幕旋转机制就打开,开始读取来由自底层设备驱动经过HAL经过JNI到传感器管理器的数据,对屏幕进行旋转设置。
1.1.Framework 层屏幕旋转原理
最终实现状态栏的快速设置功能是在 SystemUI 上。所以先从 SystemUI 入手。
1.1.1.初识SystemUI
Android 4.4,是由 Google 公司制作和研发的代号为 KitKat 的手机操作系统,于北京时间 2013 年 9 月 4 日凌晨对外公布了该 Android 新版本的名称,为 Android 4.4 (代号 KitKat 奇巧)。
Android 4.4 同时适用于Phone和Tablet(TV),因此,对于 Phone 来说 SystemUI 指的是:StatusBar(状态栏)、 NavigationBar(导航栏)。而对于 Tablet 或者是 TV 来说 SystemUI 指的是:CombinedBar(包括了 StatusBar 和 NavigationBar)。
Android 的 Phone 的信号,蓝牙标志,Wifi 标志等等这些状态显示标志都会在 StatusBar 上显示。当我们的设备开机后,首先需要给用户呈现的就是各种界面同时也包括了我们的 SystemUI,因此对于整个 Android 系统来说,SystemUI 都有举足轻重的作用。
1.1.2.分析 SystemUI 代码
1.1.2.1.从AndroidManifest.xml开始
在 Android 4.4 中,Google 整合了 Phone 和 Tablet(TV) 的 SystemUI,也就说可以根据设备的类型自动匹配相应的 SystemUI。首先从 AndroidManifest.xml 入手。
(省略)
<!-- Wifi Display -->
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<application
android:persistent="true"
android:allowClearUserData="false"
android:allowBackup="false"
android:hardwareAccelerated="true"
android:label="@string/app_label"
android:icon="@*android:drawable/platlogo"
android:process="com.android.systemui"
android:supportsRtl="true">
<!-- Broadcast receiver that gets the broadcast at boot time and starts
up everything else.
TODO: Should have an android:permission attribute
-->
<service android:name="SystemUIService"
android:exported="true"
/>
<!-- started from PhoneWindowManager
TODO: Should have an android:permission attribute -->
<service android:name=".screenshot.TakeScreenshotService"
android:process=":screenshot"
android:exported="false" />
<service android:name=".LoadAverageService"
android:exported="true" />
<service android:name=".ImageWallpaper"
android:permission="android.permission.BIND_WALLPAPER"
android:exported="true" />
(省略)
根据以上代码我们可以发现这其中注册了很多 Service,同时也包括了广播。但这里我们只关注 SystemUIService。首先要找到 SystemUIService 是如何启动的。Service 的启动,不外乎 startService(intent) 和 bindService(intent),它们都是以 intent 为对象,由于 intent 的声明也需要 SystemUIService,因此我们可以据此搜索关键词"SystemUIService"。
1.1.2.2.SystemUIService分析
经过搜索发现:
frameworks/base/services/java/com/android/server/SystemServer.java
static final void startSystemUi(Context context) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.OWNER);
}
这部分是开始了 SystemUI,可以确认下面代码是上面服务的具体实现:
frameworks/base/packages/systemui/src/com/android/systemui/SystemUIService.java
public class SystemUIService extends Service {
private static final String TAG = "SystemUIService";
/**
* The classes of the stuff to start.
*/
private final Class<?>[] SERVICES = new Class[] {
com.android.systemui.recent.Recents.class,
com.android.systemui.statusbar.SystemBars.class,
com.android.systemui.usb.StorageNotification.class,
com.android.systemui.power.PowerUI.class,
com.android.systemui.media.RingtonePlayer.class,
com.android.systemui.settings.SettingsUI.class,
};
/**
* Hold a reference on the stuff we start.
*/
private final SystemUI[] mServices = new SystemUI[SERVICES.length];
@Override
public void onCreate() {
HashMap<Class<?>, Object> components =
new HashMap<Class<?>, Object>();
final int N = SERVICES.length;
for (int i=0; i<N; i++) {
Class<?> cl = SERVICES[i];
Log.d(TAG, "loading: " + cl);
try {
mServices[i] = (SystemUI)cl.newInstance();
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
}
mServices[i].mContext = this;
mServices[i].mComponents = components;
Log.d(TAG, "running: " + mServices[i]);
mServices[i].start();
}
}
(省略)
这里初始化了以下类
Recent(最近打开程序)
com.android.systemui.recent.Recents.class
Statusbar(状态栏)
com.android.systemui.statusbar.SystemBars.class
USBStorageNotification(USB存储设备通知) com.android.systemui.usb.StorageNotification.class
PowerUI
com.android.systemui.power.PowerUI.class
RingtonePlayer
com.android.systemui.media.RingtonePlayer.class
SettingsUI(设置界面)
com.android.systemui.settings.SettingsUI.class
4.0以前版本,这里都是整合在一起的,4.4这里开始分离出来,分一个个模块。以后若是针对某个模块分析,在这里开始了分支。
1.1.2.3.Statusbar分析
接下来重点是 Statusbar(状态栏),这个类构建在:
/frameworks/base/packages/systemui/src/com/android/systemui/statusbar/SystemBars.java 分析得出接下来调用了frameworks/base/packages/systemui/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
// 创建一个快速设置菜单