Merge "Ambient: Pulse for every noisy notification exactly once" into nyc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
bd43552975
@@ -218,12 +218,6 @@
|
||||
<!-- Doze: should notifications be used as a pulse signal? -->
|
||||
<bool name="doze_pulse_on_notifications">true</bool>
|
||||
|
||||
<!-- Doze: when to pulse after a buzzworthy notification arrives -->
|
||||
<string name="doze_pulse_schedule" translatable="false">10s,30s,60s</string>
|
||||
|
||||
<!-- Doze: maximum number of times the notification pulse schedule can be reset -->
|
||||
<integer name="doze_pulse_schedule_resets">2</integer>
|
||||
|
||||
<!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
|
||||
<integer name="doze_pickup_vibration_threshold">2000</integer>
|
||||
|
||||
@@ -253,7 +247,7 @@
|
||||
<integer name="doze_pulse_duration_in_pickup">130</integer>
|
||||
|
||||
<!-- Doze: pulse parameter - once faded in, how long does it stay visible? -->
|
||||
<integer name="doze_pulse_duration_visible">3000</integer>
|
||||
<integer name="doze_pulse_duration_visible">6000</integer>
|
||||
|
||||
<!-- Doze: pulse parameter - how long does it take to fade out? -->
|
||||
<integer name="doze_pulse_duration_out">600</integer>
|
||||
|
||||
@@ -33,7 +33,7 @@ public class DozeLog {
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
private static final boolean ENABLED = true;
|
||||
private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
|
||||
private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
|
||||
static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
|
||||
|
||||
private static final int PULSE_REASONS = 4;
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.systemui.doze;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.UiModeManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
@@ -43,7 +41,6 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
||||
import com.android.systemui.SystemUIApplication;
|
||||
import com.android.systemui.statusbar.phone.DozeParameters;
|
||||
import com.android.systemui.statusbar.phone.DozeParameters.PulseSchedule;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -55,19 +52,6 @@ public class DozeService extends DreamService {
|
||||
|
||||
private static final String ACTION_BASE = "com.android.systemui.doze";
|
||||
private static final String PULSE_ACTION = ACTION_BASE + ".pulse";
|
||||
private static final String NOTIFICATION_PULSE_ACTION = ACTION_BASE + ".notification_pulse";
|
||||
private static final String EXTRA_INSTANCE = "instance";
|
||||
|
||||
/**
|
||||
* Earliest time we pulse due to a notification light after the service started.
|
||||
*
|
||||
* <p>Incoming notification light events during the blackout period are
|
||||
* delayed to the earliest time defined by this constant.</p>
|
||||
*
|
||||
* <p>This delay avoids a pulse immediately after screen off, at which
|
||||
* point the notification light is re-enabled again by NoMan.</p>
|
||||
*/
|
||||
private static final int EARLIEST_LIGHT_PULSE_AFTER_START_MS = 10 * 1000;
|
||||
|
||||
private final String mTag = String.format(TAG + ".%08x", hashCode());
|
||||
private final Context mContext = this;
|
||||
@@ -80,19 +64,14 @@ public class DozeService extends DreamService {
|
||||
private TriggerSensor mPickupSensor;
|
||||
private PowerManager mPowerManager;
|
||||
private PowerManager.WakeLock mWakeLock;
|
||||
private AlarmManager mAlarmManager;
|
||||
private UiModeManager mUiModeManager;
|
||||
private boolean mDreaming;
|
||||
private boolean mPulsing;
|
||||
private boolean mBroadcastReceiverRegistered;
|
||||
private boolean mDisplayStateSupported;
|
||||
private boolean mNotificationLightOn;
|
||||
private boolean mPowerSaveActive;
|
||||
private boolean mCarMode;
|
||||
private long mNotificationPulseTime;
|
||||
private long mLastScheduleResetTime;
|
||||
private long mEarliestPulseDueToLight;
|
||||
private int mScheduleResetsRemaining;
|
||||
|
||||
public DozeService() {
|
||||
if (DEBUG) Log.d(mTag, "new DozeService()");
|
||||
@@ -110,11 +89,11 @@ public class DozeService extends DreamService {
|
||||
pw.print(" mSigMotionSensor: "); pw.println(mSigMotionSensor);
|
||||
pw.print(" mPickupSensor:"); pw.println(mPickupSensor);
|
||||
pw.print(" mDisplayStateSupported: "); pw.println(mDisplayStateSupported);
|
||||
pw.print(" mNotificationLightOn: "); pw.println(mNotificationLightOn);
|
||||
pw.print(" mPowerSaveActive: "); pw.println(mPowerSaveActive);
|
||||
pw.print(" mCarMode: "); pw.println(mCarMode);
|
||||
pw.print(" mNotificationPulseTime: "); pw.println(mNotificationPulseTime);
|
||||
pw.print(" mScheduleResetsRemaining: "); pw.println(mScheduleResetsRemaining);
|
||||
pw.print(" mNotificationPulseTime: "); pw.println(
|
||||
DozeLog.FORMAT.format(new Date(mNotificationPulseTime
|
||||
- SystemClock.elapsedRealtime() + System.currentTimeMillis())));
|
||||
mDozeParameters.dump(pw);
|
||||
}
|
||||
|
||||
@@ -141,7 +120,6 @@ public class DozeService extends DreamService {
|
||||
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||
mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
|
||||
mWakeLock.setReferenceCounted(true);
|
||||
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
|
||||
mDisplayStateSupported = mDozeParameters.getDisplayStateSupported();
|
||||
mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
|
||||
turnDisplayOff();
|
||||
@@ -176,8 +154,6 @@ public class DozeService extends DreamService {
|
||||
}
|
||||
|
||||
mDreaming = true;
|
||||
rescheduleNotificationPulse(false /*predicate*/); // cancel any pending pulse alarms
|
||||
mEarliestPulseDueToLight = System.currentTimeMillis() + EARLIEST_LIGHT_PULSE_AFTER_START_MS;
|
||||
listenForPulseSignals(true);
|
||||
|
||||
// Ask the host to get things ready to start dozing.
|
||||
@@ -316,7 +292,6 @@ public class DozeService extends DreamService {
|
||||
private void listenForBroadcasts(boolean listen) {
|
||||
if (listen) {
|
||||
final IntentFilter filter = new IntentFilter(PULSE_ACTION);
|
||||
filter.addAction(NOTIFICATION_PULSE_ACTION);
|
||||
filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE);
|
||||
mContext.registerReceiver(mBroadcastReceiver, filter);
|
||||
mBroadcastReceiverRegistered = true;
|
||||
@@ -330,93 +305,17 @@ public class DozeService extends DreamService {
|
||||
|
||||
private void listenForNotifications(boolean listen) {
|
||||
if (listen) {
|
||||
resetNotificationResets();
|
||||
mHost.addCallback(mHostCallback);
|
||||
|
||||
// Continue to pulse for existing LEDs.
|
||||
mNotificationLightOn = mHost.isNotificationLightOn();
|
||||
if (mNotificationLightOn) {
|
||||
updateNotificationPulseDueToLight();
|
||||
}
|
||||
} else {
|
||||
mHost.removeCallback(mHostCallback);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetNotificationResets() {
|
||||
if (DEBUG) Log.d(mTag, "resetNotificationResets");
|
||||
mScheduleResetsRemaining = mDozeParameters.getPulseScheduleResets();
|
||||
}
|
||||
|
||||
private void updateNotificationPulseDueToLight() {
|
||||
long timeMs = System.currentTimeMillis();
|
||||
timeMs = Math.max(timeMs, mEarliestPulseDueToLight);
|
||||
updateNotificationPulse(timeMs);
|
||||
}
|
||||
|
||||
private void updateNotificationPulse(long notificationTimeMs) {
|
||||
if (DEBUG) Log.d(mTag, "updateNotificationPulse notificationTimeMs=" + notificationTimeMs);
|
||||
private void requestNotificationPulse() {
|
||||
if (DEBUG) Log.d(mTag, "requestNotificationPulse");
|
||||
if (!mDozeParameters.getPulseOnNotifications()) return;
|
||||
if (mScheduleResetsRemaining <= 0) {
|
||||
if (DEBUG) Log.d(mTag, "No more schedule resets remaining");
|
||||
return;
|
||||
}
|
||||
final long pulseDuration = mDozeParameters.getPulseDuration(false /*pickup*/);
|
||||
boolean pulseImmediately = System.currentTimeMillis() >= notificationTimeMs;
|
||||
if ((notificationTimeMs - mLastScheduleResetTime) >= pulseDuration) {
|
||||
mScheduleResetsRemaining--;
|
||||
mLastScheduleResetTime = notificationTimeMs;
|
||||
} else if (!pulseImmediately){
|
||||
if (DEBUG) Log.d(mTag, "Recently updated, not resetting schedule");
|
||||
return;
|
||||
}
|
||||
if (DEBUG) Log.d(mTag, "mScheduleResetsRemaining = " + mScheduleResetsRemaining);
|
||||
mNotificationPulseTime = notificationTimeMs;
|
||||
if (pulseImmediately) {
|
||||
DozeLog.traceNotificationPulse(mContext, 0);
|
||||
requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
|
||||
}
|
||||
// schedule the rest of the pulses
|
||||
rescheduleNotificationPulse(true /*predicate*/);
|
||||
}
|
||||
|
||||
private PendingIntent notificationPulseIntent(long instance) {
|
||||
return PendingIntent.getBroadcast(mContext, 0,
|
||||
new Intent(NOTIFICATION_PULSE_ACTION)
|
||||
.setPackage(getPackageName())
|
||||
.putExtra(EXTRA_INSTANCE, instance)
|
||||
.setFlags(Intent.FLAG_RECEIVER_FOREGROUND),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
private void rescheduleNotificationPulse(boolean predicate) {
|
||||
if (DEBUG) Log.d(mTag, "rescheduleNotificationPulse predicate=" + predicate);
|
||||
final PendingIntent notificationPulseIntent = notificationPulseIntent(0);
|
||||
mAlarmManager.cancel(notificationPulseIntent);
|
||||
if (!predicate) {
|
||||
if (DEBUG) Log.d(mTag, " don't reschedule: predicate is false");
|
||||
return;
|
||||
}
|
||||
final PulseSchedule schedule = mDozeParameters.getPulseSchedule();
|
||||
if (schedule == null) {
|
||||
if (DEBUG) Log.d(mTag, " don't reschedule: schedule is null");
|
||||
return;
|
||||
}
|
||||
final long now = System.currentTimeMillis();
|
||||
final long time = schedule.getNextTime(now, mNotificationPulseTime);
|
||||
if (time <= 0) {
|
||||
if (DEBUG) Log.d(mTag, " don't reschedule: time is " + time);
|
||||
return;
|
||||
}
|
||||
final long delta = time - now;
|
||||
if (delta <= 0) {
|
||||
if (DEBUG) Log.d(mTag, " don't reschedule: delta is " + delta);
|
||||
return;
|
||||
}
|
||||
final long instance = time - mNotificationPulseTime;
|
||||
if (DEBUG) Log.d(mTag, "Scheduling pulse " + instance + " in " + delta + "ms for "
|
||||
+ new Date(time));
|
||||
mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, time, notificationPulseIntent(instance));
|
||||
mNotificationPulseTime = SystemClock.elapsedRealtime();
|
||||
requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
|
||||
}
|
||||
|
||||
private static String triggerEventToString(TriggerEvent event) {
|
||||
@@ -439,13 +338,6 @@ public class DozeService extends DreamService {
|
||||
if (DEBUG) Log.d(mTag, "Received pulse intent");
|
||||
requestPulse(DozeLog.PULSE_REASON_INTENT);
|
||||
}
|
||||
if (NOTIFICATION_PULSE_ACTION.equals(intent.getAction())) {
|
||||
final long instance = intent.getLongExtra(EXTRA_INSTANCE, -1);
|
||||
if (DEBUG) Log.d(mTag, "Received notification pulse intent instance=" + instance);
|
||||
DozeLog.traceNotificationPulse(mContext, instance);
|
||||
requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
|
||||
rescheduleNotificationPulse(mNotificationLightOn);
|
||||
}
|
||||
if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
|
||||
mCarMode = true;
|
||||
if (mCarMode && mDreaming) {
|
||||
@@ -465,17 +357,13 @@ public class DozeService extends DreamService {
|
||||
@Override
|
||||
public void onBuzzBeepBlinked() {
|
||||
if (DEBUG) Log.d(mTag, "onBuzzBeepBlinked");
|
||||
updateNotificationPulse(System.currentTimeMillis());
|
||||
requestNotificationPulse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationLight(boolean on) {
|
||||
if (DEBUG) Log.d(mTag, "onNotificationLight on=" + on);
|
||||
if (mNotificationLightOn == on) return;
|
||||
mNotificationLightOn = on;
|
||||
if (mNotificationLightOn) {
|
||||
updateNotificationPulseDueToLight();
|
||||
}
|
||||
if (DEBUG) Log.d(mTag, "onNotificationLight (noop) on=" + on);
|
||||
// noop for now
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -564,17 +452,12 @@ public class DozeService extends DreamService {
|
||||
requestPulse(mPulseReason, sensorPerformsProxCheck);
|
||||
updateListener(); // reregister, this sensor only fires once
|
||||
|
||||
// reset the notification pulse schedule, but only if we think we were not triggered
|
||||
// by a notification-related vibration
|
||||
final long timeSinceNotification = System.currentTimeMillis()
|
||||
// record pickup gesture, also keep track of whether we might have been triggered
|
||||
// by recent vibration.
|
||||
final long timeSinceNotification = SystemClock.elapsedRealtime()
|
||||
- mNotificationPulseTime;
|
||||
final boolean withinVibrationThreshold =
|
||||
timeSinceNotification < mDozeParameters.getPickupVibrationThreshold();
|
||||
if (withinVibrationThreshold) {
|
||||
if (DEBUG) Log.d(mTag, "Not resetting schedule, recent notification");
|
||||
} else {
|
||||
resetNotificationResets();
|
||||
}
|
||||
if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
|
||||
DozeLog.tracePickupPulse(mContext, withinVibrationThreshold);
|
||||
}
|
||||
|
||||
@@ -38,8 +38,6 @@ public class DozeParameters {
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private static PulseSchedule sPulseSchedule;
|
||||
|
||||
private static IntInOutMatcher sPickupSubtypePerformsProxMatcher;
|
||||
|
||||
public DozeParameters(Context context) {
|
||||
@@ -61,8 +59,6 @@ public class DozeParameters {
|
||||
pw.print(" getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
|
||||
pw.print(" getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
|
||||
pw.print(" getPulseOnNotifications(): "); pw.println(getPulseOnNotifications());
|
||||
pw.print(" getPulseSchedule(): "); pw.println(getPulseSchedule());
|
||||
pw.print(" getPulseScheduleResets(): "); pw.println(getPulseScheduleResets());
|
||||
pw.print(" getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
|
||||
pw.print(" getPickupSubtypePerformsProxCheck(): ");pw.println(
|
||||
dumpPickupSubtypePerformsProxCheck());
|
||||
@@ -126,18 +122,6 @@ public class DozeParameters {
|
||||
return getBoolean("doze.pulse.notifications", R.bool.doze_pulse_on_notifications);
|
||||
}
|
||||
|
||||
public PulseSchedule getPulseSchedule() {
|
||||
final String spec = getString("doze.pulse.schedule", R.string.doze_pulse_schedule);
|
||||
if (sPulseSchedule == null || !sPulseSchedule.mSpec.equals(spec)) {
|
||||
sPulseSchedule = PulseSchedule.parse(spec);
|
||||
}
|
||||
return sPulseSchedule;
|
||||
}
|
||||
|
||||
public int getPulseScheduleResets() {
|
||||
return getInt("doze.pulse.schedule.resets", R.integer.doze_pulse_schedule_resets);
|
||||
}
|
||||
|
||||
public int getPickupVibrationThreshold() {
|
||||
return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold);
|
||||
}
|
||||
@@ -249,44 +233,4 @@ public class DozeParameters {
|
||||
return (mIsIn.get(value, mDefaultIsIn));
|
||||
}
|
||||
}
|
||||
|
||||
public static class PulseSchedule {
|
||||
private static final Pattern PATTERN = Pattern.compile("(\\d+?)s", 0);
|
||||
|
||||
private String mSpec;
|
||||
private int[] mSchedule;
|
||||
|
||||
public static PulseSchedule parse(String spec) {
|
||||
if (TextUtils.isEmpty(spec)) return null;
|
||||
try {
|
||||
final PulseSchedule rt = new PulseSchedule();
|
||||
rt.mSpec = spec;
|
||||
final String[] tokens = spec.split(",");
|
||||
rt.mSchedule = new int[tokens.length];
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
final Matcher m = PATTERN.matcher(tokens[i]);
|
||||
if (!m.matches()) throw new IllegalArgumentException("Bad token: " + tokens[i]);
|
||||
rt.mSchedule[i] = Integer.parseInt(m.group(1));
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "Parsed spec [" + spec + "] as: " + rt);
|
||||
return rt;
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(TAG, "Error parsing spec: " + spec, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Arrays.toString(mSchedule);
|
||||
}
|
||||
|
||||
public long getNextTime(long now, long notificationTime) {
|
||||
for (int i = 0; i < mSchedule.length; i++) {
|
||||
final long time = notificationTime + mSchedule[i] * 1000;
|
||||
if (time > now) return time;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user