zoukankan      html  css  js  c++  java
  • 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层怎么具体实现的亮屏和灭屏的;敬请期待。。。 。。。

    
    
    
  • 相关阅读:
    问题解决-Plugin with id 'com.github.dcendents.android-maven' not found
    hadoop 04 一 HA高可用配置
    hadoop 03 一 Hadoop机架感知配置
    Windows平台安装配置Hadoop
    hadoop 02一 hadoop配置
    hadoop 01一 hadoop安装配置
    Centos7下载和安装教程
    mysql 命令行导出数据
    RabbitMQ 集群部署(linux-centos6.5)
    Spring 集成RabbitMq
  • 原文地址:https://www.cnblogs.com/riskyer/p/3249256.html
Copyright © 2011-2022 走看看