sensor工作流程

来源:互联网 发布:linux vim 无法保存 编辑:程序博客网 时间:2024/05/22 04:35
         编写本文的目的是为何第三方软件uc浏览器8.2.2版在我们的设备上安装后是竖屏(portrait)显示的,而不是我们想要的横屏显示(landscape)。我反编译了这个apk里的AndroidManifest.xml,发现和屏幕方向相关的代码:android:screenOrientation="portrait"            android:configChanges="orientation|keyboardHidden"在这里设定了默认方向为portrait(竖屏)显示的,而configChanges属性是在设备有gsensor时有反应的,如果没有gsensor就是默认的方向显示。在Activity里有重写了  @Override     public void onConfigurationChanged(Configuration newConfig) {     super.onConfigurationChanged(newConfig); …...}这样是对屏幕方向改变时做相应的反应。这样做的好处是不会导致Acivity重启,即关闭一个Acitivity又创建一个Activity,会导致onDestroy,onCreate等事件的发生,因而屏幕切换可能会导致与Acitivity状态相关的应用出错。如果你设置了这个选项, 当手机旋转后,当前 Activity 之后调用onConfigurationChanged() 方法. 而不跑 onCreate 方法等.         整体框架如下: 其中在frameworks里又关联了几个重要的类,比如,Configuration.java在frameworks/base/core/java/android/content/res下这里定义了常量:    public static final int ORIENTATION_UNDEFINED = 0;    public static final int ORIENTATION_PORTRAIT = 1;    public static final int ORIENTATION_LANDSCAPE = 2;    public static final int ORIENTATION_SQUARE = 3;这些常量就是屏幕方向。这个类实现了Parcelable, Comparable<Configuration>接口。在Parcelable.java接口里有public void writeToParcel(Parcel dest, int flags);         * Specific orientation value for a window.         * May be any of the same values allowed         * for {@link android.content.pm.ActivityInfo#screenOrientation}.          * If not set, a default value of          * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}          * will be used.         */        public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;看英文注释这是默认的屏幕方向值。然后在这个类的public void writeToParcel(Parcel out, int parcelableFlags) {                         ….out.writeInt(screenOrientation);//往Parcel读 screenOrientation}public LayoutParams(Parcel in) {       ….      screenOrientation = in.readInt();//在 Parcel读 screenOrientation}public final int copyFrom(LayoutParams o) {            int changes = 0;….. if (screenOrientation != o.screenOrientation) {                screenOrientation = o.screenOrientation;                changes |= SCREEN_ORIENTATION_CHANGED;            return changes;        }刚才有发现了 screenOrientation的默认值为ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED。我在追综到 ActivityInfo这个类里,发现;了定义几个屏幕方向的几个常量,这些常量是在AndroidManifest.xml里各个应用主界面activity的屏幕方向的:  /**     * Options that have been set in the activity declaration in the     * manifest: {@link #FLAG_MULTIPROCESS},     * {@link #FLAG_FINISH_ON_TASK_LAUNCH}, {@link #FLAG_CLEAR_TASK_ON_LAUNCH},     * {@link #FLAG_ALWAYS_RETAIN_TASK_STATE},     * {@link #FLAG_STATE_NOT_NEEDED}, {@link #FLAG_EXCLUDE_FROM_RECENTS},     * {@link #FLAG_ALLOW_TASK_REPARENTING}, {@link #FLAG_NO_HISTORY},     * {@link #FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS}.     */    public int flags;    /**     * Constant corresponding to <code>unspecified</code> in     * the {@link android.R.attr#screenOrientation} attribute.     */    public static final int SCREEN_ORIENTATION_UNSPECIFIED = -1;    /**     * Constant corresponding to <code>landscape</code> in     * the {@link android.R.attr#screenOrientation} attribute.     */    public static final int SCREEN_ORIENTATION_LANDSCAPE = 0;    /**     * Constant corresponding to <code>portrait</code> in     * the {@link android.R.attr#screenOrientation} attribute.     */    public static final int SCREEN_ORIENTATION_PORTRAIT = 1;    /**     * Constant corresponding to <code>user</code> in     * the {@link android.R.attr#screenOrientation} attribute.     */    public static final int SCREEN_ORIENTATION_USER = 2;    /**     * Constant corresponding to <code>behind</code> in     * the {@link android.R.attr#screenOrientation} attribute.     */    public static final int SCREEN_ORIENTATION_BEHIND = 3;    /**     * Constant corresponding to <code>sensor</code> in     * the {@link android.R.attr#screenOrientation} attribute.     */    public static final int SCREEN_ORIENTATION_SENSOR = 4;      /**     * Constant corresponding to <code>sensor</code> in     * the {@link android.R.attr#screenOrientation} attribute.     */    public static final int SCREEN_ORIENTATION_NOSENSOR = 5;    /**     * The preferred screen orientation this activity would like to run in.     * From the {@link android.R.attr#screenOrientation} attribute, one of     * {@link #SCREEN_ORIENTATION_UNSPECIFIED},     * {@link #SCREEN_ORIENTATION_LANDSCAPE},      * {@link #SCREEN_ORIENTATION_PORTRAIT},     * {@link #SCREEN_ORIENTATION_USER},     * {@link #SCREEN_ORIENTATION_BEHIND},     * {@link #SCREEN_ORIENTATION_SENSOR},     * {@link #SCREEN_ORIENTATION_NOSENSOR}.     */    public int screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;ActivityInfo.java也实现了Parcelable接口,说明也能往里面读和写屏幕方向。在与ActivityInfo.java同目录(frameworks/base/core/java/android/content/pm)下有AcitivityInfo.aidl在这里只封装了parcelable ActivityInfo;。那么现在只有一条线索去追踪屏幕方向切换的实现原理和流程了。那就是WindowManager.java相关的类。我们知道WindowManager.java是给上层调用的服务,所以我发现了IWindowManager.aidl在相同目录下(frameworks/base/core/java/android/view).系统启动windowManger.java时,它会启动phoneWindowManager.java,该类有一个内部类myOrientationListener扩展自windowOrientationListener.java。windowOrientationListener.java是一个辅助类,当device的方向发生变化时,供windowManger.java调用,用来接收数据。windowOrientationListener.java 内部在sensorManger.java中进行了注册,它回监听G-sensor传来的数据,即x,y,z方向的加速度,收到数据后经过转换处理,若满足Roate条件则调用IwindowManager接口的实现类windowManagerService.java中的setRotation()方法实现转屏。SensorManager通过polling的方式从设备得到Sensor数据, Sensor数据的结构定义在sensor.h里,其中SensorManager只处理了 vector.v, vector.status, time三个域, 分发给已注册的对这些消息的监听者比如第一项 vector.v包含x,y,z三个方向的信息值,就是由 WindowOrientataionLister注册的,当 SensorManager获取到这三个值之后,会传递给 WindowOrientataionLister,后者代码位于:frameworkd/base/core/java/android/view/WindowOrientationListener.javaWindowOrientataionLister接收到这三个值之后,会计算出设备对应的orientation,并且执行 onOrientationChanged函数进一步上传WindowOrientataionLister是个纯虚类,如果在APK里需要控制方向,可以重载一个实例,而Android的系统实例对应在 PhoneWindowManager.java里,名字为MyOrientationListenerframeworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java如果需要旋转, MyOrientationListener则会调用以下代码进行窗口旋转:mWindowManager.setRotation(rotation, false, mFancyRotationAnimation);  现在追踪到SensorManager.java在目录frameworks/base/core/java/android/hardware下,同目录下有ISensorservice.aidl,因为在SensorManager.java类里有:public SensorManager(Looper mainLooper) {        mSensorService = ISensorService.Stub.asInterface(                ServiceManager.getService(Context.SENSOR_SERVICE));…..}在frameworks/base/services/java/com/android/server下有SensorService.java.这个类是通过JNI方法调用HAL层的Sensor.cpp里的方法,对硬件实现初始化和控制。在frameworks/base/core/jni/android_hardware_SensorManager.cpp和frameworks/base/services/jni/com_android_server_SensorService.cpp中都#include <hardware/sensors.h>在这个头文件中我发现#define SENSOR_TYPE_ORIENTATION         3
原创粉丝点击