Merge "Store ambient display suppression state in memory." into rvc-dev am: 1399825fe7

Change-Id: Iaa46756f1d793673fded8e17c9f48296a158e225
This commit is contained in:
Automerger Merge Worker
2020-03-04 13:09:35 +00:00
18 changed files with 235 additions and 305 deletions

View File

@@ -220,4 +220,10 @@ oneway interface IStatusBar
* Notifies SystemUI to stop tracing. * Notifies SystemUI to stop tracing.
*/ */
void stopTracing(); void stopTracing();
/**
* If true, suppresses the ambient display from showing. If false, re-enables the ambient
* display.
*/
void suppressAmbientDisplay(boolean suppress);
} }

View File

@@ -139,4 +139,10 @@ interface IStatusBarService
* Returns whether SystemUI tracing is enabled. * Returns whether SystemUI tracing is enabled.
*/ */
boolean isTracing(); boolean isTracing();
/**
* If true, suppresses the ambient display from showing. If false, re-enables the ambient
* display.
*/
void suppressAmbientDisplay(boolean suppress);
} }

View File

@@ -102,7 +102,8 @@ public class DozeFactory {
wrappedService, mDozeParameters); wrappedService, mDozeParameters);
DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock, DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock,
mWakefulnessLifecycle, mBatteryController, mDozeLog, mDockManager); mWakefulnessLifecycle, mBatteryController, mDozeLog, mDockManager,
mDozeServiceHost);
machine.setParts(new DozeMachine.Part[]{ machine.setParts(new DozeMachine.Part[]{
new DozePauser(mHandler, machine, mAlarmManager, mDozeParameters.getPolicy()), new DozePauser(mHandler, machine, mAlarmManager, mDozeParameters.getPolicy()),
new DozeFalsingManagerAdapter(mFalsingManager), new DozeFalsingManagerAdapter(mFalsingManager),
@@ -118,7 +119,6 @@ public class DozeFactory {
new DozeWallpaperState(mWallpaperManager, mBiometricUnlockController, new DozeWallpaperState(mWallpaperManager, mBiometricUnlockController,
mDozeParameters), mDozeParameters),
new DozeDockHandler(config, machine, mDockManager), new DozeDockHandler(config, machine, mDockManager),
new DozeSuppressedHandler(dozeService, config, machine),
new DozeAuthRemover(dozeService) new DozeAuthRemover(dozeService)
}); });

View File

@@ -81,6 +81,9 @@ public interface DozeHost {
*/ */
void stopPulsing(); void stopPulsing();
/** Returns whether doze is suppressed. */
boolean isDozeSuppressed();
interface Callback { interface Callback {
/** /**
* Called when a high priority notification is added. * Called when a high priority notification is added.
@@ -94,6 +97,9 @@ public interface DozeHost {
* @param active whether power save is active or not * @param active whether power save is active or not
*/ */
default void onPowerSaveChanged(boolean active) {} default void onPowerSaveChanged(boolean active) {}
/** Called when the doze suppression state changes. */
default void onDozeSuppressedChanged(boolean suppressed) {}
} }
interface PulseCallback { interface PulseCallback {

View File

@@ -134,6 +134,7 @@ public class DozeMachine {
private final AmbientDisplayConfiguration mConfig; private final AmbientDisplayConfiguration mConfig;
private final WakefulnessLifecycle mWakefulnessLifecycle; private final WakefulnessLifecycle mWakefulnessLifecycle;
private final BatteryController mBatteryController; private final BatteryController mBatteryController;
private final DozeHost mDozeHost;
private Part[] mParts; private Part[] mParts;
private final ArrayList<State> mQueuedRequests = new ArrayList<>(); private final ArrayList<State> mQueuedRequests = new ArrayList<>();
@@ -144,7 +145,7 @@ public class DozeMachine {
public DozeMachine(Service service, AmbientDisplayConfiguration config, WakeLock wakeLock, public DozeMachine(Service service, AmbientDisplayConfiguration config, WakeLock wakeLock,
WakefulnessLifecycle wakefulnessLifecycle, BatteryController batteryController, WakefulnessLifecycle wakefulnessLifecycle, BatteryController batteryController,
DozeLog dozeLog, DockManager dockManager) { DozeLog dozeLog, DockManager dockManager, DozeHost dozeHost) {
mDozeService = service; mDozeService = service;
mConfig = config; mConfig = config;
mWakefulnessLifecycle = wakefulnessLifecycle; mWakefulnessLifecycle = wakefulnessLifecycle;
@@ -152,6 +153,7 @@ public class DozeMachine {
mBatteryController = batteryController; mBatteryController = batteryController;
mDozeLog = dozeLog; mDozeLog = dozeLog;
mDockManager = dockManager; mDockManager = dockManager;
mDozeHost = dozeHost;
} }
/** Initializes the set of {@link Part}s. Must be called exactly once after construction. */ /** 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) { if (mState == State.FINISH) {
return 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); Log.i(TAG, "Doze is suppressed. Suppressing state: " + requestedState);
mDozeLog.traceDozeSuppressed(requestedState); mDozeLog.traceDozeSuppressed(requestedState);
return State.DOZE; return State.DOZE;

View File

@@ -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;
}
}
}

View File

@@ -127,7 +127,7 @@ public class DozeTriggers implements DozeMachine.Part {
mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled"); mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled");
return; return;
} }
if (mConfig.dozeSuppressed(UserHandle.USER_CURRENT)) { if (mDozeHost.isDozeSuppressed()) {
runIfNotNull(onPulseSuppressedListener); runIfNotNull(onPulseSuppressedListener);
mDozeLog.tracePulseDropped("dozeSuppressed"); mDozeLog.tracePulseDropped("dozeSuppressed");
return; return;
@@ -492,5 +492,16 @@ public class DozeTriggers implements DozeMachine.Part {
mMachine.requestState(DozeMachine.State.DOZE); 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);
}
}; };
} }

View File

@@ -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_SHOW_TOAST = 53 << MSG_SHIFT;
private static final int MSG_HIDE_TOAST = 54 << 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_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_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 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) { } default void dismissInattentiveSleepWarning(boolean animated) { }
/** Called to suppress ambient display. */
default void suppressAmbientDisplay(boolean suppress) { }
/** /**
* @see IStatusBar#showToast(String, IBinder, CharSequence, IBinder, int, * @see IStatusBar#showToast(String, IBinder, CharSequence, IBinder, int,
* ITransientNotificationCallback) * 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 final class H extends Handler {
private H(Looper l) { private H(Looper l) {
super(l); super(l);
@@ -1282,6 +1293,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
mCallbacks.get(i).onTracingStateChanged((Boolean) msg.obj); mCallbacks.get(i).onTracingStateChanged((Boolean) msg.obj);
} }
break; break;
case MSG_SUPPRESS_AMBIENT_DISPLAY:
for (Callbacks callbacks: mCallbacks) {
callbacks.suppressAmbientDisplay((boolean) msg.obj);
}
break;
} }
} }
} }

View File

@@ -93,6 +93,7 @@ public final class DozeServiceHost implements DozeHost {
private NotificationPanelViewController mNotificationPanel; private NotificationPanelViewController mNotificationPanel;
private View mAmbientIndicationContainer; private View mAmbientIndicationContainer;
private StatusBar mStatusBar; private StatusBar mStatusBar;
private boolean mSuppressed;
@Inject @Inject
public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager, public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager,
@@ -449,4 +450,18 @@ public final class DozeServiceHost implements DozeHost {
boolean getIgnoreTouchWhilePulsing() { boolean getIgnoreTouchWhilePulsing() {
return mIgnoreTouchWhilePulsing; return mIgnoreTouchWhilePulsing;
} }
void setDozeSuppressed(boolean suppressed) {
if (suppressed == mSuppressed) {
return;
}
mSuppressed = suppressed;
for (Callback callback : mCallbacks) {
callback.onDozeSuppressedChanged(suppressed);
}
}
public boolean isDozeSuppressed() {
return mSuppressed;
}
} }

View File

@@ -4287,4 +4287,8 @@ public class StatusBar extends SystemUI implements DemoMode,
return mTransientShown; return mTransientShown;
} }
@Override
public void suppressAmbientDisplay(boolean suppressed) {
mDozeServiceHost.setDozeSuppressed(suppressed);
}
} }

View File

@@ -69,6 +69,8 @@ public class DozeMachineTest extends SysuiTestCase {
@Mock @Mock
private DozeLog mDozeLog; private DozeLog mDozeLog;
@Mock private DockManager mDockManager; @Mock private DockManager mDockManager;
@Mock
private DozeHost mHost;
private DozeServiceFake mServiceFake; private DozeServiceFake mServiceFake;
private WakeLockFake mWakeLockFake; private WakeLockFake mWakeLockFake;
private AmbientDisplayConfiguration mConfigMock; private AmbientDisplayConfiguration mConfigMock;
@@ -85,7 +87,8 @@ public class DozeMachineTest extends SysuiTestCase {
when(mDockManager.isHidden()).thenReturn(false); when(mDockManager.isHidden()).thenReturn(false);
mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake, 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}); mMachine.setParts(new DozeMachine.Part[]{mPartMock});
} }
@@ -140,7 +143,7 @@ public class DozeMachineTest extends SysuiTestCase {
@Test @Test
public void testInitialize_dozeSuppressed_alwaysOnDisabled_goesToDoze() { public void testInitialize_dozeSuppressed_alwaysOnDisabled_goesToDoze() {
when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); when(mHost.isDozeSuppressed()).thenReturn(true);
when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
mMachine.requestState(INITIALIZED); mMachine.requestState(INITIALIZED);
@@ -151,7 +154,7 @@ public class DozeMachineTest extends SysuiTestCase {
@Test @Test
public void testInitialize_dozeSuppressed_alwaysOnEnabled_goesToDoze() { public void testInitialize_dozeSuppressed_alwaysOnEnabled_goesToDoze() {
when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); when(mHost.isDozeSuppressed()).thenReturn(true);
when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
mMachine.requestState(INITIALIZED); mMachine.requestState(INITIALIZED);
@@ -162,7 +165,7 @@ public class DozeMachineTest extends SysuiTestCase {
@Test @Test
public void testInitialize_dozeSuppressed_afterDocked_goesToDoze() { public void testInitialize_dozeSuppressed_afterDocked_goesToDoze() {
when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); when(mHost.isDozeSuppressed()).thenReturn(true);
when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true);
mMachine.requestState(INITIALIZED); mMachine.requestState(INITIALIZED);
@@ -173,7 +176,7 @@ public class DozeMachineTest extends SysuiTestCase {
@Test @Test
public void testInitialize_dozeSuppressed_alwaysOnDisabled_afterDockPaused_goesToDoze() { 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(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true);
when(mDockManager.isHidden()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true);
@@ -186,7 +189,7 @@ public class DozeMachineTest extends SysuiTestCase {
@Test @Test
public void testInitialize_dozeSuppressed_alwaysOnEnabled_afterDockPaused_goesToDoze() { 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(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true);
when(mDockManager.isHidden()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true);
@@ -225,7 +228,7 @@ public class DozeMachineTest extends SysuiTestCase {
@Test @Test
public void testPulseDone_dozeSuppressed_goesToSuppressed() { public void testPulseDone_dozeSuppressed_goesToSuppressed() {
when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); when(mHost.isDozeSuppressed()).thenReturn(true);
when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
mMachine.requestState(INITIALIZED); mMachine.requestState(INITIALIZED);
mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
@@ -252,7 +255,7 @@ public class DozeMachineTest extends SysuiTestCase {
@Test @Test
public void testPulseDone_dozeSuppressed_afterDocked_goesToDoze() { public void testPulseDone_dozeSuppressed_afterDocked_goesToDoze() {
when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); when(mHost.isDozeSuppressed()).thenReturn(true);
when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true);
mMachine.requestState(INITIALIZED); mMachine.requestState(INITIALIZED);
mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
@@ -281,7 +284,7 @@ public class DozeMachineTest extends SysuiTestCase {
@Test @Test
public void testPulseDone_dozeSuppressed_afterDockPaused_goesToDoze() { public void testPulseDone_dozeSuppressed_afterDockPaused_goesToDoze() {
when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true); when(mHost.isDozeSuppressed()).thenReturn(true);
when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isDocked()).thenReturn(true);
when(mDockManager.isHidden()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true);

View File

@@ -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();
}
}

View File

@@ -447,4 +447,11 @@ public class CommandQueueTest extends SysuiTestCase {
waitForIdleSync(); waitForIdleSync();
verify(mCallbacks).hideAuthenticationDialog(); verify(mCallbacks).hideAuthenticationDialog();
} }
@Test
public void testSuppressAmbientDisplay() {
mCommandQueue.suppressAmbientDisplay(true);
waitForIdleSync();
verify(mCallbacks).suppressAmbientDisplay(true);
}
} }

View File

@@ -858,6 +858,18 @@ public class StatusBarTest extends SysuiTestCase {
any(UserHandle.class)); 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 public static class TestableNotificationInterruptionStateProvider extends
NotificationInterruptionStateProvider { NotificationInterruptionStateProvider {

View File

@@ -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<Pair<String, Integer>> 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<String, Integer> 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;
}
}

View File

@@ -75,7 +75,6 @@ import android.provider.Settings.SettingNotFoundException;
import android.service.dreams.DreamManagerInternal; import android.service.dreams.DreamManagerInternal;
import android.service.vr.IVrManager; import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks; import android.service.vr.IVrStateCallbacks;
import android.util.ArraySet;
import android.util.KeyValueListParser; import android.util.KeyValueListParser;
import android.util.PrintWriterPrinter; import android.util.PrintWriterPrinter;
import android.util.Slog; import android.util.Slog;
@@ -115,7 +114,6 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
/** /**
* The power manager service is responsible for coordinating power management * The power manager service is responsible for coordinating power management
@@ -266,6 +264,7 @@ public final class PowerManagerService extends SystemService
private LogicalLight mAttentionLight; private LogicalLight mAttentionLight;
private InattentiveSleepWarningController mInattentiveSleepWarningOverlayController; private InattentiveSleepWarningController mInattentiveSleepWarningOverlayController;
private final AmbientDisplaySuppressionController mAmbientDisplaySuppressionController;
private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_POWER); 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). // but the DreamService has not yet been told to start (it's an async process).
private boolean mDozeStartInProgress; private boolean mDozeStartInProgress;
// Set of all tokens suppressing ambient display.
private final Set<String> mAmbientDisplaySuppressionTokens = new ArraySet<>();
private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver { private final class ForegroundProfileObserver extends SynchronousUserSwitchObserver {
@Override @Override
public void onUserSwitching(@UserIdInt int newUserId) throws RemoteException { public void onUserSwitching(@UserIdInt int newUserId) throws RemoteException {
@@ -785,6 +781,11 @@ public final class PowerManagerService extends SystemService
return new AmbientDisplayConfiguration(context); return new AmbientDisplayConfiguration(context);
} }
AmbientDisplaySuppressionController createAmbientDisplaySuppressionController(
Context context) {
return new AmbientDisplaySuppressionController(context);
}
InattentiveSleepWarningController createInattentiveSleepWarningController() { InattentiveSleepWarningController createInattentiveSleepWarningController() {
return new InattentiveSleepWarningController(); return new InattentiveSleepWarningController();
} }
@@ -840,6 +841,8 @@ public final class PowerManagerService extends SystemService
mHandler = new PowerManagerHandler(mHandlerThread.getLooper()); mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
mConstants = new Constants(mHandler); mConstants = new Constants(mHandler);
mAmbientDisplayConfiguration = mInjector.createAmbientDisplayConfiguration(context); mAmbientDisplayConfiguration = mInjector.createAmbientDisplayConfiguration(context);
mAmbientDisplaySuppressionController =
mInjector.createAmbientDisplaySuppressionController(context);
mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock); mAttentionDetector = new AttentionDetector(this::onUserAttention, mLock);
mBatterySavingStats = new BatterySavingStats(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) { private void boostScreenBrightnessInternal(long eventTime, int uid) {
synchronized (mLock) { synchronized (mLock) {
if (!mSystemReady || getWakefulnessLocked() == WAKEFULNESS_ASLEEP if (!mSystemReady || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
@@ -3943,6 +3926,8 @@ public final class PowerManagerService extends SystemService
if (mNotifier != null) { if (mNotifier != null) {
mNotifier.dump(pw); mNotifier.dump(pw);
} }
mAmbientDisplaySuppressionController.dump(pw);
} }
private void dumpProto(FileDescriptor fd) { private void dumpProto(FileDescriptor fd) {
@@ -5211,7 +5196,7 @@ public final class PowerManagerService extends SystemService
final int uid = Binder.getCallingUid(); final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
try { try {
suppressAmbientDisplayInternal(createAmbientDisplayToken(token, uid), suppress); mAmbientDisplaySuppressionController.suppress(token, uid, suppress);
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
@@ -5225,8 +5210,7 @@ public final class PowerManagerService extends SystemService
final int uid = Binder.getCallingUid(); final int uid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
try { try {
return mAmbientDisplaySuppressionTokens.contains( return mAmbientDisplaySuppressionController.isSuppressed(token, uid);
createAmbientDisplayToken(token, uid));
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }
@@ -5239,7 +5223,7 @@ public final class PowerManagerService extends SystemService
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
try { try {
return mAmbientDisplaySuppressionTokens.size() > 0; return mAmbientDisplaySuppressionController.isSuppressed();
} finally { } finally {
Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident);
} }

View File

@@ -63,7 +63,6 @@ import com.android.server.LocalServices;
import com.android.server.notification.NotificationDelegate; import com.android.server.notification.NotificationDelegate;
import com.android.server.policy.GlobalActionsProvider; import com.android.server.policy.GlobalActionsProvider;
import com.android.server.power.ShutdownThread; import com.android.server.power.ShutdownThread;
import com.android.server.wm.WindowManagerService;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.PrintWriter; 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() { public String[] getStatusBarIcons() {
return mContext.getResources().getStringArray(R.array.config_statusBarIcons); return mContext.getResources().getStringArray(R.array.config_statusBarIcons);
} }

View File

@@ -841,66 +841,6 @@ public class PowerManagerServiceTest {
assertThat(mService.getBinderServiceInstance().isAmbientDisplayAvailable()).isFalse(); 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 @Test
public void testIsAmbientDisplaySuppressed_default_notSuppressed() throws Exception { public void testIsAmbientDisplaySuppressed_default_notSuppressed() throws Exception {
createService(); createService();