先说现象,现象就是来电话,接通电话,把手机屏幕靠近脸部,遮挡住P-sensor,屏幕变黑了,不遮挡住P-sensor,屏幕就点亮了。接着我们来看看代码流程。
距离感应器与屏幕休眠可参考
http://blog.csdn.net/wds1181977/article/details/42125699
先来说说靠近P-sensor,不灭屏的正常的现象:
- 插入耳机
- 打开扬声器
- 打开蓝牙耳机
- 链接蓝牙键盘
步骤一: 在PhoneGlobals.java文件中onCreate()方法中:
。。。 。。。
-
- mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
- | PowerManager.ON_AFTER_RELEASE, LOG_TAG);
-
- if (mPowerManager.isWakeLockLevelSupported(
- PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
- mProximityWakeLock = mPowerManager.newWakeLock(
- PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, LOG_TAG);
- }
。。。 。。。
注意这个private PowerManager.WakeLock mProximityWakeLock;这个初始化变量,
这个mProximityWakeLock就是所说的P-Sensor锁,它是用来唤醒屏幕和使屏幕睡眠的锁。
步骤二:在PhoneGlobals.java文件中的onCreate()方法中:
-
- if (proximitySensorModeEnabled()) {
- mAccelerometerListener = new AccelerometerListener(this, this);
- }
创建加速度感应器。
步骤三:在更新Phone的状态的时候确定这个加速度的P-sensor感应器起作用;
- <span style="font-size:18px;">
-
-
-
-
-
- void updatePhoneState(PhoneConstants.State state) {
- if (state != mLastPhoneState) {
- mLastPhoneState = state;
- if (state == PhoneConstants.State.IDLE)
- PhoneGlobals.getInstance().pokeUserActivity();
- updateProximitySensorMode(state);
-
-
-
-
-
- if (state != PhoneConstants.State.IDLE) {
-
-
-
-
- if (!mUpdateLock.isHeld()) {
- mUpdateLock.acquire();
- }
- } else {
- if (!isShowingCallScreen()) {
- if (!mUpdateLock.isHeld()) {
- mUpdateLock.release();
- }
- } else {
-
- }
- }
-
- if (mAccelerometerListener != null) {
-
- mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN;
- </span><span style="color:#ff0000;"><strong><span style="font-size:24px;"> </span><span style="font-size:18px;">mAccelerometerListener.enable(state == PhoneConstants.State.OFFHOOK);</span></strong></span><span style="font-size:18px;">
- }
-
- mBeginningCall = false;
-
-
-
-
-
- if (mInCallScreen != null) {
- if (VDBG) Log.d(LOG_TAG, "updatePhoneState: state = " + state);
- if (!PhoneUtils.isDMLocked())
- mInCallScreen.updateKeyguardPolicy(state == PhoneConstants.State.OFFHOOK);
- }
- }
- }</span>
步骤四:用AccelerometerListener.java类中的监听事件来处理一些这个覆盖的改变,一共有2个状态,一个是
horizontal,一个是vertical的状态。在上述步骤三红色的调用部分注册这个监听事件:
- public void enable(boolean enable) {
- if (DEBUG) Log.d(TAG, "enable(" + enable + ")");
- synchronized (this) {
- if (enable) {
- mOrientation = ORIENTATION_UNKNOWN;
- mPendingOrientation = ORIENTATION_UNKNOWN;
- mSensorManager.registerListener(mSensorListener, mSensor,
- SensorManager.SENSOR_DELAY_NORMAL);
- } else {
- mSensorManager.unregisterListener(mSensorListener);
- mHandler.removeMessages(ORIENTATION_CHANGED);
- }
- }
- }
步骤五:监听事件的相应的过程如下:
- SensorEventListener mSensorListener = new SensorEventListener() {
- public void onSensorChanged(SensorEvent event) {
- onSensorEvent(event.values[0], event.values[1], event.values[2]);
- }
-
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
-
- }
- };
- private void onSensorEvent(double x, double y, double z) {
- if (VDEBUG) Log.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")");
-
-
-
- if (x == 0.0 || y == 0.0 || z == 0.0) return;
-
-
- double xy = Math.sqrt(x*x + y*y);
-
- double angle = Math.atan2(xy, z);
-
- angle = angle * 180.0 / Math.PI;
- int orientation = (angle > VERTICAL_ANGLE ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL);
- if (VDEBUG) Log.d(TAG, "angle: " + angle + " orientation: " + orientation);
- setOrientation(orientation);
- }
-
-
- private void setOrientation(int orientation) {
- synchronized (this) {
- if (mPendingOrientation == orientation) {
-
- return;
- }
-
-
-
-
- mHandler.removeMessages(ORIENTATION_CHANGED);
-
- if (mOrientation != orientation) {
-
-
- mPendingOrientation = orientation;
- Message m = mHandler.obtainMessage(ORIENTATION_CHANGED);
-
- int delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE
- : HORIZONTAL_DEBOUNCE);
- mHandler.sendMessageDelayed(m, delay);
- } else {
-
- mPendingOrientation = ORIENTATION_UNKNOWN;
- }
- }
- }
然后发送消息ORIENTATION_CHANGED这个改变的消息;这个消息会调用一个回调函数,然后根据状态判断,调用acquire和release()方法;
- Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case ORIENTATION_CHANGED:
- synchronized (this) {
- mOrientation = mPendingOrientation;
- if (DEBUG) {
- Log.d(TAG, "orientation: " +
- (mOrientation == ORIENTATION_HORIZONTAL ? "horizontal"
- : (mOrientation == ORIENTATION_VERTICAL ? "vertical"
- : "unknown")));
- }
- mListener.orientationChanged(mOrientation);
- }
- break;
- }
- }
- };
步骤五:回调到PhoneGlobals.java这个类的
orientationChanged()
- @Override
- public void orientationChanged(int orientation) {
- mOrientation = orientation;
- updateProximitySensorMode(mCM.getState());
- }
到这已经把Phone层的P-sensor的亮屏和灭屏说完了,回头再来屡屡这个mProximityWakeLock在framework层怎么具体实现的亮屏和灭屏的;敬请期待。。。 。。。
更正:上述的讲解是不正确的,后来经过打log,发现,这个mProximityWakeLock.acquire();和mProximityWakeLock.release(flags);只是申请这个锁,和释放这个锁,防止其他的调用,
其实,在4.2以前Phone模块的P-Sensor在PowerManagerServer.java中处理的,而Android4.2的时候,谷歌对代码进行了一些调整,所以Phone的模块的P-Sensor的控制的类在DisplayPowerController.java
路径:framework/base/services/java/com/android/server/power/DisplayPowerController.java中的:
- private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
- @Override
- public void onSensorChanged(SensorEvent event) {
- if (mProximitySensorEnabled) {
- final long time = SystemClock.uptimeMillis();
- final float distance = event.values[0];
- boolean positive = distance >= 0.0f && distance < mProximityThreshold;
- if (DEBUG) {
- Slog.d(TAG, "P-Sensor Changed: " + positive);
- }
- handleProximitySensorEvent(time, positive);
- }
- }
- <span style="color: rgb(255, 0, 0);"><strong></strong></span>
这个onSensorChanged()就是距离感应器的;这个log:
P-Sensor Changed:true 表示:靠近手机,P-sensor被遮挡住;
P-Sensor Changed:false 表示:离开手机,P-sensor没有被遮挡住;
通过这个log也能帮我们分析一些问题;这个mProximitySensorListener的注册和反注册,大家可以自己在这个类中搜索就可以了;
补充:在PowserManagerServerice.java这个类中, private LightsService.Light mButtonLight;这个变量申请的就是按键灯,像:home,返回键,menu键的灯,申请这个灯的代码:
- private LightsService mLightsService;
- 。。。 。。。
-
- mButtonLight = mLightsService.getLight(LightsService.LIGHT_ID_BUTTONS);
通过LightService可以获得键盘灯的实例,
打开灯的方法:mButtonLight.setBrightness(120);//120可以是(0~255)任意数字;
关闭灯的方法:mButtonLight.turnOff();
需求:要想使Phone通话界面的P-Sensor亮灭屏幕和按键灯同步,当屏幕灭的时候,按键灯也灭,屏幕亮的时候,按键灯也亮;其实做法很简单了,在onSensorChanged()的时候处理,扩一些接口,
具体设计的类我列举一下:
- PowerManager.java
- PowerManagerService.java
- BridgetPowerManager.java
- IPowerManager.adil
- DisPlayPowerController.java
具体代码就不详细赘述了,还是“觉知此事要躬行”;
注意在
- mLastUserActivityButtonTime = SystemClock.uptimeMillis();
- mButtonLight.setBrightness(102);
在设置打开按键灯的时候,设置一下最后一次用户触摸按钮的时间;至于为什么??大家自已到时候打log就明白了。。。 。。。
- mLastUserActivityButtonTime