blob: a905eba1f0ed7ef2380c4a51ca9e85dcf8d57746 [file] [log] [blame]
Dave Mankoff46b9d682019-09-12 13:39:42 -04001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.util;
18
19import android.content.Context;
20import android.hardware.Sensor;
21import android.hardware.SensorEvent;
22import android.hardware.SensorEventListener;
23import android.hardware.SensorManager;
24import android.util.Log;
25
26import com.android.systemui.R;
27
28import java.util.ArrayList;
29import java.util.List;
30
31import javax.inject.Inject;
32
33/**
34 * Simple wrapper around SensorManager customized for the Proximity sensor.
35 */
36public class ProximitySensor {
37 private static final String TAG = "ProxSensor";
38 private static final boolean DEBUG = false;
39
40 private final Sensor mSensor;
41 private final AsyncSensorManager mSensorManager;
42 private final boolean mUsingBrightnessSensor;
43 private final float mMaxRange;
44
45 private SensorEventListener mSensorEventListener = new SensorEventListener() {
46 @Override
47 public synchronized void onSensorChanged(SensorEvent event) {
48 onSensorEvent(event);
49 }
50
51 @Override
52 public void onAccuracyChanged(Sensor sensor, int accuracy) {
53 }
54 };
55 private boolean mNear;
56 private List<ProximitySensorListener> mListeners = new ArrayList<>();
57 private String mTag = null;
58
59 @Inject
60 public ProximitySensor(Context context, AsyncSensorManager sensorManager) {
61 mSensorManager = sensorManager;
62 Sensor sensor = findBrightnessSensor(context, sensorManager);
63
64 if (sensor == null) {
65 mUsingBrightnessSensor = false;
66 sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
67 } else {
68 mUsingBrightnessSensor = true;
69 }
70 mSensor = sensor;
71 if (mSensor != null) {
72 mMaxRange = mSensor.getMaximumRange();
73 } else {
74 mMaxRange = 0;
75 }
76 }
77
78 public void setTag(String tag) {
79 mTag = tag;
80 }
81
82 private Sensor findBrightnessSensor(Context context, SensorManager sensorManager) {
83 String sensorType = context.getString(R.string.doze_brightness_sensor_type);
84 List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);
85 Sensor sensor = null;
86 for (Sensor s : sensorList) {
87 if (sensorType.equals(s.getStringType())) {
88 sensor = s;
89 break;
90 }
91 }
92
93 return sensor;
94 }
95
96 /**
97 * Returns {@code false} if a Proximity sensor is not available.
98 */
99 public boolean getSensorAvailable() {
100 return mSensor != null;
101 }
102
103 /**
104 * Add a listener.
105 *
106 * Registers itself with the {@link SensorManager} if this is the first listener
107 * added.
108 */
109 public boolean register(ProximitySensorListener listener) {
110 if (!getSensorAvailable()) {
111 return false;
112 }
113
114 logDebug("using brightness sensor? " + mUsingBrightnessSensor);
115 mListeners.add(listener);
116 if (mListeners.size() == 1) {
117 logDebug("registering sensor listener");
118 mSensorManager.registerListener(
119 mSensorEventListener, mSensor, SensorManager.SENSOR_DELAY_GAME);
120 }
121
122 return true;
123 }
124
125 /**
126 * Remove a listener.
127 *
128 * If all listeners are removed from an instance of this class,
129 * it will unregister itself with the SensorManager.
130 */
131 public void unregister(ProximitySensorListener listener) {
132 mListeners.remove(listener);
133 if (mListeners.size() == 0) {
134 logDebug("unregistering sensor listener");
135 mSensorManager.unregisterListener(mSensorEventListener);
136 }
137 }
138
139 public boolean isNear() {
140 return getSensorAvailable() && mNear;
141 }
142
143 private void onSensorEvent(SensorEvent event) {
144 boolean near = event.values[0] < mMaxRange;
145 if (mUsingBrightnessSensor) {
146 near = event.values[0] == 0;
147 }
148 mNear = near;
149 mListeners.forEach(proximitySensorListener ->
150 proximitySensorListener.onProximitySensorEvent(
151 new ProximityEvent(mNear, event.timestamp)));
152 }
153
154 /** Implement to be notified of ProximityEvents. */
155 public interface ProximitySensorListener {
156 /** Called when the ProximitySensor changes. */
157 void onProximitySensorEvent(ProximityEvent proximityEvent);
158 }
159
160 /**
161 * Returned when the near/far state of a {@link ProximitySensor} changes.
162 */
163 public static class ProximityEvent {
164 private final boolean mNear;
165 private final long mTimestampNs;
166
167 public ProximityEvent(boolean near, long timestampNs) {
168 mNear = near;
169 mTimestampNs = timestampNs;
170 }
171
172 public boolean getNear() {
173 return mNear;
174 }
175
176 public long getTimestampNs() {
177 return mTimestampNs;
178 }
179 }
180
181 private void logDebug(String msg) {
182 if (DEBUG) {
183 Log.d(TAG, (mTag != null ? "[" + mTag + "] " : "") + msg);
184 }
185 }
186}