Android4.2中Phone的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 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层怎么具体实现的亮屏和灭屏的;敬请期待。。。 。。。

上一篇:mysql的学习笔记(八)


下一篇:location.href 跳转之后,原来位置下面的代码还会继续执行