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