Merge "Don't start dreams immediately if keyguard is occluded when docked." into tm-qpr-dev am: deb4e7788a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19763724

Change-Id: I51664a04a35c6a5f2817bcab427d1257d88132d9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Lucas Silva
2022-09-01 19:46:59 +00:00
committed by Automerger Merge Worker
6 changed files with 201 additions and 33 deletions

View File

@@ -45,6 +45,12 @@ public abstract class DreamManagerInternal {
*/ */
public abstract boolean isDreaming(); public abstract boolean isDreaming();
/**
* Ask the power manager to nap. It will eventually call back into startDream() if/when it is
* appropriate to start dreaming.
*/
public abstract void requestDream();
/** /**
* Called by the ActivityTaskManagerService to verify that the startDreamActivity * Called by the ActivityTaskManagerService to verify that the startDreamActivity
* request comes from the current active dream component. * request comes from the current active dream component.

View File

@@ -20,13 +20,13 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.PowerManager; import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock; import android.os.SystemClock;
import android.os.UserHandle; import android.os.UserHandle;
import android.provider.Settings; import android.provider.Settings;
import android.util.Slog; import android.util.Slog;
import com.android.server.LocalServices;
/** /**
* Internal helper for launching dreams to ensure consistency between the * Internal helper for launching dreams to ensure consistency between the
* <code>UiModeManagerService</code> system service and the <code>Somnambulator</code> activity. * <code>UiModeManagerService</code> system service and the <code>Somnambulator</code> activity.
@@ -75,9 +75,8 @@ public final class Sandman {
} }
private static void startDream(Context context, boolean docked) { private static void startDream(Context context, boolean docked) {
try { DreamManagerInternal dreamManagerService =
IDreamManager dreamManagerService = IDreamManager.Stub.asInterface( LocalServices.getService(DreamManagerInternal.class);
ServiceManager.getService(DreamService.DREAM_SERVICE));
if (dreamManagerService != null && !dreamManagerService.isDreaming()) { if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
if (docked) { if (docked) {
Slog.i(TAG, "Activating dream while docked."); Slog.i(TAG, "Activating dream while docked.");
@@ -97,10 +96,7 @@ public final class Sandman {
} }
// Dream. // Dream.
dreamManagerService.dream(); dreamManagerService.requestDream();
}
} catch (RemoteException ex) {
Slog.e(TAG, "Could not start dream when docked.", ex);
} }
} }

View File

@@ -359,6 +359,11 @@ final class UiModeManagerService extends SystemService {
SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode)); SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode));
} }
@VisibleForTesting
void setStartDreamImmediatelyOnDock(boolean startDreamImmediatelyOnDock) {
mStartDreamImmediatelyOnDock = startDreamImmediatelyOnDock;
}
@Override @Override
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
mCurrentUser = to.getUserIdentifier(); mCurrentUser = to.getUserIdentifier();
@@ -1824,7 +1829,8 @@ final class UiModeManagerService extends SystemService {
// If we did not start a dock app, then start dreaming if appropriate. // If we did not start a dock app, then start dreaming if appropriate.
if (category != null && !dockAppStarted && (mStartDreamImmediatelyOnDock if (category != null && !dockAppStarted && (mStartDreamImmediatelyOnDock
|| mKeyguardManager.isKeyguardLocked())) { || mWindowManager.isKeyguardShowingAndNotOccluded()
|| !mPowerManager.isInteractive())) {
Sandman.startDreamWhenDockedIfAppropriate(getContext()); Sandman.startDreamWhenDockedIfAppropriate(getContext());
} }
} }

View File

@@ -883,6 +883,11 @@ public final class DreamManagerService extends SystemService {
public ComponentName getActiveDreamComponent(boolean doze) { public ComponentName getActiveDreamComponent(boolean doze) {
return getActiveDreamComponentInternal(doze); return getActiveDreamComponentInternal(doze);
} }
@Override
public void requestDream() {
requestDreamInternal();
}
} }
private final Runnable mSystemPropertiesChanged = new Runnable() { private final Runnable mSystemPropertiesChanged = new Runnable() {

View File

@@ -20,6 +20,7 @@ android_test {
], ],
static_libs: [ static_libs: [
"frameworks-base-testutils",
"services.accessibility", "services.accessibility",
"services.core", "services.core",
"services.devicepolicy", "services.devicepolicy",
@@ -32,6 +33,7 @@ android_test {
"platformprotosnano", "platformprotosnano",
"statsdprotolite", "statsdprotolite",
"hamcrest-library", "hamcrest-library",
"servicestests-utils",
"testables", "testables",
"truth-prebuilt", "truth-prebuilt",
// TODO: remove once Android migrates to JUnit 4.12, // TODO: remove once Android migrates to JUnit 4.12,

View File

@@ -45,6 +45,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
@@ -58,31 +59,36 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.testng.Assert.assertThrows; import static org.testng.Assert.assertThrows;
import android.Manifest; import android.Manifest;
import android.app.Activity;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.IOnProjectionStateChangedListener; import android.app.IOnProjectionStateChangedListener;
import android.app.IUiModeManager; import android.app.IUiModeManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Process;
import android.os.PowerManager; 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.RemoteException; import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
import android.test.mock.MockContentResolver;
import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper; import android.testing.TestableLooper;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.twilight.TwilightListener; import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager; import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState; import com.android.server.twilight.TwilightState;
@@ -93,6 +99,7 @@ import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -107,8 +114,7 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
private static final String PACKAGE_NAME = "Diane Coffee"; private static final String PACKAGE_NAME = "Diane Coffee";
private UiModeManagerService mUiManagerService; private UiModeManagerService mUiManagerService;
private IUiModeManager mService; private IUiModeManager mService;
@Mock private MockContentResolver mContentResolver;
private ContentResolver mContentResolver;
@Mock @Mock
private WindowManagerInternal mWindowManager; private WindowManagerInternal mWindowManager;
@Mock @Mock
@@ -131,16 +137,22 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
private PackageManager mPackageManager; private PackageManager mPackageManager;
@Mock @Mock
private IBinder mBinder; private IBinder mBinder;
@Mock
private DreamManagerInternal mDreamManager;
@Captor
private ArgumentCaptor<Intent> mOrderedBroadcastIntent;
@Captor
private ArgumentCaptor<BroadcastReceiver> mOrderedBroadcastReceiver;
private BroadcastReceiver mScreenOffCallback; private BroadcastReceiver mScreenOffCallback;
private BroadcastReceiver mTimeChangedCallback; private BroadcastReceiver mTimeChangedCallback;
private BroadcastReceiver mDockStateChangedCallback;
private AlarmManager.OnAlarmListener mCustomListener; private AlarmManager.OnAlarmListener mCustomListener;
private Consumer<PowerSaveState> mPowerSaveConsumer; private Consumer<PowerSaveState> mPowerSaveConsumer;
private TwilightListener mTwilightListener; private TwilightListener mTwilightListener;
@Before @Before
public void setUp() { public void setUp() {
initMocks(this);
when(mContext.checkCallingOrSelfPermission(anyString())) when(mContext.checkCallingOrSelfPermission(anyString()))
.thenReturn(PackageManager.PERMISSION_GRANTED); .thenReturn(PackageManager.PERMISSION_GRANTED);
doAnswer(inv -> { doAnswer(inv -> {
@@ -154,6 +166,10 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
when(mLocalPowerManager.getLowPowerState(anyInt())) when(mLocalPowerManager.getLowPowerState(anyInt()))
.thenReturn(new PowerSaveState.Builder().setBatterySaverEnabled(false).build()); .thenReturn(new PowerSaveState.Builder().setBatterySaverEnabled(false).build());
when(mContext.getResources()).thenReturn(mResources); when(mContext.getResources()).thenReturn(mResources);
when(mResources.getString(com.android.internal.R.string.config_somnambulatorComponent))
.thenReturn("somnambulator");
mContentResolver = new MockContentResolver();
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mContentResolver); when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPowerManager.isInteractive()).thenReturn(true); when(mPowerManager.isInteractive()).thenReturn(true);
@@ -168,6 +184,9 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
if (filter.hasAction(Intent.ACTION_SCREEN_OFF)) { if (filter.hasAction(Intent.ACTION_SCREEN_OFF)) {
mScreenOffCallback = inv.getArgument(0); mScreenOffCallback = inv.getArgument(0);
} }
if (filter.hasAction(Intent.ACTION_DOCK_EVENT)) {
mDockStateChangedCallback = inv.getArgument(0);
}
return null; return null;
}); });
doAnswer(inv -> { doAnswer(inv -> {
@@ -182,11 +201,13 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
}).when(mAlarmManager).cancel(eq(mCustomListener)); }).when(mAlarmManager).cancel(eq(mCustomListener));
when(mContext.getSystemService(eq(Context.POWER_SERVICE))) when(mContext.getSystemService(eq(Context.POWER_SERVICE)))
.thenReturn(mPowerManager); .thenReturn(mPowerManager);
when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
when(mContext.getSystemService(eq(Context.ALARM_SERVICE))) when(mContext.getSystemService(eq(Context.ALARM_SERVICE)))
.thenReturn(mAlarmManager); .thenReturn(mAlarmManager);
addLocalService(WindowManagerInternal.class, mWindowManager); addLocalService(WindowManagerInternal.class, mWindowManager);
addLocalService(PowerManagerInternal.class, mLocalPowerManager); addLocalService(PowerManagerInternal.class, mLocalPowerManager);
addLocalService(TwilightManager.class, mTwilightManager); addLocalService(TwilightManager.class, mTwilightManager);
addLocalService(DreamManagerInternal.class, mDreamManager);
mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true, mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true,
mTwilightManager, new TestInjector()); mTwilightManager, new TestInjector());
@@ -1298,6 +1319,138 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR); assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
} }
@Test
public void dreamWhenDocked() {
setScreensaverActivateOnDock(true);
setScreensaverEnabled(true);
triggerDockIntent();
verifyAndSendResultBroadcast();
verify(mDreamManager).requestDream();
}
@Test
public void noDreamWhenDocked_dreamsDisabled() {
setScreensaverActivateOnDock(true);
setScreensaverEnabled(false);
triggerDockIntent();
verifyAndSendResultBroadcast();
verify(mDreamManager, never()).requestDream();
}
@Test
public void noDreamWhenDocked_dreamsWhenDockedDisabled() {
setScreensaverActivateOnDock(false);
setScreensaverEnabled(true);
triggerDockIntent();
verifyAndSendResultBroadcast();
verify(mDreamManager, never()).requestDream();
}
@Test
public void noDreamWhenDocked_keyguardNotShowing_interactive() {
setScreensaverActivateOnDock(true);
setScreensaverEnabled(true);
mUiManagerService.setStartDreamImmediatelyOnDock(false);
when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(false);
when(mPowerManager.isInteractive()).thenReturn(true);
triggerDockIntent();
verifyAndSendResultBroadcast();
verify(mDreamManager, never()).requestDream();
}
@Test
public void dreamWhenDocked_keyguardShowing_interactive() {
setScreensaverActivateOnDock(true);
setScreensaverEnabled(true);
mUiManagerService.setStartDreamImmediatelyOnDock(false);
when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(true);
when(mPowerManager.isInteractive()).thenReturn(false);
triggerDockIntent();
verifyAndSendResultBroadcast();
verify(mDreamManager).requestDream();
}
@Test
public void dreamWhenDocked_keyguardNotShowing_notInteractive() {
setScreensaverActivateOnDock(true);
setScreensaverEnabled(true);
mUiManagerService.setStartDreamImmediatelyOnDock(false);
when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(false);
when(mPowerManager.isInteractive()).thenReturn(false);
triggerDockIntent();
verifyAndSendResultBroadcast();
verify(mDreamManager).requestDream();
}
@Test
public void dreamWhenDocked_keyguardShowing_notInteractive() {
setScreensaverActivateOnDock(true);
setScreensaverEnabled(true);
mUiManagerService.setStartDreamImmediatelyOnDock(false);
when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(true);
when(mPowerManager.isInteractive()).thenReturn(false);
triggerDockIntent();
verifyAndSendResultBroadcast();
verify(mDreamManager).requestDream();
}
private void triggerDockIntent() {
final Intent dockedIntent =
new Intent(Intent.ACTION_DOCK_EVENT)
.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_DESK);
mDockStateChangedCallback.onReceive(mContext, dockedIntent);
}
private void verifyAndSendResultBroadcast() {
verify(mContext).sendOrderedBroadcastAsUser(
mOrderedBroadcastIntent.capture(),
any(UserHandle.class),
nullable(String.class),
mOrderedBroadcastReceiver.capture(),
nullable(Handler.class),
anyInt(),
nullable(String.class),
nullable(Bundle.class));
mOrderedBroadcastReceiver.getValue().setPendingResult(
new BroadcastReceiver.PendingResult(
Activity.RESULT_OK,
/* resultData= */ "",
/* resultExtras= */ null,
/* type= */ 0,
/* ordered= */ true,
/* sticky= */ false,
/* token= */ null,
/* userId= */ 0,
/* flags= */ 0));
mOrderedBroadcastReceiver.getValue().onReceive(
mContext,
mOrderedBroadcastIntent.getValue());
}
private void setScreensaverEnabled(boolean enable) {
Settings.Secure.putIntForUser(
mContentResolver,
Settings.Secure.SCREENSAVER_ENABLED,
enable ? 1 : 0,
UserHandle.USER_CURRENT);
}
private void setScreensaverActivateOnDock(boolean enable) {
Settings.Secure.putIntForUser(
mContentResolver,
Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
enable ? 1 : 0,
UserHandle.USER_CURRENT);
}
private void requestAllPossibleProjectionTypes() throws RemoteException { private void requestAllPossibleProjectionTypes() throws RemoteException {
for (int i = 0; i < Integer.SIZE; ++i) { for (int i = 0; i < Integer.SIZE; ++i) {
mService.requestProjection(mBinder, 1 << i, PACKAGE_NAME); mService.requestProjection(mBinder, 1 << i, PACKAGE_NAME);