Merge "Check sleep reason and time before cancelling vibrations" into tm-dev

This commit is contained in:
TreeHugger Robot
2022-05-16 22:02:05 +00:00
committed by Android (Google) Code Review
9 changed files with 246 additions and 74 deletions

View File

@@ -463,21 +463,22 @@ public final class PowerManager {
/** /**
* @hide * @hide
*/ */
public static String sleepReasonToString(int sleepReason) { public static String sleepReasonToString(@GoToSleepReason int sleepReason) {
switch (sleepReason) { switch (sleepReason) {
case GO_TO_SLEEP_REASON_ACCESSIBILITY: return "accessibility";
case GO_TO_SLEEP_REASON_APPLICATION: return "application"; case GO_TO_SLEEP_REASON_APPLICATION: return "application";
case GO_TO_SLEEP_REASON_DEVICE_ADMIN: return "device_admin"; case GO_TO_SLEEP_REASON_DEVICE_ADMIN: return "device_admin";
case GO_TO_SLEEP_REASON_TIMEOUT: return "timeout"; case GO_TO_SLEEP_REASON_DEVICE_FOLD: return "device_folded";
case GO_TO_SLEEP_REASON_LID_SWITCH: return "lid_switch";
case GO_TO_SLEEP_REASON_POWER_BUTTON: return "power_button";
case GO_TO_SLEEP_REASON_HDMI: return "hdmi";
case GO_TO_SLEEP_REASON_SLEEP_BUTTON: return "sleep_button";
case GO_TO_SLEEP_REASON_ACCESSIBILITY: return "accessibility";
case GO_TO_SLEEP_REASON_FORCE_SUSPEND: return "force_suspend";
case GO_TO_SLEEP_REASON_INATTENTIVE: return "inattentive";
case GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED: return "display_group_removed"; case GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED: return "display_group_removed";
case GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF: return "display_groups_turned_off"; case GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF: return "display_groups_turned_off";
case GO_TO_SLEEP_REASON_DEVICE_FOLD: return "device_folded"; case GO_TO_SLEEP_REASON_FORCE_SUSPEND: return "force_suspend";
case GO_TO_SLEEP_REASON_HDMI: return "hdmi";
case GO_TO_SLEEP_REASON_INATTENTIVE: return "inattentive";
case GO_TO_SLEEP_REASON_LID_SWITCH: return "lid_switch";
case GO_TO_SLEEP_REASON_POWER_BUTTON: return "power_button";
case GO_TO_SLEEP_REASON_QUIESCENT: return "quiescent";
case GO_TO_SLEEP_REASON_SLEEP_BUTTON: return "sleep_button";
case GO_TO_SLEEP_REASON_TIMEOUT: return "timeout";
default: return Integer.toString(sleepReason); default: return Integer.toString(sleepReason);
} }
} }
@@ -576,18 +577,20 @@ public final class PowerManager {
* @hide * @hide
*/ */
@IntDef(prefix = { "GO_TO_SLEEP_REASON_" }, value = { @IntDef(prefix = { "GO_TO_SLEEP_REASON_" }, value = {
GO_TO_SLEEP_REASON_ACCESSIBILITY,
GO_TO_SLEEP_REASON_APPLICATION, GO_TO_SLEEP_REASON_APPLICATION,
GO_TO_SLEEP_REASON_DEVICE_ADMIN, GO_TO_SLEEP_REASON_DEVICE_ADMIN,
GO_TO_SLEEP_REASON_TIMEOUT, GO_TO_SLEEP_REASON_DEVICE_FOLD,
GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED,
GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF,
GO_TO_SLEEP_REASON_FORCE_SUSPEND,
GO_TO_SLEEP_REASON_HDMI,
GO_TO_SLEEP_REASON_INATTENTIVE,
GO_TO_SLEEP_REASON_LID_SWITCH, GO_TO_SLEEP_REASON_LID_SWITCH,
GO_TO_SLEEP_REASON_POWER_BUTTON, GO_TO_SLEEP_REASON_POWER_BUTTON,
GO_TO_SLEEP_REASON_HDMI,
GO_TO_SLEEP_REASON_SLEEP_BUTTON,
GO_TO_SLEEP_REASON_ACCESSIBILITY,
GO_TO_SLEEP_REASON_FORCE_SUSPEND,
GO_TO_SLEEP_REASON_INATTENTIVE,
GO_TO_SLEEP_REASON_QUIESCENT, GO_TO_SLEEP_REASON_QUIESCENT,
GO_TO_SLEEP_REASON_DEVICE_FOLD GO_TO_SLEEP_REASON_SLEEP_BUTTON,
GO_TO_SLEEP_REASON_TIMEOUT,
}) })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface GoToSleepReason{} public @interface GoToSleepReason{}
@@ -704,6 +707,8 @@ public final class PowerManager {
} }
/** /**
* Information related to the device waking up, triggered by {@link #wakeUp}.
*
* @hide * @hide
*/ */
public static class WakeData { public static class WakeData {
@@ -712,9 +717,9 @@ public final class PowerManager {
this.wakeReason = wakeReason; this.wakeReason = wakeReason;
this.sleepDuration = sleepDuration; this.sleepDuration = sleepDuration;
} }
public long wakeTime; public final long wakeTime;
public @WakeReason int wakeReason; public final @WakeReason int wakeReason;
public long sleepDuration; public final long sleepDuration;
@Override @Override
public boolean equals(@Nullable Object o) { public boolean equals(@Nullable Object o) {
@@ -732,6 +737,35 @@ public final class PowerManager {
} }
} }
/**
* Information related to the device going to sleep, triggered by {@link #goToSleep}.
*
* @hide
*/
public static class SleepData {
public SleepData(long goToSleepUptimeMillis, @GoToSleepReason int goToSleepReason) {
this.goToSleepUptimeMillis = goToSleepUptimeMillis;
this.goToSleepReason = goToSleepReason;
}
public final long goToSleepUptimeMillis;
public final @GoToSleepReason int goToSleepReason;
@Override
public boolean equals(@Nullable Object o) {
if (o instanceof SleepData) {
final SleepData other = (SleepData) o;
return goToSleepUptimeMillis == other.goToSleepUptimeMillis
&& goToSleepReason == other.goToSleepReason;
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(goToSleepUptimeMillis, goToSleepReason);
}
}
/** /**
* The value to pass as the 'reason' argument to reboot() to reboot into * The value to pass as the 'reason' argument to reboot() to reboot into
* recovery mode for tasks other than applying system updates, such as * recovery mode for tasks other than applying system updates, such as
@@ -2644,6 +2678,7 @@ public final class PowerManager {
* *
* @hide * @hide
*/ */
@GoToSleepReason
public int getLastSleepReason() { public int getLastSleepReason() {
try { try {
return mService.getLastSleepReason(); return mService.getLastSleepReason();

View File

@@ -330,6 +330,9 @@ public abstract class PowerManagerInternal {
/** Returns information about the last wakeup event. */ /** Returns information about the last wakeup event. */
public abstract PowerManager.WakeData getLastWakeup(); public abstract PowerManager.WakeData getLastWakeup();
/** Returns information about the last event to go to sleep. */
public abstract PowerManager.SleepData getLastGoToSleep();
/** Allows power button to intercept a power key button press. */ /** Allows power button to intercept a power key button press. */
public abstract boolean interceptPowerKeyDown(KeyEvent event); public abstract boolean interceptPowerKeyDown(KeyEvent event);
} }

View File

@@ -86,7 +86,7 @@ message VibrationAttributesProto {
optional int32 flags = 3; optional int32 flags = 3;
} }
// Next id: 7 // Next id: 8
message VibrationProto { message VibrationProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC; option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional int64 start_time = 1; optional int64 start_time = 1;
@@ -95,6 +95,7 @@ message VibrationProto {
optional CombinedVibrationEffectProto original_effect = 4; optional CombinedVibrationEffectProto original_effect = 4;
optional VibrationAttributesProto attributes = 5; optional VibrationAttributesProto attributes = 5;
optional int32 status = 6; optional int32 status = 6;
optional int64 duration_ms = 7;
} }
// Next id: 25 // Next id: 25

View File

@@ -72,8 +72,8 @@ import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.ParcelDuration; import android.os.ParcelDuration;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.PowerManager.GoToSleepReason;
import android.os.PowerManager.ServiceType; import android.os.PowerManager.ServiceType;
import android.os.PowerManager.WakeData;
import android.os.PowerManager.WakeReason; import android.os.PowerManager.WakeReason;
import android.os.PowerManagerInternal; import android.os.PowerManagerInternal;
import android.os.PowerSaveState; import android.os.PowerSaveState;
@@ -352,7 +352,7 @@ public final class PowerManagerService extends SystemService
// Last reason the device went to sleep. // Last reason the device went to sleep.
private @WakeReason int mLastGlobalWakeReason; private @WakeReason int mLastGlobalWakeReason;
private int mLastGlobalSleepReason; private @GoToSleepReason int mLastGlobalSleepReason;
// Timestamp of last time power boost interaction was sent. // Timestamp of last time power boost interaction was sent.
private long mLastInteractivePowerHintTime; private long mLastInteractivePowerHintTime;
@@ -6350,20 +6350,26 @@ public final class PowerManagerService extends SystemService
} }
} }
@GoToSleepReason
private int getLastSleepReasonInternal() { private int getLastSleepReasonInternal() {
synchronized (mLock) { synchronized (mLock) {
return mLastGlobalSleepReason; return mLastGlobalSleepReason;
} }
} }
@VisibleForTesting
private PowerManager.WakeData getLastWakeupInternal() { private PowerManager.WakeData getLastWakeupInternal() {
synchronized (mLock) { synchronized (mLock) {
return new WakeData(mLastGlobalWakeTime, mLastGlobalWakeReason, return new PowerManager.WakeData(mLastGlobalWakeTime, mLastGlobalWakeReason,
mLastGlobalWakeTime - mLastGlobalSleepTime); mLastGlobalWakeTime - mLastGlobalSleepTime);
} }
} }
private PowerManager.SleepData getLastGoToSleepInternal() {
synchronized (mLock) {
return new PowerManager.SleepData(mLastGlobalSleepTime, mLastGlobalSleepReason);
}
}
/** /**
* If the user presses power while the proximity sensor is enabled and keeping * If the user presses power while the proximity sensor is enabled and keeping
* the screen off, then turn the screen back on by telling display manager to * the screen off, then turn the screen back on by telling display manager to
@@ -6528,10 +6534,15 @@ public final class PowerManagerService extends SystemService
} }
@Override @Override
public WakeData getLastWakeup() { public PowerManager.WakeData getLastWakeup() {
return getLastWakeupInternal(); return getLastWakeupInternal();
} }
@Override
public PowerManager.SleepData getLastGoToSleep() {
return getLastGoToSleepInternal();
}
@Override @Override
public boolean interceptPowerKeyDown(KeyEvent event) { public boolean interceptPowerKeyDown(KeyEvent event) {
return interceptPowerKeyDownInternal(event); return interceptPowerKeyDownInternal(event);

View File

@@ -71,8 +71,8 @@ final class Vibration {
IGNORED_SUPERSEDED, IGNORED_SUPERSEDED,
} }
/** Start time in CLOCK_BOOTTIME base. */ /** Start time using {@link SystemClock#uptimeMillis()}, for calculations. */
public final long startTime; public final long startUptimeMillis;
public final VibrationAttributes attrs; public final VibrationAttributes attrs;
public final long id; public final long id;
public final int uid; public final int uid;
@@ -94,11 +94,14 @@ final class Vibration {
/** /**
* Start/end times in unix epoch time. Only to be used for debugging purposes and to correlate * Start/end times in unix epoch time. Only to be used for debugging purposes and to correlate
* with other system events, any duration calculations should be done use {@link #startTime} so * with other system events, any duration calculations should be done use
* as not to be affected by discontinuities created by RTC adjustments. * {@link #startUptimeMillis} so as not to be affected by discontinuities created by RTC
* adjustments.
*/ */
private final long mStartTimeDebug; private final long mStartTimeDebug;
private long mEndTimeDebug; private long mEndTimeDebug;
/** End time using {@link SystemClock#uptimeMillis()}, for calculations. */
private long mEndUptimeMillis;
private Status mStatus; private Status mStatus;
/** A {@link CountDownLatch} to enable waiting for completion. */ /** A {@link CountDownLatch} to enable waiting for completion. */
@@ -109,7 +112,7 @@ final class Vibration {
this.token = token; this.token = token;
this.mEffect = effect; this.mEffect = effect;
this.id = id; this.id = id;
this.startTime = SystemClock.elapsedRealtime(); this.startUptimeMillis = SystemClock.uptimeMillis();
this.attrs = attrs; this.attrs = attrs;
this.uid = uid; this.uid = uid;
this.opPkg = opPkg; this.opPkg = opPkg;
@@ -131,6 +134,7 @@ final class Vibration {
return; return;
} }
mStatus = status; mStatus = status;
mEndUptimeMillis = SystemClock.uptimeMillis();
mEndTimeDebug = System.currentTimeMillis(); mEndTimeDebug = System.currentTimeMillis();
mCompletionLatch.countDown(); mCompletionLatch.countDown();
} }
@@ -225,15 +229,17 @@ final class Vibration {
/** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */ /** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */
public Vibration.DebugInfo getDebugInfo() { public Vibration.DebugInfo getDebugInfo() {
long durationMs = hasEnded() ? mEndUptimeMillis - startUptimeMillis : -1;
return new Vibration.DebugInfo( return new Vibration.DebugInfo(
mStartTimeDebug, mEndTimeDebug, mEffect, mOriginalEffect, /* scale= */ 0, attrs, mStartTimeDebug, mEndTimeDebug, durationMs, mEffect, mOriginalEffect,
uid, opPkg, reason, mStatus); /* scale= */ 0, attrs, uid, opPkg, reason, mStatus);
} }
/** Debug information about vibrations. */ /** Debug information about vibrations. */
static final class DebugInfo { static final class DebugInfo {
private final long mStartTimeDebug; private final long mStartTimeDebug;
private final long mEndTimeDebug; private final long mEndTimeDebug;
private final long mDurationMs;
private final CombinedVibration mEffect; private final CombinedVibration mEffect;
private final CombinedVibration mOriginalEffect; private final CombinedVibration mOriginalEffect;
private final float mScale; private final float mScale;
@@ -243,11 +249,12 @@ final class Vibration {
private final String mReason; private final String mReason;
private final Status mStatus; private final Status mStatus;
DebugInfo(long startTimeDebug, long endTimeDebug, CombinedVibration effect, DebugInfo(long startTimeDebug, long endTimeDebug, long durationMs,
CombinedVibration originalEffect, float scale, VibrationAttributes attrs, CombinedVibration effect, CombinedVibration originalEffect, float scale,
int uid, String opPkg, String reason, Status status) { VibrationAttributes attrs, int uid, String opPkg, String reason, Status status) {
mStartTimeDebug = startTimeDebug; mStartTimeDebug = startTimeDebug;
mEndTimeDebug = endTimeDebug; mEndTimeDebug = endTimeDebug;
mDurationMs = durationMs;
mEffect = effect; mEffect = effect;
mOriginalEffect = originalEffect; mOriginalEffect = originalEffect;
mScale = scale; mScale = scale;
@@ -266,6 +273,8 @@ final class Vibration {
.append(", endTime: ") .append(", endTime: ")
.append(mEndTimeDebug == 0 ? null .append(mEndTimeDebug == 0 ? null
: DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug))) : DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug)))
.append(", durationMs: ")
.append(mDurationMs)
.append(", status: ") .append(", status: ")
.append(mStatus.name().toLowerCase()) .append(mStatus.name().toLowerCase())
.append(", effect: ") .append(", effect: ")
@@ -290,6 +299,7 @@ final class Vibration {
final long token = proto.start(fieldId); final long token = proto.start(fieldId);
proto.write(VibrationProto.START_TIME, mStartTimeDebug); proto.write(VibrationProto.START_TIME, mStartTimeDebug);
proto.write(VibrationProto.END_TIME, mEndTimeDebug); proto.write(VibrationProto.END_TIME, mEndTimeDebug);
proto.write(VibrationProto.DURATION_MS, mDurationMs);
proto.write(VibrationProto.STATUS, mStatus.ordinal()); proto.write(VibrationProto.STATUS, mStatus.ordinal());
final long attrsToken = proto.start(VibrationProto.ATTRIBUTES); final long attrsToken = proto.start(VibrationProto.ATTRIBUTES);

View File

@@ -52,6 +52,7 @@ import android.os.Vibrator;
import android.os.Vibrator.VibrationIntensity; import android.os.Vibrator.VibrationIntensity;
import android.os.vibrator.VibrationConfig; import android.os.vibrator.VibrationConfig;
import android.provider.Settings; import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream;
@@ -121,6 +122,19 @@ final class VibrationSettings {
USAGE_PHYSICAL_EMULATION, USAGE_PHYSICAL_EMULATION,
USAGE_HARDWARE_FEEDBACK)); USAGE_HARDWARE_FEEDBACK));
/**
* Set of reasons for {@link PowerManager} going to sleep events that allows vibrations to
* continue running.
*
* <p>Some examples are timeout and inattentive, which indicates automatic screen off events.
* When a vibration is playing during one of these screen off events then it will not be
* cancelled by the service.
*/
private static final Set<Integer> POWER_MANAGER_SLEEP_REASON_ALLOWLIST = new HashSet<>(
Arrays.asList(
PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT));
private static final IntentFilter USER_SWITCHED_INTENT_FILTER = private static final IntentFilter USER_SWITCHED_INTENT_FILTER =
new IntentFilter(Intent.ACTION_USER_SWITCHED); new IntentFilter(Intent.ACTION_USER_SWITCHED);
private static final IntentFilter INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER = private static final IntentFilter INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER =
@@ -135,7 +149,8 @@ final class VibrationSettings {
private final Object mLock = new Object(); private final Object mLock = new Object();
private final Context mContext; private final Context mContext;
private final String mSystemUiPackage; private final String mSystemUiPackage;
private final SettingsContentObserver mSettingObserver; @VisibleForTesting
final SettingsContentObserver mSettingObserver;
@VisibleForTesting @VisibleForTesting
final UidObserver mUidObserver; final UidObserver mUidObserver;
@VisibleForTesting @VisibleForTesting
@@ -150,6 +165,9 @@ final class VibrationSettings {
@GuardedBy("mLock") @GuardedBy("mLock")
@Nullable @Nullable
private AudioManager mAudioManager; private AudioManager mAudioManager;
@GuardedBy("mLock")
@Nullable
private PowerManagerInternal mPowerManagerInternal;
@GuardedBy("mLock") @GuardedBy("mLock")
private boolean mVibrateInputDevices; private boolean mVibrateInputDevices;
@@ -199,10 +217,16 @@ final class VibrationSettings {
} }
public void onSystemReady() { public void onSystemReady() {
PowerManagerInternal pm = LocalServices.getService(PowerManagerInternal.class);
AudioManager am = mContext.getSystemService(AudioManager.class);
int ringerMode = am.getRingerModeInternal();
synchronized (mLock) { synchronized (mLock) {
mAudioManager = mContext.getSystemService(AudioManager.class); mPowerManagerInternal = pm;
mRingerMode = mAudioManager.getRingerModeInternal(); mAudioManager = am;
mRingerMode = ringerMode;
} }
try { try {
ActivityManager.getService().registerUidObserver(mUidObserver, ActivityManager.getService().registerUidObserver(mUidObserver,
ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
@@ -211,7 +235,6 @@ final class VibrationSettings {
// ignored; both services live in system_server // ignored; both services live in system_server
} }
PowerManagerInternal pm = LocalServices.getService(PowerManagerInternal.class);
pm.registerLowPowerModeObserver( pm.registerLowPowerModeObserver(
new PowerManagerInternal.LowPowerModeListener() { new PowerManagerInternal.LowPowerModeListener() {
@Override @Override
@@ -381,7 +404,27 @@ final class VibrationSettings {
* @return true if the vibration should be cancelled when the screen goes off, false otherwise. * @return true if the vibration should be cancelled when the screen goes off, false otherwise.
*/ */
public boolean shouldCancelVibrationOnScreenOff(int uid, String opPkg, public boolean shouldCancelVibrationOnScreenOff(int uid, String opPkg,
@VibrationAttributes.Usage int usage) { @VibrationAttributes.Usage int usage, long vibrationStartUptimeMillis) {
PowerManagerInternal pm;
synchronized (mLock) {
pm = mPowerManagerInternal;
}
if (pm != null) {
// The SleepData from PowerManager may refer to a more recent sleep than the broadcast
// that triggered this method call. That's ok because only automatic sleeps would be
// ignored here and not cancel a vibration, and those are usually triggered by timeout
// or inactivity, so it's unlikely that it will override a more active goToSleep reason.
PowerManager.SleepData sleepData = pm.getLastGoToSleep();
if ((sleepData.goToSleepUptimeMillis < vibrationStartUptimeMillis)
|| POWER_MANAGER_SLEEP_REASON_ALLOWLIST.contains(sleepData.goToSleepReason)) {
// Ignore screen off events triggered before the vibration started, and all
// automatic "go to sleep" events from allowlist.
Slog.d(TAG, "Ignoring screen off event triggered at uptime "
+ sleepData.goToSleepUptimeMillis + " for reason "
+ PowerManager.sleepReasonToString(sleepData.goToSleepReason));
return false;
}
}
if (!SYSTEM_VIBRATION_SCREEN_OFF_USAGE_ALLOWLIST.contains(usage)) { if (!SYSTEM_VIBRATION_SCREEN_OFF_USAGE_ALLOWLIST.contains(usage)) {
// Usages not allowed even for system vibrations should always be cancelled. // Usages not allowed even for system vibrations should always be cancelled.
return true; return true;
@@ -628,7 +671,8 @@ final class VibrationSettings {
} }
/** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */ /** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */
private final class SettingsContentObserver extends ContentObserver { @VisibleForTesting
final class SettingsContentObserver extends ContentObserver {
SettingsContentObserver(Handler handler) { SettingsContentObserver(Handler handler) {
super(handler); super(handler);
} }

View File

@@ -47,6 +47,7 @@ import android.os.ResultReceiver;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.ShellCallback; import android.os.ShellCallback;
import android.os.ShellCommand; import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.Trace; import android.os.Trace;
import android.os.VibrationAttributes; import android.os.VibrationAttributes;
import android.os.VibrationEffect; import android.os.VibrationEffect;
@@ -405,7 +406,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) { if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) {
// Force update of user settings before checking if this vibration effect should // Force update of user settings before checking if this vibration effect should
// be ignored or scaled. // be ignored or scaled.
mVibrationSettings.update(); mVibrationSettings.mSettingObserver.onChange(false);
} }
synchronized (mLock) { synchronized (mLock) {
@@ -1103,7 +1104,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
} }
Vibration vib = conductor.getVibration(); Vibration vib = conductor.getVibration();
return mVibrationSettings.shouldCancelVibrationOnScreenOff( return mVibrationSettings.shouldCancelVibrationOnScreenOff(
vib.uid, vib.opPkg, vib.attrs.getUsage()); vib.uid, vib.opPkg, vib.attrs.getUsage(), vib.startUptimeMillis);
} }
@GuardedBy("mLock") @GuardedBy("mLock")
@@ -1308,13 +1309,17 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
public final ExternalVibration externalVibration; public final ExternalVibration externalVibration;
public int scale; public int scale;
private final long mStartUptimeMillis;
private final long mStartTimeDebug; private final long mStartTimeDebug;
private long mEndUptimeMillis;
private long mEndTimeDebug; private long mEndTimeDebug;
private Vibration.Status mStatus; private Vibration.Status mStatus;
private ExternalVibrationHolder(ExternalVibration externalVibration) { private ExternalVibrationHolder(ExternalVibration externalVibration) {
this.externalVibration = externalVibration; this.externalVibration = externalVibration;
this.scale = IExternalVibratorService.SCALE_NONE; this.scale = IExternalVibratorService.SCALE_NONE;
mStartUptimeMillis = SystemClock.uptimeMillis();
mStartTimeDebug = System.currentTimeMillis(); mStartTimeDebug = System.currentTimeMillis();
mStatus = Vibration.Status.RUNNING; mStatus = Vibration.Status.RUNNING;
} }
@@ -1325,6 +1330,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
return; return;
} }
mStatus = status; mStatus = status;
mEndUptimeMillis = SystemClock.uptimeMillis();
mEndTimeDebug = System.currentTimeMillis(); mEndTimeDebug = System.currentTimeMillis();
} }
@@ -1341,11 +1347,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
} }
public Vibration.DebugInfo getDebugInfo() { public Vibration.DebugInfo getDebugInfo() {
long durationMs = mEndUptimeMillis == 0 ? -1 : mEndUptimeMillis - mStartUptimeMillis;
return new Vibration.DebugInfo( return new Vibration.DebugInfo(
mStartTimeDebug, mEndTimeDebug, /* effect= */ null, /* originalEffect= */ null, mStartTimeDebug, mEndTimeDebug, durationMs,
scale, externalVibration.getVibrationAttributes(), /* effect= */ null, /* originalEffect= */ null, scale,
externalVibration.getUid(), externalVibration.getPackage(), externalVibration.getVibrationAttributes(), externalVibration.getUid(),
/* reason= */ null, mStatus); externalVibration.getPackage(), /* reason= */ null, mStatus);
} }
} }

View File

@@ -277,6 +277,6 @@ public class VibrationScalerTest {
Settings.System.putIntForUser( Settings.System.putIntForUser(
mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT); mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
// FakeSettingsProvider don't support testing triggering ContentObserver yet. // FakeSettingsProvider don't support testing triggering ContentObserver yet.
mVibrationSettings.update(); mVibrationSettings.mSettingObserver.onChange(false);
} }
} }

View File

@@ -54,6 +54,7 @@ import android.content.Intent;
import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal;
import android.media.AudioManager; import android.media.AudioManager;
import android.os.Handler; import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManagerInternal; import android.os.PowerManagerInternal;
import android.os.PowerSaveState; import android.os.PowerSaveState;
import android.os.Process; import android.os.Process;
@@ -146,6 +147,8 @@ public class VibrationSettingsTest {
mVibrationSettings = new VibrationSettings(mContextSpy, mVibrationSettings = new VibrationSettings(mContextSpy,
new Handler(mTestLooper.getLooper()), mVibrationConfigMock); new Handler(mTestLooper.getLooper()), mVibrationConfigMock);
mockGoToSleep(/* goToSleepTime= */ 0, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
// Simulate System defaults. // Simulate System defaults.
setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 1); setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 1);
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0); setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0);
@@ -164,18 +167,10 @@ public class VibrationSettingsTest {
public void addListener_settingsChangeTriggerListener() { public void addListener_settingsChangeTriggerListener() {
mVibrationSettings.addListener(mListenerMock); mVibrationSettings.addListener(mListenerMock);
setUserSetting(Settings.System.VIBRATE_INPUT_DEVICES, 1); mVibrationSettings.mSettingObserver.onChange(false);
setUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 0); mVibrationSettings.mSettingObserver.onChange(false);
setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0);
setUserSetting(Settings.System.ALARM_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, 0);
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
verify(mListenerMock, times(10)).onChange(); verify(mListenerMock, times(2)).onChange();
} }
@Test @Test
@@ -479,50 +474,112 @@ public class VibrationSettingsTest {
} }
@Test @Test
public void shouldCancelVibrationOnScreenOff_withNonSystemPackageAndUid_returnsAlwaysTrue() { public void shouldCancelVibrationOnScreenOff_withEventBeforeVibration_returnsAlwaysFalse() {
long vibrateStartTime = 100;
mockGoToSleep(vibrateStartTime - 10, PowerManager.GO_TO_SLEEP_REASON_APPLICATION);
for (int usage : ALL_USAGES) { for (int usage : ALL_USAGES) {
assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff(UID, "some.app", usage)); // Non-system vibration
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
UID, "some.app", usage, vibrateStartTime));
// Vibration with UID zero
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
/* uid= */ 0, "", usage, vibrateStartTime));
// System vibration
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
Process.SYSTEM_UID, "", usage, vibrateStartTime));
// SysUI vibration
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
UID, SYSUI_PACKAGE_NAME, usage, vibrateStartTime));
}
}
@Test
public void shouldCancelVibrationOnScreenOff_withSleepReasonInAllowlist_returnsAlwaysFalse() {
long vibrateStartTime = 100;
int[] allowedSleepReasons = new int[] {
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE,
};
for (int sleepReason : allowedSleepReasons) {
mockGoToSleep(vibrateStartTime + 10, sleepReason);
for (int usage : ALL_USAGES) {
// Non-system vibration
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
UID, "some.app", usage, vibrateStartTime));
// Vibration with UID zero
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
/* uid= */ 0, "", usage, vibrateStartTime));
// System vibration
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
Process.SYSTEM_UID, "", usage, vibrateStartTime));
// SysUI vibration
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
UID, SYSUI_PACKAGE_NAME, usage, vibrateStartTime));
}
}
}
@Test
public void shouldCancelVibrationOnScreenOff_withNonSystem_returnsTrueIfReasonNotInAllowlist() {
long vibrateStartTime = 100;
mockGoToSleep(vibrateStartTime + 10, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON);
for (int usage : ALL_USAGES) {
assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff(
UID, "some.app", usage, vibrateStartTime));
} }
} }
@Test @Test
public void shouldCancelVibrationOnScreenOff_withUidZero_returnsFalseForTouchAndHardware() { public void shouldCancelVibrationOnScreenOff_withUidZero_returnsFalseForTouchAndHardware() {
long vibrateStartTime = 100;
mockGoToSleep(vibrateStartTime + 10, PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
for (int usage : ALL_USAGES) { for (int usage : ALL_USAGES) {
if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK
|| usage == USAGE_PHYSICAL_EMULATION) { || usage == USAGE_PHYSICAL_EMULATION) {
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff( assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
/* uid= */ 0, "", usage)); /* uid= */ 0, "", usage, vibrateStartTime));
} else { } else {
assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff( assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff(
/* uid= */ 0, "", usage)); /* uid= */ 0, "", usage, vibrateStartTime));
} }
} }
} }
@Test @Test
public void shouldCancelVibrationOnScreenOff_withSystemUid_returnsFalseForTouchAndHardware() { public void shouldCancelVibrationOnScreenOff_withSystemUid_returnsFalseForTouchAndHardware() {
long vibrateStartTime = 100;
mockGoToSleep(vibrateStartTime + 10, PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD);
for (int usage : ALL_USAGES) { for (int usage : ALL_USAGES) {
if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK
|| usage == USAGE_PHYSICAL_EMULATION) { || usage == USAGE_PHYSICAL_EMULATION) {
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff( assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
Process.SYSTEM_UID, "", usage)); Process.SYSTEM_UID, "", usage, vibrateStartTime));
} else { } else {
assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff( assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff(
Process.SYSTEM_UID, "", usage)); Process.SYSTEM_UID, "", usage, vibrateStartTime));
} }
} }
} }
@Test @Test
public void shouldCancelVibrationOnScreenOff_withSysUi_returnsFalseForTouchAndHardware() { public void shouldCancelVibrationOnScreenOff_withSysUiPkg_returnsFalseForTouchAndHardware() {
long vibrateStartTime = 100;
mockGoToSleep(vibrateStartTime + 10, PowerManager.GO_TO_SLEEP_REASON_HDMI);
for (int usage : ALL_USAGES) { for (int usage : ALL_USAGES) {
if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK if (usage == USAGE_TOUCH || usage == USAGE_HARDWARE_FEEDBACK
|| usage == USAGE_PHYSICAL_EMULATION) { || usage == USAGE_PHYSICAL_EMULATION) {
assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff( assertFalse(mVibrationSettings.shouldCancelVibrationOnScreenOff(
UID, SYSUI_PACKAGE_NAME, usage)); UID, SYSUI_PACKAGE_NAME, usage, vibrateStartTime));
} else { } else {
assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff( assertTrue(mVibrationSettings.shouldCancelVibrationOnScreenOff(
UID, SYSUI_PACKAGE_NAME, usage)); UID, SYSUI_PACKAGE_NAME, usage, vibrateStartTime));
} }
} }
} }
@@ -581,7 +638,6 @@ public class VibrationSettingsTest {
public void getCurrentIntensity_noHardwareFeedbackValueUsesHapticFeedbackValue() { public void getCurrentIntensity_noHardwareFeedbackValueUsesHapticFeedbackValue() {
setDefaultIntensity(USAGE_HARDWARE_FEEDBACK, VIBRATION_INTENSITY_MEDIUM); setDefaultIntensity(USAGE_HARDWARE_FEEDBACK, VIBRATION_INTENSITY_MEDIUM);
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
mVibrationSettings.update();
assertEquals(VIBRATION_INTENSITY_OFF, mVibrationSettings.getCurrentIntensity(USAGE_TOUCH)); assertEquals(VIBRATION_INTENSITY_OFF, mVibrationSettings.getCurrentIntensity(USAGE_TOUCH));
// If haptic feedback is off, fallback to default value. // If haptic feedback is off, fallback to default value.
assertEquals(VIBRATION_INTENSITY_MEDIUM, assertEquals(VIBRATION_INTENSITY_MEDIUM,
@@ -590,7 +646,6 @@ public class VibrationSettingsTest {
mVibrationSettings.getCurrentIntensity(USAGE_PHYSICAL_EMULATION)); mVibrationSettings.getCurrentIntensity(USAGE_PHYSICAL_EMULATION));
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH); setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH);
mVibrationSettings.update();
assertEquals(VIBRATION_INTENSITY_HIGH, assertEquals(VIBRATION_INTENSITY_HIGH,
mVibrationSettings.getCurrentIntensity(USAGE_TOUCH)); mVibrationSettings.getCurrentIntensity(USAGE_TOUCH));
// If haptic feedback is on, fallback to that value. // If haptic feedback is on, fallback to that value.
@@ -648,19 +703,25 @@ public class VibrationSettingsTest {
Settings.System.putStringForUser( Settings.System.putStringForUser(
mContextSpy.getContentResolver(), settingName, null, UserHandle.USER_CURRENT); mContextSpy.getContentResolver(), settingName, null, UserHandle.USER_CURRENT);
// FakeSettingsProvider doesn't support testing triggering ContentObserver yet. // FakeSettingsProvider doesn't support testing triggering ContentObserver yet.
mVibrationSettings.update(); mVibrationSettings.mSettingObserver.onChange(false);
} }
private void setUserSetting(String settingName, int value) { private void setUserSetting(String settingName, int value) {
Settings.System.putIntForUser( Settings.System.putIntForUser(
mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT); mContextSpy.getContentResolver(), settingName, value, UserHandle.USER_CURRENT);
// FakeSettingsProvider doesn't support testing triggering ContentObserver yet. // FakeSettingsProvider doesn't support testing triggering ContentObserver yet.
mVibrationSettings.update(); mVibrationSettings.mSettingObserver.onChange(false);
} }
private void setRingerMode(int ringerMode) { private void setRingerMode(int ringerMode) {
mAudioManager.setRingerModeInternal(ringerMode); mAudioManager.setRingerModeInternal(ringerMode);
assertEquals(ringerMode, mAudioManager.getRingerModeInternal()); assertEquals(ringerMode, mAudioManager.getRingerModeInternal());
mVibrationSettings.update(); mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
}
private void mockGoToSleep(long sleepTime, int reason) {
when(mPowerManagerInternalMock.getLastGoToSleep()).thenReturn(
new PowerManager.SleepData(sleepTime, reason));
} }
} }