Android4.2距离感应器
先说现象,现象就是来电话,接通电话,把手机屏幕靠近脸部,遮挡住P-sensor,屏幕变黑了,不遮挡住P-sensor,屏幕就点亮了。接着我们来看看代码流程。
距离感应器与屏幕休眠可参考
http://blog.csdn.net/wds1181977/article/details/42125699
先来说说靠近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 sensor
- if (proximitySensorModeEnabled()) {
- mAccelerometerListener = new AccelerometerListener(this, this);
- }
创建加速度感应器。
步骤三:在更新Phone的状态的时候确定这个加速度的P-sensor感应器起作用;
- <span style="font-size:18px;">/**
- * 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 call
- 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;">
- }
- // clear our beginning call flag
- mBeginningCall = 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);
- }
- }
- }</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) {
- // 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 plane
- double xy = Math.sqrt(x*x + y*y);
- // compute the vertical angle
- double angle = Math.atan2(xy, z);
- // convert to degrees
- 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) {
- // 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 timeout
- int delay = (orientation == ORIENTATION_VERTICAL ? VERTICAL_DEBOUNCE
- : HORIZONTAL_DEBOUNCE);
- mHandler.sendMessageDelayed(m, delay);
- } else {
- // no message is pending
- 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());
- }
- <pre name="code" class="java">/**
- * 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:ALPS00117091
- if (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:ALPS00117091
- if (((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...");
- <span style="color:#ff0000;"><strong>mProximityWakeLock.acquire();</strong></span>
- } 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 immediately
- int flags =
- (screenOnImmediately ? 0 : PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
- <strong><span style="color:#ff0000;">mProximityWakeLock.release(flags);</span></strong>
- } else {
- if (VDBG) {
- Log.d(LOG_TAG, "updateProximitySensorMode: lock already released.");
- }
- }
- }
- }
- }
- }</pre><br><br>
到这已经把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
Android4.2距离感应器相关推荐
- PowerManager屏幕休眠断网与距离感应器P-Sensor
PowerManager.java . 1. 应用程序获取PowerManager服务, 我们可以这样书写: PowerManager pm = (PowerManager) getSystemSe ...
- Android 距离感应器和耳机状态监测(控制Audio输出通道切换)
* 切换扬声器播放声音 or 听筒播放 * 1. 距离感应器:继承SensorEventListener这个监听,重写onSensorChanged方法 * 2. 检测耳机插入和拔出:Headse ...
- 距离感应器下的休眠唤醒机制实现
前言 从事Android framework开发已经两年了,今天起决定把工作上遇到的问题.做过的需求都用博客的形式记录一下,特地新开一个系列---Android framework开发工作记录,有需要 ...
- android距离感应器控制黑屏,白屏
最近在做一个网络通话的apk,功能和手机打sim卡电话一样.虽然只做java部分,但也遇到很多问题,其中一个就是模拟通话时的状态,要控制屏幕锁屏.我知道是通过手机上的距离感应器来实现,但也搞了好久,今 ...
- 距离感应器实现锁频教程
首先说一下android平台下的11种感应器: 1. ACCELEROMETER 加速,描述加速度的. 2.GRAVITY 重力,这个在大家都知道. ...
- android距离感应器控制屏幕灭屏白屏
最近在做一个网络通话的apk,功能和手机打sim卡电话一样.虽然只做java部分,但也遇到很多问题,其中一个就是模拟通话时的状态,要控制屏幕锁屏.我知道是通过手机上的距离感应器来实现,但也搞了好久,今 ...
- 米2距离感应器的设置问题。无法挂断电话等问题的解决
通话过程中一直黑屏,无法挂断电话 首先打开拨号界面,点击三道杠的菜单键--设置--来电时状态设置--启用距离感应器(打开 ︳),来电防误操作 直接关闭得了.
- android Phone 距离感应器锁的实现
android手机在正常打电话的过程中,靠近面部会灭屏,这个主要是PhoneApp中的mProximityWakeLock的作用.这个锁是在PhoneApp中被初始化的. if ((pm.getSup ...
- 手机中的传感器:重力感应器、加速度传感器、陀螺仪、电子罗盘和光线距离感应器
智能手机之所以受到大家的欢迎,与其具有的娱乐功能分不开,使得它不仅仅是个通话的工具.智能手机支持那么多的娱乐应用,归根结底在于它里面集成的各类传感器,主要有重力感应器.加速度传感器.陀螺仪.电子罗盘和 ...
最新文章
- ubuntu 16.04 更新后搜狗输入法无法输入中文的问题
- 3分钟解决MySQL 1032 主从错误
- Sql2000命名中的’_’好象会引发问题
- JAVA黑白圆圈图形_CSS3 黑白交替旋转圆圈
- 向量距离计算 java_Milvus 向量搜索引擎开源了!
- DL:听着歌曲《成都》三分钟看遍主流的深度学习的神经网络的发展框架(1950~2018)
- 搜索引擎的选择—百度还是谷歌?
- 5922. 统计出现过一次的公共字符串
- ASP.NET操作Excel
- Blazor服务器应用程序中使用EF Core的多租户
- java安装选择哪个可选功能_java章节习题及期末考试题答案.doc
- linux下三三维建模软件,SolidWorks是基于()原创的三维实体建模软件。A.UNIXB.WindowsC.LinuxD.Dos...
- Juniper设备管理
- JAVA ajax搜索框_JAVAEE AJAX实现搜素框关键字提示语功能
- 常见面试问题整理(考研复试面试/计算机408+数据库基础概念)
- BZOJ 4198 [Noi2015 D2T1] 荷马史诗
- hsql导入mysql_关于HSQLDB访问已有数据库文件的操作说明
- 学习打印机,了解打印命令
- 判定一个关键词的SEO优化难度等级标准
- dnf鹰犬机器人补丁_DNF补丁大全DNF东方Projece界面补丁下载