diff options
17 files changed, 705 insertions, 196 deletions
diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java index f5b2ac586bd1..2b52e967ce54 100644 --- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java +++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java @@ -22,11 +22,9 @@ import android.os.Build; import android.os.SystemProperties; import android.provider.Settings; import android.text.TextUtils; -import android.util.Log; - -import java.util.Arrays; import com.android.internal.R; +import com.android.internal.util.ArrayUtils; /** * AmbientDisplayConfiguration encapsulates reading access to the configuration of ambient display. @@ -90,7 +88,12 @@ public class AmbientDisplayConfiguration { /** {@hide} */ public boolean tapSensorAvailable() { - return !TextUtils.isEmpty(tapSensorType()); + for (String tapType : tapSensorTypeMapping()) { + if (!TextUtils.isEmpty(tapType)) { + return true; + } + } + return false; } /** {@hide} */ @@ -143,18 +146,18 @@ public class AmbientDisplayConfiguration { return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType); } - /** {@hide} */ - private String tapSensorType() { - return mContext.getResources().getString(R.string.config_dozeTapSensorType); - } - - /** {@hide} */ - public String tapSensorType(int posture) { - return getSensorFromPostureMapping( - mContext.getResources().getStringArray(R.array.config_dozeTapSensorPostureMapping), - tapSensorType(), - posture - ); + /** {@hide} + * May support multiple postures. + */ + public String[] tapSensorTypeMapping() { + String[] postureMapping = + mContext.getResources().getStringArray(R.array.config_dozeTapSensorPostureMapping); + if (ArrayUtils.isEmpty(postureMapping)) { + return new String[] { + mContext.getResources().getString(R.string.config_dozeTapSensorType) + }; + } + return postureMapping; } /** {@hide} */ @@ -253,20 +256,4 @@ public class AmbientDisplayConfiguration { private boolean boolSetting(String name, int user, int def) { return Settings.Secure.getIntForUser(mContext.getContentResolver(), name, def, user) != 0; } - - /** {@hide} */ - public static String getSensorFromPostureMapping( - String[] postureMapping, - String defaultValue, - int posture) { - String sensorType = defaultValue; - if (postureMapping != null && posture < postureMapping.length) { - sensorType = postureMapping[posture]; - } else { - Log.e(TAG, "Unsupported doze posture " + posture - + " postureMapping=" + Arrays.toString(postureMapping)); - } - - return TextUtils.isEmpty(sensorType) ? defaultValue : sensorType; - } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 845d7dc26ee5..669965bcbea5 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -26,6 +26,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; +import com.android.systemui.statusbar.policy.DevicePostureController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -268,6 +269,16 @@ public class DozeLog implements Dumpable { } /** + * Appends doze updates due to a posture change. + */ + public void tracePostureChanged( + @DevicePostureController.DevicePostureInt int posture, + String partUpdated + ) { + mLogger.logPostureChanged(posture, partUpdated); + } + + /** * Appends pulse dropped event to logs */ public void tracePulseDropped(boolean pulsePending, DozeMachine.State state, boolean blocked) { @@ -391,8 +402,8 @@ public class DozeLog implements Dumpable { case REASON_SENSOR_DOUBLE_TAP: return "doubletap"; case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; case PULSE_REASON_DOCKING: return "docking"; - case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "reach-wakelockscreen"; - case REASON_SENSOR_WAKE_UP: return "presence-wakeup"; + case PULSE_REASON_SENSOR_WAKE_REACH: return "reach-wakelockscreen"; + case REASON_SENSOR_WAKE_UP_PRESENCE: return "presence-wakeup"; case REASON_SENSOR_TAP: return "tap"; case REASON_SENSOR_UDFPS_LONG_PRESS: return "udfps"; case REASON_SENSOR_QUICK_PICKUP: return "quickPickup"; @@ -403,8 +414,8 @@ public class DozeLog implements Dumpable { @Retention(RetentionPolicy.SOURCE) @IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION, PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP, - PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP, - PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, REASON_SENSOR_TAP, + PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP_PRESENCE, + PULSE_REASON_SENSOR_WAKE_REACH, REASON_SENSOR_TAP, REASON_SENSOR_UDFPS_LONG_PRESS, REASON_SENSOR_QUICK_PICKUP}) public @interface Reason {} public static final int PULSE_REASON_NONE = -1; @@ -415,8 +426,8 @@ public class DozeLog implements Dumpable { public static final int REASON_SENSOR_DOUBLE_TAP = 4; public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; public static final int PULSE_REASON_DOCKING = 6; - public static final int REASON_SENSOR_WAKE_UP = 7; - public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8; + public static final int REASON_SENSOR_WAKE_UP_PRESENCE = 7; + public static final int PULSE_REASON_SENSOR_WAKE_REACH = 8; public static final int REASON_SENSOR_TAP = 9; public static final int REASON_SENSOR_UDFPS_LONG_PRESS = 10; public static final int REASON_SENSOR_QUICK_PICKUP = 11; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt index dc186182432f..d79bf22cced2 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt @@ -24,6 +24,7 @@ import com.android.systemui.log.LogLevel.DEBUG import com.android.systemui.log.LogLevel.ERROR import com.android.systemui.log.LogLevel.INFO import com.android.systemui.log.dagger.DozeLog +import com.android.systemui.statusbar.policy.DevicePostureController import java.text.SimpleDateFormat import java.util.Date import java.util.Locale @@ -195,6 +196,16 @@ class DozeLogger @Inject constructor( }) } + fun logPostureChanged(posture: Int, partUpdated: String) { + buffer.log(TAG, INFO, { + int1 = posture + str1 = partUpdated + }, { + "Posture changed, posture=${DevicePostureController.devicePostureToString(int1)}" + + " partUpdated=$str1" + }) + } + fun logPulseDropped(pulsePending: Boolean, state: DozeMachine.State, blocked: Boolean) { buffer.log(TAG, INFO, { bool1 = pulsePending diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index da7b389fbd36..765c24507662 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -29,16 +29,18 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; +import android.util.IndentingPrintWriter; -import com.android.systemui.dock.DockManager; import com.android.systemui.doze.dagger.BrightnessSensor; import com.android.systemui.doze.dagger.DozeScope; import com.android.systemui.doze.dagger.WrappedService; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.util.sensors.AsyncSensorManager; import java.io.PrintWriter; +import java.util.Objects; import java.util.Optional; import javax.inject.Inject; @@ -60,14 +62,17 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi private final DozeHost mDozeHost; private final Handler mHandler; private final SensorManager mSensorManager; - private final Optional<Sensor> mLightSensorOptional; + private final Optional<Sensor>[] mLightSensorOptional; // light sensors to use per posture private final WakefulnessLifecycle mWakefulnessLifecycle; private final DozeParameters mDozeParameters; - private final DockManager mDockManager; + private final DevicePostureController mDevicePostureController; + private final DozeLog mDozeLog; private final int[] mSensorToBrightness; private final int[] mSensorToScrimOpacity; private final int mScreenBrightnessDim; + @DevicePostureController.DevicePostureInt + private int mDevicePosture; private boolean mRegistered; private int mDefaultDozeBrightness; private boolean mPaused = false; @@ -83,27 +88,36 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi private int mDebugBrightnessBucket = -1; @Inject - public DozeScreenBrightness(Context context, @WrappedService DozeMachine.Service service, + public DozeScreenBrightness( + Context context, + @WrappedService DozeMachine.Service service, AsyncSensorManager sensorManager, - @BrightnessSensor Optional<Sensor> lightSensorOptional, DozeHost host, Handler handler, + @BrightnessSensor Optional<Sensor>[] lightSensorOptional, + DozeHost host, Handler handler, AlwaysOnDisplayPolicy alwaysOnDisplayPolicy, WakefulnessLifecycle wakefulnessLifecycle, DozeParameters dozeParameters, - DockManager dockManager) { + DevicePostureController devicePostureController, + DozeLog dozeLog + ) { mContext = context; mDozeService = service; mSensorManager = sensorManager; mLightSensorOptional = lightSensorOptional; + mDevicePostureController = devicePostureController; + mDevicePosture = mDevicePostureController.getDevicePosture(); mWakefulnessLifecycle = wakefulnessLifecycle; mDozeParameters = dozeParameters; mDozeHost = host; mHandler = handler; - mDockManager = dockManager; + mDozeLog = dozeLog; mDefaultDozeBrightness = alwaysOnDisplayPolicy.defaultDozeBrightness; mScreenBrightnessDim = alwaysOnDisplayPolicy.dimBrightness; mSensorToBrightness = alwaysOnDisplayPolicy.screenBrightnessArray; mSensorToScrimOpacity = alwaysOnDisplayPolicy.dimmingScrimArray; + + mDevicePostureController.addCallback(mDevicePostureCallback); } @Override @@ -133,6 +147,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi private void onDestroy() { setLightSensorEnabled(false); + mDevicePostureController.removeCallback(mDevicePostureCallback); } @Override @@ -159,7 +174,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } int scrimOpacity = -1; - if (!mLightSensorOptional.isPresent()) { + if (!isLightSensorPresent()) { // No light sensor, scrims are always transparent. scrimOpacity = 0; } else if (brightnessReady) { @@ -172,6 +187,27 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } } + private boolean lightSensorSupportsCurrentPosture() { + return mLightSensorOptional != null + && mDevicePosture < mLightSensorOptional.length; + } + + private boolean isLightSensorPresent() { + if (!lightSensorSupportsCurrentPosture()) { + return mLightSensorOptional != null && mLightSensorOptional[0].isPresent(); + } + + return mLightSensorOptional[mDevicePosture].isPresent(); + } + + private Sensor getLightSensor() { + if (!lightSensorSupportsCurrentPosture()) { + return null; + } + + return mLightSensorOptional[mDevicePosture].get(); + } + private int computeScrimOpacity(int sensorValue) { if (sensorValue < 0 || sensorValue >= mSensorToScrimOpacity.length) { return -1; @@ -220,9 +256,9 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } private void setLightSensorEnabled(boolean enabled) { - if (enabled && !mRegistered && mLightSensorOptional.isPresent()) { + if (enabled && !mRegistered && isLightSensorPresent()) { // Wait until we get an event from the sensor until indicating ready. - mRegistered = mSensorManager.registerListener(this, mLightSensorOptional.get(), + mRegistered = mSensorManager.registerListener(this, getLightSensor(), SensorManager.SENSOR_DELAY_NORMAL, mHandler); mLastSensorValue = -1; } else if (!enabled && mRegistered) { @@ -255,6 +291,41 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi /** Dump current state */ public void dump(PrintWriter pw) { - pw.println("DozeScreenBrightnessSensorRegistered=" + mRegistered); + pw.println("DozeScreenBrightness:"); + IndentingPrintWriter idpw = new IndentingPrintWriter(pw); + idpw.increaseIndent(); + idpw.println("registered=" + mRegistered); + idpw.println("posture=" + DevicePostureController.devicePostureToString(mDevicePosture)); } + + private final DevicePostureController.Callback mDevicePostureCallback = + new DevicePostureController.Callback() { + @Override + public void onPostureChanged(int posture) { + if (mDevicePosture == posture + || mLightSensorOptional.length < 2 + || posture >= mLightSensorOptional.length) { + return; + } + + final Sensor oldSensor = mLightSensorOptional[mDevicePosture].get(); + final Sensor newSensor = mLightSensorOptional[posture].get(); + if (Objects.equals(oldSensor, newSensor)) { + mDevicePosture = posture; + // uses the same sensor for the new posture + return; + } + + // cancel the previous sensor: + if (mRegistered) { + setLightSensorEnabled(false); + mDevicePosture = posture; + setLightSensorEnabled(true); + } else { + mDevicePosture = posture; + } + mDozeLog.tracePostureChanged(mDevicePosture, "DozeScreenBrightness swap " + + "{" + oldSensor + "} => {" + newSensor + "}, mRegistered=" + mRegistered); + } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 3cefce83393a..9d0591e4bda2 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -38,6 +38,7 @@ import android.util.IndentingPrintWriter; import android.util.Log; import android.view.Display; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.internal.logging.UiEvent; @@ -54,10 +55,36 @@ import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.wakelock.WakeLock; import java.io.PrintWriter; +import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; +/** + * Tracks and registers/unregisters sensors while the device is dozing based on the config + * provided by {@link AmbientDisplayConfiguration} and parameters provided by {@link DozeParameters} + * + * Sensors registration depends on: + * - sensor existence/availability + * - user configuration (some can be toggled on/off via settings) + * - use of the proximity sensor (sometimes prox cannot be registered in certain display states) + * - touch state + * - device posture + * + * Sensors will trigger the provided Callback's {@link Callback#onSensorPulse} method. + * These sensors include: + * - pickup gesture + * - single and double tap gestures + * - udfps long-press gesture + * - reach and presence gestures + * - quick pickup gesture (low-threshold pickup gesture) + * + * This class also registers a ProximitySensor that reports near/far events and will + * trigger callbacks on the provided {@link mProxCallback}. + */ public class DozeSensors { private static final boolean DEBUG = DozeService.DEBUG; @@ -68,15 +95,21 @@ public class DozeSensors { private final AsyncSensorManager mSensorManager; private final AmbientDisplayConfiguration mConfig; private final WakeLock mWakeLock; - private final Consumer<Boolean> mProxCallback; + private final DozeLog mDozeLog; private final SecureSettings mSecureSettings; - private final Callback mCallback; + private final DevicePostureController mDevicePostureController; private final boolean mScreenOffUdfpsEnabled; + + // Sensors @VisibleForTesting - protected TriggerSensor[] mSensors; + protected TriggerSensor[] mTriggerSensors; + private final ProximitySensor mProximitySensor; + + // Sensor callbacks + private final Callback mSensorCallback; // receives callbacks on registered sensor events + private final Consumer<Boolean> mProxCallback; // receives callbacks on near/far updates private final Handler mHandler = new Handler(); - private final ProximitySensor mProximitySensor; private long mDebounceFrom; private boolean mSettingRegistered; private boolean mListening; @@ -106,37 +139,47 @@ public class DozeSensors { } } - DozeSensors(Context context, AsyncSensorManager sensorManager, - DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, - Callback callback, Consumer<Boolean> proxCallback, DozeLog dozeLog, - ProximitySensor proximitySensor, SecureSettings secureSettings, + DozeSensors( + Context context, + AsyncSensorManager sensorManager, + DozeParameters dozeParameters, + AmbientDisplayConfiguration config, + WakeLock wakeLock, + Callback sensorCallback, + Consumer<Boolean> proxCallback, + DozeLog dozeLog, + ProximitySensor proximitySensor, + SecureSettings secureSettings, AuthController authController, - int devicePosture) { + DevicePostureController devicePostureController + ) { mContext = context; mSensorManager = sensorManager; mConfig = config; mWakeLock = wakeLock; mProxCallback = proxCallback; mSecureSettings = secureSettings; - mCallback = callback; + mSensorCallback = sensorCallback; + mDozeLog = dozeLog; mProximitySensor = proximitySensor; mProximitySensor.setTag(TAG); mSelectivelyRegisterProxSensors = dozeParameters.getSelectivelyRegisterSensorsUsingProx(); mListeningProxSensors = !mSelectivelyRegisterProxSensors; mScreenOffUdfpsEnabled = config.screenOffUdfpsEnabled(KeyguardUpdateMonitor.getCurrentUser()); - mDevicePosture = devicePosture; + mDevicePostureController = devicePostureController; + mDevicePosture = mDevicePostureController.getDevicePosture(); boolean udfpsEnrolled = authController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser()); boolean alwaysOn = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT); - mSensors = new TriggerSensor[] { + mTriggerSensors = new TriggerSensor[] { new TriggerSensor( mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION), null /* setting */, dozeParameters.getPulseOnSigMotion(), DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */, - false /* touchscreen */, dozeLog), + false /* touchscreen */), new TriggerSensor( mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE), Settings.Secure.DOZE_PICK_UP_GESTURE, @@ -145,18 +188,16 @@ public class DozeSensors { DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */, false /* touchscreen */, false /* ignoresSetting */, - false /* requires prox */, - dozeLog), + false /* requires prox */), new TriggerSensor( findSensor(config.doubleTapSensorType()), Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, true /* configured */, DozeLog.REASON_SENSOR_DOUBLE_TAP, dozeParameters.doubleTapReportsTouchCoordinates(), - true /* touchscreen */, - dozeLog), + true /* touchscreen */), new TriggerSensor( - findSensor(config.tapSensorType(mDevicePosture)), + findSensors(config.tapSensorTypeMapping()), Settings.Secure.DOZE_TAP_SCREEN_GESTURE, true /* settingDef */, true /* configured */, @@ -165,7 +206,7 @@ public class DozeSensors { true /* touchscreen */, false /* ignoresSetting */, dozeParameters.singleTapUsesProx(mDevicePosture) /* requiresProx */, - dozeLog), + mDevicePosture), new TriggerSensor( findSensor(config.longPressSensorType()), Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, @@ -175,8 +216,7 @@ public class DozeSensors { true /* reports touch coordinates */, true /* touchscreen */, false /* ignoresSetting */, - dozeParameters.longPressUsesProx() /* requiresProx */, - dozeLog), + dozeParameters.longPressUsesProx() /* requiresProx */), new TriggerSensor( findSensor(config.udfpsLongPressSensorType()), "doze_pulse_on_auth", @@ -186,25 +226,22 @@ public class DozeSensors { true /* reports touch coordinates */, true /* touchscreen */, false /* ignoresSetting */, - dozeParameters.longPressUsesProx(), - dozeLog), + dozeParameters.longPressUsesProx()), new PluginSensor( new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY), Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, mConfig.wakeScreenGestureAvailable() && alwaysOn, - DozeLog.REASON_SENSOR_WAKE_UP, + DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE, false /* reports touch coordinates */, - false /* touchscreen */, - dozeLog), + false /* touchscreen */), new PluginSensor( new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN), Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, mConfig.wakeScreenGestureAvailable(), - DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, + DozeLog.PULSE_REASON_SENSOR_WAKE_REACH, false /* reports touch coordinates */, false /* touchscreen */, - mConfig.getWakeLockScreenDebounce(), - dozeLog), + mConfig.getWakeLockScreenDebounce()), new TriggerSensor( findSensor(config.quickPickupSensorType()), Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, @@ -212,10 +249,11 @@ public class DozeSensors { config.quickPickupSensorEnabled(KeyguardUpdateMonitor.getCurrentUser()) && udfpsEnrolled, DozeLog.REASON_SENSOR_QUICK_PICKUP, - false /* touchCoords */, - false /* touchscreen */, dozeLog), + false /* requiresTouchCoordinates */, + false /* requiresTouchscreen */, + false /* ignoresSetting */, + false /* requiresProx */), }; - setProxListening(false); // Don't immediately start listening when we register. mProximitySensor.register( proximityEvent -> { @@ -223,17 +261,21 @@ public class DozeSensors { mProxCallback.accept(!proximityEvent.getBelow()); } }); + + mDevicePostureController.addCallback(mDevicePostureCallback); } /** - * Unregister any sensors. + * Unregister all sensors and callbacks. */ public void destroy() { // Unregisters everything, which is enough to allow gc. - for (TriggerSensor triggerSensor : mSensors) { + for (TriggerSensor triggerSensor : mTriggerSensors) { triggerSensor.setListening(false); } mProximitySensor.pause(); + + mDevicePostureController.removeCallback(mDevicePostureCallback); } /** @@ -248,6 +290,24 @@ public class DozeSensors { return findSensor(mSensorManager, type, null); } + @NonNull + private Sensor[] findSensors(@NonNull String[] types) { + Sensor[] sensorMap = new Sensor[DevicePostureController.SUPPORTED_POSTURES_SIZE]; + + // Map of sensorType => Sensor, so we reuse the same sensor if it's the same between + // postures + Map<String, Sensor> typeToSensorMap = new HashMap<>(); + for (int i = 0; i < types.length; i++) { + String sensorType = types[i]; + if (!typeToSensorMap.containsKey(sensorType)) { + typeToSensorMap.put(sensorType, findSensor(sensorType)); + } + sensorMap[i] = typeToSensorMap.get(sensorType); + } + + return sensorMap; + } + /** * Utility method to find a {@link Sensor} for the supplied string type and string name. * @@ -306,7 +366,7 @@ public class DozeSensors { */ private void updateListening() { boolean anyListening = false; - for (TriggerSensor s : mSensors) { + for (TriggerSensor s : mTriggerSensors) { boolean listen = mListening && (!s.mRequiresTouchscreen || mListeningTouchScreenSensors) && (!s.mRequiresProx || mListeningProxSensors); @@ -319,7 +379,7 @@ public class DozeSensors { if (!anyListening) { mSecureSettings.unregisterContentObserver(mSettingsObserver); } else if (!mSettingRegistered) { - for (TriggerSensor s : mSensors) { + for (TriggerSensor s : mTriggerSensors) { s.registerSettingsObserver(mSettingsObserver); } } @@ -328,7 +388,7 @@ public class DozeSensors { /** Set the listening state of only the sensors that require the touchscreen. */ public void setTouchscreenSensorsListening(boolean listening) { - for (TriggerSensor sensor : mSensors) { + for (TriggerSensor sensor : mTriggerSensors) { if (sensor.mRequiresTouchscreen) { sensor.setListening(listening); } @@ -336,7 +396,7 @@ public class DozeSensors { } public void onUserSwitched() { - for (TriggerSensor s : mSensors) { + for (TriggerSensor s : mTriggerSensors) { s.updateListening(); } } @@ -366,7 +426,7 @@ public class DozeSensors { if (userId != ActivityManager.getCurrentUser()) { return; } - for (TriggerSensor s : mSensors) { + for (TriggerSensor s : mTriggerSensors) { s.updateListening(); } } @@ -374,7 +434,7 @@ public class DozeSensors { /** Ignore the setting value of only the sensors that require the touchscreen. */ public void ignoreTouchScreenSensorsSettingInterferingWithDocking(boolean ignore) { - for (TriggerSensor sensor : mSensors) { + for (TriggerSensor sensor : mTriggerSensors) { if (sensor.mRequiresTouchscreen) { sensor.ignoreSetting(ignore); } @@ -392,7 +452,7 @@ public class DozeSensors { pw.println("mScreenOffUdfpsEnabled=" + mScreenOffUdfpsEnabled); IndentingPrintWriter idpw = new IndentingPrintWriter(pw); idpw.increaseIndent(); - for (TriggerSensor s : mSensors) { + for (TriggerSensor s : mTriggerSensors) { idpw.println("Sensor: " + s.toString()); } idpw.println("ProxSensor: " + mProximitySensor.toString()); @@ -407,7 +467,7 @@ public class DozeSensors { @VisibleForTesting class TriggerSensor extends TriggerEventListener { - final Sensor mSensor; + @NonNull final Sensor[] mSensors; // index = posture, value = sensor final boolean mConfigured; final int mPulseReason; private final String mSetting; @@ -420,27 +480,67 @@ public class DozeSensors { protected boolean mRegistered; protected boolean mDisabled; protected boolean mIgnoresSetting; - protected final DozeLog mDozeLog; - - public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason, - boolean reportsTouchCoordinates, boolean requiresTouchscreen, DozeLog dozeLog) { - this(sensor, setting, true /* settingDef */, configured, pulseReason, - reportsTouchCoordinates, requiresTouchscreen, dozeLog); - } - - public TriggerSensor(Sensor sensor, String setting, boolean settingDef, - boolean configured, int pulseReason, boolean reportsTouchCoordinates, - boolean requiresTouchscreen, DozeLog dozeLog) { - this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates, - requiresTouchscreen, false /* ignoresSetting */, - false /* requiresProx */, dozeLog); - } - - private TriggerSensor(Sensor sensor, String setting, boolean settingDef, - boolean configured, int pulseReason, boolean reportsTouchCoordinates, - boolean requiresTouchscreen, boolean ignoresSetting, boolean requiresProx, - DozeLog dozeLog) { - mSensor = sensor; + private @DevicePostureController.DevicePostureInt int mPosture; + + TriggerSensor( + Sensor sensor, + String setting, + boolean configured, + int pulseReason, + boolean reportsTouchCoordinates, + boolean requiresTouchscreen + ) { + this( + sensor, + setting, + true /* settingDef */, + configured, + pulseReason, + false /* ignoresSetting */, + false /* requiresProx */, + reportsTouchCoordinates, + requiresTouchscreen + ); + } + + TriggerSensor( + Sensor sensor, + String setting, + boolean settingDef, + boolean configured, + int pulseReason, + boolean reportsTouchCoordinates, + boolean requiresTouchscreen, + boolean ignoresSetting, + boolean requiresProx + ) { + this( + new Sensor[]{ sensor }, + setting, + settingDef, + configured, + pulseReason, + reportsTouchCoordinates, + requiresTouchscreen, + ignoresSetting, + requiresProx, + DevicePostureController.DEVICE_POSTURE_UNKNOWN + ); + } + + TriggerSensor( + @NonNull Sensor[] sensors, + String setting, + boolean settingDef, + boolean configured, + int pulseReason, + boolean reportsTouchCoordinates, + boolean requiresTouchscreen, + boolean ignoresSetting, + boolean requiresProx, + @DevicePostureController.DevicePostureInt int posture + ) { + mSensors = sensors; mSetting = setting; mSettingDefault = settingDef; mConfigured = configured; @@ -449,7 +549,43 @@ public class DozeSensors { mRequiresTouchscreen = requiresTouchscreen; mIgnoresSetting = ignoresSetting; mRequiresProx = requiresProx; - mDozeLog = dozeLog; + mPosture = posture; + } + + /** + * @return true if the sensor changed based for the new posture + */ + public boolean setPosture(@DevicePostureController.DevicePostureInt int posture) { + if (mPosture == posture + || mSensors.length < 2 + || posture >= mSensors.length) { + return false; + } + + Sensor oldSensor = mSensors[mPosture]; + Sensor newSensor = mSensors[posture]; + if (Objects.equals(oldSensor, newSensor)) { + mPosture = posture; + // uses the same sensor for the new posture + return false; + } + + // cancel the previous sensor: + if (mRegistered) { + final boolean rt = mSensorManager.cancelTriggerSensor(this, oldSensor); + if (DEBUG) { + Log.d(TAG, "posture changed, cancelTriggerSensor[" + oldSensor + "] " + + rt); + } + mRegistered = false; + } + + // update the new sensor: + mPosture = posture; + updateListening(); + mDozeLog.tracePostureChanged(mPosture, "DozeSensors swap " + + "{" + oldSensor + "} => {" + newSensor + "}, mRegistered=" + mRegistered); + return true; } public void setListening(boolean listen) { @@ -471,24 +607,23 @@ public class DozeSensors { } public void updateListening() { - if (!mConfigured || mSensor == null) return; + final Sensor sensor = mSensors[mPosture]; + if (!mConfigured || sensor == null) return; if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)) { if (!mRegistered) { - mRegistered = mSensorManager.requestTriggerSensor(this, mSensor); + mRegistered = mSensorManager.requestTriggerSensor(this, sensor); if (DEBUG) { - Log.d(TAG, "requestTriggerSensor[" + mSensor - + "] " + mRegistered); + Log.d(TAG, "requestTriggerSensor[" + sensor + "] " + mRegistered); } } else { if (DEBUG) { - Log.d(TAG, "requestTriggerSensor[" + mSensor - + "] already registered"); + Log.d(TAG, "requestTriggerSensor[" + sensor + "] already registered"); } } } else if (mRegistered) { - final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor); + final boolean rt = mSensorManager.cancelTriggerSensor(this, sensor); if (DEBUG) { - Log.d(TAG, "cancelTriggerSensor[" + mSensor + "] " + rt); + Log.d(TAG, "cancelTriggerSensor[" + sensor + "] " + rt); } mRegistered = false; } @@ -506,21 +641,29 @@ public class DozeSensors { @Override public String toString() { - return new StringBuilder("{mRegistered=").append(mRegistered) + StringBuilder sb = new StringBuilder(); + sb.append("{") + .append("mRegistered=").append(mRegistered) .append(", mRequested=").append(mRequested) .append(", mDisabled=").append(mDisabled) .append(", mConfigured=").append(mConfigured) .append(", mIgnoresSetting=").append(mIgnoresSetting) - .append(", mSensor=").append(mSensor).append("}").toString(); + .append(", mSensors=").append(Arrays.toString(mSensors)); + if (mSensors.length > 2) { + sb.append(", mPosture=") + .append(DevicePostureController.devicePostureToString(mDevicePosture)); + } + return sb.append("}").toString(); } @Override @AnyThread public void onTrigger(TriggerEvent event) { + final Sensor sensor = mSensors[mDevicePosture]; mDozeLog.traceSensor(mPulseReason); mHandler.post(mWakeLock.wrap(() -> { if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event)); - if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { + if (sensor != null && sensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { UI_EVENT_LOGGER.log(DozeSensorsUiEvent.ACTION_AMBIENT_GESTURE_PICKUP); } @@ -531,7 +674,7 @@ public class DozeSensors { screenX = event.values[0]; screenY = event.values[1]; } - mCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values); + mSensorCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values); if (!mRegistered) { updateListening(); // reregister, this sensor only fires once } @@ -569,17 +712,16 @@ public class DozeSensors { private long mDebounce; PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, - int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, - DozeLog dozeLog) { + int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) { this(sensor, setting, configured, pulseReason, reportsTouchCoordinates, - requiresTouchscreen, 0L /* debounce */, dozeLog); + requiresTouchscreen, 0L /* debounce */); } PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, - long debounce, DozeLog dozeLog) { + long debounce) { super(null, setting, configured, pulseReason, reportsTouchCoordinates, - requiresTouchscreen, dozeLog); + requiresTouchscreen); mPluginSensor = sensor; mDebounce = debounce; } @@ -633,11 +775,22 @@ public class DozeSensors { return; } if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event)); - mCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues()); + mSensorCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues()); })); } } + private final DevicePostureController.Callback mDevicePostureCallback = posture -> { + if (mDevicePosture == posture) { + return; + } + mDevicePosture = posture; + + for (TriggerSensor triggerSensor : mTriggerSensors) { + triggerSensor.setPosture(mDevicePosture); + } + }; + public interface Callback { /** diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index b17f078e24ef..20cd5b987c1c 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -99,8 +99,6 @@ public class DozeTriggers implements DozeMachine.Part { private final UiEventLogger mUiEventLogger; private final DevicePostureController mDevicePostureController; - private @DevicePostureController.DevicePostureInt int mDevicePosture; - private long mNotificationPulseTime; private boolean mPulsePending; private Runnable mAodInterruptRunnable; @@ -197,11 +195,12 @@ public class DozeTriggers implements DozeMachine.Part { mSensorManager = sensorManager; mWakeLock = wakeLock; mAllowPulseTriggers = true; + mDevicePostureController = devicePostureController; - mDevicePosture = devicePostureController.getDevicePosture(); mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor, - secureSettings, authController, mDevicePosture); + secureSettings, authController, devicePostureController); + mUiModeManager = mContext.getSystemService(UiModeManager.class); mDockManager = dockManager; mProxCheck = proxCheck; @@ -212,6 +211,10 @@ public class DozeTriggers implements DozeMachine.Part { mUiEventLogger = uiEventLogger; mKeyguardStateController = keyguardStateController; } + private final DevicePostureController.Callback mDevicePostureCallback = + posture -> { + + }; @Override public void setDozeMachine(DozeMachine dozeMachine) { @@ -284,8 +287,8 @@ public class DozeTriggers implements DozeMachine.Part { boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP; boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP; boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS; - boolean isWakeOnPresence = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP; - boolean isWakeOnReach = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN; + boolean isWakeOnPresence = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE; + boolean isWakeOnReach = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH; boolean isUdfpsLongPress = pulseReason == DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS; boolean isQuickPickup = pulseReason == DozeLog.REASON_SENSOR_QUICK_PICKUP; boolean isWakeDisplayEvent = isQuickPickup || ((isWakeOnPresence || isWakeOnReach) @@ -455,7 +458,7 @@ public class DozeTriggers implements DozeMachine.Part { mWantSensors = true; mWantTouchScreenSensors = true; if (newState == DozeMachine.State.DOZE_AOD && !sWakeDisplaySensorState) { - onWakeScreen(false, newState, DozeLog.REASON_SENSOR_WAKE_UP); + onWakeScreen(false, newState, DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE); } break; case DOZE_AOD_PAUSED: @@ -524,7 +527,7 @@ public class DozeTriggers implements DozeMachine.Part { // When already pulsing we're allowed to show the wallpaper directly without // requesting a new pulse. if (dozeState == DozeMachine.State.DOZE_PULSING - && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) { mMachine.requestState(DozeMachine.State.DOZE_PULSING_BRIGHT); return; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index fbe06b02d955..374bed31eb7d 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -155,7 +155,7 @@ public class DozeUi implements DozeMachine.Part, TunerService.Tunable, public void onPulseStarted() { try { mMachine.requestState( - reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN + reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH ? DozeMachine.State.DOZE_PULSING_BRIGHT : DozeMachine.State.DOZE_PULSING); } catch (IllegalStateException e) { diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java index 571b666e4573..32b7658b6e09 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java +++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java @@ -43,6 +43,9 @@ import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.wakelock.DelayedWakeLock; import com.android.systemui.util.wakelock.WakeLock; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import dagger.Module; @@ -94,16 +97,43 @@ public abstract class DozeModule { @Provides @BrightnessSensor - static Optional<Sensor> providesBrightnessSensor( + static Optional<Sensor>[] providesBrightnessSensors( AsyncSensorManager sensorManager, Context context, - DozeParameters dozeParameters, - DevicePostureController devicePostureController) { - return Optional.ofNullable( - DozeSensors.findSensor( - sensorManager, - context.getString(R.string.doze_brightness_sensor_type), - dozeParameters.brightnessName(devicePostureController.getDevicePosture()) - )); + DozeParameters dozeParameters) { + String[] sensorNames = dozeParameters.brightnessNames(); + if (sensorNames.length == 0 || sensorNames == null) { + // if no brightness names are specified, just use the brightness sensor type + return new Optional[]{ + Optional.ofNullable(DozeSensors.findSensor( + sensorManager, + context.getString(R.string.doze_brightness_sensor_type), + null + )) + }; + } + + // length and index of brightnessMap correspond to DevicePostureController.DevicePostureInt: + final Optional<Sensor>[] brightnessSensorMap = + new Optional[DevicePostureController.SUPPORTED_POSTURES_SIZE]; + Arrays.fill(brightnessSensorMap, Optional.empty()); + + // Map of sensorName => Sensor, so we reuse the same sensor if it's the same between + // postures + Map<String, Optional<Sensor>> nameToSensorMap = new HashMap<>(); + for (int i = 0; i < sensorNames.length; i++) { + final String sensorName = sensorNames[i]; + if (!nameToSensorMap.containsKey(sensorName)) { + nameToSensorMap.put(sensorName, + Optional.ofNullable( + DozeSensors.findSensor( + sensorManager, + context.getString(R.string.doze_brightness_sensor_type), + sensorNames[i] + ))); + } + brightnessSensorMap[i] = nameToSensorMap.get(sensorName); + } + return brightnessSensorMap; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 5bf982b908cd..49e3fe7df2be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -283,14 +283,12 @@ public class DozeParameters implements } /** - * Sensor to use for brightness changes. + * Gets the brightness string array per posture. Brightness names along with + * doze_brightness_sensor_type is used to determine the brightness sensor to use for + * the current posture. */ - public String brightnessName(@DevicePostureController.DevicePostureInt int posture) { - return AmbientDisplayConfiguration.getSensorFromPostureMapping( - mResources.getStringArray(R.array.doze_brightness_sensor_name_posture_mapping), - null /* defaultValue */, - posture - ); + public String[] brightnessNames() { + return mResources.getStringArray(R.array.doze_brightness_sensor_name_posture_mapping); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java index f289b9f20211..57b9c03ce576 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -226,11 +226,11 @@ public final class DozeServiceHost implements DozeHost { return; } - if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) { mScrimController.setWakeLockScreenSensorActive(true); } - boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN + boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH && mWakeLockScreenPerformsAuth; // Set the state to pulsing, so ScrimController will know what to do once we ask it to // execute the transition. The pulse callback will then be invoked when the scrims @@ -329,7 +329,7 @@ public final class DozeServiceHost implements DozeHost { @Override public void extendPulse(int reason) { - if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_REACH) { mScrimController.setWakeLockScreenSensorActive(true); } if (mDozeScrimController.isPulsing() && mHeadsUpManagerPhone.hasNotifications()) { diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java b/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java index 0be6068c22a4..96980b85e410 100644 --- a/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java +++ b/packages/SystemUI/src/com/android/systemui/util/sensors/SensorModule.java @@ -29,6 +29,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.util.concurrency.DelayableExecutor; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -177,9 +178,7 @@ public class SensorModule { // length and index of sensorMap correspond to DevicePostureController.DevicePostureInt: final ThresholdSensor[] sensorMap = new ThresholdSensor[DevicePostureController.SUPPORTED_POSTURES_SIZE]; - for (int i = 0; i < DevicePostureController.SUPPORTED_POSTURES_SIZE; i++) { - sensorMap[i] = noProxSensor; - } + Arrays.fill(sensorMap, noProxSensor); if (!hasPostureSupport(sensorTypes)) { Log.e("SensorModule", "config doesn't support postures," diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java index 866791cc24cb..364b5d9be2b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java @@ -67,7 +67,8 @@ public class DozeConfigurationUtil { when(config.tapGestureEnabled(anyInt())).thenReturn(true); when(config.tapSensorAvailable()).thenReturn(true); - when(config.tapSensorType(anyInt())).thenReturn(FakeSensorManager.TAP_SENSOR_TYPE); + when(config.tapSensorTypeMapping()).thenReturn( + new String[]{FakeSensorManager.TAP_SENSOR_TYPE}); when(config.dozePickupSensorAvailable()).thenReturn(false); when(config.wakeScreenGestureAvailable()).thenReturn(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java index e0520b406a0a..886f84e19e0b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java @@ -51,6 +51,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.DevicePostureController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeThreadFactory; import com.android.systemui.util.sensors.AsyncSensorManager; @@ -60,6 +61,7 @@ import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -76,6 +78,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { private DozeServiceFake mServiceFake; private FakeSensorManager.FakeGenericSensor mSensor; + private FakeSensorManager.FakeGenericSensor mSensorInner; private AsyncSensorManager mSensorManager; private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy; @Mock @@ -86,6 +89,10 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { DozeParameters mDozeParameters; @Mock DockManager mDockManager; + @Mock + DevicePostureController mDevicePostureController; + @Mock + DozeLog mDozeLog; private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor); @@ -111,9 +118,19 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { mAlwaysOnDisplayPolicy.dimBrightness = DIM_BRIGHTNESS; mAlwaysOnDisplayPolicy.dimmingScrimArray = SENSOR_TO_OPACITY; mSensor = fakeSensorManager.getFakeLightSensor(); - mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, - Optional.of(mSensor.getSensor()), mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); + mSensorInner = fakeSensorManager.getFakeLightSensor2(); + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[]{Optional.of(mSensor.getSensor())}, + mDozeHost, + null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); } @Test @@ -151,7 +168,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { @Test public void doze_doesNotUseLightSensor() { - // GIVEN the device is docked and the display state changes to ON + // GIVEN the device is DOZE and the display state changes to ON mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE); waitForSensorManager(); @@ -166,7 +183,7 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { @Test public void aod_usesLightSensor() { - // GIVEN the device is docked and the display state changes to ON + // GIVEN the device is DOZE_AOD and the display state changes to ON mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); waitForSensorManager(); @@ -209,9 +226,17 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { @Test public void testPulsing_withoutLightSensor_setsAoDDimmingScrimTransparent() throws Exception { - mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, - Optional.empty() /* sensor */, mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[] {Optional.empty()} /* sensor */, + mDozeHost, null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE); reset(mDozeHost); @@ -238,9 +263,17 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { @Test public void testNullSensor() throws Exception { - mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, - Optional.empty() /* sensor */, mDozeHost, null /* handler */, - mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[]{Optional.empty()} /* sensor */, + mDozeHost, null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); @@ -249,6 +282,130 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { } @Test + public void testSensorsSupportPostures_closed() throws Exception { + // GIVEN the device is CLOSED + when(mDevicePostureController.getDevicePosture()).thenReturn( + DevicePostureController.DEVICE_POSTURE_CLOSED); + + // GIVEN closed and opened postures use different light sensors + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[]{ + Optional.empty() /* unknown */, + Optional.of(mSensor.getSensor()) /* closed */, + Optional.of(mSensorInner.getSensor()) /* half-opened */, + Optional.of(mSensorInner.getSensor()) /* opened */, + Optional.empty() /* flipped */ + }, + mDozeHost, null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); + + // GIVEN the device is in AOD + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + waitForSensorManager(); + + // WHEN new different events are sent from the inner and outer sensors + mSensor.sendSensorEvent(3); // CLOSED sensor + mSensorInner.sendSensorEvent(4); // OPENED sensor + + // THEN brightness is updated according to the sensor for CLOSED + assertEquals(3, mServiceFake.screenBrightness); + } + + @Test + public void testSensorsSupportPostures_open() throws Exception { + // GIVEN the device is OPENED + when(mDevicePostureController.getDevicePosture()).thenReturn( + DevicePostureController.DEVICE_POSTURE_OPENED); + + // GIVEN closed and opened postures use different light sensors + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[]{ + Optional.empty() /* unknown */, + Optional.of(mSensor.getSensor()) /* closed */, + Optional.of(mSensorInner.getSensor()) /* half-opened */, + Optional.of(mSensorInner.getSensor()) /* opened */, + Optional.empty() /* flipped */ + }, + mDozeHost, null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); + + // GIVEN device is in AOD + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + waitForSensorManager(); + + // WHEN new different events are sent from the inner and outer sensors + mSensorInner.sendSensorEvent(4); // OPENED sensor + mSensor.sendSensorEvent(3); // CLOSED sensor + + // THEN brightness is updated according to the sensor for OPENED + assertEquals(4, mServiceFake.screenBrightness); + } + + @Test + public void testSensorsSupportPostures_swapPostures() throws Exception { + ArgumentCaptor<DevicePostureController.Callback> postureCallbackCaptor = + ArgumentCaptor.forClass(DevicePostureController.Callback.class); + reset(mDevicePostureController); + + // GIVEN the device starts up AOD OPENED + when(mDevicePostureController.getDevicePosture()).thenReturn( + DevicePostureController.DEVICE_POSTURE_OPENED); + + // GIVEN closed and opened postures use different light sensors + mScreen = new DozeScreenBrightness( + mContext, + mServiceFake, + mSensorManager, + new Optional[]{ + Optional.empty() /* unknown */, + Optional.of(mSensor.getSensor()) /* closed */, + Optional.of(mSensorInner.getSensor()) /* half-opened */, + Optional.of(mSensorInner.getSensor()) /* opened */, + Optional.empty() /* flipped */ + }, + mDozeHost, null /* handler */, + mAlwaysOnDisplayPolicy, + mWakefulnessLifecycle, + mDozeParameters, + mDevicePostureController, + mDozeLog); + verify(mDevicePostureController).addCallback(postureCallbackCaptor.capture()); + + // GIVEN device is in AOD + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + waitForSensorManager(); + + // WHEN the posture changes to CLOSED + postureCallbackCaptor.getValue().onPostureChanged( + DevicePostureController.DEVICE_POSTURE_CLOSED); + waitForSensorManager(); + + // WHEN new different events are sent from the inner and outer sensors + mSensor.sendSensorEvent(3); // CLOSED sensor + mSensorInner.sendSensorEvent(4); // OPENED sensor + + // THEN brightness is updated according to the sensor for CLOSED + assertEquals(3, mServiceFake.screenBrightness); + } + + @Test public void testNoBrightnessDeliveredAfterFinish() throws Exception { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java index 42e34c81a790..f525fee27e20 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java @@ -91,9 +91,9 @@ public class DozeSensorsTest extends SysuiTestCase { @Mock private AuthController mAuthController; @Mock + private DevicePostureController mDevicePostureController; + @Mock private ProximitySensor mProximitySensor; - private @DevicePostureController.DevicePostureInt int mDevicePosture = - DevicePostureController.DEVICE_POSTURE_UNKNOWN; private FakeSettings mFakeSettings = new FakeSettings(); private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener; private TestableLooper mTestableLooper; @@ -104,13 +104,14 @@ public class DozeSensorsTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); + when(mAmbientDisplayConfiguration.tapSensorTypeMapping()) + .thenReturn(new String[]{"tapSEnsor"}); when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L); when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true); doAnswer(invocation -> { ((Runnable) invocation.getArgument(0)).run(); return null; }).when(mWakeLock).wrap(any(Runnable.class)); - mDevicePosture = DevicePostureController.DEVICE_POSTURE_UNKNOWN; mDozeSensors = new TestableDozeSensors(); } @@ -127,14 +128,14 @@ public class DozeSensorsTest extends SysuiTestCase { mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class)); mTestableLooper.processAllMessages(); - verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), + verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_REACH), anyFloat(), anyFloat(), eq(null)); mDozeSensors.requestTemporaryDisable(); reset(mCallback); mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class)); mTestableLooper.processAllMessages(); - verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), + verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_REACH), anyFloat(), anyFloat(), eq(null)); } @@ -269,15 +270,80 @@ public class DozeSensorsTest extends SysuiTestCase { } @Test - public void testPostureOpen_registersCorrectTapGesture() { - // GIVEN device posture open - mDevicePosture = DevicePostureController.DEVICE_POSTURE_OPENED; + public void testPostureStartStateClosed_registersCorrectSensor() throws Exception { + // GIVEN doze sensor that supports postures + Sensor closedSensor = createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); + Sensor openedSensor = createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_LIGHT); + TriggerSensor triggerSensor = mDozeSensors.createDozeSensor( + new Sensor[] { + null /* unknown */, + closedSensor, + null /* half-opened */, + openedSensor}, + DevicePostureController.DEVICE_POSTURE_CLOSED); + + // WHEN trigger sensor requests listening + triggerSensor.setListening(true); + + // THEN the correct sensor is registered + verify(mSensorManager).requestTriggerSensor(eq(triggerSensor), eq(closedSensor)); + verify(mSensorManager, never()).requestTriggerSensor(eq(triggerSensor), eq(openedSensor)); + } + + @Test + public void testPostureChange_registersCorrectSensor() throws Exception { + // GIVEN doze sensor that supports postures + Sensor closedSensor = createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); + Sensor openedSensor = createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_LIGHT); + TriggerSensor triggerSensor = mDozeSensors.createDozeSensor( + new Sensor[] { + null /* unknown */, + closedSensor, + null /* half-opened */, + openedSensor}, + DevicePostureController.DEVICE_POSTURE_CLOSED); + + // GIVEN sensor is listening + when(mSensorManager.requestTriggerSensor(any(), any())).thenReturn(true); + triggerSensor.setListening(true); + reset(mSensorManager); + assertTrue(triggerSensor.mRegistered); + + // WHEN posture changes + boolean sensorChanged = + triggerSensor.setPosture(DevicePostureController.DEVICE_POSTURE_OPENED); + + // THEN the correct sensor is registered + assertTrue(sensorChanged); + verify(mSensorManager).requestTriggerSensor(eq(triggerSensor), eq(openedSensor)); + verify(mSensorManager, never()).requestTriggerSensor(eq(triggerSensor), eq(closedSensor)); + } + + @Test + public void testPostureChange_noSensorChange() throws Exception { + // GIVEN doze sensor that supports postures + Sensor closedSensor = createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); + Sensor openedSensor = createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_LIGHT); + TriggerSensor triggerSensor = mDozeSensors.createDozeSensor( + new Sensor[] { + null /* unknown */, + closedSensor, + openedSensor /* half-opened uses the same sensor as opened*/, + openedSensor}, + DevicePostureController.DEVICE_POSTURE_HALF_OPENED); + + // GIVEN sensor is listening + when(mSensorManager.requestTriggerSensor(any(), any())).thenReturn(true); + triggerSensor.setListening(true); + reset(mSensorManager); - // WHEN DozeSensors are initialized - new TestableDozeSensors(); + // WHEN posture changes + boolean sensorChanged = + triggerSensor.setPosture(DevicePostureController.DEVICE_POSTURE_OPENED); - // THEN we use the posture to determine which tap sensor to use - verify(mAmbientDisplayConfiguration).tapSensorType(eq(mDevicePosture)); + // THEN no change in sensor + assertFalse(sensorChanged); + verify(mSensorManager, never()).requestTriggerSensor(eq(triggerSensor), any()); } @Test @@ -311,13 +377,12 @@ public class DozeSensorsTest extends SysuiTestCase { private class TestableDozeSensors extends DozeSensors { - TestableDozeSensors() { super(getContext(), mSensorManager, mDozeParameters, mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, mDozeLog, mProximitySensor, mFakeSettings, mAuthController, - mDevicePosture); - for (TriggerSensor sensor : mSensors) { + mDevicePostureController); + for (TriggerSensor sensor : mTriggerSensors) { if (sensor instanceof PluginSensor && ((PluginSensor) sensor).mPluginSensor.getType() == TYPE_WAKE_LOCK_SCREEN) { @@ -326,7 +391,7 @@ public class DozeSensorsTest extends SysuiTestCase { mSensorTap = sensor; } } - mSensors = new TriggerSensor[] {mTriggerSensor, mSensorTap}; + mTriggerSensors = new TriggerSensor[] {mTriggerSensor, mSensorTap}; } public TriggerSensor createDozeSensor(Sensor sensor, boolean settingEnabled, @@ -337,8 +402,25 @@ public class DozeSensorsTest extends SysuiTestCase { /* configured */ true, /* pulseReason*/ 0, /* reportsTouchCoordinate*/ false, - requiresTouchScreen, - mDozeLog); + /* requiresTouchscreen */ false, + /* ignoresSetting */ false, + requiresTouchScreen); + } + + /** + * create a doze sensor that supports postures and is enabled + */ + public TriggerSensor createDozeSensor(Sensor[] sensors, int posture) { + return new TriggerSensor(/* sensor */ sensors, + /* setting name */ "test_setting", + /* settingDefault */ true, + /* configured */ true, + /* pulseReason*/ 0, + /* reportsTouchCoordinate*/ false, + /* requiresTouchscreen */ false, + /* ignoresSetting */ true, + /* requiresProx */false, + posture); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index 31fa3f841b19..35dca7ef5fce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -204,7 +204,7 @@ public class DozeTriggersTest extends SysuiTestCase { public void testProximitySensorNotAvailablel() { mProximitySensor.setSensorAvailable(false); mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, 100, 100, null); - mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, 100, 100, + mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_WAKE_REACH, 100, 100, new float[]{1}); mTriggers.onSensor(DozeLog.REASON_SENSOR_TAP, 100, 100, null); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java index 8b5ba3848500..38d7ce76f1b9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java @@ -164,7 +164,7 @@ public class DozeServiceHostTest extends SysuiTestCase { @Test public void testPulseWhileDozing_notifyAuthInterrupt() { HashSet<Integer> reasonsWantingAuth = new HashSet<>( - Collections.singletonList(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN)); + Collections.singletonList(DozeLog.PULSE_REASON_SENSOR_WAKE_REACH)); HashSet<Integer> reasonsSkippingAuth = new HashSet<>( Arrays.asList(DozeLog.PULSE_REASON_INTENT, DozeLog.PULSE_REASON_NOTIFICATION, @@ -173,7 +173,7 @@ public class DozeServiceHostTest extends SysuiTestCase { DozeLog.REASON_SENSOR_DOUBLE_TAP, DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, DozeLog.PULSE_REASON_DOCKING, - DozeLog.REASON_SENSOR_WAKE_UP, + DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE, DozeLog.REASON_SENSOR_QUICK_PICKUP, DozeLog.REASON_SENSOR_TAP)); HashSet<Integer> reasonsThatDontPulse = new HashSet<>( diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java index 6e73827fedfb..197873f15d0d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java @@ -55,6 +55,7 @@ public class FakeSensorManager extends SensorManager { private final FakeProximitySensor mFakeProximitySensor; private final FakeGenericSensor mFakeLightSensor; + private final FakeGenericSensor mFakeLightSensor2; private final FakeGenericSensor mFakeTapSensor; private final FakeGenericSensor[] mSensors; @@ -70,7 +71,8 @@ public class FakeSensorManager extends SensorManager { mSensors = new FakeGenericSensor[]{ mFakeProximitySensor = new FakeProximitySensor(proxSensor), mFakeLightSensor = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null)), - mFakeTapSensor = new FakeGenericSensor(createSensor(99, TAP_SENSOR_TYPE)) + mFakeTapSensor = new FakeGenericSensor(createSensor(99, TAP_SENSOR_TYPE)), + mFakeLightSensor2 = new FakeGenericSensor(createSensor(Sensor.TYPE_LIGHT, null)) }; } @@ -82,6 +84,10 @@ public class FakeSensorManager extends SensorManager { return mFakeLightSensor; } + public FakeGenericSensor getFakeLightSensor2() { + return mFakeLightSensor2; + } + public FakeGenericSensor getFakeTapSensor() { return mFakeTapSensor; } |