summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--core/java/android/os/PowerManager.java13
-rw-r--r--core/java/android/service/dreams/DozeHardware.java77
-rw-r--r--core/java/android/service/dreams/DreamManagerInternal.java2
-rw-r--r--core/java/android/service/dreams/DreamService.java294
-rw-r--r--core/java/android/service/dreams/IDozeHardware.aidl24
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl6
-rw-r--r--core/java/android/service/dreams/IDreamService.aidl2
-rw-r--r--core/java/android/view/WindowManagerPolicy.java22
-rw-r--r--core/res/res/values/config.xml69
-rw-r--r--core/res/res/values/symbols.xml8
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindowManager.java25
-rw-r--r--services/core/java/com/android/server/dreams/DreamController.java19
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java179
-rw-r--r--services/core/java/com/android/server/dreams/McuHal.java46
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java7
-rw-r--r--services/core/java/com/android/server/power/DisplayPowerController.java37
-rw-r--r--services/core/java/com/android/server/power/DisplayPowerRequest.java24
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java401
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java4
-rw-r--r--services/core/jni/Android.mk1
-rw-r--r--services/core/jni/com_android_server_dreams_McuHal.cpp100
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp20
-rw-r--r--services/core/jni/onload.cpp3
-rw-r--r--tests/DozeTest/Android.mk14
-rw-r--r--tests/DozeTest/AndroidManifest.xml35
-rwxr-xr-xtests/DozeTest/res/drawable-hdpi/ic_app.pngbin0 -> 3608 bytes
-rw-r--r--tests/DozeTest/res/drawable-mdpi/ic_app.pngbin0 -> 5198 bytes
-rw-r--r--tests/DozeTest/res/layout/dream.xml41
-rw-r--r--tests/DozeTest/res/values/strings.xml25
-rw-r--r--tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java165
31 files changed, 1377 insertions, 287 deletions
diff --git a/Android.mk b/Android.mk
index 687989c..7cbc339 100644
--- a/Android.mk
+++ b/Android.mk
@@ -176,6 +176,7 @@ LOCAL_SRC_FILES += \
core/java/android/print/IWriteResultCallback.aidl \
core/java/android/printservice/IPrintService.aidl \
core/java/android/printservice/IPrintServiceClient.aidl \
+ core/java/android/service/dreams/IDozeHardware.aidl \
core/java/android/service/dreams/IDreamManager.aidl \
core/java/android/service/dreams/IDreamService.aidl \
core/java/android/service/wallpaper/IWallpaperConnection.aidl \
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 5e0d489..86ef479 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -191,6 +191,18 @@ public final class PowerManager {
public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;
/**
+ * Wake lock level: Put the screen in a low power state and allow the CPU to suspend
+ * if no other wake locks are held.
+ * <p>
+ * This is used by the dream manager to implement doze mode. It currently
+ * has no effect unless the power manager is in the dozing state.
+ * </p>
+ *
+ * {@hide}
+ */
+ public static final int DOZE_WAKE_LOCK = 0x00000040;
+
+ /**
* Mask for the wake lock level component of a combined wake lock level and flags integer.
*
* @hide
@@ -418,6 +430,7 @@ public final class PowerManager {
case SCREEN_BRIGHT_WAKE_LOCK:
case FULL_WAKE_LOCK:
case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+ case DOZE_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException("Must specify a valid wake lock level.");
diff --git a/core/java/android/service/dreams/DozeHardware.java b/core/java/android/service/dreams/DozeHardware.java
new file mode 100644
index 0000000..b5e7f43
--- /dev/null
+++ b/core/java/android/service/dreams/DozeHardware.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (C) 2014 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 android.service.dreams;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Provides access to low-level hardware features that a dream may use to provide
+ * a richer user experience while dozing.
+ * <p>
+ * This class contains functions that should be called by the dream to configure
+ * hardware before starting to doze and allowing the application processor to suspend.
+ * For example, the dream may provide the hardware with enough information to render
+ * some content on its own without any further assistance from the application processor.
+ * </p><p>
+ * This object is obtained by calling {@link DreamService#getDozeHardware()}.
+ * </p>
+ *
+ * @hide experimental
+ */
+public final class DozeHardware {
+ private static final String TAG = "DozeHardware";
+
+ public static final String MSG_ENABLE_MCU = "enable_mcu";
+
+ public static final byte[] VALUE_ON = "on".getBytes();
+ public static final byte[] VALUE_OFF = "off".getBytes();
+
+ private final IDozeHardware mHardware;
+
+ DozeHardware(IDozeHardware hardware) {
+ mHardware = hardware;
+ }
+
+ /**
+ * Sets whether to enable the microcontroller.
+ *
+ * @param enable If true, enables the MCU otherwise disables it.
+ */
+ public void setEnableMcu(boolean enable) {
+ sendMessage(MSG_ENABLE_MCU, enable ? VALUE_ON : VALUE_OFF);
+ }
+
+ /**
+ * Sends a message to the doze hardware module.
+ *
+ * @param msg The name of the message to send.
+ * @param arg An optional argument data blob, may be null.
+ * @return A result data blob, may be null.
+ */
+ public byte[] sendMessage(String msg, byte[] arg) {
+ if (msg == null) {
+ throw new IllegalArgumentException("msg must not be null");
+ }
+
+ try {
+ return mHardware.sendMessage(msg, arg);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to send message to doze hardware module.", ex);
+ return null;
+ }
+ }
+}
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index 17ea996..9f7ddba 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -25,7 +25,7 @@ public abstract class DreamManagerInternal {
/**
* Called by the power manager to start a dream.
*/
- public abstract void startDream();
+ public abstract void startDream(boolean doze);
/**
* Called by the power manager to stop a dream.
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index f6b6c89..1abb1d7 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -20,12 +20,14 @@ import java.io.PrintWriter;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.AlarmManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
import android.view.ActionMode;
@@ -42,6 +44,8 @@ import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.policy.PolicyManager;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.DumpUtils.Dump;
/**
* Extend this class to implement a custom dream (available to the user as a "Daydream").
@@ -145,19 +149,26 @@ public class DreamService extends Service implements Window.Callback {
*/
public static final String DREAM_META_DATA = "android.service.dream";
+ private final IDreamManager mSandman;
private final Handler mHandler = new Handler();
private IBinder mWindowToken;
private Window mWindow;
private WindowManager mWindowManager;
- private IDreamManager mSandman;
private boolean mInteractive = false;
private boolean mLowProfile = true;
private boolean mFullscreen = false;
private boolean mScreenBright = true;
private boolean mFinished;
+ private boolean mCanDoze;
+ private boolean mDozing;
+ private DozeHardware mDozeHardware;
private boolean mDebug = false;
+ public DreamService() {
+ mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
+ }
+
/**
* @hide
*/
@@ -444,9 +455,11 @@ public class DreamService extends Service implements Window.Callback {
* correct interactions with it (seeing when it is cleared etc).
*/
public void setLowProfile(boolean lowProfile) {
- mLowProfile = lowProfile;
- int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
- applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
+ if (mLowProfile != lowProfile) {
+ mLowProfile = lowProfile;
+ int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
+ applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
+ }
}
/**
@@ -467,9 +480,11 @@ public class DreamService extends Service implements Window.Callback {
* will be cleared.
*/
public void setFullscreen(boolean fullscreen) {
- mFullscreen = fullscreen;
- int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
- applyWindowFlags(mFullscreen ? flag : 0, flag);
+ if (mFullscreen != fullscreen) {
+ mFullscreen = fullscreen;
+ int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
+ applyWindowFlags(mFullscreen ? flag : 0, flag);
+ }
}
/**
@@ -487,14 +502,16 @@ public class DreamService extends Service implements Window.Callback {
* @param screenBright True to keep the screen bright while dreaming.
*/
public void setScreenBright(boolean screenBright) {
- mScreenBright = screenBright;
- int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
- applyWindowFlags(mScreenBright ? flag : 0, flag);
+ if (mScreenBright != screenBright) {
+ mScreenBright = screenBright;
+ int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+ applyWindowFlags(mScreenBright ? flag : 0, flag);
+ }
}
/**
- * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false,
- * allowing the screen to dim if necessary.
+ * Returns whether or not this dream keeps the screen bright while dreaming.
+ * Defaults to false, allowing the screen to dim if necessary.
*
* @see #setScreenBright(boolean)
*/
@@ -503,6 +520,119 @@ public class DreamService extends Service implements Window.Callback {
}
/**
+ * Returns true if this dream is allowed to doze.
+ * <p>
+ * The value returned by this method is only meaningful when the dream has started.
+ * </p>
+ *
+ * @return True if this dream can doze.
+ * @see #startDozing
+ * @hide experimental
+ */
+ public boolean canDoze() {
+ return mCanDoze;
+ }
+
+ /**
+ * Starts dozing, entering a deep dreamy sleep.
+ * <p>
+ * Dozing enables the system to conserve power while the user is not actively interacting
+ * with the device. While dozing, the display will remain on in a low-power state
+ * and will continue to show its previous contents but the application processor and
+ * other system components will be allowed to suspend when possible.
+ * </p><p>
+ * While the application processor is suspended, the dream may stop executing code
+ * for long periods of time. Prior to being suspended, the dream may schedule periodic
+ * wake-ups to render new content by scheduling an alarm with the {@link AlarmManager}.
+ * The dream may also keep the CPU awake by acquiring a
+ * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} when necessary.
+ * Note that since the purpose of doze mode is to conserve power (especially when
+ * running on battery), the dream should not wake the CPU very often or keep it
+ * awake for very long.
+ * </p><p>
+ * It is a good idea to call this method some time after the dream's entry animation
+ * has completed and the dream is ready to doze. It is important to completely
+ * finish all of the work needed before dozing since the application processor may
+ * be suspended at any moment once this method is called unless other wake locks
+ * are being held.
+ * </p><p>
+ * Call {@link #stopDozing} or {@link #finish} to stop dozing.
+ * </p>
+ *
+ * @see #stopDozing
+ * @hide experimental
+ */
+ public void startDozing() {
+ if (mCanDoze && !mDozing) {
+ mDozing = true;
+ try {
+ mSandman.startDozing(mWindowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ }
+ }
+
+ /**
+ * Stops dozing, returns to active dreaming.
+ * <p>
+ * This method reverses the effect of {@link #startDozing}. From this moment onward,
+ * the application processor will be kept awake as long as the dream is running
+ * or until the dream starts dozing again.
+ * </p>
+ *
+ * @see #startDozing
+ * @hide experimental
+ */
+ public void stopDozing() {
+ if (mDozing) {
+ mDozing = false;
+ try {
+ mSandman.stopDozing(mWindowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ }
+ }
+
+ /**
+ * Returns true if the dream will allow the system to enter a low-power state while
+ * it is running without actually turning off the screen. Defaults to false,
+ * keeping the application processor awake while the dream is running.
+ *
+ * @return True if the dream is dozing.
+ *
+ * @see #setDozing(boolean)
+ * @hide experimental
+ */
+ public boolean isDozing() {
+ return mDozing;
+ }
+
+ /**
+ * Gets an object that may be used to access low-level hardware features that a
+ * dream may use to provide a richer user experience while dozing.
+ *
+ * @return An instance of {@link DozeHardware} or null if this device does not offer
+ * hardware support for dozing.
+ *
+ * @hide experimental
+ */
+ public DozeHardware getDozeHardware() {
+ if (mCanDoze && mDozeHardware == null) {
+ try {
+ IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken);
+ if (hardware != null) {
+ mDozeHardware = new DozeHardware(hardware);
+ }
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ }
+ return mDozeHardware;
+ }
+
+ /**
* Called when this Dream is constructed.
*/
@Override
@@ -536,7 +666,11 @@ public class DreamService extends Service implements Window.Callback {
}
/**
- * Stops the dream, detaches from the window, and wakes up.
+ * Stops the dream and detaches from the window.
+ * <p>
+ * When the dream ends, the system will be allowed to go to sleep fully unless there
+ * is a reason for it to be awake such as recent user activity or wake locks being held.
+ * </p>
*/
public final void finish() {
if (mDebug) Slog.v(TAG, "finish()");
@@ -557,10 +691,6 @@ public class DreamService extends Service implements Window.Callback {
// end public api
- private void loadSandman() {
- mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
- }
-
/**
* Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
*
@@ -572,23 +702,16 @@ public class DreamService extends Service implements Window.Callback {
return;
}
- try {
- onDreamingStopped();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in onDreamingStopped()", t);
- // we were going to stop anyway
- }
+ if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
+ onDreamingStopped();
if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
- try {
- // force our window to be removed synchronously
- mWindowManager.removeViewImmediate(mWindow.getDecorView());
- // the following will print a log message if it finds any other leaked windows
- WindowManagerGlobal.getInstance().closeAll(mWindowToken,
- this.getClass().getName(), "Dream");
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed removing window view", t);
- }
+
+ // force our window to be removed synchronously
+ mWindowManager.removeViewImmediate(mWindow.getDecorView());
+ // the following will print a log message if it finds any other leaked windows
+ WindowManagerGlobal.getInstance().closeAll(mWindowToken,
+ this.getClass().getName(), "Dream");
mWindow = null;
mWindowToken = null;
@@ -601,23 +724,30 @@ public class DreamService extends Service implements Window.Callback {
*
* @param windowToken A window token that will allow a window to be created in the correct layer.
*/
- private final void attach(IBinder windowToken) {
+ private final void attach(IBinder windowToken, boolean canDoze) {
if (mWindowToken != null) {
Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
return;
}
+ if (mFinished) {
+ Slog.w(TAG, "attach() called after dream already finished");
+ try {
+ mSandman.finishSelf(windowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ return;
+ }
if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
- if (mSandman == null) {
- loadSandman();
- }
mWindowToken = windowToken;
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
mWindow.setFormat(PixelFormat.OPAQUE);
+ mCanDoze = canDoze;
if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
@@ -642,40 +772,25 @@ public class DreamService extends Service implements Window.Callback {
mWindowManager = mWindow.getWindowManager();
if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
- try {
- applySystemUiVisibilityFlags(
- (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
- View.SYSTEM_UI_FLAG_LOW_PROFILE);
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed adding window view", t);
- safelyFinish();
- return;
- }
+ applySystemUiVisibilityFlags(
+ (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+ View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
// start it up
mHandler.post(new Runnable() {
@Override
public void run() {
- try {
- onDreamingStarted();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in onDreamingStarted()", t);
- safelyFinish();
- }
+ if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+ onDreamingStarted();
}
});
}
private void safelyFinish() {
if (mDebug) Slog.v(TAG, "safelyFinish()");
- try {
- finish();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in safelyFinish()", t);
- finishInternal();
- return;
- }
+
+ finish();
if (!mFinished) {
Slog.w(TAG, "Bad dream, did not call super.finish()");
@@ -685,19 +800,21 @@ public class DreamService extends Service implements Window.Callback {
private void finishInternal() {
if (mDebug) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
- if (mFinished) return;
- try {
+
+ if (!mFinished) {
mFinished = true;
- if (mSandman != null) {
- mSandman.finishSelf(mWindowToken);
+ if (mWindowToken == null) {
+ Slog.w(TAG, "Finish was called before the dream was attached.");
} else {
- Slog.w(TAG, "No dream manager found");
+ try {
+ mSandman.finishSelf(mWindowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
}
- stopSelf(); // if launched via any other means
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in finishInternal()", t);
+ stopSelf(); // if launched via any other means
}
}
@@ -732,32 +849,39 @@ public class DreamService extends Service implements Window.Callback {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- super.dump(fd, pw, args);
-
- pw.print(TAG + ": ");
- if (mWindowToken == null) {
- pw.println("stopped");
- } else {
- pw.println("running (token=" + mWindowToken + ")");
- }
- pw.println(" window: " + mWindow);
- pw.print(" flags:");
- if (isInteractive()) pw.print(" interactive");
- if (isLowProfile()) pw.print(" lowprofile");
- if (isFullscreen()) pw.print(" fullscreen");
- if (isScreenBright()) pw.print(" bright");
- pw.println();
+ DumpUtils.dumpAsync(mHandler, new Dump() {
+ @Override
+ public void dump(PrintWriter pw) {
+ pw.print(TAG + ": ");
+ if (mWindowToken == null) {
+ pw.println("stopped");
+ } else {
+ pw.println("running (token=" + mWindowToken + ")");
+ }
+ pw.println(" window: " + mWindow);
+ pw.print(" flags:");
+ if (isInteractive()) pw.print(" interactive");
+ if (isLowProfile()) pw.print(" lowprofile");
+ if (isFullscreen()) pw.print(" fullscreen");
+ if (isScreenBright()) pw.print(" bright");
+ if (isDozing()) pw.print(" dozing");
+ pw.println();
+ }
+ }, pw, 1000);
}
- private class DreamServiceWrapper extends IDreamService.Stub {
- public void attach(final IBinder windowToken) {
+ private final class DreamServiceWrapper extends IDreamService.Stub {
+ @Override
+ public void attach(final IBinder windowToken, final boolean canDoze) {
mHandler.post(new Runnable() {
@Override
public void run() {
- DreamService.this.attach(windowToken);
+ DreamService.this.attach(windowToken, canDoze);
}
});
}
+
+ @Override
public void detach() {
mHandler.post(new Runnable() {
@Override
diff --git a/core/java/android/service/dreams/IDozeHardware.aidl b/core/java/android/service/dreams/IDozeHardware.aidl
new file mode 100644
index 0000000..f5a657b
--- /dev/null
+++ b/core/java/android/service/dreams/IDozeHardware.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 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 android.service.dreams;
+
+/**
+ * @hide
+ */
+interface IDozeHardware {
+ byte[] sendMessage(String msg, in byte[] arg);
+}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 1c1b390..2718e31 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -16,10 +16,11 @@
package android.service.dreams;
+import android.content.ComponentName;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
-import android.content.ComponentName;
import android.os.IBinder;
+import android.service.dreams.IDozeHardware;
/** @hide */
interface IDreamManager {
@@ -31,4 +32,7 @@ interface IDreamManager {
void testDream(in ComponentName componentName);
boolean isDreaming();
void finishSelf(in IBinder token);
+ void startDozing(in IBinder token);
+ void stopDozing(in IBinder token);
+ IDozeHardware getDozeHardware(in IBinder token);
} \ No newline at end of file
diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl
index 99dc0b7..bd58f1d 100644
--- a/core/java/android/service/dreams/IDreamService.aidl
+++ b/core/java/android/service/dreams/IDreamService.aidl
@@ -20,6 +20,6 @@ package android.service.dreams;
* @hide
*/
oneway interface IDreamService {
- void attach(IBinder windowToken);
+ void attach(IBinder windowToken, boolean canDoze);
void detach();
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index c5a1b86..74dda77 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -115,20 +115,6 @@ public interface WindowManagerPolicy {
public final static int ACTION_PASS_TO_USER = 0x00000001;
/**
- * This key event should wake the device.
- * To be returned from {@link #interceptKeyBeforeQueueing}.
- * Do not return this and {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}.
- */
- public final static int ACTION_WAKE_UP = 0x00000002;
-
- /**
- * This key event should put the device to sleep (and engage keyguard if necessary)
- * To be returned from {@link #interceptKeyBeforeQueueing}.
- * Do not return this and {@link #ACTION_WAKE_UP} or {@link #ACTION_PASS_TO_USER}.
- */
- public final static int ACTION_GO_TO_SLEEP = 0x00000004;
-
- /**
* Interface to the Window Manager state associated with a particular
* window. You can hold on to an instance of this interface from the call
* to prepareAddWindow() until removeWindow().
@@ -751,8 +737,7 @@ public interface WindowManagerPolicy {
* @param policyFlags The policy flags associated with the key.
* @param isScreenOn True if the screen is already on
*
- * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
- * {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
+ * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
@@ -765,10 +750,9 @@ public interface WindowManagerPolicy {
* because it's the most fragile.
* @param policyFlags The policy flags associated with the motion.
*
- * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
- * {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
+ * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
/**
* Called from the input dispatcher thread before a key is dispatched to a window.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b34c792..559b11b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -652,6 +652,11 @@
Must be in the range specified by minimum and maximum. -->
<integer name="config_screenBrightnessSettingDefault">102</integer>
+ <!-- Screen brightness used to dim the screen while dozing in a very low power state.
+ May be less than the minimum allowed brightness setting
+ that can be set by the user. -->
+ <integer name="config_screenBrightnessDoze">1</integer>
+
<!-- Screen brightness used to dim the screen when the user activity
timeout expires. May be less than the minimum allowed brightness setting
that can be set by the user. -->
@@ -1083,6 +1088,70 @@
<!-- ComponentName of the default dream (Settings.Secure.SCREENSAVER_COMPONENT) -->
<string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+ <!-- Are we allowed to dream while not plugged in? -->
+ <bool name="config_dreamsEnabledOnBattery">false</bool>
+ <!-- Minimum battery level to allow dreaming when powered.
+ Use -1 to disable this safety feature. -->
+ <integer name="config_dreamsBatteryLevelMinimumWhenPowered">-1</integer>
+ <!-- Minimum battery level to allow dreaming when not powered.
+ Use -1 to disable this safety feature. -->
+ <integer name="config_dreamsBatteryLevelMinimumWhenNotPowered">15</integer>
+ <!-- If the battery level drops by this percentage and the user activity timeout
+ has expired, then assume the device is receiving insufficient current to charge
+ effectively and terminate the dream. Use -1 to disable this safety feature. -->
+ <integer name="config_dreamsBatteryLevelDrainCutoff">5</integer>
+
+ <!-- ComponentName of a dream to show whenever the system would otherwise have
+ gone to sleep. When the PowerManager is asked to go to sleep, it will instead
+ try to start this dream if possible. The dream should typically call startDozing()
+ to put the display into a low power state and allow the application processor
+ to be suspended. When the dream ends, the system will go to sleep as usual.
+ Specify the component name (Settings.Secure.SCREENSAVER_COMPONENT) or an
+ empty string if none.
+
+ Note that doze dreams are not subject to the same start conditions as ordinary dreams.
+ Doze dreams will run whenever the power manager is in a dozing state. -->
+ <string name="config_dozeComponent"></string>
+
+ <!-- Power Management: Specifies whether to decouple the auto-suspend state of the
+ device from the display on/off state.
+
+ When false, autosuspend_disable() will be called before the display is turned on
+ and autosuspend_enable() will be called after the display is turned off.
+ This mode provides best compatibility for devices using legacy power management
+ features such as early suspend / late resume.
+
+ When true, autosuspend_display() and autosuspend_enable() will be called
+ independently of whether the display is being turned on or off. This mode
+ enables the power manager to suspend the application processor while the
+ display is on.
+
+ This resource should be set to "true" when a doze component has been specified
+ to maximize power savings but not all devices support it.
+
+ Refer to autosuspend.h for details.
+ -->
+ <bool name="config_powerDecoupleAutoSuspendModeFromDisplay">false</bool>
+
+ <!-- Power Management: Specifies whether to decouple the interactive state of the
+ device from the display on/off state.
+
+ When false, setInteractive(..., true) will be called before the display is turned on
+ and setInteractive(..., false) will be called after the display is turned off.
+ This mode provides best compatibility for devices that expect the interactive
+ state to be tied to the display state.
+
+ When true, setInteractive(...) will be called independently of whether the display
+ is being turned on or off. This mode enables the power manager to reduce
+ clocks and disable the touch controller while the display is on.
+
+ This resource should be set to "true" when a doze component has been specified
+ to maximize power savings but not all devices support it.
+
+ Refer to power.h for details.
+ -->
+ <bool name="config_powerDecoupleInteractiveModeFromDisplay">false</bool>
+
<!-- Base "touch slop" value used by ViewConfiguration as a
movement threshold where scrolling should begin. -->
<dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6d90973..c38e753 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1504,6 +1504,7 @@
<java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
<java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
<java-symbol type="integer" name="config_screenBrightnessDim" />
+ <java-symbol type="integer" name="config_screenBrightnessDoze" />
<java-symbol type="integer" name="config_shutdownBatteryTemperature" />
<java-symbol type="integer" name="config_undockedHdmiRotation" />
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
@@ -1608,11 +1609,18 @@
<java-symbol type="xml" name="storage_list" />
<java-symbol type="bool" name="config_dreamsSupported" />
<java-symbol type="bool" name="config_dreamsEnabledByDefault" />
+ <java-symbol type="bool" name="config_dreamsEnabledOnBattery" />
<java-symbol type="bool" name="config_dreamsActivatedOnDockByDefault" />
<java-symbol type="bool" name="config_dreamsActivatedOnSleepByDefault" />
+ <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenPowered" />
+ <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenNotPowered" />
+ <java-symbol type="integer" name="config_dreamsBatteryLevelDrainCutoff" />
<java-symbol type="string" name="config_dreamsDefaultComponent" />
+ <java-symbol type="string" name="config_dozeComponent" />
<java-symbol type="string" name="enable_explore_by_touch_warning_title" />
<java-symbol type="string" name="enable_explore_by_touch_warning_message" />
+ <java-symbol type="bool" name="config_powerDecoupleAutoSuspendModeFromDisplay" />
+ <java-symbol type="bool" name="config_powerDecoupleInteractiveModeFromDisplay" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index f33ab40..76f29cd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3808,14 +3808,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (keyCode == KeyEvent.KEYCODE_POWER) {
policyFlags |= WindowManagerPolicy.FLAG_WAKE;
}
- final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
- | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
- + " policyFlags=" + Integer.toHexString(policyFlags)
- + " isWakeKey=" + isWakeKey);
+ + " policyFlags=" + Integer.toHexString(policyFlags));
}
if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
@@ -3832,6 +3829,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// the device some other way (which is why we have an exemption here for injected
// events).
int result;
+ boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
+ | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (isScreenOn || (isInjected && !isWakeKey)) {
// When the screen is on or if the key is injected pass the key to the application.
result = ACTION_PASS_TO_USER;
@@ -3839,8 +3838,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// When the screen is off and the key is not injected, determine whether
// to wake the device but don't pass the key to the application.
result = 0;
- if (down && isWakeKey && isWakeKeyWhenScreenOff(keyCode)) {
- result |= ACTION_WAKE_UP;
+ if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
+ isWakeKey = false;
}
}
@@ -3950,7 +3949,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
- result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+ mPowerManager.goToSleep(event.getEventTime());
+ isWakeKey = false;
}
}
}
@@ -3994,7 +3994,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mPowerKeyTriggered = false;
cancelPendingScreenshotChordAction();
if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
- result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+ mPowerManager.goToSleep(event.getEventTime());
+ isWakeKey = false;
}
mPendingPowerKeyUpCanceled = false;
}
@@ -4064,6 +4065,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
break;
}
}
+
+ if (isWakeKey) {
+ mPowerManager.wakeUp(event.getEventTime());
+ }
return result;
}
@@ -4104,13 +4109,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
int result = 0;
final boolean isWakeMotion = (policyFlags
& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (isWakeMotion) {
- result |= ACTION_WAKE_UP;
+ mPowerManager.wakeUp(whenNanos / 1000000);
}
return result;
}
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 85ef33e..649b5c9 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -85,6 +85,7 @@ final class DreamController {
pw.println(" mToken=" + mCurrentDream.mToken);
pw.println(" mName=" + mCurrentDream.mName);
pw.println(" mIsTest=" + mCurrentDream.mIsTest);
+ pw.println(" mCanDoze=" + mCurrentDream.mCanDoze);
pw.println(" mUserId=" + mCurrentDream.mUserId);
pw.println(" mBound=" + mCurrentDream.mBound);
pw.println(" mService=" + mCurrentDream.mService);
@@ -94,15 +95,18 @@ final class DreamController {
}
}
- public void startDream(Binder token, ComponentName name, boolean isTest, int userId) {
+ public void startDream(Binder token, ComponentName name,
+ boolean isTest, boolean canDoze, int userId) {
stopDream();
// Close the notification shade. Don't need to send to all, but better to be explicit.
mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
- Slog.i(TAG, "Starting dream: name=" + name + ", isTest=" + isTest + ", userId=" + userId);
+ Slog.i(TAG, "Starting dream: name=" + name
+ + ", isTest=" + isTest + ", canDoze=" + canDoze
+ + ", userId=" + userId);
- mCurrentDream = new DreamRecord(token, name, isTest, userId);
+ mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
try {
mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
@@ -140,7 +144,8 @@ final class DreamController {
final DreamRecord oldDream = mCurrentDream;
mCurrentDream = null;
Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
- + ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId);
+ + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+ + ", userId=" + oldDream.mUserId);
mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
@@ -187,7 +192,7 @@ final class DreamController {
private void attach(IDreamService service) {
try {
service.asBinder().linkToDeath(mCurrentDream, 0);
- service.attach(mCurrentDream.mToken);
+ service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
} catch (RemoteException ex) {
Slog.e(TAG, "The dream service died unexpectedly.", ex);
stopDream();
@@ -213,6 +218,7 @@ final class DreamController {
public final Binder mToken;
public final ComponentName mName;
public final boolean mIsTest;
+ public final boolean mCanDoze;
public final int mUserId;
public boolean mBound;
@@ -221,10 +227,11 @@ final class DreamController {
public boolean mSentStartBroadcast;
public DreamRecord(Binder token, ComponentName name,
- boolean isTest, int userId) {
+ boolean isTest, boolean canDoze, int userId) {
mToken = token;
mName = name;
mIsTest = isTest;
+ mCanDoze = canDoze;
mUserId = userId;
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index ffb113c..fd2f8a1 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -30,16 +30,20 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
import android.service.dreams.DreamService;
+import android.service.dreams.IDozeHardware;
import android.service.dreams.IDreamManager;
+import android.text.TextUtils;
import android.util.Slog;
import java.io.FileDescriptor;
@@ -64,11 +68,16 @@ public final class DreamManagerService extends SystemService {
private final DreamHandler mHandler;
private final DreamController mController;
private final PowerManager mPowerManager;
+ private final PowerManager.WakeLock mDozeWakeLock;
+ private final McuHal mMcuHal; // synchronized on self
private Binder mCurrentDreamToken;
private ComponentName mCurrentDreamName;
private int mCurrentDreamUserId;
private boolean mCurrentDreamIsTest;
+ private boolean mCurrentDreamCanDoze;
+ private boolean mCurrentDreamIsDozing;
+ private DozeHardwareWrapper mCurrentDreamDozeHardware;
public DreamManagerService(Context context) {
super(context);
@@ -77,6 +86,12 @@ public final class DreamManagerService extends SystemService {
mController = new DreamController(context, mHandler, mControllerListener);
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
+
+ mMcuHal = McuHal.open();
+ if (mMcuHal != null) {
+ mMcuHal.reset();
+ }
}
@Override
@@ -103,10 +118,15 @@ public final class DreamManagerService extends SystemService {
pw.println("DREAM MANAGER (dumpsys dreams)");
pw.println();
+ pw.println("mMcuHal=" + mMcuHal);
+ pw.println();
pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
pw.println("mCurrentDreamName=" + mCurrentDreamName);
pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest);
+ pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze);
+ pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing);
+ pw.println("mCurrentDreamDozeHardware=" + mCurrentDreamDozeHardware);
pw.println();
DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
@@ -163,16 +183,16 @@ public final class DreamManagerService extends SystemService {
private void testDreamInternal(ComponentName dream, int userId) {
synchronized (mLock) {
- startDreamLocked(dream, true /*isTest*/, userId);
+ startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId);
}
}
- private void startDreamInternal() {
- int userId = ActivityManager.getCurrentUser();
- ComponentName dream = chooseDreamForUser(userId);
+ private void startDreamInternal(boolean doze) {
+ final int userId = ActivityManager.getCurrentUser();
+ final ComponentName dream = doze ? getDozeComponent() : chooseDreamForUser(userId);
if (dream != null) {
synchronized (mLock) {
- startDreamLocked(dream, false /*isTest*/, userId);
+ startDreamLocked(dream, false /*isTest*/, doze, userId);
}
}
}
@@ -183,6 +203,44 @@ public final class DreamManagerService extends SystemService {
}
}
+ private void startDozingInternal(IBinder token) {
+ if (DEBUG) {
+ Slog.d(TAG, "Dream requested to start dozing: " + token);
+ }
+
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+ && !mCurrentDreamIsDozing) {
+ mCurrentDreamIsDozing = true;
+ mDozeWakeLock.acquire();
+ }
+ }
+ }
+
+ private void stopDozingInternal(IBinder token) {
+ if (DEBUG) {
+ Slog.d(TAG, "Dream requested to stop dozing: " + token);
+ }
+
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token && mCurrentDreamIsDozing) {
+ mCurrentDreamIsDozing = false;
+ mDozeWakeLock.release();
+ }
+ }
+ }
+
+ private IDozeHardware getDozeHardwareInternal(IBinder token) {
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+ && mCurrentDreamDozeHardware == null && mMcuHal != null) {
+ mCurrentDreamDozeHardware = new DozeHardwareWrapper();
+ return mCurrentDreamDozeHardware;
+ }
+ return null;
+ }
+ }
+
private ComponentName chooseDreamForUser(int userId) {
ComponentName[] dreams = getDreamComponentsForUser(userId);
return dreams != null && dreams.length != 0 ? dreams[0] : null;
@@ -231,6 +289,20 @@ public final class DreamManagerService extends SystemService {
return name == null ? null : ComponentName.unflattenFromString(name);
}
+ private ComponentName getDozeComponent() {
+ // Read the component from a system property to facilitate debugging.
+ // Note that for production devices, the dream should actually be declared in
+ // a config.xml resource.
+ String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
+ if (TextUtils.isEmpty(name)) {
+ // Read the component from a config.xml resource.
+ // The value should be specified in a resource overlay for the product.
+ name = mContext.getResources().getString(
+ com.android.internal.R.string.config_dozeComponent);
+ }
+ return TextUtils.isEmpty(name) ? null : ComponentName.unflattenFromString(name);
+ }
+
private boolean serviceExists(ComponentName name) {
try {
return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null;
@@ -240,9 +312,10 @@ public final class DreamManagerService extends SystemService {
}
private void startDreamLocked(final ComponentName name,
- final boolean isTest, final int userId) {
+ final boolean isTest, final boolean canDoze, final int userId) {
if (Objects.equal(mCurrentDreamName, name)
&& mCurrentDreamIsTest == isTest
+ && mCurrentDreamCanDoze == canDoze
&& mCurrentDreamUserId == userId) {
return;
}
@@ -255,12 +328,13 @@ public final class DreamManagerService extends SystemService {
mCurrentDreamToken = newToken;
mCurrentDreamName = name;
mCurrentDreamIsTest = isTest;
+ mCurrentDreamCanDoze = canDoze;
mCurrentDreamUserId = userId;
mHandler.post(new Runnable() {
@Override
public void run() {
- mController.startDream(newToken, name, isTest, userId);
+ mController.startDream(newToken, name, isTest, canDoze, userId);
}
});
}
@@ -284,7 +358,16 @@ public final class DreamManagerService extends SystemService {
mCurrentDreamToken = null;
mCurrentDreamName = null;
mCurrentDreamIsTest = false;
+ mCurrentDreamCanDoze = false;
mCurrentDreamUserId = 0;
+ if (mCurrentDreamIsDozing) {
+ mCurrentDreamIsDozing = false;
+ mDozeWakeLock.release();
+ }
+ if (mCurrentDreamDozeHardware != null) {
+ mCurrentDreamDozeHardware.release();
+ mCurrentDreamDozeHardware = null;
+ }
}
private void checkPermission(String permission) {
@@ -473,12 +556,57 @@ public final class DreamManagerService extends SystemService {
Binder.restoreCallingIdentity(ident);
}
}
+
+ @Override // Binder call
+ public void startDozing(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ startDozingInternal(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void stopDozing(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ stopDozingInternal(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public IDozeHardware getDozeHardware(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getDozeHardwareInternal(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
private final class LocalService extends DreamManagerInternal {
@Override
- public void startDream() {
- startDreamInternal();
+ public void startDream(boolean doze) {
+ startDreamInternal(doze);
}
@Override
@@ -491,4 +619,37 @@ public final class DreamManagerService extends SystemService {
return isDreamingInternal();
}
}
+
+ private final class DozeHardwareWrapper extends IDozeHardware.Stub {
+ private boolean mReleased;
+
+ public void release() {
+ synchronized (mMcuHal) {
+ if (!mReleased) {
+ mReleased = true;
+ mMcuHal.reset();
+ }
+ }
+ }
+
+ @Override // Binder call
+ public byte[] sendMessage(String msg, byte[] arg) {
+ if (msg == null) {
+ throw new IllegalArgumentException("msg must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mMcuHal) {
+ if (mReleased) {
+ throw new IllegalStateException("This operation cannot be performed "
+ + "because the dream has ended.");
+ }
+ return mMcuHal.sendMessage(msg, arg);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/dreams/McuHal.java b/services/core/java/com/android/server/dreams/McuHal.java
new file mode 100644
index 0000000..1dc79c7
--- /dev/null
+++ b/services/core/java/com/android/server/dreams/McuHal.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 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.dreams;
+
+import android.service.dreams.DozeHardware;
+
+/**
+ * Provides access to the low-level microcontroller hardware abstraction layer.
+ */
+final class McuHal {
+ private final long mPtr;
+
+ private static native long nativeOpen();
+ private static native byte[] nativeSendMessage(long ptr, String msg, byte[] arg);
+
+ private McuHal(long ptr) {
+ mPtr = ptr;
+ }
+
+ public static McuHal open() {
+ long ptr = nativeOpen();
+ return ptr != 0 ? new McuHal(ptr) : null;
+ }
+
+ public void reset() {
+ sendMessage(DozeHardware.MSG_ENABLE_MCU, DozeHardware.VALUE_OFF);
+ }
+
+ public byte[] sendMessage(String msg, byte[] arg) {
+ return nativeSendMessage(mPtr, msg, arg);
+ }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 69281bc..73033e0 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1329,8 +1329,9 @@ public class InputManagerService extends IInputManager.Stub
}
// Native callback.
- private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
- return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+ private int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
+ return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(
+ whenNanos, policyFlags);
}
// Native callback.
@@ -1491,7 +1492,7 @@ public class InputManagerService extends IInputManager.Stub
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
public long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags);
diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java
index f1be504..bd9acb9 100644
--- a/services/core/java/com/android/server/power/DisplayPowerController.java
+++ b/services/core/java/com/android/server/power/DisplayPowerController.java
@@ -193,6 +193,9 @@ final class DisplayPowerController {
// The light sensor, or null if not available or needed.
private Sensor mLightSensor;
+ // The doze screen brightness.
+ private final int mScreenBrightnessDozeConfig;
+
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
@@ -364,6 +367,9 @@ final class DisplayPowerController {
final Resources resources = context.getResources();
+ mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDoze));
+
mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDim));
@@ -559,7 +565,7 @@ final class DisplayPowerController {
final boolean mustNotify;
boolean mustInitialize = false;
boolean updateAutoBrightness = mTwilightChanged;
- boolean wasDim = false;
+ boolean wasDimOrDoze = false;
mTwilightChanged = false;
synchronized (mLock) {
@@ -579,7 +585,8 @@ final class DisplayPowerController {
!= mPendingRequestLocked.screenAutoBrightnessAdjustment) {
updateAutoBrightness = true;
}
- wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM);
+ wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
+ || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
mPowerRequest.copyFrom(mPendingRequestLocked);
mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
@@ -626,12 +633,12 @@ final class DisplayPowerController {
// Turn on the light sensor if needed.
if (mLightSensor != null) {
- setLightSensorEnabled(mPowerRequest.useAutoBrightness
- && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness);
+ setLightSensorEnabled(mPowerRequest.wantLightSensorEnabled(),
+ updateAutoBrightness);
}
// Set the screen brightness.
- if (wantScreenOn(mPowerRequest.screenState)) {
+ if (mPowerRequest.wantScreenOnAny()) {
int target;
boolean slow;
if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
@@ -648,12 +655,16 @@ final class DisplayPowerController {
slow = false;
mUsingScreenAutoBrightness = false;
}
- if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
+ if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
+ // Dim quickly to the doze state.
+ target = mScreenBrightnessDozeConfig;
+ slow = false;
+ } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
// Dim quickly by at least some minimum amount.
target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
mScreenBrightnessDimConfig);
slow = false;
- } else if (wasDim) {
+ } else if (wasDimOrDoze) {
// Brighten quickly.
slow = false;
}
@@ -666,7 +677,7 @@ final class DisplayPowerController {
// Animate the screen on or off.
if (!mScreenOffBecauseOfProximity) {
- if (wantScreenOn(mPowerRequest.screenState)) {
+ if (mPowerRequest.wantScreenOnAny()) {
// Want screen on.
// Wait for previous off animation to complete beforehand.
// It is relatively short but if we cancel it and switch to the
@@ -1211,6 +1222,7 @@ final class DisplayPowerController {
pw.println();
pw.println("Display Controller Configuration:");
+ pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
@@ -1288,15 +1300,6 @@ final class DisplayPowerController {
}
}
- private static boolean wantScreenOn(int state) {
- switch (state) {
- case DisplayPowerRequest.SCREEN_STATE_BRIGHT:
- case DisplayPowerRequest.SCREEN_STATE_DIM:
- return true;
- }
- return false;
- }
-
/**
* Asynchronous callbacks from the power controller to the power manager service.
*/
diff --git a/services/core/java/com/android/server/power/DisplayPowerRequest.java b/services/core/java/com/android/server/power/DisplayPowerRequest.java
index 22f17d7..6061a40 100644
--- a/services/core/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/core/java/com/android/server/power/DisplayPowerRequest.java
@@ -30,10 +30,11 @@ import android.os.PowerManager;
*/
final class DisplayPowerRequest {
public static final int SCREEN_STATE_OFF = 0;
- public static final int SCREEN_STATE_DIM = 1;
- public static final int SCREEN_STATE_BRIGHT = 2;
+ public static final int SCREEN_STATE_DOZE = 1;
+ public static final int SCREEN_STATE_DIM = 2;
+ public static final int SCREEN_STATE_BRIGHT = 3;
- // The requested minimum screen power state: off, dim or bright.
+ // The requested minimum screen power state: off, doze, dim or bright.
public int screenState;
// If true, the proximity sensor overrides the screen state when an object is
@@ -75,6 +76,23 @@ final class DisplayPowerRequest {
copyFrom(other);
}
+ // Returns true if we want the screen on in any mode, including doze.
+ public boolean wantScreenOnAny() {
+ return screenState != SCREEN_STATE_OFF;
+ }
+
+ // Returns true if we want the screen on in a normal mode, excluding doze.
+ // This is usually what we want to tell the rest of the system. For compatibility
+ // reasons, we pretend the screen is off when dozing.
+ public boolean wantScreenOnNormal() {
+ return screenState == SCREEN_STATE_DIM || screenState == SCREEN_STATE_BRIGHT;
+ }
+
+ public boolean wantLightSensorEnabled() {
+ // Specifically, we don't want the light sensor while dozing.
+ return useAutoBrightness && wantScreenOnNormal();
+ }
+
public void copyFrom(DisplayPowerRequest other) {
screenState = other.screenState;
useProximitySensor = other.useProximitySensor;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3dec234..16b09bc 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -83,7 +83,7 @@ public final class PowerManagerService extends com.android.server.SystemService
// Message: Sent when a user activity timeout occurs to update the power state.
private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
- // Message: Sent when the device enters or exits a napping or dreaming state.
+ // Message: Sent when the device enters or exits a dreaming or dozing state.
private static final int MSG_SANDMAN = 2;
// Message: Sent when the screen on blocker is released.
private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
@@ -117,19 +117,21 @@ public final class PowerManagerService extends com.android.server.SystemService
// Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
// The screen should be off or in the process of being turned off by the display controller.
+ // The device typically passes through the dozing state first.
private static final int WAKEFULNESS_ASLEEP = 0;
// Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep().
- // When the user activity timeout expires, the device may start napping or go to sleep.
+ // When the user activity timeout expires, the device may start dreaming or go to sleep.
private static final int WAKEFULNESS_AWAKE = 1;
- // Wakefulness: The device is napping. It is deciding whether to dream or go to sleep
- // but hasn't gotten around to it yet. It can be awoken by a call to wakeUp(), which
- // ends the nap. User activity may brighten the screen but does not end the nap.
- private static final int WAKEFULNESS_NAPPING = 2;
// Wakefulness: The device is dreaming. It can be awoken by a call to wakeUp(),
// which ends the dream. The device goes to sleep when goToSleep() is called, when
// the dream ends or when unplugged.
// User activity may brighten the screen but does not end the dream.
- private static final int WAKEFULNESS_DREAMING = 3;
+ private static final int WAKEFULNESS_DREAMING = 2;
+ // Wakefulness: The device is dozing. It is almost asleep but is allowing a special
+ // low-power "doze" dream to run which keeps the display on but lets the application
+ // processor be suspended. It can be awoken by a call to wakeUp() which ends the dream.
+ // The device fully goes to sleep if the dream cannot be started or ends on its own.
+ private static final int WAKEFULNESS_DOZING = 3;
// Summarizes the state of all active wakelocks.
private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -138,6 +140,7 @@ public final class PowerManagerService extends com.android.server.SystemService
private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3;
private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
+ private static final int WAKE_LOCK_DOZE = 1 << 6;
// Summarizes the user activity state.
private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -164,11 +167,6 @@ public final class PowerManagerService extends com.android.server.SystemService
// Poll interval in milliseconds for watching boot animation finished.
private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
- // If the battery level drops by this percentage and the user activity timeout
- // has expired, then assume the device is receiving insufficient current to charge
- // effectively and terminate the dream.
- private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5;
-
private final Context mContext;
private LightsManager mLightsManager;
private BatteryService mBatteryService;
@@ -195,6 +193,10 @@ public final class PowerManagerService extends com.android.server.SystemService
// This is distinct from the screen power state, which is managed separately.
private int mWakefulness;
+ // True if the sandman has just been summoned for the first time since entering the
+ // dreaming or dozing state. Indicates whether a new dream should begin.
+ private boolean mSandmanSummoned;
+
// True if MSG_SANDMAN has been scheduled.
private boolean mSandmanScheduled;
@@ -265,6 +267,14 @@ public final class PowerManagerService extends com.android.server.SystemService
// True if boot completed occurred. We keep the screen on until this happens.
private boolean mBootCompleted;
+ // True if auto-suspend mode is enabled.
+ // Refer to autosuspend.h.
+ private boolean mAutoSuspendModeEnabled;
+
+ // True if interactive mode is enabled.
+ // Refer to power.h.
+ private boolean mInteractiveModeEnabled;
+
// True if the device is plugged into a power source.
private boolean mIsPowered;
@@ -282,6 +292,12 @@ public final class PowerManagerService extends com.android.server.SystemService
// The current dock state.
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ // True to decouple auto-suspend mode from the display state.
+ private boolean mDecoupleAutoSuspendModeFromDisplayConfig;
+
+ // True to decouple interactive mode from the display state.
+ private boolean mDecoupleInteractiveModeFromDisplayConfig;
+
// True if the device should wake up when plugged or unplugged.
private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
@@ -300,6 +316,22 @@ public final class PowerManagerService extends com.android.server.SystemService
// Default value for dreams activate-on-dock
private boolean mDreamsActivatedOnDockByDefaultConfig;
+ // True if dreams can run while not plugged in.
+ private boolean mDreamsEnabledOnBatteryConfig;
+
+ // Minimum battery level to allow dreaming when powered.
+ // Use -1 to disable this safety feature.
+ private int mDreamsBatteryLevelMinimumWhenPoweredConfig;
+
+ // Minimum battery level to allow dreaming when not powered.
+ // Use -1 to disable this safety feature.
+ private int mDreamsBatteryLevelMinimumWhenNotPoweredConfig;
+
+ // If the battery level drops by this percentage and the user activity timeout
+ // has expired, then assume the device is receiving insufficient current to charge
+ // effectively and terminate the dream. Use -1 to disable this safety feature.
+ private int mDreamsBatteryLevelDrainCutoffConfig;
+
// True if dreams are enabled by the user.
private boolean mDreamsEnabledSetting;
@@ -523,6 +555,10 @@ public final class PowerManagerService extends com.android.server.SystemService
private void readConfigurationLocked() {
final Resources resources = mContext.getResources();
+ mDecoupleAutoSuspendModeFromDisplayConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
+ mDecoupleInteractiveModeFromDisplayConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
@@ -535,6 +571,14 @@ public final class PowerManagerService extends com.android.server.SystemService
com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
+ mDreamsEnabledOnBatteryConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsEnabledOnBattery);
+ mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger(
+ com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenPowered);
+ mDreamsBatteryLevelMinimumWhenNotPoweredConfig = resources.getInteger(
+ com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenNotPowered);
+ mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger(
+ com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff);
}
private void updateSettingsLocked() {
@@ -762,6 +806,7 @@ public final class PowerManagerService extends com.android.server.SystemService
case PowerManager.SCREEN_DIM_WAKE_LOCK:
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
case PowerManager.FULL_WAKE_LOCK:
+ case PowerManager.DOZE_WAKE_LOCK:
return true;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
@@ -794,7 +839,8 @@ public final class PowerManagerService extends com.android.server.SystemService
}
if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
- || mWakefulness == WAKEFULNESS_ASLEEP || !mBootCompleted || !mSystemReady) {
+ || mWakefulness == WAKEFULNESS_ASLEEP || mWakefulness == WAKEFULNESS_DOZING
+ || !mBootCompleted || !mSystemReady) {
return false;
}
@@ -843,18 +889,21 @@ public final class PowerManagerService extends com.android.server.SystemService
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
Slog.i(TAG, "Waking up from sleep...");
- sendPendingNotificationsLocked();
- mNotifier.onWakeUpStarted();
- mSendWakeUpFinishedNotificationWhenReady = true;
break;
case WAKEFULNESS_DREAMING:
Slog.i(TAG, "Waking up from dream...");
break;
- case WAKEFULNESS_NAPPING:
- Slog.i(TAG, "Waking up from nap...");
+ case WAKEFULNESS_DOZING:
+ Slog.i(TAG, "Waking up from dozing...");
break;
}
+ if (mWakefulness != WAKEFULNESS_DREAMING) {
+ sendPendingNotificationsLocked();
+ mNotifier.onWakeUpStarted();
+ mSendWakeUpFinishedNotificationWhenReady = true;
+ }
+
mLastWakeTime = eventTime;
mWakefulness = WAKEFULNESS_AWAKE;
mDirty |= DIRTY_WAKEFULNESS;
@@ -877,13 +926,17 @@ public final class PowerManagerService extends com.android.server.SystemService
}
}
+ // This method is called goToSleep for historical reasons but we actually start
+ // dozing before really going to sleep.
@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason) {
if (DEBUG_SPEW) {
Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason);
}
- if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+ if (eventTime < mLastWakeTime
+ || mWakefulness == WAKEFULNESS_ASLEEP
+ || mWakefulness == WAKEFULNESS_DOZING
|| !mBootCompleted || !mSystemReady) {
return false;
}
@@ -907,7 +960,8 @@ public final class PowerManagerService extends com.android.server.SystemService
mLastSleepTime = eventTime;
mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_ASLEEP;
+ mWakefulness = WAKEFULNESS_DOZING;
+ mSandmanSummoned = true;
// Report the number of wake locks that will be cleared by going to sleep.
int numWakeLocksCleared = 0;
@@ -947,7 +1001,26 @@ public final class PowerManagerService extends com.android.server.SystemService
Slog.i(TAG, "Nap time...");
mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_NAPPING;
+ mWakefulness = WAKEFULNESS_DREAMING;
+ mSandmanSummoned = true;
+ return true;
+ }
+
+ // Done dozing, drop everything and go to sleep.
+ private boolean reallyGoToSleepNoUpdateLocked(long eventTime) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime);
+ }
+
+ if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+ || !mBootCompleted || !mSystemReady) {
+ return false;
+ }
+
+ Slog.i(TAG, "Sleeping...");
+
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_ASLEEP;
return true;
}
@@ -1023,7 +1096,7 @@ public final class PowerManagerService extends com.android.server.SystemService
mPlugType = mBatteryService.getPlugType();
mBatteryLevel = mBatteryService.getBatteryLevel();
- if (DEBUG) {
+ if (DEBUG_SPEW) {
Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
+ ", mIsPowered=" + mIsPowered
+ ", oldPlugType=" + oldPlugType
@@ -1083,8 +1156,7 @@ public final class PowerManagerService extends com.android.server.SystemService
}
// If already dreaming and becoming powered, then don't wake.
- if (mIsPowered && (mWakefulness == WAKEFULNESS_NAPPING
- || mWakefulness == WAKEFULNESS_DREAMING)) {
+ if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) {
return false;
}
@@ -1131,35 +1203,45 @@ public final class PowerManagerService extends com.android.server.SystemService
mWakeLockSummary |= WAKE_LOCK_CPU;
break;
case PowerManager.FULL_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU
| WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ }
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
}
break;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ }
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
}
break;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ }
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
}
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING
+ || mWakefulness == WAKEFULNESS_DOZING) {
mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
break;
+ case PowerManager.DOZE_WAKE_LOCK:
+ if (mWakefulness == WAKEFULNESS_DOZING) {
+ mWakeLockSummary |= WAKE_LOCK_DOZE;
+ }
+ break;
}
}
@@ -1184,7 +1266,8 @@ public final class PowerManagerService extends com.android.server.SystemService
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
long nextTimeout = 0;
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
final int screenOffTimeout = getScreenOffTimeoutLocked();
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
@@ -1205,8 +1288,7 @@ public final class PowerManagerService extends com.android.server.SystemService
&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
if (now < nextTimeout
- && mDisplayPowerRequest.screenState
- != DisplayPowerRequest.SCREEN_STATE_OFF) {
+ && mDisplayPowerRequest.wantScreenOnNormal()) {
mUserActivitySummary = mDisplayPowerRequest.screenState
== DisplayPowerRequest.SCREEN_STATE_BRIGHT ?
USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM;
@@ -1268,7 +1350,7 @@ public final class PowerManagerService extends com.android.server.SystemService
/**
* Updates the wakefulness of the device.
*
- * This is the function that decides whether the device should start napping
+ * This is the function that decides whether the device should start dreaming
* based on the current wake locks and user activity state. It may modify mDirty
* if the wakefulness changes.
*
@@ -1357,7 +1439,7 @@ public final class PowerManagerService extends com.android.server.SystemService
}
/**
- * Called when the device enters or exits a napping or dreaming state.
+ * Called when the device enters or exits a dreaming or dozing state.
*
* We do this asynchronously because we must call out of the power manager to start
* the dream and we don't want to hold our lock while doing so. There is a risk that
@@ -1365,46 +1447,60 @@ public final class PowerManagerService extends com.android.server.SystemService
*/
private void handleSandman() { // runs on handler thread
// Handle preconditions.
- boolean startDreaming = false;
+ final boolean startDreaming;
+ final int wakefulness;
synchronized (mLock) {
mSandmanScheduled = false;
- boolean canDream = canDreamLocked();
- if (DEBUG_SPEW) {
- Slog.d(TAG, "handleSandman: canDream=" + canDream
- + ", mWakefulness=" + wakefulnessToString(mWakefulness));
- }
-
- if (canDream && mWakefulness == WAKEFULNESS_NAPPING) {
- startDreaming = true;
+ wakefulness = mWakefulness;
+ if (mSandmanSummoned) {
+ startDreaming = ((wakefulness == WAKEFULNESS_DREAMING && canDreamLocked())
+ || wakefulness == WAKEFULNESS_DOZING);
+ mSandmanSummoned = false;
+ } else {
+ startDreaming = false;
}
}
// Start dreaming if needed.
// We only control the dream on the handler thread, so we don't need to worry about
// concurrent attempts to start or stop the dream.
- boolean isDreaming = false;
+ final boolean isDreaming;
if (mDreamManager != null) {
+ // Restart the dream whenever the sandman is summoned.
if (startDreaming) {
- mDreamManager.startDream();
+ mDreamManager.stopDream();
+ mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
}
isDreaming = mDreamManager.isDreaming();
+ } else {
+ isDreaming = false;
}
// Update dream state.
- // We might need to stop the dream again if the preconditions changed.
- boolean continueDreaming = false;
synchronized (mLock) {
- if (isDreaming && canDreamLocked()) {
- if (mWakefulness == WAKEFULNESS_NAPPING) {
- mWakefulness = WAKEFULNESS_DREAMING;
- mDirty |= DIRTY_WAKEFULNESS;
- mBatteryLevelWhenDreamStarted = mBatteryLevel;
- updatePowerStateLocked();
- continueDreaming = true;
- } else if (mWakefulness == WAKEFULNESS_DREAMING) {
- if (!isBeingKeptAwakeLocked()
+ // Remember the initial battery level when the dream started.
+ if (startDreaming && isDreaming) {
+ mBatteryLevelWhenDreamStarted = mBatteryLevel;
+ if (wakefulness == WAKEFULNESS_DOZING) {
+ Slog.i(TAG, "Dozing...");
+ } else {
+ Slog.i(TAG, "Dreaming...");
+ }
+ }
+
+ // If preconditions changed, wait for the next iteration to determine
+ // whether the dream should continue (or be restarted).
+ if (mSandmanSummoned || mWakefulness != wakefulness) {
+ return; // wait for next cycle
+ }
+
+ // Determine whether the dream should continue.
+ if (wakefulness == WAKEFULNESS_DREAMING) {
+ if (isDreaming && canDreamLocked()) {
+ if (mDreamsBatteryLevelDrainCutoffConfig >= 0
&& mBatteryLevel < mBatteryLevelWhenDreamStarted
- - DREAM_BATTERY_LEVEL_DRAIN_CUTOFF) {
+ - mDreamsBatteryLevelDrainCutoffConfig
+ && !isBeingKeptAwakeLocked()) {
// If the user activity timeout expired and the battery appears
// to be draining faster than it is charging then stop dreaming
// and go to sleep.
@@ -1414,53 +1510,64 @@ public final class PowerManagerService extends com.android.server.SystemService
+ mBatteryLevelWhenDreamStarted + "%. "
+ "Battery level now: " + mBatteryLevel + "%.");
} else {
- continueDreaming = true;
+ return; // continue dreaming
}
}
- }
- if (!continueDreaming) {
- handleDreamFinishedLocked();
+
+ // Dream has ended or will be stopped. Update the power state.
+ if (isItBedTimeYetLocked()) {
+ goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ updatePowerStateLocked();
+ } else {
+ wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
+ updatePowerStateLocked();
+ }
+ } else if (wakefulness == WAKEFULNESS_DOZING) {
+ if (isDreaming) {
+ return; // continue dozing
+ }
+
+ // Doze has ended or will be stopped. Update the power state.
+ reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis());
+ updatePowerStateLocked();
}
}
- // Stop dreaming if needed.
- // It's possible that something else changed to make us need to start the dream again.
- // If so, then the power manager will have posted another message to the handler
- // to take care of it later.
- if (mDreamManager != null) {
- if (!continueDreaming) {
- mDreamManager.stopDream();
- }
+ // Stop dream.
+ if (isDreaming) {
+ mDreamManager.stopDream();
}
}
/**
- * Returns true if the device is allowed to dream in its current state
- * assuming that it is currently napping or dreaming.
+ * Returns true if the device is allowed to dream in its current state.
+ * This function is not called when dozing.
*/
private boolean canDreamLocked() {
- return mDreamsSupportedConfig
- && mDreamsEnabledSetting
- && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
- && mBootCompleted
- && (mIsPowered || isBeingKeptAwakeLocked());
- }
-
- /**
- * Called when a dream is ending to figure out what to do next.
- */
- private void handleDreamFinishedLocked() {
- if (mWakefulness == WAKEFULNESS_NAPPING
- || mWakefulness == WAKEFULNESS_DREAMING) {
- if (isItBedTimeYetLocked()) {
- goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
- PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
- updatePowerStateLocked();
- } else {
- wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
- updatePowerStateLocked();
+ if (mWakefulness != WAKEFULNESS_DREAMING
+ || !mDreamsSupportedConfig
+ || !mDreamsEnabledSetting
+ || !mDisplayPowerRequest.wantScreenOnNormal()
+ || !mBootCompleted) {
+ return false;
+ }
+ if (!isBeingKeptAwakeLocked()) {
+ if (!mIsPowered && !mDreamsEnabledByDefaultConfig) {
+ return false;
+ }
+ if (!mIsPowered
+ && mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0
+ && mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) {
+ return false;
+ }
+ if (mIsPowered
+ && mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0
+ && mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) {
+ return false;
}
}
+ return true;
}
private void handleScreenOnBlockerReleased() {
@@ -1482,11 +1589,11 @@ public final class PowerManagerService extends com.android.server.SystemService
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
- int newScreenState = getDesiredScreenPowerStateLocked();
+ final int newScreenState = getDesiredScreenPowerStateLocked();
if (newScreenState != mDisplayPowerRequest.screenState) {
mDisplayPowerRequest.screenState = newScreenState;
nativeSetPowerState(
- newScreenState != DisplayPowerRequest.SCREEN_STATE_OFF,
+ mDisplayPowerRequest.wantScreenOnNormal(),
newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
}
@@ -1555,6 +1662,10 @@ public final class PowerManagerService extends com.android.server.SystemService
return DisplayPowerRequest.SCREEN_STATE_OFF;
}
+ if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
+ return DisplayPowerRequest.SCREEN_STATE_DOZE;
+ }
+
if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
|| (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
|| !mBootCompleted) {
@@ -1606,7 +1717,18 @@ public final class PowerManagerService extends com.android.server.SystemService
*/
private void updateSuspendBlockerLocked() {
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
- final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
+ final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
+ final boolean autoSuspend = !needDisplaySuspendBlocker;
+
+ // Disable auto-suspend if needed.
+ if (!autoSuspend) {
+ if (mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(false);
+ }
+ if (mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(true);
+ }
+ }
// First acquire suspend blockers if needed.
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
@@ -1627,17 +1749,27 @@ public final class PowerManagerService extends com.android.server.SystemService
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
+
+ // Enable auto-suspend if needed.
+ if (autoSuspend) {
+ if (mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(false);
+ }
+ if (mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(true);
+ }
+ }
}
/**
* Return true if we must keep a suspend blocker active on behalf of the display.
* We do so if the screen is on or is in transition between states.
*/
- private boolean needDisplaySuspendBlocker() {
+ private boolean needDisplaySuspendBlockerLocked() {
if (!mDisplayReady) {
return true;
}
- if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+ if (mDisplayPowerRequest.wantScreenOnNormal()) {
// If we asked for the screen to be on but it is off due to the proximity
// sensor then we may suspend but only if the configuration allows it.
// On some hardware it may not be safe to suspend because the proximity
@@ -1647,13 +1779,34 @@ public final class PowerManagerService extends com.android.server.SystemService
return true;
}
}
+ // Let the system suspend if the screen is off or dozing.
return false;
}
+ private void setAutoSuspendModeLocked(boolean enable) {
+ if (enable != mAutoSuspendModeEnabled) {
+ if (DEBUG) {
+ Slog.d(TAG, "Setting auto-suspend mode to " + enable);
+ }
+ mAutoSuspendModeEnabled = enable;
+ nativeSetAutoSuspend(enable);
+ }
+ }
+
+ private void setInteractiveModeLocked(boolean enable) {
+ if (enable != mInteractiveModeEnabled) {
+ if (DEBUG) {
+ Slog.d(TAG, "Setting interactive mode to " + enable);
+ }
+ mInteractiveModeEnabled = enable;
+ nativeSetInteractive(enable);
+ }
+ }
+
private boolean isScreenOnInternal() {
synchronized (mLock) {
return !mSystemReady
- || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF;
+ || mDisplayPowerRequest.wantScreenOnNormal();
}
}
@@ -1871,10 +2024,13 @@ public final class PowerManagerService extends com.android.server.SystemService
pw.println(" mProximityPositive=" + mProximityPositive);
pw.println(" mBootCompleted=" + mBootCompleted);
pw.println(" mSystemReady=" + mSystemReady);
+ pw.println(" mAutoSuspendModeEnabled=" + mAutoSuspendModeEnabled);
+ pw.println(" mInteactiveModeEnabled=" + mInteractiveModeEnabled);
pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
pw.println(" mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
pw.println(" mSandmanScheduled=" + mSandmanScheduled);
+ pw.println(" mSandmanSummoned=" + mSandmanSummoned);
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
pw.println(" mSendWakeUpFinishedNotificationWhenReady="
@@ -1890,6 +2046,10 @@ public final class PowerManagerService extends com.android.server.SystemService
pw.println();
pw.println("Settings and Configuration:");
+ pw.println(" mDecoupleAutoSuspendModeFromDisplayConfig="
+ + mDecoupleAutoSuspendModeFromDisplayConfig);
+ pw.println(" mDecoupleInteractiveModeFromDisplayConfig="
+ + mDecoupleInteractiveModeFromDisplayConfig);
pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig="
+ mWakeUpWhenPluggedOrUnpluggedConfig);
pw.println(" mSuspendWhenScreenOffDueToProximityConfig="
@@ -1900,6 +2060,14 @@ public final class PowerManagerService extends com.android.server.SystemService
+ mDreamsActivatedOnSleepByDefaultConfig);
pw.println(" mDreamsActivatedOnDockByDefaultConfig="
+ mDreamsActivatedOnDockByDefaultConfig);
+ pw.println(" mDreamsEnabledOnBatteryConfig="
+ + mDreamsEnabledOnBatteryConfig);
+ pw.println(" mDreamsBatteryLevelMinimumWhenPoweredConfig="
+ + mDreamsBatteryLevelMinimumWhenPoweredConfig);
+ pw.println(" mDreamsBatteryLevelMinimumWhenNotPoweredConfig="
+ + mDreamsBatteryLevelMinimumWhenNotPoweredConfig);
+ pw.println(" mDreamsBatteryLevelDrainCutoffConfig="
+ + mDreamsBatteryLevelDrainCutoffConfig);
pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting);
pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
@@ -1975,8 +2143,8 @@ public final class PowerManagerService extends com.android.server.SystemService
return "Awake";
case WAKEFULNESS_DREAMING:
return "Dreaming";
- case WAKEFULNESS_NAPPING:
- return "Napping";
+ case WAKEFULNESS_DOZING:
+ return "Dozing";
default:
return Integer.toString(wakefulness);
}
@@ -2153,6 +2321,7 @@ public final class PowerManagerService extends com.android.server.SystemService
+ " (uid=" + mOwnerUid + ", pid=" + mOwnerPid + ", ws=" + mWorkSource + ")";
}
+ @SuppressWarnings("deprecation")
private String getLockLevelString() {
switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.FULL_WAKE_LOCK:
@@ -2165,6 +2334,8 @@ public final class PowerManagerService extends com.android.server.SystemService
return "PARTIAL_WAKE_LOCK ";
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
+ case PowerManager.DOZE_WAKE_LOCK:
+ return "DOZE_WAKE_LOCK ";
default:
return "??? ";
}
@@ -2295,16 +2466,24 @@ public final class PowerManagerService extends com.android.server.SystemService
synchronized (this) {
mBlanked = true;
mDisplayManagerInternal.blankAllDisplaysFromPowerManager();
- nativeSetInteractive(false);
- nativeSetAutoSuspend(true);
+ if (!mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(false);
+ }
+ if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(true);
+ }
}
}
@Override
public void unblankAllDisplays() {
synchronized (this) {
- nativeSetAutoSuspend(false);
- nativeSetInteractive(true);
+ if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(false);
+ }
+ if (!mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(true);
+ }
mDisplayManagerInternal.unblankAllDisplaysFromPowerManager();
mBlanked = false;
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 803b9ac..4aae5c1 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -364,8 +364,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
* motion event processing when the screen is off since these events are normally
* dropped. */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
- return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
+ return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(whenNanos, policyFlags);
}
/* Provides an opportunity for the window manager policy to process a key before
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 1a3ce63..d1cfff4 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -6,6 +6,7 @@ LOCAL_SRC_FILES += \
$(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
diff --git a/services/core/jni/com_android_server_dreams_McuHal.cpp b/services/core/jni/com_android_server_dreams_McuHal.cpp
new file mode 100644
index 0000000..a6d9297
--- /dev/null
+++ b/services/core/jni/com_android_server_dreams_McuHal.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#define LOG_TAG "McuHal"
+
+//#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <ScopedUtfChars.h>
+#include <ScopedPrimitiveArray.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <hardware/mcu.h>
+
+namespace android {
+
+static jlong nativeOpen(JNIEnv* env, jclass clazz) {
+ mcu_module_t* module = NULL;
+ status_t err = hw_get_module(MCU_HARDWARE_MODULE_ID,
+ (hw_module_t const**)&module);
+ if (err) {
+ ALOGE("Couldn't load %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
+ return 0;
+ }
+
+ err = module->init(module);
+ if (err) {
+ ALOGE("Couldn't initialize %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
+ return 0;
+ }
+
+ return reinterpret_cast<jlong>(module);
+}
+
+static jbyteArray nativeSendMessage(JNIEnv* env, jclass clazz,
+ jlong ptr, jstring msgStr, jbyteArray argArray) {
+ mcu_module_t* module = reinterpret_cast<mcu_module_t*>(ptr);
+
+ ScopedUtfChars msg(env, msgStr);
+ ALOGV("Sending message %s to MCU", msg.c_str());
+
+ void* result = NULL;
+ size_t resultSize = 0;
+ status_t err;
+ if (argArray) {
+ ScopedByteArrayRO arg(env, argArray);
+ err = module->sendMessage(module, msg.c_str(), arg.get(), arg.size(),
+ &result, &resultSize);
+ } else {
+ err = module->sendMessage(module, msg.c_str(), NULL, 0, &result, &resultSize);
+ }
+ if (err) {
+ ALOGE("Couldn't send message to MCU (%s)", strerror(-err));
+ return NULL;
+ }
+
+ if (!result) {
+ return NULL;
+ }
+
+ jbyteArray resultArray = env->NewByteArray(resultSize);
+ if (resultArray) {
+ env->SetByteArrayRegion(resultArray, 0, resultSize, static_cast<jbyte*>(result));
+ }
+ free(result);
+ return resultArray;
+}
+
+static JNINativeMethod gMcuHalMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeOpen", "()J",
+ (void*) nativeOpen },
+ { "nativeSendMessage", "(JLjava/lang/String;[B)[B",
+ (void*) nativeSendMessage },
+};
+
+int register_android_server_dreams_McuHal(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/dreams/McuHal",
+ gMcuHalMethods, NELEM(gMcuHalMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+ return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 0542ce0..697f56d 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -144,8 +144,6 @@ static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t styl
enum {
WM_ACTION_PASS_TO_USER = 1,
- WM_ACTION_WAKE_UP = 2,
- WM_ACTION_GO_TO_SLEEP = 4,
};
@@ -834,7 +832,7 @@ void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& p
JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
- policyFlags);
+ when, policyFlags);
if (checkAndClearExceptionFromCallback(env,
"interceptMotionBeforeQueueingWhenScreenOff")) {
wmActions = 0;
@@ -850,20 +848,6 @@ void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& p
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
uint32_t& policyFlags) {
- if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- ALOGD("handleInterceptActions: Going to sleep.");
-#endif
- android_server_PowerManagerService_goToSleep(when);
- }
-
- if (wmActions & WM_ACTION_WAKE_UP) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- ALOGD("handleInterceptActions: Waking up.");
-#endif
- android_server_PowerManagerService_wakeUp(when);
- }
-
if (wmActions & WM_ACTION_PASS_TO_USER) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
@@ -1402,7 +1386,7 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
clazz,
- "interceptMotionBeforeQueueingWhenScreenOff", "(I)I");
+ "interceptMotionBeforeQueueingWhenScreenOff", "(JI)I");
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
"interceptKeyBeforeDispatching",
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index efc34a2..00986d5 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -36,6 +36,7 @@ int register_android_server_location_GpsLocationProvider(JNIEnv* env);
int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_AssetAtlasService(JNIEnv* env);
+int register_android_server_dreams_McuHal(JNIEnv* env);
};
using namespace android;
@@ -67,7 +68,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
register_android_server_ConsumerIrService(env);
-
+ register_android_server_dreams_McuHal(env);
return JNI_VERSION_1_4;
}
diff --git a/tests/DozeTest/Android.mk b/tests/DozeTest/Android.mk
new file mode 100644
index 0000000..01f10e5
--- /dev/null
+++ b/tests/DozeTest/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := DozeTest
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/DozeTest/AndroidManifest.xml b/tests/DozeTest/AndroidManifest.xml
new file mode 100644
index 0000000..c199f69
--- /dev/null
+++ b/tests/DozeTest/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.dreams.dozetest">
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <application android:label="@string/app_name">
+ <service
+ android:name="DozeTestDream"
+ android:exported="true"
+ android:icon="@drawable/ic_app"
+ android:label="@string/doze_dream_name">
+ <!-- Commented out to prevent this dream from appearing in the list of
+ dreams that the user can select via the Settings application.
+ <intent-filter>
+ <action android:name="android.service.dreams.DreamService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ -->
+ </service>
+ </application>
+</manifest>
diff --git a/tests/DozeTest/res/drawable-hdpi/ic_app.png b/tests/DozeTest/res/drawable-hdpi/ic_app.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/tests/DozeTest/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/DozeTest/res/drawable-mdpi/ic_app.png b/tests/DozeTest/res/drawable-mdpi/ic_app.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/tests/DozeTest/res/drawable-mdpi/ic_app.png
Binary files differ
diff --git a/tests/DozeTest/res/layout/dream.xml b/tests/DozeTest/res/layout/dream.xml
new file mode 100644
index 0000000..1c8fd3f
--- /dev/null
+++ b/tests/DozeTest/res/layout/dream.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/alarm_clock_label" />
+ <TextView android:id="@+id/alarm_clock"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/tick_clock_label" />
+ <TextClock android:id="@+id/tick_clock"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/DozeTest/res/values/strings.xml b/tests/DozeTest/res/values/strings.xml
new file mode 100644
index 0000000..f21911f
--- /dev/null
+++ b/tests/DozeTest/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<resources>
+ <!-- Name of the package of basic screensavers, shown in Settings > Apps. [CHAR LIMIT=40] -->
+ <string name="app_name">Doze Test</string>
+
+ <!-- Name of the screensaver. [CHAR LIMIT=40] -->
+ <string name="doze_dream_name">Doze Test</string>
+
+ <string name="alarm_clock_label">This clock is updated using the Alarm Manager</string>
+ <string name="tick_clock_label">This clock is updated using TIME_TICK Broadcasts</string>
+</resources>
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
new file mode 100644
index 0000000..bf35db4
--- /dev/null
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014 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.dreams.dozetest;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PowerManager;
+import android.service.dreams.DozeHardware;
+import android.service.dreams.DreamService;
+import android.text.format.DateFormat;
+import android.util.Log;
+import android.widget.TextView;
+
+import java.util.Date;
+
+/**
+ * Simple test for doze mode.
+ * <p>
+ * adb shell setprop debug.doze.component com.android.dreams.dozetest/.DozeTestDream
+ * </p>
+ */
+public class DozeTestDream extends DreamService {
+ private static final String TAG = DozeTestDream.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ // Amount of time to allow to update the time shown on the screen before releasing
+ // the wakelock. This timeout is design to compensate for the fact that we don't
+ // currently have a way to know when time display contents have actually been
+ // refreshed once the dream has finished rendering a new frame.
+ private static final int UPDATE_TIME_TIMEOUT = 100;
+
+ // A doze hardware message string we use for end-to-end testing.
+ // Doesn't mean anything. Real hardware won't handle it.
+ private static final String TEST_PING_MESSAGE = "test.ping";
+
+ private PowerManager mPowerManager;
+ private PowerManager.WakeLock mWakeLock;
+ private AlarmManager mAlarmManager;
+ private PendingIntent mAlarmIntent;
+
+ private TextView mAlarmClock;
+
+ private final Date mTime = new Date();
+ private java.text.DateFormat mTimeFormat;
+
+ private boolean mDreaming;
+ private DozeHardware mDozeHardware;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+ mAlarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
+
+ Intent intent = new Intent("com.android.dreams.dozetest.ACTION_ALARM");
+ intent.setPackage(getPackageName());
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(intent.getAction());
+ registerReceiver(mAlarmReceiver, filter);
+ mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ unregisterReceiver(mAlarmReceiver);
+ mAlarmIntent.cancel();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ setInteractive(false);
+ setLowProfile(true);
+ setFullscreen(true);
+ setContentView(R.layout.dream);
+
+ mAlarmClock = (TextView)findViewById(R.id.alarm_clock);
+
+ mTimeFormat = DateFormat.getTimeFormat(this);
+ }
+
+ @Override
+ public void onDreamingStarted() {
+ super.onDreamingStarted();
+
+ mDreaming = true;
+ mDozeHardware = getDozeHardware();
+
+ Log.d(TAG, "Dream started: canDoze=" + canDoze()
+ + ", dozeHardware=" + mDozeHardware);
+
+ performTimeUpdate();
+
+ if (mDozeHardware != null) {
+ mDozeHardware.sendMessage(TEST_PING_MESSAGE, null);
+ mDozeHardware.setEnableMcu(true);
+ }
+ startDozing();
+ }
+
+ @Override
+ public void onDreamingStopped() {
+ super.onDreamingStopped();
+
+ mDreaming = false;
+ if (mDozeHardware != null) {
+ mDozeHardware.setEnableMcu(false);
+ mDozeHardware = null;
+ }
+
+ Log.d(TAG, "Dream ended: isDozing=" + isDozing());
+
+ stopDozing();
+ cancelTimeUpdate();
+ }
+
+ private void performTimeUpdate() {
+ if (mDreaming) {
+ long now = System.currentTimeMillis();
+ now -= now % 60000; // back up to last minute boundary
+
+ mTime.setTime(now);
+ mAlarmClock.setText(mTimeFormat.format(mTime));
+
+ mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, now + 60000, mAlarmIntent);
+
+ mWakeLock.acquire(UPDATE_TIME_TIMEOUT);
+ }
+ }
+
+ private void cancelTimeUpdate() {
+ mAlarmManager.cancel(mAlarmIntent);
+ }
+
+ private final BroadcastReceiver mAlarmReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ performTimeUpdate();
+ }
+ };
+}