先说现象,现象就是来电话,接通电话,把手机屏幕靠近脸部,遮挡住P-sensor,屏幕变黑了,不遮挡住P-sensor,屏幕就点亮了。接着我们来看看代码流程。

先来说说靠近P-sensor,不灭屏的正常的现象:

  1. 插入耳机
  2. 打开扬声器
  3. 打开蓝牙耳机
  4. 链接蓝牙键盘

步骤一:在PhoneGlobals.java文件中onCreate()方法中:

。。。 。。。

// lock used to keep the processor awake, when we don't care for the display.mPartialWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK| PowerManager.ON_AFTER_RELEASE, LOG_TAG);// Wake lock used to control proximity sensor behavior.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()方法中:

// create mAccelerometerListener only if we are using the proximity sensorif (proximitySensorModeEnabled()) {mAccelerometerListener = new AccelerometerListener(this, this);}

创建加速度感应器。

步骤三:在更新Phone的状态的时候确定这个加速度的P-sensor感应器起作用;

/*** Notifies the phone app when the phone state changes.** This method will updates various states inside Phone app (e.g. proximity sensor mode,* accelerometer listener state, update-lock state, etc.)*//* package */ void updatePhoneState(PhoneConstants.State state) {if (state != mLastPhoneState) {mLastPhoneState = state;if (state == PhoneConstants.State.IDLE)PhoneGlobals.getInstance().pokeUserActivity();updateProximitySensorMode(state);// Try to acquire or release UpdateLock.//// Watch out: we don't release the lock here when the screen is still in foreground.// At that time InCallScreen will release it on onPause().if (state != PhoneConstants.State.IDLE) {// UpdateLock is a recursive lock, while we may get "acquire" request twice and// "release" request once for a single call (RINGING + OFFHOOK and IDLE).// We need to manually ensure the lock is just acquired once for each (and this// will prevent other possible buggy situations too).if (!mUpdateLock.isHeld()) {mUpdateLock.acquire();}} else {if (!isShowingCallScreen()) {if (!mUpdateLock.isHeld()) {mUpdateLock.release();}} else {// For this case InCallScreen will take care of the release() call.}}if (mAccelerometerListener != null) {// use accelerometer to augment proximity sensor when in callmOrientation = AccelerometerListener.ORIENTATION_UNKNOWN; mAccelerometerListener.enable(state == PhoneConstants.State.OFFHOOK);}// clear our beginning call flagmBeginningCall = false;// While we are in call, the in-call screen should dismiss the keyguard.// This allows the user to press Home to go directly home without going through// an insecure lock screen.// But we do not want to do this if there is no active call so we do not// bypass the keyguard if the call is not answered or declined.if (mInCallScreen != null) {if (VDBG) Log.d(LOG_TAG, "updatePhoneState: state = " + state);if (!PhoneUtils.isDMLocked())mInCallScreen.updateKeyguardPolicy(state == PhoneConstants.State.OFFHOOK);}}}

步骤四:用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) {// ignore}};
private void onSensorEvent(double x, double y, double z) {if (VDEBUG) Log.d(TAG, "onSensorEvent(" + x + ", " + y + ", " + z + ")");// If some values are exactly zero, then likely the sensor is not powered up yet.// ignore these events to avoid false horizontal positives.if (x == 0.0 || y == 0.0 || z == 0.0) return;// magnitude of the acceleration vector projected onto XY planedouble xy = Math.sqrt(x*x + y*y);// compute the vertical angledouble angle = Math.atan2(xy, z);// convert to degreesangle = 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) {// Pending orientation has not changed, so do nothing.return;}// Cancel any pending messages.// We will either start a new timer or cancel alltogether// if the orientation has not changed.mHandler.removeMessages(ORIENTATION_CHANGED);if (mOrientation != orientation) {// Set timer to send an event if the orientation has changed since its// previously reported value.mPendingOrientation = orientation;Message m = mHandler.obtainMessage(ORIENTATION_CHANGED);// set delay to our debounce timeoutint delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE: HORIZONTAL_DEBOUNCE);mHandler.sendMessageDelayed(m, delay);} else {// no message is pendingmPendingOrientation = 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()

@Overridepublic void orientationChanged(int orientation) {mOrientation = orientation;updateProximitySensorMode(mCM.getState());}
/*** Updates the wake lock used to control proximity sensor behavior,* based on the current state of the phone.  This method is called* from the CallNotifier on any phone state change.** On devices that have a proximity sensor, to avoid false touches* during a call, we hold a PROXIMITY_SCREEN_OFF_WAKE_LOCK wake lock* whenever the phone is off hook.  (When held, that wake lock causes* the screen to turn off automatically when the sensor detects an* object close to the screen.)** This method is a no-op for devices that don't have a proximity* sensor.** Note this method doesn't care if the InCallScreen is the foreground* activity or not.  That's because we want the proximity sensor to be* enabled any time the phone is in use, to avoid false cheek events* for whatever app you happen to be running.** Proximity wake lock will *not* be held if any one of the* conditions is true while on a call:* 1) If the audio is routed via Bluetooth* 2) If a wired headset is connected* 3) if the speaker is ON* 4) If the slider is open(i.e. the hardkeyboard is *not* hidden)** @param state current state of the phone (see {@link Phone#State})*//* package */ void updateProximitySensorMode(PhoneConstants.State state) {boolean isRingingWhenActive = false;//MTK81281 add isRingingWhenActive for Cr:ALPS00117091if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: state = " + state);if (proximitySensorModeEnabled()) {synchronized (mProximityWakeLock) {// turn proximity sensor off and turn screen on immediately if// we are using a headset, the keyboard is open, or the device// is being held in a horizontal position.boolean screenOnImmediately = (isHeadsetPlugged()|| PhoneUtils.isSpeakerOn(this)|| isBluetoothHeadsetAudioOn()|| mIsHardKeyboardOpen);if (FeatureOption.MTK_VT3G324M_SUPPORT) {screenOnImmediately = screenOnImmediately ||((!VTCallUtils.isVTIdle()) && (!VTCallUtils.isVTRinging()));}// We do not keep the screen off when the user is outside in-call screen and we are// horizontal, but we do not force it on when we become horizontal until the// proximity sensor goes negative.// this horizontal is not the same portrait.boolean horizontal =(mOrientation == AccelerometerListener.ORIENTATION_HORIZONTAL);screenOnImmediately |= !isShowingCallScreenForProximity() && horizontal;if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: mBeginningCall = " + mBeginningCall);if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: screenOnImmediately = " + screenOnImmediately);//MTK81281 add isRingingWhenActive for Cr:ALPS00117091 start    //when a call is activeand p-sensor turn off the screen,  //another call or vtcall in we don't release the lock and acquire again//(the prowermanagerservice will turn on and off the screen and it's a problem)//instead ,we don't release the lock(prowermanagerservice will not turn on and off the screen)isRingingWhenActive = (state == PhoneConstants.State.RINGING)&& (mCM.getActiveFgCallState() == Call.State.ACTIVE)&& (mCM.getFirstActiveRingingCall().getState() == Call.State.WAITING);if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: isRingingWhenActive = " + isRingingWhenActive);//MTK81281 add  isRingingWhenActive for Cr:ALPS00117091 end//MTK81281 add isRingingWhenActive for Cr:ALPS00117091if (((state == PhoneConstants.State.OFFHOOK) || mBeginningCall || isRingingWhenActive)&& !screenOnImmediately) {// Phone is in use!  Arrange for the screen to turn off// automatically when the sensor detects a close object.if (!mProximityWakeLock.isHeld()) {if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring...");mProximityWakeLock.acquire();} else {if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: lock already held.");}} else {// Phone is either idle, or ringing.  We don't want any// special proximity sensor behavior in either case.if (mProximityWakeLock.isHeld()) {if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: releasing...");// Wait until user has moved the phone away from his head if we are// releasing due to the phone call ending.// Qtherwise, turn screen on immediatelyint flags =(screenOnImmediately ? 0 : PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);mProximityWakeLock.release(flags);} else {if (VDBG) {Log.d(LOG_TAG, "updateProximitySensorMode: lock already released.");}}}}}}

到这已经把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() {@Overridepublic 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);}}

这个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

Android4.2中Phone的P-sensor的应用的分析。相关推荐

  1. android陀螺仪手机垂直角度,Android设备中实现陀螺仪(Orientation Sensor)

    //加入需要的宏定义 #define  ID_BASE           SENSORS_HANDLE_BASE #define  ID_ACCELERATION   (ID_BASE+0) #de ...

  2. Android4.0中添加新语言实现方案(以缅甸语为例)

    查看了网上的一些 关于Android2.3实现的添加新的语言的方案.我没有验证过但发现在4.0中不适用 不适用的原因 是: Android4.0中关于 icu4c模块(处理语言国际化模块)是通过dat ...

  3. 关于“android4.0中,在通话界面进入锁屏界面后出现两个电话图标”这一Bug的解决方法

    bug名称: android4.0中,在通话界面进入锁屏界面后出现两个电话图标          1. 问题出现的流程与原因:             在通话界面中熄屏后第一次点亮屏幕时会出现二个电话 ...

  4. 三:Sensor SLPI层代码分析---

    三:Sensor SLPI层代码分析 在学习SLPI侧代码前我们先了解下SEE的registry&config. registry 放在/persist/sensors/registry/re ...

  5. python使用sklearn中的make_blobs函数生成聚类(clustering)分析需要的仿真数据、matplotlib可视化生成的仿真数据

    python使用sklearn中的make_blobs函数生成聚类(clustering)分析需要的仿真数据.matplotlib可视化生成的仿真数据 目录

  6. python的用途实例-python中pass语句意义与作用(实例分析)

    想必大家都是刚刚才开始接触python这门语言的,今天这篇文章就来带大家来了解一下python这门语言之中常常会用到的一个语句pass语句.想必大家都很好奇python中pass作用是什么,接下来我就 ...

  7. char几个字节java_java中的char占几个字节实例分析

    java中的char占几个字节实例分析 1:"字节"是byte,"位"是bit : 2: 1 byte = 8 bit : char 在Java中是2个字节.j ...

  8. 中职学校的学生计算机基础较弱,中职学校计算机专业教学的现状分析及对策探究.doc...

    中职学校计算机专业教学的现状分析及对策探究 中职学校计算机专业教学的现状分析及对策探究 摘 要: 随着信息技术的发展,计算机已经成为人们日常学习和生活中不可或缺的工具,这也对中职计算机专业毕业生的能力 ...

  9. android中使用jni对字符串加解密实现分析

    android中使用jni对字符串加解密实现分析 近期项目有个需求.就是要对用户的敏感信息进行加密处理,比方用户的账户password,手机号等私密信息.在java中,就对字符串的加解密我们能够使用A ...

  10. 视频直播中用户连麦技术模型与特点分析

    本文章来源与网络(视频直播中用户连麦技术模型与特点分析 - 老头慢慢飞 - 博客园) 随着Web与移动视频直播应用的深度发展,有用户参与互动的视频直播技术被越来越多平台所支持,原来的RTMP流媒体方案 ...

最新文章

  1. (二)SpringMVC之执行的过程
  2. 项目代码结构 Dao,Service,Controller,Util,Model 含义
  3. Codeforces Round #316 (Div. 2) D. Tree Requests dfs序
  4. 最大整数(Noip1998连接多位数)
  5. 两数之和——双指针法
  6. 判断ipad还是安卓_?谷歌认输,iPad或成唯一赢家,安卓平板路在何方?
  7. Android Studio如何减小APK体积
  8. pythoncad二次开发视频_AutoCAD ObjectARX 二次开发(2020版)--4,使用ARX向导创建CAD二次开发项目(编程框架)--...
  9. Spring的@Scheduled任务调度
  10. JMM同步原语之final域的内存语义
  11. 华为云云容器快速搭建网站实践随记—利用私有镜像搭建GuestBook
  12. Git 标签(tag)相关操作
  13. ElasticSearch 如何使用 TDigest 算法计算亿级数据的百分位数?
  14. ATL WTL 实现分析(四)
  15. 添加同名工具后台验证后不跳转且保留用户输入的数值
  16. 分享一个 pycharm 专业版的永久使用方法
  17. 什么是硬件加速引擎?
  18. 解决“各种”软件图标显示错误问题
  19. 项目质量管理的几种常规方法
  20. 作为程序员,推荐5种编程语言!

热门文章

  1. python pip更改源
  2. 《云计算:原理与范式》一3.10 企业对企业集成服务
  3. Android Studio中R报错(cnanot resolve symbol R)
  4. ORA-12504:TNS:监听程序在CONNECT_DATA中未获得SERVICE_NAME
  5. nagios无法安装check_mysql插件的问题
  6. PHP获取文件夹内所有文件包括子目录文件的名称或路径
  7. 亟待学习的内容 提醒贴
  8. 一个月被曝五次数据泄露,ElasticSearch还行不行?
  9. js基础知识学习(二)
  10. Async/await 和 Promises 区别