sensor工作流程

			         
	编写本文的目的是为何第三方软件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.java
WindowOrientataionLister接收到这三个值之后,会计算出设备对应的orientation,并且执行 onOrientationChanged函数进一步上传

WindowOrientataionLister是个纯虚类,如果在APK里需要控制方向,可以重载一个实例,
而Android的系统实例对应在 PhoneWindowManager.java里,名字为MyOrientationListener
frameworks/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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值