RESTRICT AUTOMERGE ProximitySensor now supports dual-sensor approach.
The ProximitySensor now supports the concept of a primary and a secondary hardware sensor. The primary sensor is used for a first pass check if the phone covered. When triggered, it then checks the secondary sensor for confirmation (if there is one). It does not send a proximity event until the secondary sensor confirms (or rejects) the reading. The secondary sensor is, in fact, the source of truth. This is necessary as sometimes keeping the secondary sensor on for extends periods is undesirable. It may, however, result in increased latency for proximity readings. Phones should configure this via a config.xml overlay. If no proximity sensor is set (primary or secondary) we fall back to the default Sensor.TYPE_PROXIMITY. If proximity_sensor_type is set in config.xml, that will be used as the primary sensor. If proximity_sensor_secondary_type is set, that will function as the secondary sensor. If no secondary is set, only the primary will be used. This CL also introduces the ThresholdSensor interface. This is a simple sensor wrapper for sensors that need to report a binary above/below value. ProximitySensor now implements this interface and also takes in ThresholdSensor as its primary and secondary inputs. Bug: 147026387 Test: atest SystemUITests && manual Change-Id: I1e808e591f1db05c664df6190670cb92315f63f3 Merged-In: I1e808e591f1db05c664df6190670cb92315f63f3
This commit is contained in:
@@ -205,6 +205,14 @@
|
|||||||
far break points. A sensor value less than this is considered "near". -->
|
far break points. A sensor value less than this is considered "near". -->
|
||||||
<item name="proximity_sensor_threshold" translatable="false" format="float" type="dimen"></item>
|
<item name="proximity_sensor_threshold" translatable="false" format="float" type="dimen"></item>
|
||||||
|
|
||||||
|
<!-- Override value to use for proximity sensor as confirmation for proximity_sensor_type. -->
|
||||||
|
<string name="proximity_sensor_secondary_type" translatable="false"></string>
|
||||||
|
|
||||||
|
<!-- If using proximity_sensor_confirmation_type, specifies a threshold value to distinguish
|
||||||
|
near and far break points. A sensor value less than this is considered "near". -->
|
||||||
|
<item name="proximity_sensor_secondary_threshold" translatable="false" format="float"
|
||||||
|
type="dimen"></item>
|
||||||
|
|
||||||
<!-- Doze: pulse parameter - how long does it take to fade in? -->
|
<!-- Doze: pulse parameter - how long does it take to fade in? -->
|
||||||
<integer name="doze_pulse_duration_in">130</integer>
|
<integer name="doze_pulse_duration_in">130</integer>
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class FalsingManagerProxy implements FalsingManager, Dumpable {
|
|||||||
mUiBgExecutor = uiBgExecutor;
|
mUiBgExecutor = uiBgExecutor;
|
||||||
mStatusBarStateController = statusBarStateController;
|
mStatusBarStateController = statusBarStateController;
|
||||||
mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
|
mProximitySensor.setTag(PROXIMITY_SENSOR_TAG);
|
||||||
mProximitySensor.setSensorDelay(SensorManager.SENSOR_DELAY_GAME);
|
mProximitySensor.setDelay(SensorManager.SENSOR_DELAY_GAME);
|
||||||
mDeviceConfig = deviceConfig;
|
mDeviceConfig = deviceConfig;
|
||||||
mDeviceConfigListener =
|
mDeviceConfigListener =
|
||||||
properties -> onDeviceConfigPropertiesChanged(context, properties.getNamespace());
|
properties -> onDeviceConfigPropertiesChanged(context, properties.getNamespace());
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
|||||||
import com.android.systemui.statusbar.StatusBarState;
|
import com.android.systemui.statusbar.StatusBarState;
|
||||||
import com.android.systemui.util.DeviceConfigProxy;
|
import com.android.systemui.util.DeviceConfigProxy;
|
||||||
import com.android.systemui.util.sensors.ProximitySensor;
|
import com.android.systemui.util.sensors.ProximitySensor;
|
||||||
|
import com.android.systemui.util.sensors.ThresholdSensor;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
@@ -76,7 +77,7 @@ public class BrightLineFalsingManager implements FalsingManager {
|
|||||||
|
|
||||||
private final List<FalsingClassifier> mClassifiers;
|
private final List<FalsingClassifier> mClassifiers;
|
||||||
|
|
||||||
private ProximitySensor.ProximitySensorListener mSensorEventListener = this::onProximityEvent;
|
private ThresholdSensor.Listener mSensorEventListener = this::onProximityEvent;
|
||||||
|
|
||||||
private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
|
private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
|
||||||
new KeyguardUpdateMonitorCallback() {
|
new KeyguardUpdateMonitorCallback() {
|
||||||
@@ -240,7 +241,7 @@ public class BrightLineFalsingManager implements FalsingManager {
|
|||||||
mClassifiers.forEach((classifier) -> classifier.onTouchEvent(motionEvent));
|
mClassifiers.forEach((classifier) -> classifier.onTouchEvent(motionEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onProximityEvent(ProximitySensor.ProximityEvent proximityEvent) {
|
private void onProximityEvent(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
|
||||||
// TODO: some of these classifiers might allow us to abort early, meaning we don't have to
|
// TODO: some of these classifiers might allow us to abort early, meaning we don't have to
|
||||||
// make these calls.
|
// make these calls.
|
||||||
mClassifiers.forEach((classifier) -> classifier.onProximityEvent(proximityEvent));
|
mClassifiers.forEach((classifier) -> classifier.onProximityEvent(proximityEvent));
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ abstract class FalsingClassifier {
|
|||||||
/**
|
/**
|
||||||
* Called when a ProximityEvent occurs (change in near/far).
|
* Called when a ProximityEvent occurs (change in near/far).
|
||||||
*/
|
*/
|
||||||
void onProximityEvent(ProximitySensor.ProximityEvent proximityEvent) {};
|
void onProximityEvent(ProximitySensor.ThresholdSensorEvent proximityEvent) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The phone screen has turned on and we need to begin falsing detection.
|
* The phone screen has turned on and we need to begin falsing detection.
|
||||||
|
|||||||
@@ -101,8 +101,8 @@ class ProximityClassifier extends FalsingClassifier {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProximityEvent(
|
public void onProximityEvent(
|
||||||
ProximitySensor.ProximityEvent proximityEvent) {
|
ProximitySensor.ThresholdSensorEvent proximityEvent) {
|
||||||
boolean near = proximityEvent.getNear();
|
boolean near = proximityEvent.getBelow();
|
||||||
long timestampNs = proximityEvent.getTimestampNs();
|
long timestampNs = proximityEvent.getTimestampNs();
|
||||||
logDebug("Sensor is: " + near + " at time " + timestampNs);
|
logDebug("Sensor is: " + near + " at time " + timestampNs);
|
||||||
update(near, timestampNs);
|
update(near, timestampNs);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import android.content.pm.LauncherApps;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ShortcutManager;
|
import android.content.pm.ShortcutManager;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
import android.hardware.SensorPrivacyManager;
|
import android.hardware.SensorPrivacyManager;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
@@ -240,6 +241,12 @@ public class SystemServicesModule {
|
|||||||
return context.getResources();
|
return context.getResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
static SensorManager providesSensorManager(Context context) {
|
||||||
|
return context.getSystemService(SensorManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
static SensorPrivacyManager provideSensorPrivacyManager(Context context) {
|
static SensorPrivacyManager provideSensorPrivacyManager(Context context) {
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
|
|||||||
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
import com.android.systemui.statusbar.policy.HeadsUpManager;
|
||||||
import com.android.systemui.util.concurrency.ConcurrencyModule;
|
import com.android.systemui.util.concurrency.ConcurrencyModule;
|
||||||
import com.android.systemui.util.sensors.AsyncSensorManager;
|
import com.android.systemui.util.sensors.AsyncSensorManager;
|
||||||
|
import com.android.systemui.util.sensors.SensorModule;
|
||||||
import com.android.systemui.util.time.SystemClock;
|
import com.android.systemui.util.time.SystemClock;
|
||||||
import com.android.systemui.util.time.SystemClockImpl;
|
import com.android.systemui.util.time.SystemClockImpl;
|
||||||
|
|
||||||
@@ -62,7 +63,8 @@ import dagger.Provides;
|
|||||||
ConcurrencyModule.class,
|
ConcurrencyModule.class,
|
||||||
LogModule.class,
|
LogModule.class,
|
||||||
PeopleHubModule.class,
|
PeopleHubModule.class,
|
||||||
SettingsModule.class
|
SensorModule.class,
|
||||||
|
SettingsModule.class,
|
||||||
},
|
},
|
||||||
subcomponents = {StatusBarComponent.class,
|
subcomponents = {StatusBarComponent.class,
|
||||||
NotificationRowComponent.class,
|
NotificationRowComponent.class,
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ public class DozeSensors {
|
|||||||
|
|
||||||
public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager,
|
public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager,
|
||||||
DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
|
DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
|
||||||
Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog) {
|
Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog,
|
||||||
|
ProximitySensor proximitySensor) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mAlarmManager = alarmManager;
|
mAlarmManager = alarmManager;
|
||||||
mSensorManager = sensorManager;
|
mSensorManager = sensorManager;
|
||||||
@@ -153,12 +154,12 @@ public class DozeSensors {
|
|||||||
dozeLog),
|
dozeLog),
|
||||||
};
|
};
|
||||||
|
|
||||||
mProximitySensor = new ProximitySensor(context.getResources(), sensorManager);
|
mProximitySensor = proximitySensor;
|
||||||
setProxListening(false); // Don't immediately start listening when we register.
|
setProxListening(false); // Don't immediately start listening when we register.
|
||||||
mProximitySensor.register(
|
mProximitySensor.register(
|
||||||
proximityEvent -> {
|
proximityEvent -> {
|
||||||
if (proximityEvent != null) {
|
if (proximityEvent != null) {
|
||||||
mProxCallback.accept(!proximityEvent.getNear());
|
mProxCallback.accept(!proximityEvent.getBelow());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ public class DozeTriggers implements DozeMachine.Part {
|
|||||||
AlarmManager alarmManager, AmbientDisplayConfiguration config,
|
AlarmManager alarmManager, AmbientDisplayConfiguration config,
|
||||||
DozeParameters dozeParameters, AsyncSensorManager sensorManager, Handler handler,
|
DozeParameters dozeParameters, AsyncSensorManager sensorManager, Handler handler,
|
||||||
WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager,
|
WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager,
|
||||||
ProximitySensor proximitySensor,
|
ProximitySensor proximitySensor, DozeLog dozeLog,
|
||||||
DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher) {
|
BroadcastDispatcher broadcastDispatcher) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mMachine = machine;
|
mMachine = machine;
|
||||||
mDozeHost = dozeHost;
|
mDozeHost = dozeHost;
|
||||||
@@ -103,7 +103,8 @@ public class DozeTriggers implements DozeMachine.Part {
|
|||||||
mWakeLock = wakeLock;
|
mWakeLock = wakeLock;
|
||||||
mAllowPulseTriggers = allowPulseTriggers;
|
mAllowPulseTriggers = allowPulseTriggers;
|
||||||
mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
|
mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
|
||||||
config, wakeLock, this::onSensor, this::onProximityFar, dozeLog);
|
config, wakeLock, this::onSensor, this::onProximityFar, dozeLog,
|
||||||
|
proximitySensor);
|
||||||
mUiModeManager = mContext.getSystemService(UiModeManager.class);
|
mUiModeManager = mContext.getSystemService(UiModeManager.class);
|
||||||
mDockManager = dockManager;
|
mDockManager = dockManager;
|
||||||
mProxCheck = new ProximitySensor.ProximityCheck(proximitySensor, handler);
|
mProxCheck = new ProximitySensor.ProximityCheck(proximitySensor, handler);
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ public class AsyncSensorManager extends SensorManager
|
|||||||
private final List<SensorManagerPlugin> mPlugins;
|
private final List<SensorManagerPlugin> mPlugins;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public AsyncSensorManager(Context context, PluginManager pluginManager) {
|
public AsyncSensorManager(SensorManager sensorManager, PluginManager pluginManager) {
|
||||||
this(context.getSystemService(SensorManager.class), pluginManager, null);
|
this(sensorManager, pluginManager, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.util.sensors;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
|
||||||
|
import javax.inject.Qualifier;
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
@Documented
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@interface PrimaryProxSensor {
|
||||||
|
}
|
||||||
@@ -16,92 +16,119 @@
|
|||||||
|
|
||||||
package com.android.systemui.util.sensors;
|
package com.android.systemui.util.sensors;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.hardware.Sensor;
|
|
||||||
import android.hardware.SensorEvent;
|
|
||||||
import android.hardware.SensorEventListener;
|
|
||||||
import android.hardware.SensorManager;
|
import android.hardware.SensorManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.systemui.R;
|
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
|
import com.android.systemui.util.Assert;
|
||||||
|
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple wrapper around SensorManager customized for the Proximity sensor.
|
* Wrapper around SensorManager customized for the Proximity sensor.
|
||||||
|
*
|
||||||
|
* The ProximitySensor supports the concept of a primary and a
|
||||||
|
* secondary hardware sensor. The primary sensor is used for a first
|
||||||
|
* pass check if the phone covered. When triggered, it then checks
|
||||||
|
* the secondary sensor for confirmation (if there is one). It does
|
||||||
|
* not send a proximity event until the secondary sensor confirms (or
|
||||||
|
* rejects) the reading. The secondary sensor is, in fact, the source
|
||||||
|
* of truth.
|
||||||
|
*
|
||||||
|
* This is necessary as sometimes keeping the secondary sensor on for
|
||||||
|
* extends periods is undesirable. It may, however, result in increased
|
||||||
|
* latency for proximity readings.
|
||||||
|
*
|
||||||
|
* Phones should configure this via a config.xml overlay. If no
|
||||||
|
* proximity sensor is set (primary or secondary) we fall back to the
|
||||||
|
* default Sensor.TYPE_PROXIMITY. If proximity_sensor_type is set in
|
||||||
|
* config.xml, that will be used as the primary sensor. If
|
||||||
|
* proximity_sensor_secondary_type is set, that will function as the
|
||||||
|
* secondary sensor. If no secondary is set, only the primary will be
|
||||||
|
* used.
|
||||||
*/
|
*/
|
||||||
public class ProximitySensor {
|
public class ProximitySensor implements ThresholdSensor {
|
||||||
private static final String TAG = "ProxSensor";
|
private static final String TAG = "ProxSensor";
|
||||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
private static final long SECONDARY_PING_INTERVAL_MS = 5000;
|
||||||
|
|
||||||
private final Sensor mSensor;
|
private final ThresholdSensor mPrimaryThresholdSensor;
|
||||||
private final AsyncSensorManager mSensorManager;
|
private final ThresholdSensor mSecondaryThresholdSensor;
|
||||||
private final float mThreshold;
|
private final DelayableExecutor mDelayableExecutor;
|
||||||
private List<ProximitySensorListener> mListeners = new ArrayList<>();
|
private final List<ThresholdSensor.Listener> mListeners = new ArrayList<>();
|
||||||
private String mTag = null;
|
private String mTag = null;
|
||||||
@VisibleForTesting ProximityEvent mLastEvent;
|
private ThresholdSensorEvent mLastPrimaryEvent;
|
||||||
private int mSensorDelay = SensorManager.SENSOR_DELAY_NORMAL;
|
@VisibleForTesting
|
||||||
|
ThresholdSensorEvent mLastEvent;
|
||||||
private boolean mPaused;
|
private boolean mPaused;
|
||||||
private boolean mRegistered;
|
private boolean mRegistered;
|
||||||
|
private Runnable mCancelSecondaryRunnable;
|
||||||
|
private boolean mInitializedListeners = false;
|
||||||
|
|
||||||
private SensorEventListener mSensorEventListener = new SensorEventListener() {
|
private ThresholdSensor.Listener mPrimaryEventListener = new ThresholdSensor.Listener() {
|
||||||
@Override
|
@Override
|
||||||
public synchronized void onSensorChanged(SensorEvent event) {
|
public void onThresholdCrossed(ThresholdSensorEvent event) {
|
||||||
onSensorEvent(event);
|
onPrimarySensorEvent(event);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private ThresholdSensor.Listener mSecondaryEventListener = new ThresholdSensor.Listener() {
|
||||||
@Override
|
@Override
|
||||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
public void onThresholdCrossed(ThresholdSensorEvent event) {
|
||||||
|
// This sensor should only be used briefly. Turn it off as soon as we get a reading.
|
||||||
|
mSecondaryThresholdSensor.pause();
|
||||||
|
|
||||||
|
// Only check the secondary as long as the primary thinks we're near.
|
||||||
|
if (!mLastPrimaryEvent.getBelow()) {
|
||||||
|
mCancelSecondaryRunnable = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logDebug("Secondary sensor event: " + event.getBelow() + ".");
|
||||||
|
|
||||||
|
onSensorEvent(event);
|
||||||
|
|
||||||
|
// Check this sensor again in a moment.
|
||||||
|
mCancelSecondaryRunnable = mDelayableExecutor.executeDelayed(
|
||||||
|
mSecondaryThresholdSensor::resume, SECONDARY_PING_INTERVAL_MS);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ProximitySensor(@Main Resources resources,
|
public ProximitySensor(@PrimaryProxSensor ThresholdSensor primary,
|
||||||
AsyncSensorManager sensorManager) {
|
@SecondaryProxSensor ThresholdSensor secondary,
|
||||||
mSensorManager = sensorManager;
|
@Main DelayableExecutor delayableExecutor) {
|
||||||
|
mPrimaryThresholdSensor = primary;
|
||||||
Sensor sensor = findCustomProxSensor(resources);
|
mSecondaryThresholdSensor = secondary;
|
||||||
float threshold = 0;
|
mDelayableExecutor = delayableExecutor;
|
||||||
if (sensor != null) {
|
|
||||||
try {
|
|
||||||
threshold = getCustomProxThreshold(resources);
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
Log.e(TAG, "Can not load custom proximity sensor.", e);
|
|
||||||
sensor = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (sensor == null) {
|
|
||||||
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
|
||||||
if (sensor != null) {
|
|
||||||
threshold = sensor.getMaximumRange();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mThreshold = threshold;
|
|
||||||
|
|
||||||
mSensor = sensor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setTag(String tag) {
|
public void setTag(String tag) {
|
||||||
mTag = tag;
|
mTag = tag;
|
||||||
|
mPrimaryThresholdSensor.setTag(tag + ":primary");
|
||||||
|
mSecondaryThresholdSensor.setTag(tag + ":secondary");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSensorDelay(int sensorDelay) {
|
@Override
|
||||||
mSensorDelay = sensorDelay;
|
public void setDelay(int delay) {
|
||||||
|
Assert.isMainThread();
|
||||||
|
mPrimaryThresholdSensor.setDelay(delay);
|
||||||
|
mSecondaryThresholdSensor.setDelay(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregister with the {@link SensorManager} without unsetting listeners on this object.
|
* Unregister with the {@link SensorManager} without unsetting listeners on this object.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void pause() {
|
public void pause() {
|
||||||
|
Assert.isMainThread();
|
||||||
mPaused = true;
|
mPaused = true;
|
||||||
unregisterInternal();
|
unregisterInternal();
|
||||||
}
|
}
|
||||||
@@ -109,41 +136,13 @@ public class ProximitySensor {
|
|||||||
/**
|
/**
|
||||||
* Register with the {@link SensorManager}. No-op if no listeners are registered on this object.
|
* Register with the {@link SensorManager}. No-op if no listeners are registered on this object.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void resume() {
|
public void resume() {
|
||||||
|
Assert.isMainThread();
|
||||||
mPaused = false;
|
mPaused = false;
|
||||||
registerInternal();
|
registerInternal();
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Returns a brightness sensor that can be used for proximity purposes.
|
|
||||||
*/
|
|
||||||
private Sensor findCustomProxSensor(Resources resources) {
|
|
||||||
String sensorType = resources.getString(R.string.proximity_sensor_type);
|
|
||||||
if (sensorType.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
|
|
||||||
Sensor sensor = null;
|
|
||||||
for (Sensor s : sensorList) {
|
|
||||||
if (sensorType.equals(s.getStringType())) {
|
|
||||||
sensor = s;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sensor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a threshold value that can be used along with {@link #findCustomProxSensor}
|
|
||||||
*/
|
|
||||||
private float getCustomProxThreshold(Resources resources) {
|
|
||||||
try {
|
|
||||||
return resources.getFloat(R.dimen.proximity_sensor_threshold);
|
|
||||||
} catch (Resources.NotFoundException e) {
|
|
||||||
throw new IllegalStateException("R.dimen.proximity_sensor_threshold must be set.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if we are registered with the SensorManager.
|
* Returns true if we are registered with the SensorManager.
|
||||||
@@ -155,38 +154,46 @@ public class ProximitySensor {
|
|||||||
/**
|
/**
|
||||||
* Returns {@code false} if a Proximity sensor is not available.
|
* Returns {@code false} if a Proximity sensor is not available.
|
||||||
*/
|
*/
|
||||||
public boolean getSensorAvailable() {
|
@Override
|
||||||
return mSensor != null;
|
public boolean isLoaded() {
|
||||||
|
return mPrimaryThresholdSensor.isLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a listener.
|
* Add a listener.
|
||||||
*
|
*
|
||||||
* Registers itself with the {@link SensorManager} if this is the first listener
|
* Registers itself with the {@link SensorManager} if this is the first listener
|
||||||
* added. If a cool down is currently running, the sensor will be registered when it is over.
|
* added. If the ProximitySensor is paused, it will be registered when resumed.
|
||||||
*/
|
*/
|
||||||
public boolean register(ProximitySensorListener listener) {
|
@Override
|
||||||
if (!getSensorAvailable()) {
|
public void register(ThresholdSensor.Listener listener) {
|
||||||
return false;
|
Assert.isMainThread();
|
||||||
|
if (!isLoaded()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mListeners.contains(listener)) {
|
if (mListeners.contains(listener)) {
|
||||||
Log.d(TAG, "ProxListener registered multiple times: " + listener);
|
logDebug("ProxListener registered multiple times: " + listener);
|
||||||
} else {
|
} else {
|
||||||
mListeners.add(listener);
|
mListeners.add(listener);
|
||||||
}
|
}
|
||||||
registerInternal();
|
registerInternal();
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void registerInternal() {
|
protected void registerInternal() {
|
||||||
|
Assert.isMainThread();
|
||||||
if (mRegistered || mPaused || mListeners.isEmpty()) {
|
if (mRegistered || mPaused || mListeners.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!mInitializedListeners) {
|
||||||
|
mPrimaryThresholdSensor.register(mPrimaryEventListener);
|
||||||
|
mSecondaryThresholdSensor.pause();
|
||||||
|
mSecondaryThresholdSensor.register(mSecondaryEventListener);
|
||||||
|
mInitializedListeners = true;
|
||||||
|
}
|
||||||
logDebug("Registering sensor listener");
|
logDebug("Registering sensor listener");
|
||||||
|
mPrimaryThresholdSensor.resume();
|
||||||
mRegistered = true;
|
mRegistered = true;
|
||||||
mSensorManager.registerListener(mSensorEventListener, mSensor, mSensorDelay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -195,7 +202,9 @@ public class ProximitySensor {
|
|||||||
* If all listeners are removed from an instance of this class,
|
* If all listeners are removed from an instance of this class,
|
||||||
* it will unregister itself with the SensorManager.
|
* it will unregister itself with the SensorManager.
|
||||||
*/
|
*/
|
||||||
public void unregister(ProximitySensorListener listener) {
|
@Override
|
||||||
|
public void unregister(ThresholdSensor.Listener listener) {
|
||||||
|
Assert.isMainThread();
|
||||||
mListeners.remove(listener);
|
mListeners.remove(listener);
|
||||||
if (mListeners.size() == 0) {
|
if (mListeners.size() == 0) {
|
||||||
unregisterInternal();
|
unregisterInternal();
|
||||||
@@ -203,34 +212,77 @@ public class ProximitySensor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void unregisterInternal() {
|
protected void unregisterInternal() {
|
||||||
|
Assert.isMainThread();
|
||||||
if (!mRegistered) {
|
if (!mRegistered) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logDebug("unregistering sensor listener");
|
logDebug("unregistering sensor listener");
|
||||||
mSensorManager.unregisterListener(mSensorEventListener);
|
mPrimaryThresholdSensor.pause();
|
||||||
|
mSecondaryThresholdSensor.pause();
|
||||||
|
if (mCancelSecondaryRunnable != null) {
|
||||||
|
mCancelSecondaryRunnable.run();
|
||||||
|
mCancelSecondaryRunnable = null;
|
||||||
|
}
|
||||||
|
mLastPrimaryEvent = null; // Forget what we know.
|
||||||
|
mLastEvent = null;
|
||||||
mRegistered = false;
|
mRegistered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isNear() {
|
public Boolean isNear() {
|
||||||
return getSensorAvailable() && mLastEvent != null ? mLastEvent.getNear() : null;
|
return isLoaded() && mLastEvent != null ? mLastEvent.getBelow() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update all listeners with the last value this class received from the sensor. */
|
/** Update all listeners with the last value this class received from the sensor. */
|
||||||
public void alertListeners() {
|
public void alertListeners() {
|
||||||
mListeners.forEach(proximitySensorListener ->
|
Assert.isMainThread();
|
||||||
proximitySensorListener.onSensorEvent(mLastEvent));
|
if (mLastEvent == null) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSensorEvent(SensorEvent event) {
|
List<ThresholdSensor.Listener> listeners = new ArrayList<>(mListeners);
|
||||||
boolean near = event.values[0] < mThreshold;
|
listeners.forEach(proximitySensorListener ->
|
||||||
mLastEvent = new ProximityEvent(near, event.timestamp);
|
proximitySensorListener.onThresholdCrossed(mLastEvent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onPrimarySensorEvent(ThresholdSensorEvent event) {
|
||||||
|
Assert.isMainThread();
|
||||||
|
if (mLastPrimaryEvent != null && event.getBelow() == mLastPrimaryEvent.getBelow()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastPrimaryEvent = event;
|
||||||
|
|
||||||
|
if (event.getBelow() && mSecondaryThresholdSensor.isLoaded()) {
|
||||||
|
logDebug("Primary sensor is near. Checking secondary.");
|
||||||
|
if (mCancelSecondaryRunnable == null) {
|
||||||
|
mSecondaryThresholdSensor.resume();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!mSecondaryThresholdSensor.isLoaded()) {
|
||||||
|
logDebug("Primary sensor event: " + event.getBelow() + ". No secondary.");
|
||||||
|
} else {
|
||||||
|
logDebug("Primary sensor event: " + event.getBelow() + ".");
|
||||||
|
}
|
||||||
|
onSensorEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSensorEvent(ThresholdSensorEvent event) {
|
||||||
|
Assert.isMainThread();
|
||||||
|
if (mLastEvent != null && event.getBelow() == mLastEvent.getBelow()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mLastEvent = event;
|
||||||
alertListeners();
|
alertListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("{registered=%s, paused=%s, near=%s, sensor=%s}",
|
return String.format("{registered=%s, paused=%s, near=%s, primarySensor=%s, "
|
||||||
isRegistered(), mPaused, isNear(), mSensor);
|
+ "secondarySensor=%s}",
|
||||||
|
isRegistered(), mPaused, isNear(), mPrimaryThresholdSensor,
|
||||||
|
mSecondaryThresholdSensor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,11 +300,11 @@ public class ProximitySensor {
|
|||||||
mSensor.setTag("prox_check");
|
mSensor.setTag("prox_check");
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
mSensor.pause();
|
mSensor.pause();
|
||||||
ProximitySensorListener listener = proximityEvent -> {
|
ThresholdSensor.Listener listener = proximityEvent -> {
|
||||||
mCallbacks.forEach(
|
mCallbacks.forEach(
|
||||||
booleanConsumer ->
|
booleanConsumer ->
|
||||||
booleanConsumer.accept(
|
booleanConsumer.accept(
|
||||||
proximityEvent == null ? null : proximityEvent.getNear()));
|
proximityEvent == null ? null : proximityEvent.getBelow()));
|
||||||
mCallbacks.clear();
|
mCallbacks.clear();
|
||||||
mSensor.pause();
|
mSensor.pause();
|
||||||
};
|
};
|
||||||
@@ -274,7 +326,7 @@ public class ProximitySensor {
|
|||||||
* Query the proximity sensor, timing out if no result.
|
* Query the proximity sensor, timing out if no result.
|
||||||
*/
|
*/
|
||||||
public void check(long timeoutMs, Consumer<Boolean> callback) {
|
public void check(long timeoutMs, Consumer<Boolean> callback) {
|
||||||
if (!mSensor.getSensorAvailable()) {
|
if (!mSensor.isLoaded()) {
|
||||||
callback.accept(null);
|
callback.accept(null);
|
||||||
}
|
}
|
||||||
mCallbacks.add(callback);
|
mCallbacks.add(callback);
|
||||||
@@ -285,43 +337,6 @@ public class ProximitySensor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implement to be notified of ProximityEvents. */
|
|
||||||
public interface ProximitySensorListener {
|
|
||||||
/** Called when the ProximitySensor changes. */
|
|
||||||
void onSensorEvent(ProximityEvent proximityEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returned when the near/far state of a {@link ProximitySensor} changes.
|
|
||||||
*/
|
|
||||||
public static class ProximityEvent {
|
|
||||||
private final boolean mNear;
|
|
||||||
private final long mTimestampNs;
|
|
||||||
|
|
||||||
public ProximityEvent(boolean near, long timestampNs) {
|
|
||||||
mNear = near;
|
|
||||||
mTimestampNs = timestampNs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getNear() {
|
|
||||||
return mNear;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimestampNs() {
|
|
||||||
return mTimestampNs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimestampMs() {
|
|
||||||
return mTimestampNs / 1000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format((Locale) null, "{near=%s, timestamp_ns=%d}", mNear, mTimestampNs);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void logDebug(String msg) {
|
private void logDebug(String msg) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, (mTag != null ? "[" + mTag + "] " : "") + msg);
|
Log.d(TAG, (mTag != null ? "[" + mTag + "] " : "") + msg);
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.util.sensors;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
|
||||||
|
import javax.inject.Qualifier;
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
@Documented
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@interface SecondaryProxSensor {
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.util.sensors;
|
||||||
|
|
||||||
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
|
|
||||||
|
import com.android.systemui.R;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dagger module for Sensor related classes.
|
||||||
|
*/
|
||||||
|
@Module
|
||||||
|
public class SensorModule {
|
||||||
|
@Provides
|
||||||
|
@PrimaryProxSensor
|
||||||
|
static ThresholdSensor providePrimaryProxSensor(SensorManager sensorManager,
|
||||||
|
ThresholdSensorImpl.Builder thresholdSensorBuilder) {
|
||||||
|
try {
|
||||||
|
return thresholdSensorBuilder
|
||||||
|
.setSensorDelay(SensorManager.SENSOR_DELAY_NORMAL)
|
||||||
|
.setSensorResourceId(R.string.proximity_sensor_type)
|
||||||
|
.setThresholdResourceId(R.dimen.proximity_sensor_threshold)
|
||||||
|
.build();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
Sensor defaultSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
|
||||||
|
return thresholdSensorBuilder
|
||||||
|
.setSensor(defaultSensor)
|
||||||
|
.setThresholdValue(defaultSensor.getMaximumRange())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@SecondaryProxSensor
|
||||||
|
static ThresholdSensor provideSecondaryProxSensor(
|
||||||
|
ThresholdSensorImpl.Builder thresholdSensorBuilder) {
|
||||||
|
try {
|
||||||
|
return thresholdSensorBuilder
|
||||||
|
.setSensorResourceId(R.string.proximity_sensor_secondary_type)
|
||||||
|
.setThresholdResourceId(R.dimen.proximity_sensor_secondary_threshold)
|
||||||
|
.build();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
return thresholdSensorBuilder.setSensor(null).setThresholdValue(0).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.util.sensors;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper class for sensors that have a boolean state - above/below.
|
||||||
|
*/
|
||||||
|
public interface ThresholdSensor {
|
||||||
|
/**
|
||||||
|
* Optional label to use for logging.
|
||||||
|
*
|
||||||
|
* This should be set to something meaningful by owner of the instance.
|
||||||
|
*/
|
||||||
|
void setTag(String tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the delay used when registering the sensor.
|
||||||
|
*
|
||||||
|
* If the sensor is already registered, this should cause it to re-register with the new
|
||||||
|
* delay.
|
||||||
|
*/
|
||||||
|
void setDelay(int delay);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if this sensor successfully loads and can be listened to.
|
||||||
|
*/
|
||||||
|
boolean isLoaded();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers with the sensor and calls the supplied callback on value change.
|
||||||
|
*
|
||||||
|
* If this instance is paused, the listener will be recorded, but no registration with
|
||||||
|
* the underlying physical sensor will occur until {@link #resume()} is called.
|
||||||
|
*
|
||||||
|
* @see #unregister(Listener)
|
||||||
|
*/
|
||||||
|
void register(Listener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters from the physical sensor without removing any supplied listeners.
|
||||||
|
*
|
||||||
|
* No events will be sent to listeners as long as this sensor is paused.
|
||||||
|
*
|
||||||
|
* @see #resume()
|
||||||
|
* @see #unregister(Listener)
|
||||||
|
*/
|
||||||
|
void pause();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resumes listening to the physical sensor after previously pausing.
|
||||||
|
*
|
||||||
|
* @see #pause()
|
||||||
|
*/
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister a listener with the sensor.
|
||||||
|
*
|
||||||
|
* @see #register(Listener)
|
||||||
|
*/
|
||||||
|
void unregister(Listener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for listening to events on {@link ThresholdSensor}
|
||||||
|
*/
|
||||||
|
interface Listener {
|
||||||
|
/**
|
||||||
|
* Called whenever the threshold for the registered sensor is crossed.
|
||||||
|
*/
|
||||||
|
void onThresholdCrossed(ThresholdSensorEvent event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returned when the below/above state of a {@link ThresholdSensor} changes.
|
||||||
|
*/
|
||||||
|
class ThresholdSensorEvent {
|
||||||
|
private final boolean mBelow;
|
||||||
|
private final long mTimestampNs;
|
||||||
|
|
||||||
|
public ThresholdSensorEvent(boolean below, long timestampNs) {
|
||||||
|
mBelow = below;
|
||||||
|
mTimestampNs = timestampNs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getBelow() {
|
||||||
|
return mBelow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestampNs() {
|
||||||
|
return mTimestampNs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestampMs() {
|
||||||
|
return mTimestampNs / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format((Locale) null, "{near=%s, timestamp_ns=%d}", mBelow, mTimestampNs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.util.sensors;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEvent;
|
||||||
|
import android.hardware.SensorEventListener;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
|
import com.android.systemui.util.Assert;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
class ThresholdSensorImpl implements ThresholdSensor {
|
||||||
|
private static final String TAG = "ThresholdSensor";
|
||||||
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
|
||||||
|
private final AsyncSensorManager mSensorManager;
|
||||||
|
private final Sensor mSensor;
|
||||||
|
private final float mThreshold;
|
||||||
|
private boolean mRegistered;
|
||||||
|
private boolean mPaused;
|
||||||
|
private List<Listener> mListeners = new ArrayList<>();
|
||||||
|
private Boolean mLastBelow;
|
||||||
|
private String mTag;
|
||||||
|
private int mSensorDelay;
|
||||||
|
|
||||||
|
private SensorEventListener mSensorEventListener = new SensorEventListener() {
|
||||||
|
@Override
|
||||||
|
public void onSensorChanged(SensorEvent event) {
|
||||||
|
boolean below = event.values[0] < mThreshold;
|
||||||
|
logDebug("Sensor value: " + event.values[0]);
|
||||||
|
onSensorEvent(below, event.timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private ThresholdSensorImpl(AsyncSensorManager sensorManager,
|
||||||
|
Sensor sensor, float threshold, int sensorDelay) {
|
||||||
|
mSensorManager = sensorManager;
|
||||||
|
mSensor = sensor;
|
||||||
|
mThreshold = threshold;
|
||||||
|
mSensorDelay = sensorDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTag(String tag) {
|
||||||
|
mTag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDelay(int delay) {
|
||||||
|
if (delay == mSensorDelay) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSensorDelay = delay;
|
||||||
|
if (isLoaded()) {
|
||||||
|
unregisterInternal();
|
||||||
|
registerInternal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLoaded() {
|
||||||
|
return mSensor != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean isRegistered() {
|
||||||
|
return mRegistered;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the listener with the sensor.
|
||||||
|
*
|
||||||
|
* Multiple listeners are not supported at this time.
|
||||||
|
*
|
||||||
|
* Returns true if the listener was successfully registered. False otherwise.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void register(Listener listener) {
|
||||||
|
Assert.isMainThread();
|
||||||
|
if (!mListeners.contains(listener)) {
|
||||||
|
mListeners.add(listener);
|
||||||
|
}
|
||||||
|
registerInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregister(Listener listener) {
|
||||||
|
Assert.isMainThread();
|
||||||
|
mListeners.remove(listener);
|
||||||
|
unregisterInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister with the {@link SensorManager} without unsetting listeners on this object.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void pause() {
|
||||||
|
Assert.isMainThread();
|
||||||
|
mPaused = true;
|
||||||
|
unregisterInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register with the {@link SensorManager}. No-op if no listeners are registered on this object.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void resume() {
|
||||||
|
Assert.isMainThread();
|
||||||
|
mPaused = false;
|
||||||
|
registerInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void alertListenersInternal(boolean below, long timestampNs) {
|
||||||
|
List<Listener> listeners = new ArrayList<>(mListeners);
|
||||||
|
listeners.forEach(listener ->
|
||||||
|
listener.onThresholdCrossed(new ThresholdSensorEvent(below, timestampNs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerInternal() {
|
||||||
|
Assert.isMainThread();
|
||||||
|
if (mRegistered || mPaused || mListeners.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logDebug("Registering sensor listener");
|
||||||
|
mSensorManager.registerListener(mSensorEventListener, mSensor, mSensorDelay);
|
||||||
|
mRegistered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregisterInternal() {
|
||||||
|
Assert.isMainThread();
|
||||||
|
if (!mRegistered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
logDebug("Unregister sensor listener");
|
||||||
|
mSensorManager.unregisterListener(mSensorEventListener);
|
||||||
|
mRegistered = false;
|
||||||
|
mLastBelow = null; // Forget what we know.
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSensorEvent(boolean below, long timestampNs) {
|
||||||
|
Assert.isMainThread();
|
||||||
|
if (mLastBelow != null && mLastBelow == below) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mLastBelow = below;
|
||||||
|
alertListenersInternal(below, timestampNs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("{registered=%s, paused=%s, threshold=%s, sensor=%s}",
|
||||||
|
isLoaded(), mRegistered, mPaused, mThreshold, mSensor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logDebug(String msg) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, (mTag != null ? "[" + mTag + "] " : "") + msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Builder {
|
||||||
|
private final Resources mResources;
|
||||||
|
private final AsyncSensorManager mSensorManager;
|
||||||
|
private int mSensorDelay = SensorManager.SENSOR_DELAY_NORMAL;;
|
||||||
|
private float mThresholdValue;
|
||||||
|
private Sensor mSensor;
|
||||||
|
private boolean mSensorSet;
|
||||||
|
private boolean mThresholdSet;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Builder(@Main Resources resources, AsyncSensorManager sensorManager) {
|
||||||
|
mResources = resources;
|
||||||
|
mSensorManager = sensorManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Builder setSensorDelay(int sensorDelay) {
|
||||||
|
mSensorDelay = sensorDelay;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder setSensorResourceId(int sensorResourceId) {
|
||||||
|
setSensorType(mResources.getString(sensorResourceId));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder setThresholdResourceId(int thresholdResourceId) {
|
||||||
|
try {
|
||||||
|
setThresholdValue(mResources.getFloat(thresholdResourceId));
|
||||||
|
} catch (Resources.NotFoundException e) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder setSensorType(String sensorType) {
|
||||||
|
Sensor sensor = findSensorByType(sensorType);
|
||||||
|
if (sensor != null) {
|
||||||
|
setSensor(sensor);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder setThresholdValue(float thresholdValue) {
|
||||||
|
mThresholdValue = thresholdValue;
|
||||||
|
mThresholdSet = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Builder setSensor(Sensor sensor) {
|
||||||
|
mSensor = sensor;
|
||||||
|
mSensorSet = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link ThresholdSensor} backed by a {@link ThresholdSensorImpl}.
|
||||||
|
*/
|
||||||
|
public ThresholdSensor build() {
|
||||||
|
if (!mSensorSet) {
|
||||||
|
throw new IllegalStateException("A sensor was not successfully set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mThresholdSet) {
|
||||||
|
throw new IllegalStateException("A threshold was not successfully set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ThresholdSensorImpl(
|
||||||
|
mSensorManager, mSensor, mThresholdValue, mSensorDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Sensor findSensorByType(String sensorType) {
|
||||||
|
if (sensorType.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
|
||||||
|
Sensor sensor = null;
|
||||||
|
for (Sensor s : sensorList) {
|
||||||
|
if (sensorType.equals(s.getStringType())) {
|
||||||
|
sensor = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sensor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController;
|
|||||||
import com.android.systemui.util.DeviceConfigProxy;
|
import com.android.systemui.util.DeviceConfigProxy;
|
||||||
import com.android.systemui.util.DeviceConfigProxyFake;
|
import com.android.systemui.util.DeviceConfigProxyFake;
|
||||||
import com.android.systemui.util.sensors.ProximitySensor;
|
import com.android.systemui.util.sensors.ProximitySensor;
|
||||||
|
import com.android.systemui.util.sensors.ThresholdSensor;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -77,7 +78,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testRegisterSensor() {
|
public void testRegisterSensor() {
|
||||||
mFalsingManager.onScreenTurningOn();
|
mFalsingManager.onScreenTurningOn();
|
||||||
verify(mProximitySensor).register(any(ProximitySensor.ProximitySensorListener.class));
|
verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -85,7 +86,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
|
|||||||
mFalsingManager.onScreenTurningOn();
|
mFalsingManager.onScreenTurningOn();
|
||||||
reset(mProximitySensor);
|
reset(mProximitySensor);
|
||||||
mFalsingManager.onScreenOff();
|
mFalsingManager.onScreenOff();
|
||||||
verify(mProximitySensor).unregister(any(ProximitySensor.ProximitySensorListener.class));
|
verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -93,9 +94,9 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
|
|||||||
mFalsingManager.onScreenTurningOn();
|
mFalsingManager.onScreenTurningOn();
|
||||||
reset(mProximitySensor);
|
reset(mProximitySensor);
|
||||||
mFalsingManager.setQsExpanded(true);
|
mFalsingManager.setQsExpanded(true);
|
||||||
verify(mProximitySensor).unregister(any(ProximitySensor.ProximitySensorListener.class));
|
verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
|
||||||
mFalsingManager.setQsExpanded(false);
|
mFalsingManager.setQsExpanded(false);
|
||||||
verify(mProximitySensor).register(any(ProximitySensor.ProximitySensorListener.class));
|
verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -103,9 +104,9 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
|
|||||||
mFalsingManager.onScreenTurningOn();
|
mFalsingManager.onScreenTurningOn();
|
||||||
reset(mProximitySensor);
|
reset(mProximitySensor);
|
||||||
mFalsingManager.onBouncerShown();
|
mFalsingManager.onBouncerShown();
|
||||||
verify(mProximitySensor).unregister(any(ProximitySensor.ProximitySensorListener.class));
|
verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
|
||||||
mFalsingManager.onBouncerHidden();
|
mFalsingManager.onBouncerHidden();
|
||||||
verify(mProximitySensor).register(any(ProximitySensor.ProximitySensorListener.class));
|
verify(mProximitySensor).register(any(ThresholdSensor.Listener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -113,6 +114,6 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
|
|||||||
mFalsingManager.onScreenTurningOn();
|
mFalsingManager.onScreenTurningOn();
|
||||||
reset(mProximitySensor);
|
reset(mProximitySensor);
|
||||||
mStatusBarStateController.setState(StatusBarState.SHADE);
|
mStatusBarStateController.setState(StatusBarState.SHADE);
|
||||||
verify(mProximitySensor).unregister(any(ProximitySensor.ProximitySensorListener.class));
|
verify(mProximitySensor).unregister(any(ThresholdSensor.Listener.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,8 @@ public class ProximityClassifierTest extends ClassifierTest {
|
|||||||
motionEvent.recycle();
|
motionEvent.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProximitySensor.ProximityEvent createSensorEvent(boolean covered, long timestampMs) {
|
private ProximitySensor.ThresholdSensorEvent createSensorEvent(
|
||||||
return new ProximitySensor.ProximityEvent(covered, timestampMs * NS_PER_MS);
|
boolean covered, long timestampMs) {
|
||||||
|
return new ProximitySensor.ThresholdSensorEvent(covered, timestampMs * NS_PER_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import com.android.systemui.doze.DozeSensors.TriggerSensor;
|
|||||||
import com.android.systemui.plugins.SensorManagerPlugin;
|
import com.android.systemui.plugins.SensorManagerPlugin;
|
||||||
import com.android.systemui.statusbar.phone.DozeParameters;
|
import com.android.systemui.statusbar.phone.DozeParameters;
|
||||||
import com.android.systemui.util.sensors.AsyncSensorManager;
|
import com.android.systemui.util.sensors.AsyncSensorManager;
|
||||||
|
import com.android.systemui.util.sensors.ProximitySensor;
|
||||||
import com.android.systemui.util.wakelock.WakeLock;
|
import com.android.systemui.util.wakelock.WakeLock;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -83,6 +84,9 @@ public class DozeSensorsTest extends SysuiTestCase {
|
|||||||
private DozeLog mDozeLog;
|
private DozeLog mDozeLog;
|
||||||
@Mock
|
@Mock
|
||||||
private Sensor mProximitySensor;
|
private Sensor mProximitySensor;
|
||||||
|
@Mock
|
||||||
|
private ProximitySensor mMockProxSensor;
|
||||||
|
|
||||||
private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
|
private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
|
||||||
private TestableLooper mTestableLooper;
|
private TestableLooper mTestableLooper;
|
||||||
private DozeSensors mDozeSensors;
|
private DozeSensors mDozeSensors;
|
||||||
@@ -104,9 +108,9 @@ public class DozeSensorsTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testRegisterProx() {
|
public void testRegisterProx() {
|
||||||
// We should not register with the sensor manager initially.
|
// We should not register with the sensor manager initially.
|
||||||
verify(mSensorManager, never()).registerListener(any(), any(Sensor.class), anyInt());
|
verify(mMockProxSensor).pause();
|
||||||
mDozeSensors.setProxListening(true);
|
mDozeSensors.setProxListening(true);
|
||||||
verify(mSensorManager).registerListener(any(), any(Sensor.class), anyInt());
|
verify(mMockProxSensor).resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -162,7 +166,8 @@ public class DozeSensorsTest extends SysuiTestCase {
|
|||||||
|
|
||||||
TestableDozeSensors() {
|
TestableDozeSensors() {
|
||||||
super(getContext(), mAlarmManager, mSensorManager, mDozeParameters,
|
super(getContext(), mAlarmManager, mSensorManager, mDozeParameters,
|
||||||
mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog);
|
mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog,
|
||||||
|
mMockProxSensor);
|
||||||
for (TriggerSensor sensor : mSensors) {
|
for (TriggerSensor sensor : mSensors) {
|
||||||
if (sensor instanceof PluginSensor
|
if (sensor instanceof PluginSensor
|
||||||
&& ((PluginSensor) sensor).mPluginSensor.getType()
|
&& ((PluginSensor) sensor).mPluginSensor.getType()
|
||||||
|
|||||||
@@ -42,10 +42,13 @@ import com.android.systemui.SysuiTestCase;
|
|||||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||||
import com.android.systemui.dock.DockManager;
|
import com.android.systemui.dock.DockManager;
|
||||||
import com.android.systemui.statusbar.phone.DozeParameters;
|
import com.android.systemui.statusbar.phone.DozeParameters;
|
||||||
|
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||||
import com.android.systemui.util.sensors.AsyncSensorManager;
|
import com.android.systemui.util.sensors.AsyncSensorManager;
|
||||||
import com.android.systemui.util.sensors.FakeProximitySensor;
|
import com.android.systemui.util.sensors.FakeProximitySensor;
|
||||||
import com.android.systemui.util.sensors.FakeSensorManager;
|
import com.android.systemui.util.sensors.FakeSensorManager;
|
||||||
|
import com.android.systemui.util.sensors.FakeThresholdSensor;
|
||||||
import com.android.systemui.util.sensors.ProximitySensor;
|
import com.android.systemui.util.sensors.ProximitySensor;
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock;
|
||||||
import com.android.systemui.util.wakelock.WakeLock;
|
import com.android.systemui.util.wakelock.WakeLock;
|
||||||
import com.android.systemui.util.wakelock.WakeLockFake;
|
import com.android.systemui.util.wakelock.WakeLockFake;
|
||||||
|
|
||||||
@@ -71,10 +74,12 @@ public class DozeTriggersTest extends SysuiTestCase {
|
|||||||
private BroadcastDispatcher mBroadcastDispatcher;
|
private BroadcastDispatcher mBroadcastDispatcher;
|
||||||
@Mock
|
@Mock
|
||||||
private DockManager mDockManager;
|
private DockManager mDockManager;
|
||||||
|
|
||||||
private DozeTriggers mTriggers;
|
private DozeTriggers mTriggers;
|
||||||
private FakeSensorManager mSensors;
|
private FakeSensorManager mSensors;
|
||||||
private Sensor mTapSensor;
|
private Sensor mTapSensor;
|
||||||
private FakeProximitySensor mProximitySensor;
|
private FakeProximitySensor mProximitySensor;
|
||||||
|
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -86,7 +91,10 @@ public class DozeTriggersTest extends SysuiTestCase {
|
|||||||
WakeLock wakeLock = new WakeLockFake();
|
WakeLock wakeLock = new WakeLockFake();
|
||||||
AsyncSensorManager asyncSensorManager =
|
AsyncSensorManager asyncSensorManager =
|
||||||
new AsyncSensorManager(mSensors, null, new Handler());
|
new AsyncSensorManager(mSensors, null, new Handler());
|
||||||
mProximitySensor = new FakeProximitySensor(getContext().getResources(), asyncSensorManager);
|
|
||||||
|
FakeThresholdSensor thresholdSensor = new FakeThresholdSensor();
|
||||||
|
thresholdSensor.setLoaded(true);
|
||||||
|
mProximitySensor = new FakeProximitySensor(thresholdSensor, null, mExecutor);
|
||||||
|
|
||||||
mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, config, parameters,
|
mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, config, parameters,
|
||||||
asyncSensorManager, Handler.createAsync(Looper.myLooper()), wakeLock, true,
|
asyncSensorManager, Handler.createAsync(Looper.myLooper()), wakeLock, true,
|
||||||
@@ -104,17 +112,17 @@ public class DozeTriggersTest extends SysuiTestCase {
|
|||||||
mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
|
mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
|
||||||
clearInvocations(mMachine);
|
clearInvocations(mMachine);
|
||||||
|
|
||||||
mProximitySensor.setLastEvent(new ProximitySensor.ProximityEvent(true, 1));
|
mProximitySensor.setLastEvent(new ProximitySensor.ThresholdSensorEvent(true, 1));
|
||||||
captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
|
captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
|
||||||
mProximitySensor.alertListeners();
|
mProximitySensor.alertListeners();
|
||||||
|
|
||||||
verify(mMachine, never()).requestState(any());
|
verify(mMachine, never()).requestState(any());
|
||||||
verify(mMachine, never()).requestPulse(anyInt());
|
verify(mMachine, never()).requestPulse(anyInt());
|
||||||
|
|
||||||
captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
|
mProximitySensor.setLastEvent(new ProximitySensor.ThresholdSensorEvent(false, 2));
|
||||||
waitForSensorManager();
|
|
||||||
mProximitySensor.setLastEvent(new ProximitySensor.ProximityEvent(false, 2));
|
|
||||||
mProximitySensor.alertListeners();
|
mProximitySensor.alertListeners();
|
||||||
|
waitForSensorManager();
|
||||||
|
captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
|
||||||
|
|
||||||
verify(mMachine).requestPulse(anyInt());
|
verify(mMachine).requestPulse(anyInt());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,15 @@
|
|||||||
|
|
||||||
package com.android.systemui.util.sensors;
|
package com.android.systemui.util.sensors;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||||
|
|
||||||
public class FakeProximitySensor extends ProximitySensor {
|
public class FakeProximitySensor extends ProximitySensor {
|
||||||
private boolean mAvailable;
|
private boolean mAvailable;
|
||||||
|
|
||||||
public FakeProximitySensor(Resources resources, AsyncSensorManager sensorManager) {
|
public FakeProximitySensor(ThresholdSensor primary, ThresholdSensor secondary,
|
||||||
super(resources, sensorManager);
|
DelayableExecutor delayableExecutor) {
|
||||||
|
super(primary, secondary == null ? new FakeThresholdSensor() : secondary,
|
||||||
|
delayableExecutor);
|
||||||
mAvailable = true;
|
mAvailable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,12 +32,12 @@ public class FakeProximitySensor extends ProximitySensor {
|
|||||||
mAvailable = available;
|
mAvailable = available;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLastEvent(ProximityEvent event) {
|
public void setLastEvent(ThresholdSensorEvent event) {
|
||||||
mLastEvent = event;
|
mLastEvent = event;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getSensorAvailable() {
|
public boolean isLoaded() {
|
||||||
return mAvailable;
|
return mAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.util.sensors;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class FakeThresholdSensor implements ThresholdSensor {
|
||||||
|
private boolean mIsLoaded;
|
||||||
|
private boolean mPaused;
|
||||||
|
private List<Listener> mListeners = new ArrayList<>();
|
||||||
|
|
||||||
|
public FakeThresholdSensor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTag(String tag) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDelay(int delay) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLoaded() {
|
||||||
|
return mIsLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pause() {
|
||||||
|
mPaused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resume() {
|
||||||
|
mPaused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void register(ThresholdSensor.Listener listener) {
|
||||||
|
mListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregister(ThresholdSensor.Listener listener) {
|
||||||
|
mListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoaded(boolean loaded) {
|
||||||
|
mIsLoaded = loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
void triggerEvent(boolean below, long timestampNs) {
|
||||||
|
if (!mPaused) {
|
||||||
|
for (Listener listener : mListeners) {
|
||||||
|
listener.onThresholdCrossed(new ThresholdSensorEvent(below, timestampNs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isPaused() {
|
||||||
|
return mPaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNumListeners() {
|
||||||
|
return mListeners.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.util.sensors;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner;
|
||||||
|
import android.testing.TestableLooper;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner.class)
|
||||||
|
@TestableLooper.RunWithLooper
|
||||||
|
public class ProximitySensorDualTest extends SysuiTestCase {
|
||||||
|
private ProximitySensor mProximitySensor;
|
||||||
|
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
|
||||||
|
private FakeThresholdSensor mThresholdSensorPrimary;
|
||||||
|
private FakeThresholdSensor mThresholdSensorSecondary;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
allowTestableLooperAsMainThread();
|
||||||
|
mThresholdSensorPrimary = new FakeThresholdSensor();
|
||||||
|
mThresholdSensorPrimary.setLoaded(true);
|
||||||
|
mThresholdSensorSecondary = new FakeThresholdSensor();
|
||||||
|
mThresholdSensorSecondary.setLoaded(true);
|
||||||
|
|
||||||
|
mProximitySensor = new ProximitySensor(
|
||||||
|
mThresholdSensorPrimary, mThresholdSensorSecondary, mFakeExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleListener() {
|
||||||
|
TestableListener listener = new TestableListener();
|
||||||
|
|
||||||
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
|
mProximitySensor.register(listener);
|
||||||
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
|
assertFalse(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
|
||||||
|
// Trigger second sensor. Nothing should happen yet.
|
||||||
|
mThresholdSensorSecondary.triggerEvent(true, 0);
|
||||||
|
assertFalse(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
|
||||||
|
// Trigger first sensor. Our second sensor is now registered.
|
||||||
|
mThresholdSensorPrimary.triggerEvent(true, 0);
|
||||||
|
assertFalse(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertFalse(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
|
||||||
|
// Trigger second sensor.
|
||||||
|
mThresholdSensorSecondary.triggerEvent(true, 0);
|
||||||
|
assertFalse(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertTrue(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
|
||||||
|
mProximitySensor.unregister(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSecondaryPausing() {
|
||||||
|
TestableListener listener = new TestableListener();
|
||||||
|
|
||||||
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
|
mProximitySensor.register(listener);
|
||||||
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
|
||||||
|
// Trigger first sensor. Our second sensor is now registered.
|
||||||
|
mThresholdSensorPrimary.triggerEvent(true, 0);
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
|
||||||
|
// Trigger second sensor.
|
||||||
|
mThresholdSensorSecondary.triggerEvent(true, 0);
|
||||||
|
assertTrue(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
|
||||||
|
// Advance time. Second sensor should resume.
|
||||||
|
mFakeExecutor.advanceClockToNext();
|
||||||
|
mFakeExecutor.runNextReady();
|
||||||
|
assertFalse(mThresholdSensorSecondary.isPaused());
|
||||||
|
|
||||||
|
// Triggering should pause again.
|
||||||
|
mThresholdSensorSecondary.triggerEvent(false, 0);
|
||||||
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(2, listener.mCallCount);
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
|
||||||
|
mProximitySensor.unregister(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnregister() {
|
||||||
|
TestableListener listener = new TestableListener();
|
||||||
|
|
||||||
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
|
mProximitySensor.register(listener);
|
||||||
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
|
assertFalse(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
|
||||||
|
mThresholdSensorPrimary.triggerEvent(true, 0);
|
||||||
|
mThresholdSensorSecondary.triggerEvent(true, 0);
|
||||||
|
assertFalse(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertTrue(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
|
mProximitySensor.unregister(listener);
|
||||||
|
assertTrue(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPauseAndResume() {
|
||||||
|
TestableListener listener = new TestableListener();
|
||||||
|
|
||||||
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
|
mProximitySensor.register(listener);
|
||||||
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
|
||||||
|
mThresholdSensorPrimary.triggerEvent(true, 0);
|
||||||
|
mThresholdSensorSecondary.triggerEvent(true, 0);
|
||||||
|
assertFalse(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertTrue(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
|
mProximitySensor.pause();
|
||||||
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
|
assertTrue(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
|
||||||
|
// More events do nothing when paused.
|
||||||
|
mThresholdSensorSecondary.triggerEvent(false, 1);
|
||||||
|
assertTrue(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
|
mProximitySensor.resume();
|
||||||
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
|
// Still matches our previous call
|
||||||
|
assertTrue(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
|
// Need to trigger the primary sensor before the secondary re-registers itself.
|
||||||
|
mThresholdSensorPrimary.triggerEvent(true, 3);
|
||||||
|
mThresholdSensorSecondary.triggerEvent(false, 3);
|
||||||
|
assertFalse(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(2, listener.mCallCount);
|
||||||
|
|
||||||
|
mProximitySensor.unregister(listener);
|
||||||
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrimarySecondaryDisagreement() {
|
||||||
|
TestableListener listener = new TestableListener();
|
||||||
|
|
||||||
|
mProximitySensor.register(listener);
|
||||||
|
assertFalse(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
|
||||||
|
// Trigger our sensors with different values. Secondary overrides primary.
|
||||||
|
mThresholdSensorPrimary.triggerEvent(true, 0);
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
mThresholdSensorSecondary.triggerEvent(false, 0);
|
||||||
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensorSecondary.resume();
|
||||||
|
mThresholdSensorSecondary.triggerEvent(true, 0);
|
||||||
|
assertTrue(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(2, listener.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensorSecondary.resume();
|
||||||
|
mThresholdSensorSecondary.triggerEvent(false, 0);
|
||||||
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(3, listener.mCallCount);
|
||||||
|
|
||||||
|
mProximitySensor.unregister(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrimaryCancelsSecondary() {
|
||||||
|
TestableListener listener = new TestableListener();
|
||||||
|
|
||||||
|
mProximitySensor.register(listener);
|
||||||
|
assertFalse(mThresholdSensorPrimary.isPaused());
|
||||||
|
assertTrue(mThresholdSensorSecondary.isPaused());
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensorPrimary.triggerEvent(true, 0);
|
||||||
|
assertNull(listener.mLastEvent);
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
mThresholdSensorSecondary.triggerEvent(true, 0);
|
||||||
|
assertTrue(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
|
// When the primary reports false, the secondary is no longer needed. We get an immediate
|
||||||
|
// report.
|
||||||
|
mThresholdSensorPrimary.triggerEvent(false, 1);
|
||||||
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(2, listener.mCallCount);
|
||||||
|
|
||||||
|
// The secondary is now ignored. No more work is scheduled.
|
||||||
|
mFakeExecutor.advanceClockToNext();
|
||||||
|
mFakeExecutor.runNextReady();
|
||||||
|
mThresholdSensorSecondary.triggerEvent(true, 0);
|
||||||
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
|
assertEquals(2, listener.mCallCount);
|
||||||
|
assertEquals(0, mFakeExecutor.numPending());
|
||||||
|
|
||||||
|
mProximitySensor.unregister(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TestableListener implements ThresholdSensor.Listener {
|
||||||
|
ThresholdSensor.ThresholdSensorEvent mLastEvent;
|
||||||
|
int mCallCount = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onThresholdCrossed(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
|
||||||
|
mLastEvent = proximityEvent;
|
||||||
|
mCallCount++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -21,33 +21,40 @@ import static org.junit.Assert.assertFalse;
|
|||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
import android.testing.TestableLooper;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.util.concurrency.FakeExecutor;
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for ProximitySensor that rely on a single hardware sensor.
|
||||||
|
*/
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
@TestableLooper.RunWithLooper
|
@TestableLooper.RunWithLooper
|
||||||
public class ProximitySensorTest extends SysuiTestCase {
|
public class ProximitySensorSingleTest extends SysuiTestCase {
|
||||||
|
|
||||||
private ProximitySensor mProximitySensor;
|
private ProximitySensor mProximitySensor;
|
||||||
private FakeSensorManager.FakeProximitySensor mFakeProximitySensor;
|
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
|
||||||
|
private FakeThresholdSensor mThresholdSensor;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
FakeSensorManager sensorManager = new FakeSensorManager(getContext());
|
MockitoAnnotations.initMocks(this);
|
||||||
AsyncSensorManager asyncSensorManager = new AsyncSensorManager(
|
allowTestableLooperAsMainThread();
|
||||||
sensorManager, null, new Handler());
|
mThresholdSensor = new FakeThresholdSensor();
|
||||||
mFakeProximitySensor = sensorManager.getFakeProximitySensor();
|
mThresholdSensor.setLoaded(true);
|
||||||
mProximitySensor = new ProximitySensor(getContext().getResources(), asyncSensorManager);
|
|
||||||
|
mProximitySensor = new ProximitySensor(
|
||||||
|
mThresholdSensor, new FakeThresholdSensor(), mFakeExecutor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -56,19 +63,17 @@ public class ProximitySensorTest extends SysuiTestCase {
|
|||||||
|
|
||||||
assertFalse(mProximitySensor.isRegistered());
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
mProximitySensor.register(listener);
|
mProximitySensor.register(listener);
|
||||||
waitForSensorManager();
|
|
||||||
assertTrue(mProximitySensor.isRegistered());
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
assertNull(listener.mLastEvent);
|
assertNull(listener.mLastEvent);
|
||||||
|
|
||||||
mFakeProximitySensor.sendProximityResult(true);
|
mThresholdSensor.triggerEvent(false, 0);
|
||||||
assertFalse(listener.mLastEvent.getNear());
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
assertEquals(listener.mCallCount, 1);
|
assertEquals(1, listener.mCallCount);
|
||||||
mFakeProximitySensor.sendProximityResult(false);
|
mThresholdSensor.triggerEvent(true, 0);
|
||||||
assertTrue(listener.mLastEvent.getNear());
|
assertTrue(listener.mLastEvent.getBelow());
|
||||||
assertEquals(listener.mCallCount, 2);
|
assertEquals(2, listener.mCallCount);
|
||||||
|
|
||||||
mProximitySensor.unregister(listener);
|
mProximitySensor.unregister(listener);
|
||||||
waitForSensorManager();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -79,28 +84,25 @@ public class ProximitySensorTest extends SysuiTestCase {
|
|||||||
assertFalse(mProximitySensor.isRegistered());
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
|
|
||||||
mProximitySensor.register(listenerA);
|
mProximitySensor.register(listenerA);
|
||||||
waitForSensorManager();
|
|
||||||
assertTrue(mProximitySensor.isRegistered());
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
mProximitySensor.register(listenerB);
|
mProximitySensor.register(listenerB);
|
||||||
waitForSensorManager();
|
|
||||||
assertTrue(mProximitySensor.isRegistered());
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
assertNull(listenerA.mLastEvent);
|
assertNull(listenerA.mLastEvent);
|
||||||
assertNull(listenerB.mLastEvent);
|
assertNull(listenerB.mLastEvent);
|
||||||
|
|
||||||
mFakeProximitySensor.sendProximityResult(true);
|
mThresholdSensor.triggerEvent(false, 0);
|
||||||
assertFalse(listenerA.mLastEvent.getNear());
|
assertFalse(listenerA.mLastEvent.getBelow());
|
||||||
assertFalse(listenerB.mLastEvent.getNear());
|
assertFalse(listenerB.mLastEvent.getBelow());
|
||||||
assertEquals(listenerA.mCallCount, 1);
|
assertEquals(1, listenerA.mCallCount);
|
||||||
assertEquals(listenerB.mCallCount, 1);
|
assertEquals(1, listenerB.mCallCount);
|
||||||
mFakeProximitySensor.sendProximityResult(false);
|
mThresholdSensor.triggerEvent(true, 1);
|
||||||
assertTrue(listenerA.mLastEvent.getNear());
|
assertTrue(listenerA.mLastEvent.getBelow());
|
||||||
assertTrue(listenerB.mLastEvent.getNear());
|
assertTrue(listenerB.mLastEvent.getBelow());
|
||||||
assertEquals(listenerA.mCallCount, 2);
|
assertEquals(2, listenerA.mCallCount);
|
||||||
assertEquals(listenerB.mCallCount, 2);
|
assertEquals(2, listenerB.mCallCount);
|
||||||
|
|
||||||
mProximitySensor.unregister(listenerA);
|
mProximitySensor.unregister(listenerA);
|
||||||
mProximitySensor.unregister(listenerB);
|
mProximitySensor.unregister(listenerB);
|
||||||
waitForSensorManager();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -110,22 +112,19 @@ public class ProximitySensorTest extends SysuiTestCase {
|
|||||||
assertFalse(mProximitySensor.isRegistered());
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
|
|
||||||
mProximitySensor.register(listenerA);
|
mProximitySensor.register(listenerA);
|
||||||
waitForSensorManager();
|
|
||||||
assertTrue(mProximitySensor.isRegistered());
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
mProximitySensor.register(listenerA);
|
mProximitySensor.register(listenerA);
|
||||||
waitForSensorManager();
|
|
||||||
assertTrue(mProximitySensor.isRegistered());
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
assertNull(listenerA.mLastEvent);
|
assertNull(listenerA.mLastEvent);
|
||||||
|
|
||||||
mFakeProximitySensor.sendProximityResult(true);
|
mThresholdSensor.triggerEvent(false, 0);
|
||||||
assertFalse(listenerA.mLastEvent.getNear());
|
assertFalse(listenerA.mLastEvent.getBelow());
|
||||||
assertEquals(listenerA.mCallCount, 1);
|
assertEquals(1, listenerA.mCallCount);
|
||||||
mFakeProximitySensor.sendProximityResult(false);
|
mThresholdSensor.triggerEvent(true, 1);
|
||||||
assertTrue(listenerA.mLastEvent.getNear());
|
assertTrue(listenerA.mLastEvent.getBelow());
|
||||||
assertEquals(listenerA.mCallCount, 2);
|
assertEquals(2, listenerA.mCallCount);
|
||||||
|
|
||||||
mProximitySensor.unregister(listenerA);
|
mProximitySensor.unregister(listenerA);
|
||||||
waitForSensorManager();
|
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testUnregister() {
|
public void testUnregister() {
|
||||||
@@ -133,16 +132,14 @@ public class ProximitySensorTest extends SysuiTestCase {
|
|||||||
|
|
||||||
assertFalse(mProximitySensor.isRegistered());
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
mProximitySensor.register(listener);
|
mProximitySensor.register(listener);
|
||||||
waitForSensorManager();
|
|
||||||
assertTrue(mProximitySensor.isRegistered());
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
assertNull(listener.mLastEvent);
|
assertNull(listener.mLastEvent);
|
||||||
|
|
||||||
mFakeProximitySensor.sendProximityResult(true);
|
mThresholdSensor.triggerEvent(false, 0);
|
||||||
assertFalse(listener.mLastEvent.getNear());
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
assertEquals(listener.mCallCount, 1);
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
mProximitySensor.unregister(listener);
|
mProximitySensor.unregister(listener);
|
||||||
waitForSensorManager();
|
|
||||||
assertFalse(mProximitySensor.isRegistered());
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,39 +149,35 @@ public class ProximitySensorTest extends SysuiTestCase {
|
|||||||
|
|
||||||
assertFalse(mProximitySensor.isRegistered());
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
mProximitySensor.register(listener);
|
mProximitySensor.register(listener);
|
||||||
waitForSensorManager();
|
|
||||||
assertTrue(mProximitySensor.isRegistered());
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
assertNull(listener.mLastEvent);
|
assertNull(listener.mLastEvent);
|
||||||
|
|
||||||
mFakeProximitySensor.sendProximityResult(true);
|
mThresholdSensor.triggerEvent(false, 0);
|
||||||
assertFalse(listener.mLastEvent.getNear());
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
assertEquals(listener.mCallCount, 1);
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
mProximitySensor.pause();
|
mProximitySensor.pause();
|
||||||
waitForSensorManager();
|
|
||||||
assertFalse(mProximitySensor.isRegistered());
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
|
|
||||||
// More events do nothing when paused.
|
// More events do nothing when paused.
|
||||||
mFakeProximitySensor.sendProximityResult(true);
|
mThresholdSensor.triggerEvent(false, 1);
|
||||||
assertFalse(listener.mLastEvent.getNear());
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
assertEquals(listener.mCallCount, 1);
|
assertEquals(1, listener.mCallCount);
|
||||||
mFakeProximitySensor.sendProximityResult(false);
|
mThresholdSensor.triggerEvent(true, 2);
|
||||||
assertFalse(listener.mLastEvent.getNear());
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
assertEquals(listener.mCallCount, 1);
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
mProximitySensor.resume();
|
mProximitySensor.resume();
|
||||||
waitForSensorManager();
|
|
||||||
assertTrue(mProximitySensor.isRegistered());
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
// Still matches our previous call
|
// Still matches our previous call
|
||||||
assertFalse(listener.mLastEvent.getNear());
|
assertFalse(listener.mLastEvent.getBelow());
|
||||||
assertEquals(listener.mCallCount, 1);
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
mFakeProximitySensor.sendProximityResult(true);
|
mThresholdSensor.triggerEvent(true, 3);
|
||||||
assertFalse(listener.mLastEvent.getNear());
|
assertTrue(listener.mLastEvent.getBelow());
|
||||||
assertEquals(listener.mCallCount, 2);
|
assertEquals(2, listener.mCallCount);
|
||||||
|
|
||||||
mProximitySensor.unregister(listener);
|
mProximitySensor.unregister(listener);
|
||||||
waitForSensorManager();
|
|
||||||
assertFalse(mProximitySensor.isRegistered());
|
assertFalse(mProximitySensor.isRegistered());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,46 +190,35 @@ public class ProximitySensorTest extends SysuiTestCase {
|
|||||||
|
|
||||||
mProximitySensor.register(listenerA);
|
mProximitySensor.register(listenerA);
|
||||||
mProximitySensor.register(listenerB);
|
mProximitySensor.register(listenerB);
|
||||||
waitForSensorManager();
|
|
||||||
assertTrue(mProximitySensor.isRegistered());
|
assertTrue(mProximitySensor.isRegistered());
|
||||||
assertNull(listenerA.mLastEvent);
|
assertNull(listenerA.mLastEvent);
|
||||||
assertNull(listenerB.mLastEvent);
|
assertNull(listenerB.mLastEvent);
|
||||||
|
|
||||||
mProximitySensor.alertListeners();
|
mProximitySensor.alertListeners();
|
||||||
assertNull(listenerA.mLastEvent);
|
assertNull(listenerA.mLastEvent);
|
||||||
assertEquals(listenerA.mCallCount, 1);
|
assertEquals(0, listenerA.mCallCount);
|
||||||
assertNull(listenerB.mLastEvent);
|
assertNull(listenerB.mLastEvent);
|
||||||
assertEquals(listenerB.mCallCount, 1);
|
assertEquals(0, listenerB.mCallCount);
|
||||||
|
|
||||||
mFakeProximitySensor.sendProximityResult(false);
|
mThresholdSensor.triggerEvent(true, 0);
|
||||||
assertTrue(listenerA.mLastEvent.getNear());
|
assertTrue(listenerA.mLastEvent.getBelow());
|
||||||
assertEquals(listenerA.mCallCount, 2);
|
assertEquals(1, listenerA.mCallCount);
|
||||||
assertTrue(listenerB.mLastEvent.getNear());
|
assertTrue(listenerB.mLastEvent.getBelow());
|
||||||
assertEquals(listenerB.mCallCount, 2);
|
assertEquals(1, listenerB.mCallCount);
|
||||||
|
|
||||||
mProximitySensor.unregister(listenerA);
|
mProximitySensor.unregister(listenerA);
|
||||||
mProximitySensor.unregister(listenerB);
|
mProximitySensor.unregister(listenerB);
|
||||||
waitForSensorManager();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestableListener implements ProximitySensor.ProximitySensorListener {
|
private static class TestableListener implements ThresholdSensor.Listener {
|
||||||
ProximitySensor.ProximityEvent mLastEvent;
|
ThresholdSensor.ThresholdSensorEvent mLastEvent;
|
||||||
int mCallCount = 0;
|
int mCallCount = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSensorEvent(ProximitySensor.ProximityEvent proximityEvent) {
|
public void onThresholdCrossed(ThresholdSensor.ThresholdSensorEvent proximityEvent) {
|
||||||
mLastEvent = proximityEvent;
|
mLastEvent = proximityEvent;
|
||||||
mCallCount++;
|
mCallCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
|
||||||
mLastEvent = null;
|
|
||||||
mCallCount = 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private void waitForSensorManager() {
|
|
||||||
TestableLooper.get(this).processAllMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.systemui.util.sensors;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
|
import android.testing.AndroidTestingRunner;
|
||||||
|
import android.testing.TestableLooper;
|
||||||
|
|
||||||
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner.class)
|
||||||
|
@TestableLooper.RunWithLooper
|
||||||
|
public class ThresholdSensorImplTest extends SysuiTestCase {
|
||||||
|
|
||||||
|
private ThresholdSensorImpl mThresholdSensor;
|
||||||
|
private FakeSensorManager.FakeProximitySensor mFakeProximitySensor;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
allowTestableLooperAsMainThread();
|
||||||
|
FakeSensorManager sensorManager = new FakeSensorManager(getContext());
|
||||||
|
|
||||||
|
AsyncSensorManager asyncSensorManager = new AsyncSensorManager(
|
||||||
|
sensorManager, null, new Handler());
|
||||||
|
|
||||||
|
mFakeProximitySensor = sensorManager.getFakeProximitySensor();
|
||||||
|
ThresholdSensorImpl.Builder thresholdSensorBuilder = new ThresholdSensorImpl.Builder(
|
||||||
|
null, asyncSensorManager);
|
||||||
|
mThresholdSensor = (ThresholdSensorImpl) thresholdSensorBuilder
|
||||||
|
.setSensor(mFakeProximitySensor.getSensor())
|
||||||
|
.setThresholdValue(mFakeProximitySensor.getSensor().getMaximumRange())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleListener() {
|
||||||
|
TestableListener listener = new TestableListener();
|
||||||
|
|
||||||
|
assertFalse(mThresholdSensor.isRegistered());
|
||||||
|
mThresholdSensor.register(listener);
|
||||||
|
waitForSensorManager();
|
||||||
|
assertTrue(mThresholdSensor.isRegistered());
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
|
||||||
|
mFakeProximitySensor.sendProximityResult(true);
|
||||||
|
assertFalse(listener.mBelow);
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
mFakeProximitySensor.sendProximityResult(false);
|
||||||
|
assertTrue(listener.mBelow);
|
||||||
|
assertEquals(2, listener.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensor.unregister(listener);
|
||||||
|
waitForSensorManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultiListener() {
|
||||||
|
TestableListener listenerA = new TestableListener();
|
||||||
|
TestableListener listenerB = new TestableListener();
|
||||||
|
|
||||||
|
assertFalse(mThresholdSensor.isRegistered());
|
||||||
|
|
||||||
|
mThresholdSensor.register(listenerA);
|
||||||
|
waitForSensorManager();
|
||||||
|
assertTrue(mThresholdSensor.isRegistered());
|
||||||
|
mThresholdSensor.register(listenerB);
|
||||||
|
waitForSensorManager();
|
||||||
|
assertTrue(mThresholdSensor.isRegistered());
|
||||||
|
assertEquals(0, listenerA.mCallCount);
|
||||||
|
assertEquals(0, listenerB.mCallCount);
|
||||||
|
|
||||||
|
|
||||||
|
mFakeProximitySensor.sendProximityResult(true);
|
||||||
|
assertFalse(listenerA.mBelow);
|
||||||
|
assertFalse(listenerB.mBelow);
|
||||||
|
assertEquals(1, listenerA.mCallCount);
|
||||||
|
assertEquals(1, listenerB.mCallCount);
|
||||||
|
mFakeProximitySensor.sendProximityResult(false);
|
||||||
|
assertTrue(listenerA.mBelow);
|
||||||
|
assertTrue(listenerB.mBelow);
|
||||||
|
assertEquals(2, listenerA.mCallCount);
|
||||||
|
assertEquals(2, listenerB.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensor.unregister(listenerA);
|
||||||
|
mThresholdSensor.unregister(listenerB);
|
||||||
|
waitForSensorManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDuplicateListener() {
|
||||||
|
TestableListener listenerA = new TestableListener();
|
||||||
|
|
||||||
|
assertFalse(mThresholdSensor.isRegistered());
|
||||||
|
|
||||||
|
mThresholdSensor.register(listenerA);
|
||||||
|
waitForSensorManager();
|
||||||
|
assertTrue(mThresholdSensor.isRegistered());
|
||||||
|
mThresholdSensor.register(listenerA);
|
||||||
|
waitForSensorManager();
|
||||||
|
assertTrue(mThresholdSensor.isRegistered());
|
||||||
|
assertEquals(0, listenerA.mCallCount);
|
||||||
|
|
||||||
|
mFakeProximitySensor.sendProximityResult(true);
|
||||||
|
assertFalse(listenerA.mBelow);
|
||||||
|
assertEquals(1, listenerA.mCallCount);
|
||||||
|
mFakeProximitySensor.sendProximityResult(false);
|
||||||
|
assertTrue(listenerA.mBelow);
|
||||||
|
assertEquals(2, listenerA.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensor.unregister(listenerA);
|
||||||
|
waitForSensorManager();
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testUnregister() {
|
||||||
|
TestableListener listener = new TestableListener();
|
||||||
|
|
||||||
|
assertFalse(mThresholdSensor.isRegistered());
|
||||||
|
mThresholdSensor.register(listener);
|
||||||
|
waitForSensorManager();
|
||||||
|
assertTrue(mThresholdSensor.isRegistered());
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
|
||||||
|
mFakeProximitySensor.sendProximityResult(true);
|
||||||
|
assertFalse(listener.mBelow);
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensor.unregister(listener);
|
||||||
|
waitForSensorManager();
|
||||||
|
assertFalse(mThresholdSensor.isRegistered());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPauseAndResume() {
|
||||||
|
TestableListener listener = new TestableListener();
|
||||||
|
|
||||||
|
assertFalse(mThresholdSensor.isRegistered());
|
||||||
|
mThresholdSensor.register(listener);
|
||||||
|
waitForSensorManager();
|
||||||
|
assertTrue(mThresholdSensor.isRegistered());
|
||||||
|
assertEquals(0, listener.mCallCount);
|
||||||
|
|
||||||
|
mFakeProximitySensor.sendProximityResult(true);
|
||||||
|
assertFalse(listener.mBelow);
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensor.pause();
|
||||||
|
waitForSensorManager();
|
||||||
|
assertFalse(mThresholdSensor.isRegistered());
|
||||||
|
|
||||||
|
// More events do nothing when paused.
|
||||||
|
mFakeProximitySensor.sendProximityResult(true);
|
||||||
|
assertFalse(listener.mBelow);
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
mFakeProximitySensor.sendProximityResult(false);
|
||||||
|
assertFalse(listener.mBelow);
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensor.resume();
|
||||||
|
waitForSensorManager();
|
||||||
|
assertTrue(mThresholdSensor.isRegistered());
|
||||||
|
// Still matches our previous call
|
||||||
|
assertFalse(listener.mBelow);
|
||||||
|
assertEquals(1, listener.mCallCount);
|
||||||
|
|
||||||
|
mFakeProximitySensor.sendProximityResult(false);
|
||||||
|
assertTrue(listener.mBelow);
|
||||||
|
assertEquals(2, listener.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensor.unregister(listener);
|
||||||
|
waitForSensorManager();
|
||||||
|
assertFalse(mThresholdSensor.isRegistered());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAlertListeners() {
|
||||||
|
TestableListener listenerA = new TestableListener();
|
||||||
|
TestableListener listenerB = new TestableListener();
|
||||||
|
|
||||||
|
assertFalse(mThresholdSensor.isRegistered());
|
||||||
|
|
||||||
|
mThresholdSensor.register(listenerA);
|
||||||
|
mThresholdSensor.register(listenerB);
|
||||||
|
waitForSensorManager();
|
||||||
|
assertTrue(mThresholdSensor.isRegistered());
|
||||||
|
assertEquals(0, listenerA.mCallCount);
|
||||||
|
assertEquals(0, listenerB.mCallCount);
|
||||||
|
|
||||||
|
mFakeProximitySensor.sendProximityResult(true);
|
||||||
|
assertFalse(listenerA.mBelow);
|
||||||
|
assertEquals(1, listenerA.mCallCount);
|
||||||
|
assertFalse(listenerB.mBelow);
|
||||||
|
assertEquals(1, listenerB.mCallCount);
|
||||||
|
|
||||||
|
mFakeProximitySensor.sendProximityResult(false);
|
||||||
|
assertTrue(listenerA.mBelow);
|
||||||
|
assertEquals(2, listenerA.mCallCount);
|
||||||
|
assertTrue(listenerB.mBelow);
|
||||||
|
assertEquals(2, listenerB.mCallCount);
|
||||||
|
|
||||||
|
mThresholdSensor.unregister(listenerA);
|
||||||
|
mThresholdSensor.unregister(listenerB);
|
||||||
|
waitForSensorManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TestableListener implements ThresholdSensor.Listener {
|
||||||
|
boolean mBelow;
|
||||||
|
long mTimestampNs;
|
||||||
|
int mCallCount;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onThresholdCrossed(ThresholdSensor.ThresholdSensorEvent event) {
|
||||||
|
mBelow = event.getBelow();
|
||||||
|
mTimestampNs = event.getTimestampNs();
|
||||||
|
mCallCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitForSensorManager() {
|
||||||
|
TestableLooper.get(this).processAllMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user