diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java index f3fb1efb7decb..ec56e15dbd8d4 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -33,6 +33,8 @@ public interface DozeHost { boolean isPulsingBlocked(); void startPendingIntentDismissingKeyguard(PendingIntent intent); + void abortPulsing(); + void extendPulse(); interface Callback { default void onNotificationHeadsUp() {} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index f27521e20bbca..1cc5fb956c99d 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -58,12 +58,15 @@ public class DozeMachine { /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */ DOZE_PULSE_DONE, /** Doze is done. DozeService is finished. */ - FINISH; + FINISH, + /** AOD, but the display is temporarily off. */ + DOZE_AOD_PAUSED; boolean canPulse() { switch (this) { case DOZE: case DOZE_AOD: + case DOZE_AOD_PAUSED: return true; default: return false; @@ -85,6 +88,7 @@ public class DozeMachine { case UNINITIALIZED: case INITIALIZED: case DOZE: + case DOZE_AOD_PAUSED: return Display.STATE_OFF; case DOZE_PULSING: case DOZE_AOD: @@ -241,6 +245,11 @@ public class DozeMachine { if (mState == State.FINISH) { return State.FINISH; } + if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD || mState == State.DOZE) + && requestedState == State.DOZE_PULSE_DONE) { + Log.i(TAG, "Dropping pulse done because current state is already done: " + mState); + return mState; + } if (requestedState == State.DOZE_REQUEST_PULSE && !mState.canPulse()) { Log.i(TAG, "Dropping pulse request because current state can't pulse: " + mState); return mState; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index 2ac06579f259e..73f522244a608 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -22,6 +22,8 @@ import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; @@ -40,6 +42,7 @@ import com.android.systemui.util.wakelock.WakeLock; import java.io.PrintWriter; import java.util.List; +import java.util.function.Consumer; public class DozeSensors { @@ -55,18 +58,22 @@ public class DozeSensors { private final DozeParameters mDozeParameters; private final AmbientDisplayConfiguration mConfig; private final WakeLock mWakeLock; + private final Consumer mProxCallback; private final Callback mCallback; private final Handler mHandler = new Handler(); + private final ProxSensor mProxSensor; public DozeSensors(Context context, SensorManager sensorManager, DozeParameters dozeParameters, - AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback) { + AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback, + Consumer proxCallback) { mContext = context; mSensorManager = sensorManager; mDozeParameters = dozeParameters; mConfig = config; mWakeLock = wakeLock; + mProxCallback = proxCallback; mResolver = mContext.getContentResolver(); mSensors = new TriggerSensor[] { @@ -86,6 +93,8 @@ public class DozeSensors { true /* configured */, DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP) }; + + mProxSensor = new ProxSensor(); mCallback = callback; } @@ -129,6 +138,10 @@ public class DozeSensors { } } + public void setProxListening(boolean listen) { + mProxSensor.setRegistered(listen); + } + private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { @Override public void onChange(boolean selfChange, Uri uri, int userId) { @@ -152,6 +165,43 @@ public class DozeSensors { } } + private class ProxSensor implements SensorEventListener { + + boolean mRegistered; + Boolean mCurrentlyFar; + + void setRegistered(boolean register) { + if (mRegistered == register) { + // Send an update even if we don't re-register. + mHandler.post(() -> { + if (mCurrentlyFar != null) { + mProxCallback.accept(mCurrentlyFar); + } + }); + return; + } + if (register) { + mRegistered = mSensorManager.registerListener(this, + mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY), + SensorManager.SENSOR_DELAY_NORMAL, mHandler); + } else { + mSensorManager.unregisterListener(this); + mRegistered = false; + mCurrentlyFar = null; + } + } + + @Override + public void onSensorChanged(SensorEvent event) { + mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange(); + mProxCallback.accept(mCurrentlyFar); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + } + private class TriggerSensor extends TriggerEventListener { final Sensor mSensor; final boolean mConfigured; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 1b9bf73847b58..9b3593b9cbdda 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -46,6 +46,7 @@ import java.io.PrintWriter; public class DozeTriggers implements DozeMachine.Part { private static final String TAG = "DozeTriggers"; + private static final boolean DEBUG = DozeService.DEBUG; /** adb shell am broadcast -a com.android.systemui.doze.pulse com.android.systemui */ private static final String PULSE_ACTION = "com.android.systemui.doze.pulse"; @@ -81,7 +82,7 @@ public class DozeTriggers implements DozeMachine.Part { mWakeLock = wakeLock; mAllowPulseTriggers = allowPulseTriggers; mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters, config, - wakeLock, this::onSensor); + wakeLock, this::onSensor, this::onProximityFar); mUiModeManager = mContext.getSystemService(UiModeManager.class); } @@ -113,6 +114,22 @@ public class DozeTriggers implements DozeMachine.Part { } } + private void onProximityFar(boolean far) { + final boolean near = !far; + DozeMachine.State state = mMachine.getState(); + if (near && state == DozeMachine.State.DOZE_PULSING) { + if (DEBUG) Log.i(TAG, "Prox NEAR, ending pulse"); + mMachine.requestState(DozeMachine.State.DOZE_PULSE_DONE); + } + if (far && state == DozeMachine.State.DOZE_AOD_PAUSED) { + if (DEBUG) Log.i(TAG, "Prox FAR, unpausing AOD"); + mMachine.requestState(DozeMachine.State.DOZE_AOD); + } else if (near && state == DozeMachine.State.DOZE_AOD) { + if (DEBUG) Log.i(TAG, "Prox NEAR, pausing AOD"); + mMachine.requestState(DozeMachine.State.DOZE_AOD_PAUSED); + } + } + private void onCarMode() { mMachine.requestState(DozeMachine.State.FINISH); } @@ -131,15 +148,21 @@ public class DozeTriggers implements DozeMachine.Part { break; case DOZE: case DOZE_AOD: + case DOZE_AOD_PAUSED: + mDozeSensors.setProxListening(newState != DozeMachine.State.DOZE); mDozeSensors.setListening(true); if (oldState != DozeMachine.State.INITIALIZED) { mDozeSensors.reregisterAllSensors(); } break; + case DOZE_PULSING: + mDozeSensors.setProxListening(true); + break; case FINISH: mBroadcastReceiver.unregister(mContext); mDozeHost.removeCallback(mHostCallback); mDozeSensors.setListening(false); + mDozeSensors.setProxListening(false); break; default: } @@ -156,6 +179,7 @@ public class DozeTriggers implements DozeMachine.Part { private void requestPulse(final int reason, boolean performedProxCheck) { Assert.isMainThread(); + mDozeHost.extendPulse(); if (mPulsePending || !mAllowPulseTriggers || !canPulse()) { return; } @@ -286,6 +310,8 @@ public class DozeTriggers implements DozeMachine.Part { } private class TriggerReceiver extends BroadcastReceiver { + private boolean mRegistered; + @Override public void onReceive(Context context, Intent intent) { if (PULSE_ACTION.equals(intent.getAction())) { @@ -301,14 +327,22 @@ public class DozeTriggers implements DozeMachine.Part { } public void register(Context context) { + if (mRegistered) { + return; + } IntentFilter filter = new IntentFilter(PULSE_ACTION); filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE); filter.addAction(Intent.ACTION_USER_SWITCHED); context.registerReceiver(this, filter); + mRegistered = true; } public void unregister(Context context) { + if (!mRegistered) { + return; + } context.unregisterReceiver(this); + mRegistered = false; } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index f577654c724c3..6098a20a0c648 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -75,11 +75,14 @@ public class DozeUi implements DozeMachine.Part { scheduleTimeTick(); break; case DOZE: + case DOZE_AOD_PAUSED: unscheduleTimeTick(); break; case DOZE_REQUEST_PULSE: pulseWhileDozing(DozeLog.PULSE_REASON_NOTIFICATION /* TODO */); break; + case DOZE_PULSE_DONE: + mHost.abortPulsing(); case INITIALIZED: mHost.startDozing(); break; 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 c3f8d9711b9c2..40776ea92db79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -158,6 +158,10 @@ public class DozeParameters { return sPickupSubtypePerformsProxMatcher.isIn(subType); } + public int getPulseVisibleDurationExtended() { + return 2 * getPulseVisibleDuration(); + } + /** * Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java index b78f7482b9f38..c5f23c5e066ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java @@ -30,6 +30,7 @@ import com.android.keyguard.KeyguardStatusView; import com.android.systemui.Interpolators; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; +import com.android.systemui.doze.DozeTriggers; /** * Controller which handles all the doze animations of the scrims. @@ -43,8 +44,6 @@ public class DozeScrimController { private final ScrimController mScrimController; private final Context mContext; - private final View mStackScroller; - private final NotificationPanelView mNotificationPanelView; private boolean mDozing; private DozeHost.PulseCallback mPulseCallback; @@ -53,24 +52,22 @@ public class DozeScrimController { private Animator mBehindAnimator; private float mInFrontTarget; private float mBehindTarget; + private boolean mDozingAborted; - public DozeScrimController(ScrimController scrimController, Context context, - View stackScroller, NotificationPanelView notificationPanelView) { + public DozeScrimController(ScrimController scrimController, Context context) { mContext = context; - mStackScroller = stackScroller; mScrimController = scrimController; mDozeParameters = new DozeParameters(context); - mNotificationPanelView = notificationPanelView; } public void setDozing(boolean dozing, boolean animate) { if (mDozing == dozing) return; mDozing = dozing; if (mDozing) { + mDozingAborted = false; abortAnimations(); mScrimController.setDozeBehindAlpha(1f); mScrimController.setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? 0f : 1f); - mNotificationPanelView.setDark(true); } else { cancelPulsing(); if (animate) { @@ -85,8 +82,6 @@ public class DozeScrimController { mScrimController.setDozeBehindAlpha(0f); mScrimController.setDozeInFrontAlpha(0f); } - // TODO: animate - mNotificationPanelView.setDark(false); } } @@ -116,10 +111,19 @@ public class DozeScrimController { cancelPulsing(); if (mDozing) { mScrimController.setDozeBehindAlpha(1f); - mScrimController.setDozeInFrontAlpha(1f); + mScrimController.setDozeInFrontAlpha( + mDozeParameters.getAlwaysOn() && !mDozingAborted ? 0f : 1f); } } + /** + * Aborts dozing immediately. + */ + public void abortDoze() { + mDozingAborted = true; + abortPulsing(); + } + public void onScreenTurnedOn() { if (isPulsing()) { final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP @@ -139,12 +143,17 @@ public class DozeScrimController { return mDozing; } + public void extendPulse() { + mHandler.removeCallbacks(mPulseOut); + } + private void cancelPulsing() { if (DEBUG) Log.d(TAG, "Cancel pulsing"); if (mPulseCallback != null) { mHandler.removeCallbacks(mPulseIn); mHandler.removeCallbacks(mPulseOut); + mHandler.removeCallbacks(mPulseOutExtended); pulseFinished(); } } @@ -271,12 +280,23 @@ public class DozeScrimController { if (DEBUG) Log.d(TAG, "Pulse in finished, mDozing=" + mDozing); if (!mDozing) return; mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration()); + mHandler.postDelayed(mPulseOutExtended, + mDozeParameters.getPulseVisibleDurationExtended()); + } + }; + + private final Runnable mPulseOutExtended = new Runnable() { + @Override + public void run() { + mHandler.removeCallbacks(mPulseOut); + mPulseOut.run(); } }; private final Runnable mPulseOut = new Runnable() { @Override public void run() { + mHandler.removeCallbacks(mPulseOutExtended); if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing); if (!mDozing) return; startScrimAnimation(true /* inFront */, mDozeParameters.getAlwaysOn() ? 0 : 1, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java index 2bb3cbc31cebb..92069142a61fa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java @@ -221,7 +221,7 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback { case MODE_WAKE_AND_UNLOCK: Trace.beginSection("MODE_WAKE_AND_UNLOCK"); mStatusBarWindowManager.setStatusBarFocusable(false); - mDozeScrimController.abortPulsing(); + mDozeScrimController.abortDoze(); mKeyguardViewMediator.onWakeAndUnlocking(); mScrimController.setWakeAndUnlocking(); if (mStatusBar.getNavigationBarView() != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index d3cb6a4a87826..fbf53e396b3cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -1114,8 +1114,7 @@ public class StatusBar extends SystemUI implements DemoMode, } mHeadsUpManager.addListener(mScrimController); mStackScroller.setScrimController(mScrimController); - mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller, - mNotificationPanel); + mDozeScrimController = new DozeScrimController(mScrimController, context); // Other icons mVolumeComponent = getComponent(VolumeComponent.class); @@ -4332,6 +4331,7 @@ public class StatusBar extends SystemUI implements DemoMode, mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation); mScrimController.setDozing(mDozing); mKeyguardIndicationController.setDozing(mDozing); + mNotificationPanel.setDark(mDozing); // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock // for pulsing so the Keyguard fade-out animation scrim can take over. @@ -4958,6 +4958,7 @@ public class StatusBar extends SystemUI implements DemoMode, mDozing = mDozingRequested && mState == StatusBarState.KEYGUARD || mFingerprintUnlockController.getMode() == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; + mStatusBarWindowManager.setDozing(mDozing); updateDozingState(); Trace.endSection(); } @@ -5065,6 +5066,16 @@ public class StatusBar extends SystemUI implements DemoMode, StatusBar.this.startPendingIntentDismissingKeyguard(intent); } + @Override + public void abortPulsing() { + mDozeScrimController.abortPulsing(); + } + + @Override + public void extendPulse() { + mDozeScrimController.extendPulse(); + } + } // Begin Extra BaseStatusBar methods. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index deb0070ccbc01..0326e4025a795 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -118,7 +118,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; } - if (state.keyguardShowing && !state.backdropShowing) { + if (state.keyguardShowing && !state.backdropShowing && !state.dozing) { mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; } else { mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; @@ -357,6 +357,11 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D apply(mCurrentState); } + public void setDozing(boolean dozing) { + mCurrentState.dozing = dozing; + apply(mCurrentState); + } + public void setBarHeight(int barHeight) { mBarHeight = barHeight; apply(mCurrentState); @@ -404,6 +409,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D boolean remoteInputActive; boolean forcePluginOpen; + boolean dozing; private boolean isKeyguardShowingAndNotOccluded() { return keyguardShowing && !keyguardOccluded; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java index 1848d4ea438bf..1a09d75be6325 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java @@ -255,6 +255,9 @@ public class StatusBarWindowView extends FrameLayout { if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { mStackScrollLayout.closeControlsIfOutsideTouch(ev); } + if (mService.isDozing()) { + mService.mDozeScrimController.extendPulse(); + } return super.dispatchTouchEvent(ev); }