summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Will Leshner <wleshner@google.com> 2022-09-27 16:23:40 -0700
committer Will Leshner <wleshner@google.com> 2022-11-01 10:16:43 -0700
commitbffe18bf287807f8cdab3564d8844a8d79df72d0 (patch)
tree095e99f7e7293ebc5fdb59111f769dad2cd7a85c
parentd2cb23038f48536f96c04466a8567c52758d611e (diff)
Implement alternate power button behavior for dreams.
This change implements a power button behavior that prioritizes entering a dream on press, rather than turning off the screen. Bug: 245961904 Test: Manually as follows: Make sure config_shortPressOnPowerBehavior is set to SHORT_PRESS_POWER_DREAM_OR_SLEEP. 1. Set screensaver to dock then dock device. Make sure tapping power button when screen on goes to dream. Make sure tapping power button when screen off goes to dream. Make sure tapping power button while dreaming turns display off. 2. Set screensaver to charge then plug in device. Make sure tapping power button when screen on goes to dream. Make sure tapping power button when screen off goes to dream. Make sure tapping power button while dreaming turns display off. 3. Set screensaver to charge or dock and perform the same tests as above. 4. Set screensaver to dock and then undock device. Make sure tapping power button does not start dreaming. Note that the device may charge while docked, so setting screensaver to charge may act the same when docked or charging. Merged-In: I9b6859b4933839841b76b832f275dcc14313f192 Change-Id: Id0c37612b866111ed265ac282963611429bfb36b
-rw-r--r--core/java/android/service/dreams/DreamManagerInternal.java7
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java148
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java48
3 files changed, 199 insertions, 4 deletions
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index 295171ca9bbd..5f30ad054c50 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -54,6 +54,13 @@ public abstract class DreamManagerInternal {
public abstract void requestDream();
/**
+ * Whether dreaming can start given user settings and the current dock/charge state.
+ *
+ * @param isScreenOn True if the screen is currently on.
+ */
+ public abstract boolean canStartDreaming(boolean isScreenOn);
+
+ /**
* Called by the ActivityTaskManagerService to verify that the startDreamActivity
* request comes from the current active dream component.
*
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 5589673973c3..b785eb017e29 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -23,12 +23,14 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static com.android.server.wm.ActivityInterceptorCallback.DREAM_MANAGER_ORDERED_ID;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.TaskInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -39,6 +41,8 @@ import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.input.InputManagerInternal;
+import android.net.Uri;
+import android.os.BatteryManager;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -72,6 +76,8 @@ import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -88,6 +94,15 @@ public final class DreamManagerService extends SystemService {
private static final String DOZE_WAKE_LOCK_TAG = "dream:doze";
private static final String DREAM_WAKE_LOCK_TAG = "dream:dream";
+ /** Constants for the when to activate dreams. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({DREAM_ON_DOCK, DREAM_ON_CHARGE, DREAM_ON_DOCK_OR_CHARGE})
+ public @interface WhenToDream {}
+ private static final int DREAM_DISABLED = 0x0;
+ private static final int DREAM_ON_DOCK = 0x1;
+ private static final int DREAM_ON_CHARGE = 0x2;
+ private static final int DREAM_ON_DOCK_OR_CHARGE = 0x3;
+
private final Object mLock = new Object();
private final Context mContext;
@@ -101,12 +116,20 @@ public final class DreamManagerService extends SystemService {
private final DreamUiEventLogger mDreamUiEventLogger;
private final ComponentName mAmbientDisplayComponent;
private final boolean mDismissDreamOnActivityStart;
+ private final boolean mDreamsOnlyEnabledForSystemUser;
+ private final boolean mDreamsEnabledByDefaultConfig;
+ private final boolean mDreamsActivatedOnChargeByDefault;
+ private final boolean mDreamsActivatedOnDockByDefault;
@GuardedBy("mLock")
private DreamRecord mCurrentDream;
private boolean mForceAmbientDisplayEnabled;
- private final boolean mDreamsOnlyEnabledForSystemUser;
+ private SettingsObserver mSettingsObserver;
+ private boolean mDreamsEnabledSetting;
+ @WhenToDream private int mWhenToDream;
+ private boolean mIsDocked;
+ private boolean mIsCharging;
// A temporary dream component that, when present, takes precedence over user configured dream
// component.
@@ -144,6 +167,37 @@ public final class DreamManagerService extends SystemService {
}
};
+ private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mIsCharging = BatteryManager.ACTION_CHARGING.equals(intent.getAction());
+ }
+ };
+
+ private final BroadcastReceiver mDockStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) {
+ final int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+ Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ mIsDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ }
+ }
+ };
+
+ private final class SettingsObserver extends ContentObserver {
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ synchronized (mLock) {
+ updateWhenToDreamSettings();
+ }
+ }
+ }
+
public DreamManagerService(Context context) {
super(context);
mContext = context;
@@ -164,6 +218,14 @@ public final class DreamManagerService extends SystemService {
mContext.getResources().getBoolean(R.bool.config_dreamsOnlyEnabledForSystemUser);
mDismissDreamOnActivityStart = mContext.getResources().getBoolean(
R.bool.config_dismissDreamOnActivityStart);
+
+ mDreamsEnabledByDefaultConfig = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_dreamsEnabledByDefault);
+ mDreamsActivatedOnChargeByDefault = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
+ mDreamsActivatedOnDockByDefault = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
+ mSettingsObserver = new SettingsObserver(mHandler);
}
@Override
@@ -197,6 +259,30 @@ public final class DreamManagerService extends SystemService {
DREAM_MANAGER_ORDERED_ID,
mActivityInterceptorCallback);
}
+
+ mContext.registerReceiver(
+ mDockStateReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT));
+ IntentFilter chargingIntentFilter = new IntentFilter();
+ chargingIntentFilter.addAction(BatteryManager.ACTION_CHARGING);
+ chargingIntentFilter.addAction(BatteryManager.ACTION_DISCHARGING);
+ mContext.registerReceiver(mChargingReceiver, chargingIntentFilter);
+
+ mSettingsObserver = new SettingsObserver(mHandler);
+ mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+ Settings.Secure.SCREENSAVER_ENABLED),
+ false, mSettingsObserver, UserHandle.USER_ALL);
+
+ // We don't get an initial broadcast for the batter state, so we have to initialize
+ // directly from BatteryManager.
+ mIsCharging = mContext.getSystemService(BatteryManager.class).isCharging();
+
+ updateWhenToDreamSettings();
}
}
@@ -207,6 +293,14 @@ public final class DreamManagerService extends SystemService {
pw.println("mCurrentDream=" + mCurrentDream);
pw.println("mForceAmbientDisplayEnabled=" + mForceAmbientDisplayEnabled);
pw.println("mDreamsOnlyEnabledForSystemUser=" + mDreamsOnlyEnabledForSystemUser);
+ pw.println("mDreamsEnabledSetting=" + mDreamsEnabledSetting);
+ pw.println("mForceAmbientDisplayEnabled=" + mForceAmbientDisplayEnabled);
+ pw.println("mDreamsOnlyEnabledForSystemUser=" + mDreamsOnlyEnabledForSystemUser);
+ pw.println("mDreamsActivatedOnDockByDefault=" + mDreamsActivatedOnDockByDefault);
+ pw.println("mDreamsActivatedOnChargeByDefault=" + mDreamsActivatedOnChargeByDefault);
+ pw.println("mIsDocked=" + mIsDocked);
+ pw.println("mIsCharging=" + mIsCharging);
+ pw.println("mWhenToDream=" + mWhenToDream);
pw.println("getDozeComponent()=" + getDozeComponent());
pw.println();
@@ -214,7 +308,28 @@ public final class DreamManagerService extends SystemService {
}
}
- /** Whether a real dream is occurring. */
+ private void updateWhenToDreamSettings() {
+ synchronized (mLock) {
+ final ContentResolver resolver = mContext.getContentResolver();
+
+ final int activateWhenCharging = (Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+ mDreamsActivatedOnChargeByDefault ? 1 : 0,
+ UserHandle.USER_CURRENT) != 0) ? DREAM_ON_CHARGE : DREAM_DISABLED;
+ final int activateWhenDocked = (Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ mDreamsActivatedOnDockByDefault ? 1 : 0,
+ UserHandle.USER_CURRENT) != 0) ? DREAM_ON_DOCK : DREAM_DISABLED;
+ mWhenToDream = activateWhenCharging + activateWhenDocked;
+
+ mDreamsEnabledSetting = (Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.SCREENSAVER_ENABLED,
+ mDreamsEnabledByDefaultConfig ? 1 : 0,
+ UserHandle.USER_CURRENT) != 0);
+ }
+ }
+
+ /** Whether a real dream is occurring. */
private boolean isDreamingInternal() {
synchronized (mLock) {
return mCurrentDream != null && !mCurrentDream.isPreview
@@ -236,6 +351,30 @@ public final class DreamManagerService extends SystemService {
}
}
+ /** Whether dreaming can start given user settings and the current dock/charge state. */
+ private boolean canStartDreamingInternal(boolean isScreenOn) {
+ synchronized (mLock) {
+ // Can't start dreaming if we are already dreaming.
+ if (isScreenOn && isDreamingInternal()) {
+ return false;
+ }
+
+ if (!mDreamsEnabledSetting) {
+ return false;
+ }
+
+ if ((mWhenToDream & DREAM_ON_CHARGE) == DREAM_ON_CHARGE) {
+ return mIsCharging;
+ }
+
+ if ((mWhenToDream & DREAM_ON_DOCK) == DREAM_ON_DOCK) {
+ return mIsDocked;
+ }
+
+ return false;
+ }
+ }
+
protected void requestStartDreamFromShell() {
requestDreamInternal();
}
@@ -869,6 +1008,11 @@ public final class DreamManagerService extends SystemService {
}
@Override
+ public boolean canStartDreaming(boolean isScreenOn) {
+ return canStartDreamingInternal(isScreenOn);
+ }
+
+ @Override
public ComponentName getActiveDreamComponent(boolean doze) {
return getActiveDreamComponentInternal(doze);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index fa0d41c5ac2f..352d4be6c7ce 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -256,6 +256,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final int SHORT_PRESS_POWER_GO_HOME = 4;
static final int SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME = 5;
static final int SHORT_PRESS_POWER_LOCK_OR_SLEEP = 6;
+ static final int SHORT_PRESS_POWER_DREAM_OR_SLEEP = 7;
// must match: config_LongPressOnPowerBehavior in config.xml
static final int LONG_PRESS_POWER_NOTHING = 0;
@@ -971,7 +972,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
} else if (count > 3 && count <= getMaxMultiPressPowerCount()) {
Slog.d(TAG, "No behavior defined for power press count " + count);
- } else if (count == 1 && interactive && !beganFromNonInteractive) {
+ } else if (count == 1 && interactive) {
+ if (beganFromNonInteractive) {
+ // The screen off case, where we might want to start dreaming on power button press.
+ attemptToDreamFromShortPowerButtonPress(false, () -> {});
+ return;
+ }
if (mSideFpsEventHandler.shouldConsumeSinglePress(eventTime)) {
Slog.i(TAG, "Suppressing power key because the user is interacting with the "
+ "fingerprint sensor");
@@ -1020,11 +1026,39 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
break;
}
+ case SHORT_PRESS_POWER_DREAM_OR_SLEEP: {
+ attemptToDreamFromShortPowerButtonPress(
+ true,
+ () -> sleepDefaultDisplayFromPowerButton(eventTime, 0));
+ break;
+ }
}
}
}
/**
+ * Attempt to dream from a power button press.
+ *
+ * @param isScreenOn Whether the screen is currently on.
+ * @param noDreamAction The action to perform if dreaming is not possible.
+ */
+ private void attemptToDreamFromShortPowerButtonPress(
+ boolean isScreenOn, Runnable noDreamAction) {
+ if (mShortPressOnPowerBehavior != SHORT_PRESS_POWER_DREAM_OR_SLEEP) {
+ noDreamAction.run();
+ return;
+ }
+
+ final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal();
+ if (dreamManagerInternal == null || !dreamManagerInternal.canStartDreaming(isScreenOn)) {
+ noDreamAction.run();
+ return;
+ }
+
+ dreamManagerInternal.requestDream();
+ }
+
+ /**
* Sends the default display to sleep as a result of a power button press.
*
* @return {@code true} if the device was sent to sleep, {@code false} if the device did not
@@ -1595,7 +1629,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// If there's a dream running then use home to escape the dream
// but don't actually go home.
- if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
+ final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal();
+ if (dreamManagerInternal != null && dreamManagerInternal.isDreaming()) {
mDreamManagerInternal.stopDream(false /*immediate*/, "short press on home" /*reason*/);
return;
}
@@ -2483,6 +2518,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ private DreamManagerInternal getDreamManagerInternal() {
+ if (mDreamManagerInternal == null) {
+ // If mDreamManagerInternal is null, attempt to re-fetch it.
+ mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
+ }
+
+ return mDreamManagerInternal;
+ }
+
private void updateWakeGestureListenerLp() {
if (shouldEnableWakeGestureLp()) {
mWakeGestureListener.requestWakeUpTrigger();