191197049c458f07092b31501d2ed512180b13d58Chiao Cheng/*
291197049c458f07092b31501d2ed512180b13d58Chiao Cheng * Copyright (C) 2011 The Android Open Source Project
391197049c458f07092b31501d2ed512180b13d58Chiao Cheng *
491197049c458f07092b31501d2ed512180b13d58Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
591197049c458f07092b31501d2ed512180b13d58Chiao Cheng * you may not use this file except in compliance with the License.
691197049c458f07092b31501d2ed512180b13d58Chiao Cheng * You may obtain a copy of the License at
791197049c458f07092b31501d2ed512180b13d58Chiao Cheng *
891197049c458f07092b31501d2ed512180b13d58Chiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
991197049c458f07092b31501d2ed512180b13d58Chiao Cheng *
1091197049c458f07092b31501d2ed512180b13d58Chiao Cheng * Unless required by applicable law or agreed to in writing, software
1191197049c458f07092b31501d2ed512180b13d58Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
1291197049c458f07092b31501d2ed512180b13d58Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1391197049c458f07092b31501d2ed512180b13d58Chiao Cheng * See the License for the specific language governing permissions and
1491197049c458f07092b31501d2ed512180b13d58Chiao Cheng * limitations under the License.
1591197049c458f07092b31501d2ed512180b13d58Chiao Cheng */
1691197049c458f07092b31501d2ed512180b13d58Chiao Cheng
1791197049c458f07092b31501d2ed512180b13d58Chiao Chengpackage com.android.dialer;
1891197049c458f07092b31501d2ed512180b13d58Chiao Cheng
1991197049c458f07092b31501d2ed512180b13d58Chiao Chengimport android.content.Context;
2091197049c458f07092b31501d2ed512180b13d58Chiao Chengimport android.hardware.Sensor;
2191197049c458f07092b31501d2ed512180b13d58Chiao Chengimport android.hardware.SensorEvent;
2291197049c458f07092b31501d2ed512180b13d58Chiao Chengimport android.hardware.SensorEventListener;
2391197049c458f07092b31501d2ed512180b13d58Chiao Chengimport android.hardware.SensorManager;
2491197049c458f07092b31501d2ed512180b13d58Chiao Cheng
2591197049c458f07092b31501d2ed512180b13d58Chiao Chengimport javax.annotation.concurrent.GuardedBy;
2691197049c458f07092b31501d2ed512180b13d58Chiao Cheng
2791197049c458f07092b31501d2ed512180b13d58Chiao Cheng/**
2891197049c458f07092b31501d2ed512180b13d58Chiao Cheng * Manages the proximity sensor and notifies a listener when enabled.
2991197049c458f07092b31501d2ed512180b13d58Chiao Cheng */
3091197049c458f07092b31501d2ed512180b13d58Chiao Chengpublic class ProximitySensorManager {
3191197049c458f07092b31501d2ed512180b13d58Chiao Cheng    /**
3291197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * Listener of the state of the proximity sensor.
3391197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
3491197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * This interface abstracts two possible states for the proximity sensor, near and far.
3591197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
3691197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * The actual meaning of these states depends on the actual sensor.
3791197049c458f07092b31501d2ed512180b13d58Chiao Cheng     */
3891197049c458f07092b31501d2ed512180b13d58Chiao Cheng    public interface Listener {
3991197049c458f07092b31501d2ed512180b13d58Chiao Cheng        /** Called when the proximity sensor transitions from the far to the near state. */
4091197049c458f07092b31501d2ed512180b13d58Chiao Cheng        public void onNear();
4191197049c458f07092b31501d2ed512180b13d58Chiao Cheng        /** Called when the proximity sensor transitions from the near to the far state. */
4291197049c458f07092b31501d2ed512180b13d58Chiao Cheng        public void onFar();
4391197049c458f07092b31501d2ed512180b13d58Chiao Cheng    }
4491197049c458f07092b31501d2ed512180b13d58Chiao Cheng
4591197049c458f07092b31501d2ed512180b13d58Chiao Cheng    public static enum State {
4691197049c458f07092b31501d2ed512180b13d58Chiao Cheng        NEAR, FAR
4791197049c458f07092b31501d2ed512180b13d58Chiao Cheng    }
4891197049c458f07092b31501d2ed512180b13d58Chiao Cheng
4991197049c458f07092b31501d2ed512180b13d58Chiao Cheng    private final ProximitySensorEventListener mProximitySensorListener;
5091197049c458f07092b31501d2ed512180b13d58Chiao Cheng
5191197049c458f07092b31501d2ed512180b13d58Chiao Cheng    /**
5291197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * The current state of the manager, i.e., whether it is currently tracking the state of the
5391197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * sensor.
5491197049c458f07092b31501d2ed512180b13d58Chiao Cheng     */
5591197049c458f07092b31501d2ed512180b13d58Chiao Cheng    private boolean mManagerEnabled;
5691197049c458f07092b31501d2ed512180b13d58Chiao Cheng
5791197049c458f07092b31501d2ed512180b13d58Chiao Cheng    /**
5891197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * The listener to the state of the sensor.
5991197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
6091197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * Contains most of the logic concerning tracking of the sensor.
6191197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
6291197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * After creating an instance of this object, one should call {@link #register()} and
6391197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * {@link #unregister()} to enable and disable the notifications.
6491197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
6591197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * Instead of calling unregister, one can call {@link #unregisterWhenFar()} to unregister the
6691197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * listener the next time the sensor reaches the {@link State#FAR} state if currently in the
6791197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * {@link State#NEAR} state.
6891197049c458f07092b31501d2ed512180b13d58Chiao Cheng     */
6991197049c458f07092b31501d2ed512180b13d58Chiao Cheng    private static class ProximitySensorEventListener implements SensorEventListener {
7091197049c458f07092b31501d2ed512180b13d58Chiao Cheng        private static final float FAR_THRESHOLD = 5.0f;
7191197049c458f07092b31501d2ed512180b13d58Chiao Cheng
7291197049c458f07092b31501d2ed512180b13d58Chiao Cheng        private final SensorManager mSensorManager;
7391197049c458f07092b31501d2ed512180b13d58Chiao Cheng        private final Sensor mProximitySensor;
7491197049c458f07092b31501d2ed512180b13d58Chiao Cheng        private final float mMaxValue;
7591197049c458f07092b31501d2ed512180b13d58Chiao Cheng        private final Listener mListener;
7691197049c458f07092b31501d2ed512180b13d58Chiao Cheng
7791197049c458f07092b31501d2ed512180b13d58Chiao Cheng        /**
7891197049c458f07092b31501d2ed512180b13d58Chiao Cheng         * The last state of the sensor.
7991197049c458f07092b31501d2ed512180b13d58Chiao Cheng         * <p>
8091197049c458f07092b31501d2ed512180b13d58Chiao Cheng         * Before registering and after unregistering we are always in the {@link State#FAR} state.
8191197049c458f07092b31501d2ed512180b13d58Chiao Cheng         */
8291197049c458f07092b31501d2ed512180b13d58Chiao Cheng        @GuardedBy("this") private State mLastState;
8391197049c458f07092b31501d2ed512180b13d58Chiao Cheng        /**
8491197049c458f07092b31501d2ed512180b13d58Chiao Cheng         * If this flag is set to true, we are waiting to reach the {@link State#FAR} state and
8591197049c458f07092b31501d2ed512180b13d58Chiao Cheng         * should notify the listener and unregister when that happens.
8691197049c458f07092b31501d2ed512180b13d58Chiao Cheng         */
8791197049c458f07092b31501d2ed512180b13d58Chiao Cheng        @GuardedBy("this") private boolean mWaitingForFarState;
8891197049c458f07092b31501d2ed512180b13d58Chiao Cheng
8991197049c458f07092b31501d2ed512180b13d58Chiao Cheng        public ProximitySensorEventListener(SensorManager sensorManager, Sensor proximitySensor,
9091197049c458f07092b31501d2ed512180b13d58Chiao Cheng                Listener listener) {
9191197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mSensorManager = sensorManager;
9291197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mProximitySensor = proximitySensor;
9391197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mMaxValue = proximitySensor.getMaximumRange();
9491197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mListener = listener;
9591197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // Initialize at far state.
9691197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mLastState = State.FAR;
9791197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mWaitingForFarState = false;
9891197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
9991197049c458f07092b31501d2ed512180b13d58Chiao Cheng
10091197049c458f07092b31501d2ed512180b13d58Chiao Cheng        @Override
10191197049c458f07092b31501d2ed512180b13d58Chiao Cheng        public void onSensorChanged(SensorEvent event) {
10291197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // Make sure we have a valid value.
10391197049c458f07092b31501d2ed512180b13d58Chiao Cheng            if (event.values == null) return;
10491197049c458f07092b31501d2ed512180b13d58Chiao Cheng            if (event.values.length == 0) return;
10591197049c458f07092b31501d2ed512180b13d58Chiao Cheng            float value = event.values[0];
10691197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // Convert the sensor into a NEAR/FAR state.
10791197049c458f07092b31501d2ed512180b13d58Chiao Cheng            State state = getStateFromValue(value);
10891197049c458f07092b31501d2ed512180b13d58Chiao Cheng            synchronized (this) {
10991197049c458f07092b31501d2ed512180b13d58Chiao Cheng                // No change in state, do nothing.
11091197049c458f07092b31501d2ed512180b13d58Chiao Cheng                if (state == mLastState) return;
11191197049c458f07092b31501d2ed512180b13d58Chiao Cheng                // Keep track of the current state.
11291197049c458f07092b31501d2ed512180b13d58Chiao Cheng                mLastState = state;
11391197049c458f07092b31501d2ed512180b13d58Chiao Cheng                // If we are waiting to reach the far state and we are now in it, unregister.
11491197049c458f07092b31501d2ed512180b13d58Chiao Cheng                if (mWaitingForFarState && mLastState == State.FAR) {
11591197049c458f07092b31501d2ed512180b13d58Chiao Cheng                    unregisterWithoutNotification();
11691197049c458f07092b31501d2ed512180b13d58Chiao Cheng                }
11791197049c458f07092b31501d2ed512180b13d58Chiao Cheng            }
11891197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // Notify the listener of the state change.
11991197049c458f07092b31501d2ed512180b13d58Chiao Cheng            switch (state) {
12091197049c458f07092b31501d2ed512180b13d58Chiao Cheng                case NEAR:
12191197049c458f07092b31501d2ed512180b13d58Chiao Cheng                    mListener.onNear();
12291197049c458f07092b31501d2ed512180b13d58Chiao Cheng                    break;
12391197049c458f07092b31501d2ed512180b13d58Chiao Cheng
12491197049c458f07092b31501d2ed512180b13d58Chiao Cheng                case FAR:
12591197049c458f07092b31501d2ed512180b13d58Chiao Cheng                    mListener.onFar();
12691197049c458f07092b31501d2ed512180b13d58Chiao Cheng                    break;
12791197049c458f07092b31501d2ed512180b13d58Chiao Cheng            }
12891197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
12991197049c458f07092b31501d2ed512180b13d58Chiao Cheng
13091197049c458f07092b31501d2ed512180b13d58Chiao Cheng        @Override
13191197049c458f07092b31501d2ed512180b13d58Chiao Cheng        public void onAccuracyChanged(Sensor sensor, int accuracy) {
13291197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // Nothing to do here.
13391197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
13491197049c458f07092b31501d2ed512180b13d58Chiao Cheng
13591197049c458f07092b31501d2ed512180b13d58Chiao Cheng        /** Returns the state of the sensor given its current value. */
13691197049c458f07092b31501d2ed512180b13d58Chiao Cheng        private State getStateFromValue(float value) {
13791197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // Determine if the current value corresponds to the NEAR or FAR state.
13891197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // Take case of the case where the proximity sensor is binary: if the current value is
13991197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // equal to the maximum, we are always in the FAR state.
14091197049c458f07092b31501d2ed512180b13d58Chiao Cheng            return (value > FAR_THRESHOLD || value == mMaxValue) ? State.FAR : State.NEAR;
14191197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
14291197049c458f07092b31501d2ed512180b13d58Chiao Cheng
14391197049c458f07092b31501d2ed512180b13d58Chiao Cheng        /**
14491197049c458f07092b31501d2ed512180b13d58Chiao Cheng         * Unregister the next time the sensor reaches the {@link State#FAR} state.
14591197049c458f07092b31501d2ed512180b13d58Chiao Cheng         */
14691197049c458f07092b31501d2ed512180b13d58Chiao Cheng        public synchronized void unregisterWhenFar() {
14791197049c458f07092b31501d2ed512180b13d58Chiao Cheng            if (mLastState == State.FAR) {
14891197049c458f07092b31501d2ed512180b13d58Chiao Cheng                // We are already in the far state, just unregister now.
14991197049c458f07092b31501d2ed512180b13d58Chiao Cheng                unregisterWithoutNotification();
15091197049c458f07092b31501d2ed512180b13d58Chiao Cheng            } else {
15191197049c458f07092b31501d2ed512180b13d58Chiao Cheng                mWaitingForFarState = true;
15291197049c458f07092b31501d2ed512180b13d58Chiao Cheng            }
15391197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
15491197049c458f07092b31501d2ed512180b13d58Chiao Cheng
15591197049c458f07092b31501d2ed512180b13d58Chiao Cheng        /** Register the listener and call the listener as necessary. */
15691197049c458f07092b31501d2ed512180b13d58Chiao Cheng        public synchronized void register() {
15791197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // It is okay to register multiple times.
15891197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mSensorManager.registerListener(this, mProximitySensor, SensorManager.SENSOR_DELAY_UI);
15991197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // We should no longer be waiting for the far state if we are registering again.
16091197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mWaitingForFarState = false;
16191197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
16291197049c458f07092b31501d2ed512180b13d58Chiao Cheng
16391197049c458f07092b31501d2ed512180b13d58Chiao Cheng        public void unregister() {
16491197049c458f07092b31501d2ed512180b13d58Chiao Cheng            State lastState;
16591197049c458f07092b31501d2ed512180b13d58Chiao Cheng            synchronized (this) {
16691197049c458f07092b31501d2ed512180b13d58Chiao Cheng                unregisterWithoutNotification();
16791197049c458f07092b31501d2ed512180b13d58Chiao Cheng                lastState = mLastState;
16891197049c458f07092b31501d2ed512180b13d58Chiao Cheng                // Always go back to the FAR state. That way, when we register again we will get a
16991197049c458f07092b31501d2ed512180b13d58Chiao Cheng                // transition when the sensor gets into the NEAR state.
17091197049c458f07092b31501d2ed512180b13d58Chiao Cheng                mLastState = State.FAR;
17191197049c458f07092b31501d2ed512180b13d58Chiao Cheng            }
17291197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // Notify the listener if we changed the state to FAR while unregistering.
17391197049c458f07092b31501d2ed512180b13d58Chiao Cheng            if (lastState != State.FAR) {
17491197049c458f07092b31501d2ed512180b13d58Chiao Cheng                mListener.onFar();
17591197049c458f07092b31501d2ed512180b13d58Chiao Cheng            }
17691197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
17791197049c458f07092b31501d2ed512180b13d58Chiao Cheng
17891197049c458f07092b31501d2ed512180b13d58Chiao Cheng        @GuardedBy("this")
17991197049c458f07092b31501d2ed512180b13d58Chiao Cheng        private void unregisterWithoutNotification() {
18091197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mSensorManager.unregisterListener(this);
18191197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mWaitingForFarState = false;
18291197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
18391197049c458f07092b31501d2ed512180b13d58Chiao Cheng    }
18491197049c458f07092b31501d2ed512180b13d58Chiao Cheng
18591197049c458f07092b31501d2ed512180b13d58Chiao Cheng    public ProximitySensorManager(Context context, Listener listener) {
18691197049c458f07092b31501d2ed512180b13d58Chiao Cheng        SensorManager sensorManager =
18791197049c458f07092b31501d2ed512180b13d58Chiao Cheng                (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
18891197049c458f07092b31501d2ed512180b13d58Chiao Cheng        Sensor proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
18991197049c458f07092b31501d2ed512180b13d58Chiao Cheng        if (proximitySensor == null) {
19091197049c458f07092b31501d2ed512180b13d58Chiao Cheng            // If there is no sensor, we should not do anything.
19191197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mProximitySensorListener = null;
19291197049c458f07092b31501d2ed512180b13d58Chiao Cheng        } else {
19391197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mProximitySensorListener =
19491197049c458f07092b31501d2ed512180b13d58Chiao Cheng                    new ProximitySensorEventListener(sensorManager, proximitySensor, listener);
19591197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
19691197049c458f07092b31501d2ed512180b13d58Chiao Cheng    }
19791197049c458f07092b31501d2ed512180b13d58Chiao Cheng
19891197049c458f07092b31501d2ed512180b13d58Chiao Cheng    /**
19991197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * Enables the proximity manager.
20091197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
20191197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * The listener will start getting notifications of events.
20291197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
20391197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * This method is idempotent.
20491197049c458f07092b31501d2ed512180b13d58Chiao Cheng     */
20591197049c458f07092b31501d2ed512180b13d58Chiao Cheng    public void enable() {
20691197049c458f07092b31501d2ed512180b13d58Chiao Cheng        if (mProximitySensorListener != null && !mManagerEnabled) {
20791197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mProximitySensorListener.register();
20891197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mManagerEnabled = true;
20991197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
21091197049c458f07092b31501d2ed512180b13d58Chiao Cheng    }
21191197049c458f07092b31501d2ed512180b13d58Chiao Cheng
21291197049c458f07092b31501d2ed512180b13d58Chiao Cheng    /**
21391197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * Disables the proximity manager.
21491197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
21591197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * The listener will stop receiving notifications of events, possibly after receiving a last
21691197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * {@link Listener#onFar()} callback.
21791197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
21891197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * If {@code waitForFarState} is true, if the sensor is not currently in the {@link State#FAR}
21991197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * state, the listener will receive a {@link Listener#onFar()} callback the next time the sensor
22091197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * actually reaches the {@link State#FAR} state.
22191197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
22291197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * If {@code waitForFarState} is false, the listener will receive a {@link Listener#onFar()}
22391197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * callback immediately if the sensor is currently not in the {@link State#FAR} state.
22491197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * <p>
22591197049c458f07092b31501d2ed512180b13d58Chiao Cheng     * This method is idempotent.
22691197049c458f07092b31501d2ed512180b13d58Chiao Cheng     */
22791197049c458f07092b31501d2ed512180b13d58Chiao Cheng    public void disable(boolean waitForFarState) {
22891197049c458f07092b31501d2ed512180b13d58Chiao Cheng        if (mProximitySensorListener != null && mManagerEnabled) {
22991197049c458f07092b31501d2ed512180b13d58Chiao Cheng            if (waitForFarState) {
23091197049c458f07092b31501d2ed512180b13d58Chiao Cheng                mProximitySensorListener.unregisterWhenFar();
23191197049c458f07092b31501d2ed512180b13d58Chiao Cheng            } else {
23291197049c458f07092b31501d2ed512180b13d58Chiao Cheng                mProximitySensorListener.unregister();
23391197049c458f07092b31501d2ed512180b13d58Chiao Cheng            }
23491197049c458f07092b31501d2ed512180b13d58Chiao Cheng            mManagerEnabled = false;
23591197049c458f07092b31501d2ed512180b13d58Chiao Cheng        }
23691197049c458f07092b31501d2ed512180b13d58Chiao Cheng    }
23791197049c458f07092b31501d2ed512180b13d58Chiao Cheng}
238