diff options
| author | 2022-04-13 22:55:36 +0000 | |
|---|---|---|
| committer | 2022-04-13 22:55:36 +0000 | |
| commit | b89dd9bc78be5d34d768e2ea9853208e06de801a (patch) | |
| tree | 7d6c165670a6de2c03082d3d2564a09419eca884 | |
| parent | 601853b582e700577fb70c5438db23995170ab2e (diff) | |
| parent | 241f728308a869fb61069a5384b9665596cba622 (diff) | |
Merge "Play charging feedback on a background thread" into tm-dev
5 files changed, 89 insertions, 24 deletions
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index aede4b1e2f5d..685b744c8062 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -64,6 +64,8 @@ import com.android.server.policy.WindowManagerPolicy; import com.android.server.statusbar.StatusBarManagerInternal; import java.io.PrintWriter; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; /** * Sends broadcasts about important power state changes. @@ -133,6 +135,7 @@ public class Notifier { private final DisplayManagerInternal mDisplayManagerInternal; private final NotifierHandler mHandler; + private final Executor mBackgroundExecutor; private final Intent mScreenOnIntent; private final Intent mScreenOffIntent; @@ -169,9 +172,12 @@ public class Notifier { // True if a user activity message should be sent. private boolean mUserActivityPending; + private final AtomicBoolean mIsPlayingChargingStartedFeedback = new AtomicBoolean(false); + public Notifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector, + Executor backgroundExecutor) { mContext = context; mBatteryStats = batteryStats; mAppOps = mContext.getSystemService(AppOpsManager.class); @@ -188,6 +194,7 @@ public class Notifier { mVibrator = mContext.getSystemService(Vibrator.class); mHandler = new NotifierHandler(looper); + mBackgroundExecutor = backgroundExecutor; mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON); mScreenOnIntent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND @@ -824,25 +831,36 @@ public class Notifier { return; } - // vibrate - final boolean vibrate = Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0; - if (vibrate) { - mVibrator.vibrate(CHARGING_VIBRATION_EFFECT, HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES); + if (!mIsPlayingChargingStartedFeedback.compareAndSet(false, true)) { + // there's already a charging started feedback Runnable scheduled to run on the + // background thread, so let's not execute another + return; } - // play sound - final String soundPath = Settings.Global.getString(mContext.getContentResolver(), - wireless ? Settings.Global.WIRELESS_CHARGING_STARTED_SOUND - : Settings.Global.CHARGING_STARTED_SOUND); - final Uri soundUri = Uri.parse("file://" + soundPath); - if (soundUri != null) { - final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); - if (sfx != null) { - sfx.setStreamType(AudioManager.STREAM_SYSTEM); - sfx.play(); + // vibrate & play sound on a background thread + mBackgroundExecutor.execute(() -> { + // vibrate + final boolean vibrate = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.CHARGING_VIBRATION_ENABLED, 1, userId) != 0; + if (vibrate) { + mVibrator.vibrate(CHARGING_VIBRATION_EFFECT, + HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES); } - } + + // play sound + final String soundPath = Settings.Global.getString(mContext.getContentResolver(), + wireless ? Settings.Global.WIRELESS_CHARGING_STARTED_SOUND + : Settings.Global.CHARGING_STARTED_SOUND); + final Uri soundUri = Uri.parse("file://" + soundPath); + if (soundUri != null) { + final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri); + if (sfx != null) { + sfx.setStreamType(AudioManager.STREAM_SYSTEM); + sfx.play(); + } + } + mIsPlayingChargingStartedFeedback.set(false); + }); } private void showWirelessChargingStarted(int batteryLevel, @UserIdInt int userId) { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 6e78ecb83005..e0da0e8bdf35 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -140,6 +140,7 @@ import java.util.Arrays; import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.concurrent.Executor; /** * The power manager service is responsible for coordinating power management @@ -905,10 +906,11 @@ public final class PowerManagerService extends SystemService static class Injector { Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector, + Executor backgroundExecutor) { return new Notifier( looper, context, batteryStats, suspendBlocker, policy, faceDownDetector, - screenUndimDetector); + screenUndimDetector, backgroundExecutor); } SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) { @@ -1227,7 +1229,8 @@ public final class PowerManagerService extends SystemService mBatteryStats = BatteryStatsService.getService(); mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats, mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"), - mPolicy, mFaceDownDetector, mScreenUndimDetector); + mPolicy, mFaceDownDetector, mScreenUndimDetector, + BackgroundThread.getExecutor()); mPowerGroups.append(Display.DEFAULT_DISPLAY_GROUP, new PowerGroup(WAKEFULNESS_AWAKE, mPowerGroupWakefulnessChangeListener, diff --git a/services/tests/mockingservicestests/src/com/android/server/power/PowerManagerServiceMockingTest.java b/services/tests/mockingservicestests/src/com/android/server/power/PowerManagerServiceMockingTest.java index 9cf6c0325024..5c4657fb0027 100644 --- a/services/tests/mockingservicestests/src/com/android/server/power/PowerManagerServiceMockingTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/power/PowerManagerServiceMockingTest.java @@ -67,6 +67,8 @@ import com.android.server.power.batterysaver.BatterySaverStateMachine; import com.android.server.power.batterysaver.BatterySavingStats; import com.android.server.testutils.OffsettableClock; +import java.util.concurrent.Executor; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -164,7 +166,8 @@ public class PowerManagerServiceMockingTest { @Override Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector, + Executor executor) { return mNotifierMock; } diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java index a3223d6d2b7b..8f5f0e6fe131 100644 --- a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java +++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java @@ -16,6 +16,8 @@ package com.android.server.power; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -56,6 +58,8 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.concurrent.Executor; + /** * Tests for {@link com.android.server.power.Notifier} */ @@ -79,6 +83,7 @@ public class NotifierTest { private Context mContextSpy; private Resources mResourcesSpy; private TestLooper mTestLooper = new TestLooper(); + private FakeExecutor mTestExecutor = new FakeExecutor(); private Notifier mNotifier; @Before @@ -107,6 +112,7 @@ public class NotifierTest { // WHEN wired charging starts mNotifier.onWiredChargingStarted(USER_ID); mTestLooper.dispatchAll(); + mTestExecutor.simulateAsyncExecutionOfLastCommand(); // THEN the device vibrates once verify(mVibrator, times(1)).vibrate(any(), any(VibrationAttributes.class)); @@ -122,6 +128,7 @@ public class NotifierTest { // WHEN wired charging starts mNotifier.onWiredChargingStarted(USER_ID); mTestLooper.dispatchAll(); + mTestExecutor.simulateAsyncExecutionOfLastCommand(); // THEN the device doesn't vibrate verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class)); @@ -137,6 +144,7 @@ public class NotifierTest { // WHEN wireless charging starts mNotifier.onWirelessChargingStarted(5, USER_ID); mTestLooper.dispatchAll(); + mTestExecutor.simulateAsyncExecutionOfLastCommand(); // THEN the device vibrates once verify(mVibrator, times(1)).vibrate(any(), any(VibrationAttributes.class)); @@ -152,6 +160,7 @@ public class NotifierTest { // WHEN wireless charging starts mNotifier.onWirelessChargingStarted(5, USER_ID); mTestLooper.dispatchAll(); + mTestExecutor.simulateAsyncExecutionOfLastCommand(); // THEN the device doesn't vibrate verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class)); @@ -170,6 +179,7 @@ public class NotifierTest { // WHEN wired charging starts mNotifier.onWiredChargingStarted(USER_ID); mTestLooper.dispatchAll(); + mTestExecutor.simulateAsyncExecutionOfLastCommand(); // THEN the device doesn't vibrate verify(mVibrator, never()).vibrate(any(), any(VibrationAttributes.class)); @@ -186,6 +196,7 @@ public class NotifierTest { // WHEN wireless charging starts mNotifier.onWirelessChargingStarted(5, USER_ID); mTestLooper.dispatchAll(); + mTestExecutor.simulateAsyncExecutionOfLastCommand(); // THEN the charging animation is triggered verify(mStatusBarManagerInternal, times(1)).showChargingAnimation(5); @@ -202,6 +213,7 @@ public class NotifierTest { // WHEN wireless charging starts mNotifier.onWirelessChargingStarted(5, USER_ID); mTestLooper.dispatchAll(); + mTestExecutor.simulateAsyncExecutionOfLastCommand(); // THEN the charging animation never gets called verify(mStatusBarManagerInternal, never()).showChargingAnimation(anyInt()); @@ -211,7 +223,8 @@ public class NotifierTest { @Override Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector, + Executor backgroundExecutor) { return mNotifierMock; } @@ -300,6 +313,32 @@ public class NotifierTest { mInjector.createSuspendBlocker(mService, "testBlocker"), null, null, - null); + null, + mTestExecutor); + } + + private static class FakeExecutor implements Executor { + private Runnable mLastCommand; + + @Override + public void execute(Runnable command) { + assertNull(mLastCommand); + assertNotNull(command); + mLastCommand = command; + } + + public Runnable getAndResetLastCommand() { + Runnable toReturn = mLastCommand; + mLastCommand = null; + return toReturn; + } + + public void simulateAsyncExecutionOfLastCommand() { + Runnable toRun = getAndResetLastCommand(); + if (toRun != null) { + toRun.run(); + } + } } + } diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index c9721dbecdb4..fbcad62988be 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -109,6 +109,7 @@ import org.mockito.stubbing.Answer; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; /** @@ -220,7 +221,8 @@ public class PowerManagerServiceTest { @Override Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats, SuspendBlocker suspendBlocker, WindowManagerPolicy policy, - FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector) { + FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector, + Executor executor) { return mNotifierMock; } |