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 |