Merge "Do not unregister lift when prox is covered" into qt-r1-dev am: e2c873275b

am: 78aec06815

Change-Id: I8a6f22f8e634f6ba21344dcec1d1d668e2ea65b1
This commit is contained in:
Lucas Dupin
2019-06-28 19:39:37 -07:00
committed by android-build-merger
7 changed files with 99 additions and 320 deletions

View File

@@ -197,25 +197,9 @@
<!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
<integer name="doze_pickup_vibration_threshold">2000</integer>
<!-- Doze: can we assume the pickup sensor includes a proximity check?
This is ignored if doze_pickup_subtype_performs_proximity_check is not empty.
@deprecated: use doze_pickup_subtype_performs_proximity_check instead.-->
<!-- Doze: can we assume the pickup sensor includes a proximity check? -->
<bool name="doze_pickup_performs_proximity_check">false</bool>
<!-- Doze: a list of pickup sensor subtypes that perform a proximity check before they trigger.
If not empty, either * or !* must appear to specify the default.
If empty, falls back to doze_pickup_performs_proximity_check.
Examples: 1,2,3,!* -> subtypes 1,2 and 3 perform the check, all others don't.
!1,!2,* -> subtypes 1 and 2 don't perform the check, all others do.
!8,* -> subtype 8 does not perform the check, all others do
1,1,* -> illegal, every item may only appear once
1,!1,* -> illegal, no contradictions allowed
1,2 -> illegal, need either * or !*
1,,4a3 -> illegal, no empty or non-numeric terms allowed
-->
<string name="doze_pickup_subtype_performs_proximity_check"></string>
<!-- Type of a sensor that provides a low-power estimate of the desired display
brightness, suitable to listen to while the device is asleep (e.g. during
always-on display) -->

View File

