Analysis of the P-sensor application of phone in android4.2.

Source: Internet
Author: User
Tags call back

First, the phenomenon is to call the phone, connect the phone, close the screen of the phone to the face, block p-sensor, the screen turns black, do not block p-sensor, the screen is lit up. Next let's take a look at the code process.

Step 1: In the oncreate () method in the phoneglobals. Java file:

... ...

// 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);            }

... ...

Pay attention to this private powermanager. wakelock mproximitywakelock; this initialization variable,

This mproximitywakelock is called the p-sensor lock, which is used to wake up the screen and sleep the screen.


Step 2: In the oncreate () method in the phoneglobals. Java file:

// create mAccelerometerListener only if we are using the proximity sensor            if (proximitySensorModeEnabled()) {                mAccelerometerListener = new AccelerometerListener(this, this);            }

Create an acceleration sensor.


Step 3: Determine the p-sensor Sensor for this acceleration when updating the phone status;

/**     * 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);            }        }    }

Step 4: Use the listener event in the accelerometerlistener. Java class to handle some changes to the overwrite. There are two statuses, one is

Horizontal, one is vertical state. Register the listener in the red part of Step 3:

 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);            }        }    }

Step 5: process the listener event as follows:

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;            }        }    }

Then, the orientation_changed message is sent. A callback function is called for the changed message and the acquire and release () methods are called Based on the status;

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;            }        }    };

Step 5: call back to orientationchanged () of the phoneglobals. Java class ()

@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.");                        }                    }                }            }        }    }

By now, we have finished the p-sensor on and off-screen on the phone layer. Then we will go back and find out how to implement the mproximitywakelock on the framework layer; coming soon... ...

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.