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

 
  

 

你可能感兴趣的:(android)