resolved conflicts for merge of baaa080b to master

Change-Id: I3ee12321e298f7a2ea577a99f30c49f3bb497fae
This commit is contained in:
Jeff Brown
2014-02-20 18:05:03 -08:00
32 changed files with 1376 additions and 277 deletions

View File

@ -183,6 +183,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 \

View File

@ -190,6 +190,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.
*
@ -437,6 +449,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.");

View File

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

View File

@ -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.

View File

@ -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)
*/
@ -502,6 +519,119 @@ public class DreamService extends Service implements Window.Callback {
return getWindowFlagValue(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, mScreenBright);
}
/**
* 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.
*/
@ -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

View File

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

View File

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

View File

@ -20,6 +20,6 @@ package android.service.dreams;
* @hide
*/
oneway interface IDreamService {
void attach(IBinder windowToken);
void attach(IBinder windowToken, boolean canDoze);
void detach();
}

View File

@ -118,20 +118,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
@ -760,8 +746,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);
@ -774,10 +759,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.

View File

@ -658,6 +658,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. -->
@ -1089,6 +1094,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>

View File

@ -1500,6 +1500,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" />
@ -1604,11 +1605,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" />

View File

@ -3799,14 +3799,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
@ -3823,6 +3820,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;
@ -3830,8 +3829,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;
}
}
@ -3941,7 +3940,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;
}
}
}
@ -3988,7 +3988,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;
}
@ -4058,6 +4059,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
break;
}
}
if (isWakeKey) {
mPowerManager.wakeUp(event.getEventTime());
}
return result;
}
@ -4098,13 +4103,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;
}

View File

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

View File

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

View File

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

View File

@ -1366,8 +1366,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.
@ -1527,7 +1528,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);

View File

@ -201,7 +201,7 @@ class AutomaticBrightnessController {
public void updatePowerState(DisplayPowerRequest request) {
if (setScreenAutoBrightnessAdjustment(request.screenAutoBrightnessAdjustment)
|| setLightSensorEnabled(request.useAutoBrightness
&& DisplayPowerRequest.wantScreenOn(request.screenState))) {
&& request.wantScreenOnNormal())) {
updateAutoBrightness(false /*sendUpdate*/);
}
}

View File

@ -147,6 +147,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// The proximity sensor, or null if not available or needed.
private Sensor mProximitySensor;
// The doze screen brightness.
private final int mScreenBrightnessDozeConfig;
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
@ -259,6 +262,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
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));
@ -432,7 +438,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Update the power state request.
final boolean mustNotify;
boolean mustInitialize = false;
boolean wasDim = false;
boolean wasDimOrDoze = false;
synchronized (mLock) {
mPendingUpdatePowerStateLocked = false;
@ -447,7 +453,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mPendingRequestChangedLocked = false;
mustInitialize = true;
} else if (mPendingRequestChangedLocked) {
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;
@ -498,7 +505,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
// Set the screen brightness.
if (DisplayPowerRequest.wantScreenOn(mPowerRequest.screenState)) {
if (mPowerRequest.wantScreenOnAny()) {
int target;
boolean slow;
int screenAutoBrightness = mAutomaticBrightnessController != null ?
@ -517,12 +524,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
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;
}
@ -535,7 +546,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Animate the screen on or off.
if (!mScreenOffBecauseOfProximity) {
if (DisplayPowerRequest.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
@ -804,6 +815,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
pw.println();
pw.println("Display Controller Configuration:");
pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);

View File

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

View File

@ -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();
}
}
@ -1887,10 +2040,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="
@ -1906,6 +2062,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="
@ -1916,6 +2076,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);
@ -1991,8 +2159,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);
}
@ -2169,6 +2337,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:
@ -2181,6 +2350,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 "??? ";
}
@ -2311,16 +2482,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;
}

View File

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

View File

@ -8,6 +8,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 \

View File

@ -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 */

View File

@ -151,8 +151,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,
};
@ -844,7 +842,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;
@ -860,20 +858,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 {
@ -1412,7 +1396,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",

View File

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

14
tests/DozeTest/Android.mk Normal file
View File

@ -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))

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

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

View File

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

View File

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