| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * libjingle | |
| 3 * Copyright 2014 Google Inc. | |
| 4 * | |
| 5 * Redistribution and use in source and binary forms, with or without | |
| 6 * modification, are permitted provided that the following conditions are met: | |
| 7 * | |
| 8 * 1. Redistributions of source code must retain the above copyright notice, | |
| 9 * this list of conditions and the following disclaimer. | |
| 10 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
| 11 * this list of conditions and the following disclaimer in the documentation | |
| 12 * and/or other materials provided with the distribution. | |
| 13 * 3. The name of the author may not be used to endorse or promote products | |
| 14 * derived from this software without specific prior written permission. | |
| 15 * | |
| 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
| 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
| 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
| 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
| 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
| 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
| 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
| 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 26 */ | |
| 27 | |
| 28 package org.appspot.apprtc; | |
| 29 | |
| 30 import org.appspot.apprtc.util.AppRTCUtils; | |
| 31 import org.appspot.apprtc.util.AppRTCUtils.NonThreadSafe; | |
| 32 | |
| 33 import android.content.Context; | |
| 34 import android.hardware.Sensor; | |
| 35 import android.hardware.SensorEvent; | |
| 36 import android.hardware.SensorEventListener; | |
| 37 import android.hardware.SensorManager; | |
| 38 import android.os.Build; | |
| 39 import android.util.Log; | |
| 40 | |
| 41 /** | |
| 42 * AppRTCProximitySensor manages functions related to the proximity sensor in | |
| 43 * the AppRTC demo. | |
| 44 * On most device, the proximity sensor is implemented as a boolean-sensor. | |
| 45 * It returns just two values "NEAR" or "FAR". Thresholding is done on the LUX | |
| 46 * value i.e. the LUX value of the light sensor is compared with a threshold. | |
| 47 * A LUX-value more than the threshold means the proximity sensor returns "FAR". | |
| 48 * Anything less than the threshold value and the sensor returns "NEAR". | |
| 49 */ | |
| 50 public class AppRTCProximitySensor implements SensorEventListener { | |
| 51 private static final String TAG = "AppRTCProximitySensor"; | |
| 52 | |
| 53 // This class should be created, started and stopped on one thread | |
| 54 // (e.g. the main thread). We use |nonThreadSafe| to ensure that this is | |
| 55 // the case. Only active when |DEBUG| is set to true. | |
| 56 private final NonThreadSafe nonThreadSafe = new AppRTCUtils.NonThreadSafe(); | |
| 57 | |
| 58 private final Runnable onSensorStateListener; | |
| 59 private final SensorManager sensorManager; | |
| 60 private Sensor proximitySensor = null; | |
| 61 private boolean lastStateReportIsNear = false; | |
| 62 | |
| 63 /** Construction */ | |
| 64 static AppRTCProximitySensor create(Context context, | |
| 65 Runnable sensorStateListener) { | |
| 66 return new AppRTCProximitySensor(context, sensorStateListener); | |
| 67 } | |
| 68 | |
| 69 private AppRTCProximitySensor(Context context, Runnable sensorStateListener) { | |
| 70 Log.d(TAG, "AppRTCProximitySensor" + AppRTCUtils.getThreadInfo()); | |
| 71 onSensorStateListener = sensorStateListener; | |
| 72 sensorManager = ((SensorManager) context.getSystemService( | |
| 73 Context.SENSOR_SERVICE)); | |
| 74 } | |
| 75 | |
| 76 /** | |
| 77 * Activate the proximity sensor. Also do initializtion if called for the | |
| 78 * first time. | |
| 79 */ | |
| 80 public boolean start() { | |
| 81 checkIfCalledOnValidThread(); | |
| 82 Log.d(TAG, "start" + AppRTCUtils.getThreadInfo()); | |
| 83 if (!initDefaultSensor()) { | |
| 84 // Proximity sensor is not supported on this device. | |
| 85 return false; | |
| 86 } | |
| 87 sensorManager.registerListener( | |
| 88 this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL); | |
| 89 return true; | |
| 90 } | |
| 91 | |
| 92 /** Deactivate the proximity sensor. */ | |
| 93 public void stop() { | |
| 94 checkIfCalledOnValidThread(); | |
| 95 Log.d(TAG, "stop" + AppRTCUtils.getThreadInfo()); | |
| 96 if (proximitySensor == null) { | |
| 97 return; | |
| 98 } | |
| 99 sensorManager.unregisterListener(this, proximitySensor); | |
| 100 } | |
| 101 | |
| 102 /** Getter for last reported state. Set to true if "near" is reported. */ | |
| 103 public boolean sensorReportsNearState() { | |
| 104 checkIfCalledOnValidThread(); | |
| 105 return lastStateReportIsNear; | |
| 106 } | |
| 107 | |
| 108 @Override | |
| 109 public final void onAccuracyChanged(Sensor sensor, int accuracy) { | |
| 110 checkIfCalledOnValidThread(); | |
| 111 AppRTCUtils.assertIsTrue(sensor.getType() == Sensor.TYPE_PROXIMITY); | |
| 112 if (accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) { | |
| 113 Log.e(TAG, "The values returned by this sensor cannot be trusted"); | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 @Override | |
| 118 public final void onSensorChanged(SensorEvent event) { | |
| 119 checkIfCalledOnValidThread(); | |
| 120 AppRTCUtils.assertIsTrue(event.sensor.getType() == Sensor.TYPE_PROXIMITY); | |
| 121 // As a best practice; do as little as possible within this method and | |
| 122 // avoid blocking. | |
| 123 float distanceInCentimeters = event.values[0]; | |
| 124 if (distanceInCentimeters < proximitySensor.getMaximumRange()) { | |
| 125 Log.d(TAG, "Proximity sensor => NEAR state"); | |
| 126 lastStateReportIsNear = true; | |
| 127 } else { | |
| 128 Log.d(TAG, "Proximity sensor => FAR state"); | |
| 129 lastStateReportIsNear = false; | |
| 130 } | |
| 131 | |
| 132 // Report about new state to listening client. Client can then call | |
| 133 // sensorReportsNearState() to query the current state (NEAR or FAR). | |
| 134 if (onSensorStateListener != null) { | |
| 135 onSensorStateListener.run(); | |
| 136 } | |
| 137 | |
| 138 Log.d(TAG, "onSensorChanged" + AppRTCUtils.getThreadInfo() + ": " | |
| 139 + "accuracy=" + event.accuracy | |
| 140 + ", timestamp=" + event.timestamp + ", distance=" + event.values[0]); | |
| 141 } | |
| 142 | |
| 143 /** | |
| 144 * Get default proximity sensor if it exists. Tablet devices (e.g. Nexus 7) | |
| 145 * does not support this type of sensor and false will be retured in such | |
| 146 * cases. | |
| 147 */ | |
| 148 private boolean initDefaultSensor() { | |
| 149 if (proximitySensor != null) { | |
| 150 return true; | |
| 151 } | |
| 152 proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); | |
| 153 if (proximitySensor == null) { | |
| 154 return false; | |
| 155 } | |
| 156 logProximitySensorInfo(); | |
| 157 return true; | |
| 158 } | |
| 159 | |
| 160 /** Helper method for logging information about the proximity sensor. */ | |
| 161 private void logProximitySensorInfo() { | |
| 162 if (proximitySensor == null) { | |
| 163 return; | |
| 164 } | |
| 165 StringBuilder info = new StringBuilder("Proximity sensor: "); | |
| 166 info.append("name=" + proximitySensor.getName()); | |
| 167 info.append(", vendor: " + proximitySensor.getVendor()); | |
| 168 info.append(", power: " + proximitySensor.getPower()); | |
| 169 info.append(", resolution: " + proximitySensor.getResolution()); | |
| 170 info.append(", max range: " + proximitySensor.getMaximumRange()); | |
| 171 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { | |
| 172 // Added in API level 9. | |
| 173 info.append(", min delay: " + proximitySensor.getMinDelay()); | |
| 174 } | |
| 175 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { | |
| 176 // Added in API level 20. | |
| 177 info.append(", type: " + proximitySensor.getStringType()); | |
| 178 } | |
| 179 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | |
| 180 // Added in API level 21. | |
| 181 info.append(", max delay: " + proximitySensor.getMaxDelay()); | |
| 182 info.append(", reporting mode: " + proximitySensor.getReportingMode()); | |
| 183 info.append(", isWakeUpSensor: " + proximitySensor.isWakeUpSensor()); | |
| 184 } | |
| 185 Log.d(TAG, info.toString()); | |
| 186 } | |
| 187 | |
| 188 /** | |
| 189 * Helper method for debugging purposes. Ensures that method is | |
| 190 * called on same thread as this object was created on. | |
| 191 */ | |
| 192 private void checkIfCalledOnValidThread() { | |
| 193 if (!nonThreadSafe.calledOnValidThread()) { | |
| 194 throw new IllegalStateException("Method is not called on valid thread"); | |
| 195 } | |
| 196 } | |
| 197 } | |
| OLD | NEW |