Android4.2中Phone的P-sensor的应用的分析。
先说现象,现象就是来电话,接通电话,把手机屏幕靠近脸部,遮挡住P-sensor,屏幕变黑了,不遮挡住P-sensor,屏幕就点亮了。接着我们来看看代码流程。
先来说说靠近P-sensor,不灭屏的正常的现象:
- 插入耳机
- 打开扬声器
- 打开蓝牙耳机
- 链接蓝牙键盘
步骤一:在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的应用的分析。相关推荐
- android陀螺仪手机垂直角度,Android设备中实现陀螺仪(Orientation Sensor)
//加入需要的宏定义 #define ID_BASE SENSORS_HANDLE_BASE #define ID_ACCELERATION (ID_BASE+0) #de ...
- Android4.0中添加新语言实现方案(以缅甸语为例)
查看了网上的一些 关于Android2.3实现的添加新的语言的方案.我没有验证过但发现在4.0中不适用 不适用的原因 是: Android4.0中关于 icu4c模块(处理语言国际化模块)是通过dat ...
- 关于“android4.0中,在通话界面进入锁屏界面后出现两个电话图标”这一Bug的解决方法
bug名称: android4.0中,在通话界面进入锁屏界面后出现两个电话图标 1. 问题出现的流程与原因: 在通话界面中熄屏后第一次点亮屏幕时会出现二个电话 ...
- 三:Sensor SLPI层代码分析---
三:Sensor SLPI层代码分析 在学习SLPI侧代码前我们先了解下SEE的registry&config. registry 放在/persist/sensors/registry/re ...
- python使用sklearn中的make_blobs函数生成聚类(clustering)分析需要的仿真数据、matplotlib可视化生成的仿真数据
python使用sklearn中的make_blobs函数生成聚类(clustering)分析需要的仿真数据.matplotlib可视化生成的仿真数据 目录
- python的用途实例-python中pass语句意义与作用(实例分析)
想必大家都是刚刚才开始接触python这门语言的,今天这篇文章就来带大家来了解一下python这门语言之中常常会用到的一个语句pass语句.想必大家都很好奇python中pass作用是什么,接下来我就 ...
- char几个字节java_java中的char占几个字节实例分析
java中的char占几个字节实例分析 1:"字节"是byte,"位"是bit : 2: 1 byte = 8 bit : char 在Java中是2个字节.j ...
- 中职学校的学生计算机基础较弱,中职学校计算机专业教学的现状分析及对策探究.doc...
中职学校计算机专业教学的现状分析及对策探究 中职学校计算机专业教学的现状分析及对策探究 摘 要: 随着信息技术的发展,计算机已经成为人们日常学习和生活中不可或缺的工具,这也对中职计算机专业毕业生的能力 ...
- android中使用jni对字符串加解密实现分析
android中使用jni对字符串加解密实现分析 近期项目有个需求.就是要对用户的敏感信息进行加密处理,比方用户的账户password,手机号等私密信息.在java中,就对字符串的加解密我们能够使用A ...
- 视频直播中用户连麦技术模型与特点分析
本文章来源与网络(视频直播中用户连麦技术模型与特点分析 - 老头慢慢飞 - 博客园) 随着Web与移动视频直播应用的深度发展,有用户参与互动的视频直播技术被越来越多平台所支持,原来的RTMP流媒体方案 ...
最新文章
- (二)SpringMVC之执行的过程
- 项目代码结构 Dao,Service,Controller,Util,Model 含义
- Codeforces Round #316 (Div. 2) D. Tree Requests dfs序
- 最大整数(Noip1998连接多位数)
- 两数之和——双指针法
- 判断ipad还是安卓_?谷歌认输,iPad或成唯一赢家,安卓平板路在何方?
- Android Studio如何减小APK体积
- pythoncad二次开发视频_AutoCAD ObjectARX 二次开发(2020版)--4,使用ARX向导创建CAD二次开发项目(编程框架)--...
- Spring的@Scheduled任务调度
- JMM同步原语之final域的内存语义
- 华为云云容器快速搭建网站实践随记—利用私有镜像搭建GuestBook
- Git 标签(tag)相关操作
- ElasticSearch 如何使用 TDigest 算法计算亿级数据的百分位数?
- ATL WTL 实现分析(四)
- 添加同名工具后台验证后不跳转且保留用户输入的数值
- 分享一个 pycharm 专业版的永久使用方法
- 什么是硬件加速引擎?
- 解决“各种”软件图标显示错误问题
- 项目质量管理的几种常规方法
- 作为程序员,推荐5种编程语言!