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



原文地址:https://www.cnblogs.com/riskyer/p/3249256.html