From 65f26b780c9eb7b3130e673cd2da944aff0b44fa Mon Sep 17 00:00:00 2001 From: Yogisha Dixit Date: Fri, 7 Feb 2020 17:30:49 +0000 Subject: [PATCH] Store ambient display suppression state in memory. We were previously using a secure setting, which means that the suppression state would be persisted across reboots. Test: atest SystemUITests, atest FrameworksServicesTests:PowerManagerServiceTest Change-Id: I3016bdabc67c15b8759a78ce92f4d9262b1380a3 Bug: 147587449 (cherry picked from commit 05f9538c2ee72b1cffdb1223fa70c02e59b84579) --- .../internal/statusbar/IStatusBar.aidl | 6 + .../internal/statusbar/IStatusBarService.aidl | 6 + .../android/systemui/doze/DozeFactory.java | 4 +- .../com/android/systemui/doze/DozeHost.java | 6 + .../android/systemui/doze/DozeMachine.java | 6 +- .../systemui/doze/DozeSuppressedHandler.java | 124 ------------------ .../android/systemui/doze/DozeTriggers.java | 13 +- .../systemui/statusbar/CommandQueue.java | 16 +++ .../statusbar/phone/DozeServiceHost.java | 15 +++ .../systemui/statusbar/phone/StatusBar.java | 4 + .../systemui/doze/DozeMachineTest.java | 21 +-- .../doze/DozeSuppressedHandlerTest.java | 77 ----------- .../systemui/statusbar/CommandQueueTest.java | 7 + .../statusbar/phone/StatusBarTest.java | 12 ++ .../AmbientDisplaySuppressionController.java | 109 +++++++++++++++ .../server/power/PowerManagerService.java | 42 ++---- .../statusbar/StatusBarManagerService.java | 12 +- .../server/power/PowerManagerServiceTest.java | 60 --------- 18 files changed, 235 insertions(+), 305 deletions(-) delete mode 100644 packages/SystemUI/src/com/android/systemui/doze/DozeSuppressedHandler.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressedHandlerTest.java create mode 100644 services/core/java/com/android/server/power/AmbientDisplaySuppressionController.java diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 21067127a8e7e..380a20c88d569 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -220,4 +220,10 @@ oneway interface IStatusBar * Notifies SystemUI to stop tracing. */ void stopTracing(); + + /** + * If true, suppresses the ambient display from showing. If false, re-enables the ambient + * display. + */ + void suppressAmbientDisplay(boolean suppress); } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 5ce83c2db44dd..9907b9975afe3 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -139,4 +139,10 @@ interface IStatusBarService * Returns whether SystemUI tracing is enabled. */ boolean isTracing(); + + /** + * If true, suppresses the ambient display from showing. If false, re-enables the ambient + * display. + */ + void suppressAmbientDisplay(boolean suppress); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 6f655bb0b209e..8117bbb0de1db 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -102,7 +102,8 @@ public class DozeFactory { wrappedService, mDozeParameters); DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock, - mWakefulnessLifecycle, mBatteryController, mDozeLog, mDockManager); + mWakefulnessLifecycle, mBatteryController, mDozeLog, mDockManager, + mDozeServiceHost); machine.setParts(new DozeMachine.Part[]{ new DozePauser(mHandler, machine, mAlarmManager, mDozeParameters.getPolicy()), new DozeFalsingManagerAdapter(mFalsingManager), @@ -118,7 +119,6 @@ public class DozeFactory { new DozeWallpaperState(mWallpaperManager, mBiometricUnlockController, mDozeParameters), new DozeDockHandler(config, machine, mDockManager), - new DozeSuppressedHandler(dozeService, config, machine), new DozeAuthRemover(dozeService) }); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java index d1047e216ec46..9c25b3596be63 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java @@ -81,6 +81,9 @@ public interface DozeHost { */ void stopPulsing(); + /** Returns whether doze is suppressed. */ + boolean isDozeSuppressed(); + interface Callback { /** * Called when a high priority notification is added. @@ -94,6 +97,9 @@ public interface DozeHost { * @param active whether power save is active or not */ default void onPowerSaveChanged(boolean active) {} + + /** Called when the doze suppression state changes. */ + default void onDozeSuppressedChanged(boolean suppressed) {} } interface PulseCallback { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index 6e81d3a110981..3bed3384c91f2 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -134,6 +134,7 @@ public class DozeMachine { private final AmbientDisplayConfiguration mConfig; private final WakefulnessLifecycle mWakefulnessLifecycle; private final BatteryController mBatteryController; + private final DozeHost mDozeHost; private Part[] mParts; private final ArrayList mQueuedRequests = new ArrayList<>(); @@ -144,7 +145,7 @@ public class DozeMachine { public DozeMachine(Service service, AmbientDisplayConfiguration config, WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle, BatteryController batteryController, - DozeLog dozeLog, DockManager dockManager) { + DozeLog dozeLog, DockManager dockManager, DozeHost dozeHost) { mDozeService = service; mConfig = config; mWakefulnessLifecycle = wakefulnessLifecycle; @@ -152,6 +153,7 @@ public class DozeMachine { mBatteryController = batteryController; mDozeLog = dozeLog; mDockManager = dockManager; + mDozeHost = dozeHost; } /** Initializes the set of {@link Part}s. Must be called exactly once after construction. */ @@ -328,7 +330,7 @@ public class DozeMachine { if (mState == State.FINISH) { return State.FINISH; } - if (mConfig.dozeSuppressed(UserHandle.USER_CURRENT) && requestedState.isAlwaysOn()) { + if (mDozeHost.isDozeSuppressed() && requestedState.isAlwaysOn()) { Log.i(TAG, "Doze is suppressed. Suppressing state: " + requestedState); mDozeLog.traceDozeSuppressed(requestedState); return State.DOZE; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressedHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressedHandler.java deleted file mode 100644 index 3a5c1a0890f96..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressedHandler.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.doze; - -import static java.util.Objects.requireNonNull; - -import android.app.ActivityManager; -import android.content.ContentResolver; -import android.content.Context; -import android.database.ContentObserver; -import android.hardware.display.AmbientDisplayConfiguration; -import android.net.Uri; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -/** Handles updating the doze state when doze is suppressed. */ -public final class DozeSuppressedHandler implements DozeMachine.Part { - - private static final String TAG = DozeSuppressedHandler.class.getSimpleName(); - private static final boolean DEBUG = DozeService.DEBUG; - - private final ContentResolver mResolver; - private final AmbientDisplayConfiguration mConfig; - private final DozeMachine mMachine; - private final DozeSuppressedSettingObserver mSettingObserver; - private final Handler mHandler = new Handler(); - - public DozeSuppressedHandler(Context context, AmbientDisplayConfiguration config, - DozeMachine machine) { - this(context, config, machine, null); - } - - @VisibleForTesting - DozeSuppressedHandler(Context context, AmbientDisplayConfiguration config, DozeMachine machine, - DozeSuppressedSettingObserver observer) { - mResolver = context.getContentResolver(); - mConfig = requireNonNull(config); - mMachine = requireNonNull(machine); - if (observer == null) { - mSettingObserver = new DozeSuppressedSettingObserver(mHandler); - } else { - mSettingObserver = observer; - } - } - - @Override - public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { - switch (newState) { - case INITIALIZED: - mSettingObserver.register(); - break; - case FINISH: - mSettingObserver.unregister(); - break; - default: - // no-op - } - } - - /** - * Listens to changes to the DOZE_SUPPRESSED secure setting and updates the doze state - * accordingly. - */ - final class DozeSuppressedSettingObserver extends ContentObserver { - private boolean mRegistered; - - private DozeSuppressedSettingObserver(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange, Uri uri, int userId) { - if (userId != ActivityManager.getCurrentUser()) { - return; - } - final DozeMachine.State nextState; - if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) - && !mConfig.dozeSuppressed(UserHandle.USER_CURRENT)) { - nextState = DozeMachine.State.DOZE_AOD; - } else { - nextState = DozeMachine.State.DOZE; - } - mMachine.requestState(nextState); - } - - void register() { - if (mRegistered) { - return; - } - mResolver.registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.SUPPRESS_DOZE), - false, this, UserHandle.USER_CURRENT); - Log.d(TAG, "Register"); - mRegistered = true; - } - - void unregister() { - if (!mRegistered) { - return; - } - mResolver.unregisterContentObserver(this); - Log.d(TAG, "Unregister"); - mRegistered = false; - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 305a4c870d91d..09d7d26e4dfed 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -127,7 +127,7 @@ public class DozeTriggers implements DozeMachine.Part { mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled"); return; } - if (mConfig.dozeSuppressed(UserHandle.USER_CURRENT)) { + if (mDozeHost.isDozeSuppressed()) { runIfNotNull(onPulseSuppressedListener); mDozeLog.tracePulseDropped("dozeSuppressed"); return; @@ -492,5 +492,16 @@ public class DozeTriggers implements DozeMachine.Part { mMachine.requestState(DozeMachine.State.DOZE); } } + + @Override + public void onDozeSuppressedChanged(boolean suppressed) { + final DozeMachine.State nextState; + if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) && !suppressed) { + nextState = DozeMachine.State.DOZE_AOD; + } else { + nextState = DozeMachine.State.DOZE; + } + mMachine.requestState(nextState); + } }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 64f083024ce1b..3fe348f3ea029 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -125,6 +125,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< private static final int MSG_SHOW_TOAST = 53 << MSG_SHIFT; private static final int MSG_HIDE_TOAST = 54 << MSG_SHIFT; private static final int MSG_TRACING_STATE_CHANGED = 55 << MSG_SHIFT; + private static final int MSG_SUPPRESS_AMBIENT_DISPLAY = 56 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -316,6 +317,9 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< */ default void dismissInattentiveSleepWarning(boolean animated) { } + /** Called to suppress ambient display. */ + default void suppressAmbientDisplay(boolean suppress) { } + /** * @see IStatusBar#showToast(String, IBinder, CharSequence, IBinder, int, * ITransientNotificationCallback) @@ -950,6 +954,13 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } } + @Override + public void suppressAmbientDisplay(boolean suppress) { + synchronized (mLock) { + mHandler.obtainMessage(MSG_SUPPRESS_AMBIENT_DISPLAY, suppress).sendToTarget(); + } + } + private final class H extends Handler { private H(Looper l) { super(l); @@ -1282,6 +1293,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< mCallbacks.get(i).onTracingStateChanged((Boolean) msg.obj); } break; + case MSG_SUPPRESS_AMBIENT_DISPLAY: + for (Callbacks callbacks: mCallbacks) { + callbacks.suppressAmbientDisplay((boolean) msg.obj); + } + break; } } } 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 56e5cb08f6d1c..abae4d8eb96ed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -93,6 +93,7 @@ public final class DozeServiceHost implements DozeHost { private NotificationPanelViewController mNotificationPanel; private View mAmbientIndicationContainer; private StatusBar mStatusBar; + private boolean mSuppressed; @Inject public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager, @@ -449,4 +450,18 @@ public final class DozeServiceHost implements DozeHost { boolean getIgnoreTouchWhilePulsing() { return mIgnoreTouchWhilePulsing; } + + void setDozeSuppressed(boolean suppressed) { + if (suppressed == mSuppressed) { + return; + } + mSuppressed = suppressed; + for (Callback callback : mCallbacks) { + callback.onDozeSuppressedChanged(suppressed); + } + } + + public boolean isDozeSuppressed() { + return mSuppressed; + } } 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 19df9727c97c3..89c19394f6023 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -4287,4 +4287,8 @@ public class StatusBar extends SystemUI implements DemoMode, return mTransientShown; } + @Override + public void suppressAmbientDisplay(boolean suppressed) { + mDozeServiceHost.setDozeSuppressed(suppressed); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index 63cbca9255a6f..c483314918fc3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -69,6 +69,8 @@ public class DozeMachineTest extends SysuiTestCase { @Mock private DozeLog mDozeLog; @Mock private DockManager mDockManager; + @Mock + private DozeHost mHost; private DozeServiceFake mServiceFake; private WakeLockFake mWakeLockFake; private AmbientDisplayConfiguration mConfigMock; @@ -85,7 +87,8 @@ public class DozeMachineTest extends SysuiTestCase { when(mDockManager.isHidden()).thenReturn(false); mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake, - mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog, mDockManager); + mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog, mDockManager, + mHost); mMachine.setParts(new DozeMachine.Part[]{mPartMock}); } @@ -140,7 +143,7 @@ public class DozeMachineTest extends SysuiTestCase { @Test public void testInitialize_dozeSuppressed_alwaysOnDisabled_goesToDoze() { - when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mHost.isDozeSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); mMachine.requestState(INITIALIZED); @@ -151,7 +154,7 @@ public class DozeMachineTest extends SysuiTestCase { @Test public void testInitialize_dozeSuppressed_alwaysOnEnabled_goesToDoze() { - when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mHost.isDozeSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); mMachine.requestState(INITIALIZED); @@ -162,7 +165,7 @@ public class DozeMachineTest extends SysuiTestCase { @Test public void testInitialize_dozeSuppressed_afterDocked_goesToDoze() { - when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mHost.isDozeSuppressed()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); mMachine.requestState(INITIALIZED); @@ -173,7 +176,7 @@ public class DozeMachineTest extends SysuiTestCase { @Test public void testInitialize_dozeSuppressed_alwaysOnDisabled_afterDockPaused_goesToDoze() { - when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mHost.isDozeSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true); @@ -186,7 +189,7 @@ public class DozeMachineTest extends SysuiTestCase { @Test public void testInitialize_dozeSuppressed_alwaysOnEnabled_afterDockPaused_goesToDoze() { - when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mHost.isDozeSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true); @@ -225,7 +228,7 @@ public class DozeMachineTest extends SysuiTestCase { @Test public void testPulseDone_dozeSuppressed_goesToSuppressed() { - when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mHost.isDozeSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); mMachine.requestState(INITIALIZED); mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); @@ -252,7 +255,7 @@ public class DozeMachineTest extends SysuiTestCase { @Test public void testPulseDone_dozeSuppressed_afterDocked_goesToDoze() { - when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mHost.isDozeSuppressed()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); mMachine.requestState(INITIALIZED); mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); @@ -281,7 +284,7 @@ public class DozeMachineTest extends SysuiTestCase { @Test public void testPulseDone_dozeSuppressed_afterDockPaused_goesToDoze() { - when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); + when(mHost.isDozeSuppressed()).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressedHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressedHandlerTest.java deleted file mode 100644 index 5bdca76d449cf..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressedHandlerTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.doze; - -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import android.hardware.display.AmbientDisplayConfiguration; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper.RunWithLooper; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.doze.DozeSuppressedHandler.DozeSuppressedSettingObserver; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@RunWithLooper -public class DozeSuppressedHandlerTest extends SysuiTestCase { - @Mock private DozeMachine mMachine; - @Mock private DozeSuppressedSettingObserver mObserver; - private AmbientDisplayConfiguration mConfig; - private DozeSuppressedHandler mSuppressedHandler; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mConfig = DozeConfigurationUtil.createMockConfig(); - mSuppressedHandler = new DozeSuppressedHandler(mContext, mConfig, mMachine, mObserver); - } - - @Test - public void transitionTo_initialized_registersObserver() throws Exception { - mSuppressedHandler.transitionTo(DozeMachine.State.UNINITIALIZED, - DozeMachine.State.INITIALIZED); - - verify(mObserver).register(); - } - - @Test - public void transitionTo_finish_unregistersObserver() throws Exception { - mSuppressedHandler.transitionTo(DozeMachine.State.INITIALIZED, - DozeMachine.State.FINISH); - - verify(mObserver).unregister(); - } - - @Test - public void transitionTo_doze_doesNothing() throws Exception { - mSuppressedHandler.transitionTo(DozeMachine.State.INITIALIZED, - DozeMachine.State.DOZE); - - verify(mObserver, never()).register(); - verify(mObserver, never()).unregister(); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 24c372cef7cb7..7c6da630b3bfb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -447,4 +447,11 @@ public class CommandQueueTest extends SysuiTestCase { waitForIdleSync(); verify(mCallbacks).hideAuthenticationDialog(); } + + @Test + public void testSuppressAmbientDisplay() { + mCommandQueue.suppressAmbientDisplay(true); + waitForIdleSync(); + verify(mCallbacks).suppressAmbientDisplay(true); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 0035b98c9a8de..b87f3441678e4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -859,6 +859,18 @@ public class StatusBarTest extends SysuiTestCase { any(UserHandle.class)); } + @Test + public void testSuppressAmbientDisplay_suppress() { + mStatusBar.suppressAmbientDisplay(true); + verify(mDozeServiceHost).setDozeSuppressed(true); + } + + @Test + public void testSuppressAmbientDisplay_unsuppress() { + mStatusBar.suppressAmbientDisplay(false); + verify(mDozeServiceHost).setDozeSuppressed(false); + } + public static class TestableNotificationInterruptionStateProvider extends NotificationInterruptionStateProvider { diff --git a/services/core/java/com/android/server/power/AmbientDisplaySuppressionController.java b/services/core/java/com/android/server/power/AmbientDisplaySuppressionController.java new file mode 100644 index 0000000000000..3bb90ce38a733 --- /dev/null +++ b/services/core/java/com/android/server/power/AmbientDisplaySuppressionController.java @@ -0,0 +1,109 @@ +/** + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.power; + +import static java.util.Objects.requireNonNull; + +import android.annotation.NonNull; +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.ArraySet; +import android.util.Pair; +import android.util.Slog; + +import com.android.internal.statusbar.IStatusBarService; + +import java.io.PrintWriter; +import java.util.Collections; +import java.util.Set; + +/** + * Communicates with System UI to suppress the ambient display. + */ +public class AmbientDisplaySuppressionController { + private static final String TAG = "AmbientDisplaySuppressionController"; + + private final Context mContext; + private final Set> mSuppressionTokens; + private IStatusBarService mStatusBarService; + + AmbientDisplaySuppressionController(Context context) { + mContext = requireNonNull(context); + mSuppressionTokens = Collections.synchronizedSet(new ArraySet<>()); + } + + /** + * Suppresses ambient display. + * + * @param token A persistible identifier for the ambient display suppression. + * @param callingUid The uid of the calling application. + * @param suppress If true, suppresses the ambient display. Otherwise, unsuppresses it. + */ + public void suppress(@NonNull String token, int callingUid, boolean suppress) { + Pair suppressionToken = Pair.create(requireNonNull(token), callingUid); + + if (suppress) { + mSuppressionTokens.add(suppressionToken); + } else { + mSuppressionTokens.remove(suppressionToken); + } + + try { + synchronized (mSuppressionTokens) { + getStatusBar().suppressAmbientDisplay(isSuppressed()); + } + } catch (RemoteException e) { + Slog.e(TAG, "Failed to suppress ambient display", e); + } + } + + /** + * Returns whether ambient display is suppressed for the given token. + * + * @param token A persistible identifier for the ambient display suppression. + * @param callingUid The uid of the calling application. + */ + public boolean isSuppressed(@NonNull String token, int callingUid) { + return mSuppressionTokens.contains(Pair.create(requireNonNull(token), callingUid)); + } + + /** + * Returns whether ambient display is suppressed. + */ + public boolean isSuppressed() { + return !mSuppressionTokens.isEmpty(); + } + + /** + * Dumps the state of ambient display suppression and the list of suppression tokens into + * {@code pw}. + */ + public void dump(PrintWriter pw) { + pw.println("AmbientDisplaySuppressionController:"); + pw.println(" ambientDisplaySuppressed=" + isSuppressed()); + pw.println(" mSuppressionTokens=" + mSuppressionTokens); + } + + private synchronized IStatusBarService getStatusBar() { + if (mStatusBarService == null) { + mStatusBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + } + return mStatusBarService; + } +} diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index e6c23b66eba22..f04be0b1aa9d3 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -75,7 +75,6 @@ import android.provider.Settings.SettingNotFoundException; import android.service.dreams.DreamManagerInternal; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; -import android.util.ArraySet; import android.util.KeyValueListParser; import android.util.PrintWriterPrinter; import android.util.Slog; @@ -115,7 +114,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; -import java.util.Set; /** * The power manager service is responsible for coordinating power management @@ -266,6 +264,7 @@ public final class PowerManagerService extends SystemService private LogicalLight mAttentionLight; private InattentiveSleepWarningController mInattentiveSleepWarningOverlayController; + private final AmbientDisplaySuppressionController mAmbientDisplaySuppressionController; private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_POWER); @@ -585,9 +584,6 @@ public final class PowerManagerService extends SystemService // but the DreamService has not yet been told to start (it's an async process). private boolean mDozeStartInProgress; - // Set of all tokens suppressing ambient display. - private final Set mAmbientDisplaySuppressionTokens = new ArraySet<>(); - private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver { @Override public void onUserSwitching(@UserIdInt int newUserId) throws RemoteException { @@ -785,6 +781,11 @@ public final class PowerManagerService extends SystemService return new AmbientDisplayConfiguration(context); } + AmbientDisplaySuppressionController createAmbientDisplaySuppressionController( + Context context) { + return new AmbientDisplaySuppressionController(context); + } + InattentiveSleepWarningController createInattentiveSleepWarningController() { return new InattentiveSleepWarningController(); } @@ -840,6 +841,8 @@ public final class PowerManagerService extends SystemService mHandler = new PowerManagerHandler(mHandlerThread.getLooper()); mConstants = new Constants(mHandler); mAmbientDisplayConfiguration = mInjector.createAmbientDisplayConfiguration(context); + mAmbientDisplaySuppressionController = + mInjector.createAmbientDisplaySuppressionController(context); mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock); mBatterySavingStats = new BatterySavingStats(mLock); @@ -3488,26 +3491,6 @@ public final class PowerManagerService extends SystemService } } - private void suppressAmbientDisplayInternal(String token, boolean suppress) { - if (DEBUG_SPEW) { - Slog.d(TAG, "Suppress ambient display for token " + token + ": " + suppress); - } - - if (suppress) { - mAmbientDisplaySuppressionTokens.add(token); - } else { - mAmbientDisplaySuppressionTokens.remove(token); - } - - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.SUPPRESS_DOZE, - Math.min(mAmbientDisplaySuppressionTokens.size(), 1)); - } - - private String createAmbientDisplayToken(String token, int callingUid) { - return callingUid + "_" + token; - } - private void boostScreenBrightnessInternal(long eventTime, int uid) { synchronized (mLock) { if (!mSystemReady || getWakefulnessLocked() == WAKEFULNESS_ASLEEP @@ -3943,6 +3926,8 @@ public final class PowerManagerService extends SystemService if (mNotifier != null) { mNotifier.dump(pw); } + + mAmbientDisplaySuppressionController.dump(pw); } private void dumpProto(FileDescriptor fd) { @@ -5211,7 +5196,7 @@ public final class PowerManagerService extends SystemService final int uid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { - suppressAmbientDisplayInternal(createAmbientDisplayToken(token, uid), suppress); + mAmbientDisplaySuppressionController.suppress(token, uid, suppress); } finally { Binder.restoreCallingIdentity(ident); } @@ -5225,8 +5210,7 @@ public final class PowerManagerService extends SystemService final int uid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { - return mAmbientDisplaySuppressionTokens.contains( - createAmbientDisplayToken(token, uid)); + return mAmbientDisplaySuppressionController.isSuppressed(token, uid); } finally { Binder.restoreCallingIdentity(ident); } @@ -5239,7 +5223,7 @@ public final class PowerManagerService extends SystemService final long ident = Binder.clearCallingIdentity(); try { - return mAmbientDisplaySuppressionTokens.size() > 0; + return mAmbientDisplaySuppressionController.isSuppressed(); } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 9a30f1de70f0d..19fb660208281 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -63,7 +63,6 @@ import com.android.server.LocalServices; import com.android.server.notification.NotificationDelegate; import com.android.server.policy.GlobalActionsProvider; import com.android.server.power.ShutdownThread; -import com.android.server.wm.WindowManagerService; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -1453,6 +1452,17 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } } + @Override + public void suppressAmbientDisplay(boolean suppress) { + enforceStatusBarService(); + if (mBar != null) { + try { + mBar.suppressAmbientDisplay(suppress); + } catch (RemoteException ex) { + } + } + } + public String[] getStatusBarIcons() { return mContext.getResources().getStringArray(R.array.config_statusBarIcons); } 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 0ee2f55fbde05..5e8de42f8ce02 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -841,66 +841,6 @@ public class PowerManagerServiceTest { assertThat(mService.getBinderServiceInstance().isAmbientDisplayAvailable()).isFalse(); } - @Test - public void testSuppressAmbientDisplay_suppressed() throws Exception { - createService(); - mService.getBinderServiceInstance().suppressAmbientDisplay("test", true); - - assertThat(Settings.Secure.getInt(mContextSpy.getContentResolver(), - Settings.Secure.SUPPRESS_DOZE)).isEqualTo(1); - } - - @Test - public void testSuppressAmbientDisplay_multipleCallers_suppressed() throws Exception { - createService(); - mService.getBinderServiceInstance().suppressAmbientDisplay("test1", true); - mService.getBinderServiceInstance().suppressAmbientDisplay("test2", false); - - assertThat(Settings.Secure.getInt(mContextSpy.getContentResolver(), - Settings.Secure.SUPPRESS_DOZE)).isEqualTo(1); - } - - @Test - public void testSuppressAmbientDisplay_suppressTwice_suppressed() throws Exception { - createService(); - mService.getBinderServiceInstance().suppressAmbientDisplay("test", true); - mService.getBinderServiceInstance().suppressAmbientDisplay("test", true); - - assertThat(Settings.Secure.getInt(mContextSpy.getContentResolver(), - Settings.Secure.SUPPRESS_DOZE)).isEqualTo(1); - } - - @Test - public void testSuppressAmbientDisplay_suppressTwiceThenUnsuppress_notSuppressed() - throws Exception { - createService(); - mService.getBinderServiceInstance().suppressAmbientDisplay("test", true); - mService.getBinderServiceInstance().suppressAmbientDisplay("test", true); - mService.getBinderServiceInstance().suppressAmbientDisplay("test", false); - - assertThat(Settings.Secure.getInt(mContextSpy.getContentResolver(), - Settings.Secure.SUPPRESS_DOZE)).isEqualTo(0); - } - - @Test - public void testSuppressAmbientDisplay_notSuppressed() throws Exception { - createService(); - mService.getBinderServiceInstance().suppressAmbientDisplay("test", false); - - assertThat(Settings.Secure.getInt(mContextSpy.getContentResolver(), - Settings.Secure.SUPPRESS_DOZE)).isEqualTo(0); - } - - @Test - public void testSuppressAmbientDisplay_unsuppressTwice_notSuppressed() throws Exception { - createService(); - mService.getBinderServiceInstance().suppressAmbientDisplay("test", false); - mService.getBinderServiceInstance().suppressAmbientDisplay("test", false); - - assertThat(Settings.Secure.getInt(mContextSpy.getContentResolver(), - Settings.Secure.SUPPRESS_DOZE)).isEqualTo(0); - } - @Test public void testIsAmbientDisplaySuppressed_default_notSuppressed() throws Exception { createService();