@@ -76,6 +76,8 @@ public class DozeSensors {
private final ProxSensor mProxSensor;
private long mDebounceFrom;
private boolean mSettingRegistered;
private boolean mListening;
private boolean mPaused;
public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager,
DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
@@ -100,9 +102,12 @@ public class DozeSensors {
mPickupSensor = new TriggerSensor(
mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
Settings.Secure.DOZE_PICK_UP_GESTURE,
true /* settingDef */,
config.dozePickupSensorAvailable(),
DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */,
false /* touchscreen */),
false /* touchscreen */,
false /* ignoresSetting */,
mDozeParameters.getPickupPerformsProxCheck()),
new TriggerSensor(
findSensorWithType(config.doubleTapSensorType()),
Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
@@ -170,11 +175,49 @@ public class DozeSensors {
return null;
}
/**
* If sensors should be registered and sending signals.
*/
public void setListening(boolean listen) {
for (TriggerSensor s : mSensors) {
s.setListening(listen);
if (mListening == listen) {
return;
}
registerSettingsObserverIfNeeded(listen);
mListening = listen;
updateListening();
}
/**
* Unregister sensors, when listening, unless they are prox gated.
* @see #setListening(boolean)
*/
public void setPaused(boolean paused) {
if (mPaused == paused) {
return;
}
mPaused = paused;
updateListening();
}
private void updateListening() {
boolean anyListening = false;
for (TriggerSensor s : mSensors) {
// We don't want to be listening while we're PAUSED (prox sensor is covered)
// except when the sensor is already gated by prox.
boolean listen = mListening && (!mPaused || s.performsProxCheck());
s.setListening(listen);
if (listen) {
anyListening = true;
}
}
if (!anyListening) {
mResolver.unregisterContentObserver(mSettingsObserver);
} else if (!mSettingRegistered) {
for (TriggerSensor s : mSensors) {
s.registerSettingsObserver(mSettingsObserver);
}
}
mSettingRegistered = anyListening;
}
/** Set the listening state of only the sensors that require the touchscreen. */
@@ -236,17 +279,6 @@ public class DozeSensors {
return mProxSensor.mCurrentlyFar;
}
private void registerSettingsObserverIfNeeded(boolean register) {
if (!register) {
mResolver.unregisterContentObserver(mSettingsObserver);
} else if (!mSettingRegistered) {
for (TriggerSensor s : mSensors) {
s.registerSettingsObserver(mSettingsObserver);
}
}
mSettingRegistered = register;
}
private class ProxSensor implements SensorEventListener {
boolean mRequested;
@@ -334,10 +366,11 @@ public class DozeSensors {
final Sensor mSensor;
final boolean mConfigured;
final int mPulseReason;
final String mSetting;
final boolean mReportsTouchCoordinates;
final boolean mSettingDefault;
final boolean mRequiresTouchscreen;
private final String mSetting;
private final boolean mReportsTouchCoordinates;
private final boolean mSettingDefault;
private final boolean mRequiresTouchscreen;
private final boolean mSensorPerformsProxCheck;
protected boolean mRequested;
protected boolean mRegistered;
@@ -354,12 +387,14 @@ public class DozeSensors {
boolean configured, int pulseReason, boolean reportsTouchCoordinates,
boolean requiresTouchscreen) {
this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates,
requiresTouchscreen, false /* ignoresSetting */);
requiresTouchscreen, false /* ignoresSetting */,
false /* sensorPerformsProxCheck */);
}
private TriggerSensor(Sensor sensor, String setting, boolean settingDef,
boolean configured, int pulseReason, boolean reportsTouchCoordinates,
boolean requiresTouchscreen, boolean ignoresSetting) {
boolean requiresTouchscreen, boolean ignoresSetting,
boolean sensorPerformsProxCheck) {
mSensor = sensor;
mSetting = setting;
mSettingDefault = settingDef;
@@ -368,6 +403,7 @@ public class DozeSensors {
mReportsTouchCoordinates = reportsTouchCoordinates;
mRequiresTouchscreen = requiresTouchscreen;
mIgnoresSetting = ignoresSetting;
mSensorPerformsProxCheck = sensorPerformsProxCheck;
}
public void setListening(boolean listen) {
@@ -427,14 +463,11 @@ public class DozeSensors {
DozeLog.traceSensor(mContext, mPulseReason);
mHandler.post(mWakeLock.wrap(() -> {
if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
boolean sensorPerformsProxCheck = false;
if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
int subType = (int) event.values[0];
MetricsLogger.action(
mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE,
subType);
sensorPerformsProxCheck =
mDozeParameters.getPickupSubtypePerformsProxCheck(subType);
}
mRegistered = false;
@@ -444,7 +477,7 @@ public class DozeSensors {
screenX = event.values[0];
screenY = event.values[1];
}
mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck, screenX, screenY,
mCallback.onSensorPulse(mPulseReason, mSensorPerformsProxCheck, screenX, screenY,
event.values);
if (!mRegistered) {
updateListener(); // reregister, this sensor only fires once
@@ -452,6 +485,15 @@ public class DozeSensors {
}));
}
/**
* If the sensor itself performs proximity checks, to avoid pocket dialing.
* Gated sensors don't need to be stopped when the {@link DozeMachine} is
* {@link DozeMachine.State#DOZE_AOD_PAUSED}.
*/
public boolean performsProxCheck() {
return mSensorPerformsProxCheck;
}
public void registerSettingsObserver(ContentObserver settingsObserver) {
if (mConfigured && !TextUtils.isEmpty(mSetting)) {
mResolver.registerContentObserver(

View File

@@ -296,6 +296,7 @@ public class DozeTriggers implements DozeMachine.Part {
case DOZE_AOD:
mDozeSensors.setProxListening(newState != DozeMachine.State.DOZE);
mDozeSensors.setListening(true);
mDozeSensors.setPaused(false);
if (newState == DozeMachine.State.DOZE_AOD && !sWakeDisplaySensorState) {
onWakeScreen(false, newState);
}
@@ -303,12 +304,13 @@ public class DozeTriggers implements DozeMachine.Part {
case DOZE_AOD_PAUSED:
case DOZE_AOD_PAUSING:
mDozeSensors.setProxListening(true);
mDozeSensors.setListening(false);
mDozeSensors.setPaused(true);
break;
case DOZE_PULSING:
case DOZE_PULSING_BRIGHT:
mDozeSensors.setTouchscreenSensorsListening(false);
mDozeSensors.setProxListening(true);
mDozeSensors.setPaused(false);
break;
case DOZE_PULSE_DONE:
mDozeSensors.requestTemporaryDisable();

View File

@@ -22,9 +22,7 @@ import android.os.PowerManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.MathUtils;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
@@ -41,13 +39,11 @@ import java.io.PrintWriter;
public class DozeParameters implements TunerService.Tunable,
com.android.systemui.plugins.statusbar.DozeParameters {
private static final int MAX_DURATION = 60 * 1000;
public static final String DOZE_SENSORS_WAKE_UP_FULLY = "doze_sensors_wake_up_fully";
public static final boolean FORCE_NO_BLANKING =
SystemProperties.getBoolean("debug.force_no_blanking", false);
public static final boolean FORCE_BLANKING =
SystemProperties.getBoolean("debug.force_blanking", false);
private static IntInOutMatcher sPickupSubtypePerformsProxMatcher;
private static DozeParameters sInstance;
private final Context mContext;
@@ -92,20 +88,6 @@ public class DozeParameters implements TunerService.Tunable,
pw.print(" getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
pw.print(" getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
pw.print(" getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
pw.print(" getPickupSubtypePerformsProxCheck(): ");pw.println(
dumpPickupSubtypePerformsProxCheck());
}
private String dumpPickupSubtypePerformsProxCheck() {
// Refresh sPickupSubtypePerformsProxMatcher
getPickupSubtypePerformsProxCheck(0);
if (sPickupSubtypePerformsProxMatcher == null) {
return "fallback: " + mContext.getResources().getBoolean(
R.bool.doze_pickup_performs_proximity_check);
} else {
return "spec: " + sPickupSubtypePerformsProxMatcher.mSpec;
}
}
public boolean getDisplayStateSupported() {
@@ -225,21 +207,8 @@ public class DozeParameters implements TunerService.Tunable,
return SystemProperties.get(propName, mContext.getString(resId));
}
public boolean getPickupSubtypePerformsProxCheck(int subType) {
String spec = getString("doze.pickup.proxcheck",
R.string.doze_pickup_subtype_performs_proximity_check);
if (TextUtils.isEmpty(spec)) {
// Fall back to non-subtype based property.
return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
}
if (sPickupSubtypePerformsProxMatcher == null
|| !TextUtils.equals(spec, sPickupSubtypePerformsProxMatcher.mSpec)) {
sPickupSubtypePerformsProxMatcher = new IntInOutMatcher(spec);
}
return sPickupSubtypePerformsProxMatcher.isIn(subType);
public boolean getPickupPerformsProxCheck() {
return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
}
public int getPulseVisibleDurationExtended() {
@@ -258,81 +227,4 @@ public class DozeParameters implements TunerService.Tunable,
public AlwaysOnDisplayPolicy getPolicy() {
return mAlwaysOnPolicy;
}
/**
* Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are
* listed, will not match numbers that are listed with a ! prefix, and will match / not match
* unlisted numbers depending on whether * or !* is present.
*
* * -> match any numbers that are not explicitly listed
* !* -> don't match any numbers that are not explicitly listed
* 2 -> match 2
* !3 -> don't match 3
*
* It is illegal to specify:
* - an empty spec
* - a spec containing that are empty, or a lone !
* - a spec for anything other than numbers or *
* - multiple terms for the same number / multiple *s
*/
public static class IntInOutMatcher {
private static final String WILDCARD = "*";
private static final char OUT_PREFIX = '!';
private final SparseBooleanArray mIsIn;
private final boolean mDefaultIsIn;
final String mSpec;
public IntInOutMatcher(String spec) {
if (TextUtils.isEmpty(spec)) {
throw new IllegalArgumentException("Spec must not be empty");
}
boolean defaultIsIn = false;
boolean foundWildcard = false;
mSpec = spec;
mIsIn = new SparseBooleanArray();
for (String itemPrefixed : spec.split(",", -1)) {
if (itemPrefixed.length() == 0) {
throw new IllegalArgumentException(
"Illegal spec, must not have zero-length items: `" + spec + "`");
}
boolean isIn = itemPrefixed.charAt(0) != OUT_PREFIX;
String item = isIn ? itemPrefixed : itemPrefixed.substring(1);
if (itemPrefixed.length() == 0) {
throw new IllegalArgumentException(
"Illegal spec, must not have zero-length items: `" + spec + "`");
}
if (WILDCARD.equals(item)) {
if (foundWildcard) {
throw new IllegalArgumentException("Illegal spec, `" + WILDCARD +
"` must not appear multiple times in `" + spec + "`");
}
defaultIsIn = isIn;
foundWildcard = true;
} else {
int key = Integer.parseInt(item);
if (mIsIn.indexOfKey(key) >= 0) {
throw new IllegalArgumentException("Illegal spec, `" + key +
"` must not appear multiple times in `" + spec + "`");
}
mIsIn.put(key, isIn);
}
}
if (!foundWildcard) {
throw new IllegalArgumentException("Illegal spec, must specify either * or !*");
}
mDefaultIsIn = defaultIsIn;
}
public boolean isIn(int value) {
return (mIsIn.get(value, mDefaultIsIn));
}
}
}

View File

@@ -36,7 +36,7 @@ public class DozeConfigurationUtil {
when(params.getPulseOnSigMotion()).thenReturn(false);
when(params.getPickupVibrationThreshold()).thenReturn(0);
when(params.getProxCheckBeforePulse()).thenReturn(true);
when(params.getPickupSubtypePerformsProxCheck(anyInt())).thenReturn(true);
when(params.getPickupPerformsProxCheck()).thenReturn(true);
when(params.getPolicy()).thenReturn(mock(AlwaysOnDisplayPolicy.class));
when(params.doubleTapReportsTouchCoordinates()).thenReturn(false);

View File

@@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -77,7 +78,9 @@ public class DozeSensorsTest extends SysuiTestCase {
@Mock
private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
@Mock
private TriggerSensor mMockTriggerSensor;
private TriggerSensor mTriggerSensor;
@Mock
private TriggerSensor mProxGatedTriggerSensor;
private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
private TestableLooper mTestableLooper;
private DozeSensors mDozeSensors;
@@ -85,6 +88,7 @@ public class DozeSensorsTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mProxGatedTriggerSensor.performsProxCheck()).thenReturn(true);
mTestableLooper = TestableLooper.get(this);
when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
@@ -114,21 +118,34 @@ public class DozeSensorsTest extends SysuiTestCase {
@Test
public void testSetListening_firstTrue_registerSettingsObserver() {
mDozeSensors.mSensors = new TriggerSensor[] {mMockTriggerSensor};
mDozeSensors.setListening(true);
verify(mMockTriggerSensor).registerSettingsObserver(any(ContentObserver.class));
verify(mTriggerSensor).registerSettingsObserver(any(ContentObserver.class));
}
@Test
public void testSetListening_twiceTrue_onlyRegisterSettingsObserverOnce() {
mDozeSensors.mSensors = new TriggerSensor[] {mMockTriggerSensor};
mDozeSensors.setListening(true);
mDozeSensors.setListening(true);
mDozeSensors.setListening(true);
verify(mTriggerSensor, times(1)).registerSettingsObserver(any(ContentObserver.class));
}
verify(mMockTriggerSensor, times(1)).registerSettingsObserver(any(ContentObserver.class));
@Test
public void testSetPaused_onlyPausesNonGatedSensors() {
mDozeSensors.setListening(true);
verify(mTriggerSensor).setListening(eq(true));
verify(mProxGatedTriggerSensor).setListening(eq(true));
clearInvocations(mTriggerSensor, mProxGatedTriggerSensor);
mDozeSensors.setPaused(true);
verify(mTriggerSensor).setListening(eq(false));
verify(mProxGatedTriggerSensor).setListening(eq(true));
clearInvocations(mTriggerSensor, mProxGatedTriggerSensor);
mDozeSensors.setPaused(false);
verify(mTriggerSensor).setListening(eq(true));
verify(mProxGatedTriggerSensor).setListening(eq(true));
}
private class TestableDozeSensors extends DozeSensors {
@@ -144,6 +161,7 @@ public class DozeSensorsTest extends SysuiTestCase {
mWakeLockScreenListener = (PluginSensor) sensor;
}
}
mSensors = new TriggerSensor[] {mTriggerSensor, mProxGatedTriggerSensor};
}
}
}

View File

@@ -16,10 +16,6 @@
package com.android.systemui.statusbar.phone;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -33,7 +29,6 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.doze.DozeScreenState;
import com.android.systemui.statusbar.phone.DozeParameters.IntInOutMatcher;
import org.junit.Assert;
import org.junit.Test;
@@ -43,160 +38,6 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class DozeParametersTest extends SysuiTestCase {
@Test
public void test_inOutMatcher_defaultIn() {
IntInOutMatcher intInOutMatcher = new IntInOutMatcher("*");
assertTrue(intInOutMatcher.isIn(1));
assertTrue(intInOutMatcher.isIn(-1));
assertTrue(intInOutMatcher.isIn(0));
}
@Test
public void test_inOutMatcher_defaultOut() {
IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!*");
assertFalse(intInOutMatcher.isIn(1));
assertFalse(intInOutMatcher.isIn(-1));
assertFalse(intInOutMatcher.isIn(0));
}
@Test
public void test_inOutMatcher_someIn() {
IntInOutMatcher intInOutMatcher = new IntInOutMatcher("1,2,3,!*");
assertTrue(intInOutMatcher.isIn(1));
assertTrue(intInOutMatcher.isIn(2));
assertTrue(intInOutMatcher.isIn(3));
assertFalse(intInOutMatcher.isIn(0));
assertFalse(intInOutMatcher.isIn(4));
}
@Test
public void test_inOutMatcher_someOut() {
IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!1,!2,!3,*");
assertFalse(intInOutMatcher.isIn(1));
assertFalse(intInOutMatcher.isIn(2));
assertFalse(intInOutMatcher.isIn(3));
assertTrue(intInOutMatcher.isIn(0));
assertTrue(intInOutMatcher.isIn(4));
}
@Test
public void test_inOutMatcher_mixed() {
IntInOutMatcher intInOutMatcher = new IntInOutMatcher("!1,2,!3,*");
assertFalse(intInOutMatcher.isIn(1));
assertTrue(intInOutMatcher.isIn(2));
assertFalse(intInOutMatcher.isIn(3));
assertTrue(intInOutMatcher.isIn(0));
assertTrue(intInOutMatcher.isIn(4));
}
@Test
public void test_inOutMatcher_failEmpty() {
try {
new IntInOutMatcher("");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void test_inOutMatcher_failNull() {
try {
new IntInOutMatcher(null);
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void test_inOutMatcher_failEmptyClause() {
try {
new IntInOutMatcher("!1,*,");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void test_inOutMatcher_failDuplicate() {
try {
new IntInOutMatcher("!1,*,!1");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void test_inOutMatcher_failDuplicateDefault() {
try {
new IntInOutMatcher("!1,*,*");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void test_inOutMatcher_failMalformedNot() {
try {
new IntInOutMatcher("!,*");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void test_inOutMatcher_failText() {
try {
new IntInOutMatcher("!abc,*");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void test_inOutMatcher_failContradiction() {
try {
new IntInOutMatcher("1,!1,*");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void test_inOutMatcher_failContradictionDefault() {
try {
new IntInOutMatcher("1,*,!*");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void test_inOutMatcher_failMissingDefault() {
try {
new IntInOutMatcher("1");
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
// expected
}
}
@Test
public void test_setControlScreenOffAnimation_setsDozeAfterScreenOff_false() {
TestableDozeParameters dozeParameters = new TestableDozeParameters(getContext());