1 /* 2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 package org.appspot.apprtc; 12 13 import android.content.Context; 14 import android.hardware.Sensor; 15 import android.hardware.SensorEvent; 16 import android.hardware.SensorEventListener; 17 import android.hardware.SensorManager; 18 import android.os.Build; 19 import android.support.annotation.Nullable; 20 import android.util.Log; 21 import org.appspot.apprtc.util.AppRTCUtils; 22 import org.webrtc.ThreadUtils; 23 24 /** 25 * AppRTCProximitySensor manages functions related to the proximity sensor in 26 * the AppRTC demo. 27 * On most device, the proximity sensor is implemented as a boolean-sensor. 28 * It returns just two values "NEAR" or "FAR". Thresholding is done on the LUX 29 * value i.e. the LUX value of the light sensor is compared with a threshold. 30 * A LUX-value more than the threshold means the proximity sensor returns "FAR". 31 * Anything less than the threshold value and the sensor returns "NEAR". 32 */ 33 public class AppRTCProximitySensor implements SensorEventListener { 34 private static final String TAG = "AppRTCProximitySensor"; 35 36 // This class should be created, started and stopped on one thread 37 // (e.g. the main thread). We use |nonThreadSafe| to ensure that this is 38 // the case. Only active when |DEBUG| is set to true. 39 private final ThreadUtils.ThreadChecker threadChecker = new ThreadUtils.ThreadChecker(); 40 41 private final Runnable onSensorStateListener; 42 private final SensorManager sensorManager; 43 @Nullable private Sensor proximitySensor; 44 private boolean lastStateReportIsNear; 45 46 /** Construction */ create(Context context, Runnable sensorStateListener)47 static AppRTCProximitySensor create(Context context, Runnable sensorStateListener) { 48 return new AppRTCProximitySensor(context, sensorStateListener); 49 } 50 AppRTCProximitySensor(Context context, Runnable sensorStateListener)51 private AppRTCProximitySensor(Context context, Runnable sensorStateListener) { 52 Log.d(TAG, "AppRTCProximitySensor" + AppRTCUtils.getThreadInfo()); 53 onSensorStateListener = sensorStateListener; 54 sensorManager = ((SensorManager) context.getSystemService(Context.SENSOR_SERVICE)); 55 } 56 57 /** 58 * Activate the proximity sensor. Also do initialization if called for the 59 * first time. 60 */ start()61 public boolean start() { 62 threadChecker.checkIsOnValidThread(); 63 Log.d(TAG, "start" + AppRTCUtils.getThreadInfo()); 64 if (!initDefaultSensor()) { 65 // Proximity sensor is not supported on this device. 66 return false; 67 } 68 sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL); 69 return true; 70 } 71 72 /** Deactivate the proximity sensor. */ stop()73 public void stop() { 74 threadChecker.checkIsOnValidThread(); 75 Log.d(TAG, "stop" + AppRTCUtils.getThreadInfo()); 76 if (proximitySensor == null) { 77 return; 78 } 79 sensorManager.unregisterListener(this, proximitySensor); 80 } 81 82 /** Getter for last reported state. Set to true if "near" is reported. */ sensorReportsNearState()83 public boolean sensorReportsNearState() { 84 threadChecker.checkIsOnValidThread(); 85 return lastStateReportIsNear; 86 } 87 88 @Override onAccuracyChanged(Sensor sensor, int accuracy)89 public final void onAccuracyChanged(Sensor sensor, int accuracy) { 90 threadChecker.checkIsOnValidThread(); 91 AppRTCUtils.assertIsTrue(sensor.getType() == Sensor.TYPE_PROXIMITY); 92 if (accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) { 93 Log.e(TAG, "The values returned by this sensor cannot be trusted"); 94 } 95 } 96 97 @Override onSensorChanged(SensorEvent event)98 public final void onSensorChanged(SensorEvent event) { 99 threadChecker.checkIsOnValidThread(); 100 AppRTCUtils.assertIsTrue(event.sensor.getType() == Sensor.TYPE_PROXIMITY); 101 // As a best practice; do as little as possible within this method and 102 // avoid blocking. 103 float distanceInCentimeters = event.values[0]; 104 if (distanceInCentimeters < proximitySensor.getMaximumRange()) { 105 Log.d(TAG, "Proximity sensor => NEAR state"); 106 lastStateReportIsNear = true; 107 } else { 108 Log.d(TAG, "Proximity sensor => FAR state"); 109 lastStateReportIsNear = false; 110 } 111 112 // Report about new state to listening client. Client can then call 113 // sensorReportsNearState() to query the current state (NEAR or FAR). 114 if (onSensorStateListener != null) { 115 onSensorStateListener.run(); 116 } 117 118 Log.d(TAG, "onSensorChanged" + AppRTCUtils.getThreadInfo() + ": " 119 + "accuracy=" + event.accuracy + ", timestamp=" + event.timestamp + ", distance=" 120 + event.values[0]); 121 } 122 123 /** 124 * Get default proximity sensor if it exists. Tablet devices (e.g. Nexus 7) 125 * does not support this type of sensor and false will be returned in such 126 * cases. 127 */ initDefaultSensor()128 private boolean initDefaultSensor() { 129 if (proximitySensor != null) { 130 return true; 131 } 132 proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); 133 if (proximitySensor == null) { 134 return false; 135 } 136 logProximitySensorInfo(); 137 return true; 138 } 139 140 /** Helper method for logging information about the proximity sensor. */ logProximitySensorInfo()141 private void logProximitySensorInfo() { 142 if (proximitySensor == null) { 143 return; 144 } 145 StringBuilder info = new StringBuilder("Proximity sensor: "); 146 info.append("name=").append(proximitySensor.getName()); 147 info.append(", vendor: ").append(proximitySensor.getVendor()); 148 info.append(", power: ").append(proximitySensor.getPower()); 149 info.append(", resolution: ").append(proximitySensor.getResolution()); 150 info.append(", max range: ").append(proximitySensor.getMaximumRange()); 151 info.append(", min delay: ").append(proximitySensor.getMinDelay()); 152 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { 153 // Added in API level 20. 154 info.append(", type: ").append(proximitySensor.getStringType()); 155 } 156 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 157 // Added in API level 21. 158 info.append(", max delay: ").append(proximitySensor.getMaxDelay()); 159 info.append(", reporting mode: ").append(proximitySensor.getReportingMode()); 160 info.append(", isWakeUpSensor: ").append(proximitySensor.isWakeUpSensor()); 161 } 162 Log.d(TAG, info.toString()); 163 } 164 } 165