先说现象,现象就是来电话,接通电话,把手机屏幕靠近脸部,遮挡住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 sensor if (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 call mOrientation = AccelerometerListener.ORIENTATION_UNKNOWN; mAccelerometerListener.enable(state == PhoneConstants.State.OFFHOOK); } // 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); } } }
步骤四:用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()); }
/** * 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..."); 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 immediately int 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层怎么具体实现的亮屏和灭屏的;敬请期待。。。 。。。