Disabling sleep mode on Android

Published on May 5, 2011

Archived Notice

This article has been archived and may contain broken links, photos and out-of-date information. If you have any questions, please Contact Us.

Android's user-focused, touchscreen-driven interface lends itself well to fixed-point applications such as kiosks and control panels.  However, since it was originally designed for mobile devices, there are a few features that need to be tweaked. For example, Android puts itself to sleep after a certain amount of inactivity. You may not want your device to sleep at all -- in fact, if you haven't hooked up Android buttons somewhere on your device, you might not be able to wake it up when it does so. Fortunately, this is a quick fix. Let's talk about power management a little first, though. Apps that need to keep the screen on, such as a video player, can acquire a wake lock to instruct the system to temporarily change its power management policy.  Read up on the PowerManager class for details on how to do this in your own application.  So long as a wake lock is held by an application, the system has to stay awake to the degree specified by the wake lock. So, one easy way to keep the system awake would be to insert a wake lock into the home application (in our case, Launcher2) that gets held throughout its lifetime.  Here's a patch Eric wrote for Launcher2 that demonstrates this (the root directory, btw, is my-android/packages/apps/Launcher2):

diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 606f6f8..84ee599 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -50,7 +50,6 @@
         android:label="@string/permlab_write_settings"
         android:description="@string/permdesc_write_settings"/>
-
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/androi
index 85a9b9d..eda92d9 100644
--- a/src/com/android/launcher2/LauncherApplication.java
+++ b/src/com/android/launcher2/LauncherApplication.java
@@ -23,16 +23,10 @@ import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.os.Handler;
 import dalvik.system.VMRuntime;
-import android.os.PowerManager;
-import android.app.Activity;
-import android.content.Context;
-import android.content.Context;
-import android.content.Context;
--- a/AndroidManifest.xml
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 606f6f8..84ee599 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -50,7 +50,6 @@
         android:label="@string/permlab_write_settings"
         android:description="@string/permdesc_write_settings"/>
-
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java
index 85a9b9d..eda92d9 100644
--- a/src/com/android/launcher2/LauncherApplication.java
+++ b/src/com/android/launcher2/LauncherApplication.java
@@ -23,16 +23,10 @@ import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.os.Handler;
 import dalvik.system.VMRuntime;
-import android.os.PowerManager;
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.PowerManager;
 public class LauncherApplication extends Application {
     public LauncherModel mModel;
     public IconCache mIconCache;
-    protected PowerManager.WakeLock mWakeLock;
     @Override
     public void onCreate() {
@@ -58,10 +52,6 @@ public class LauncherApplication extends Application {
         ContentResolver resolver = getContentResolver();
         resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true,
                 mFavoritesObserver);
-
-        final PowerManager pm = (PowerManager) getSystemService(Context.POWER_S
-        this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My Tag");
-        this.mWakeLock.acquire();
     }
     /**
A slightly hackier way to do this would be to go into the framework and 'cut the cord', so to speak, that forces the system to sleep. Wake locks and other power management-related activities are managed by the PowerManagerService.  This class sits directly on top of the native hardware management code and converts requests by the upper layers into actual power state change commands. If you run Android with PowerManagerService.mSpew enabled, you'll see a heap of messages from PowerManagerService while you're interacting with the device that clues you in to how much work the service actually performs. The first place I looked for a solution was in setPowerState(), which is matched by a native method in the hardware abstraction layer. There is a state variable in there that holds a bitmask of various power state flags, and it gets updated every time setPowerState() gets called.  It'd be easy enough to toss in something like
if ((mPowerState & (SCREEN_ON_BIT | SCREEN_BRIGHT)) != 0) {
    Slog.d(TAG, "No sleep till Brooklyn!");
    return;
}
... at the beginning of the method, and that would keep the entire method from ever turning off the display.  This falls squarely in the category of 'bandaid', though, which you'll see if you keep your eye on the system log. setPowerState() gets called on a timer, setTimeoutLocked(), which is set when the system detects a userActivity(), in other words, when you touch the screen.  If we modify setPowerState(), the timer will still get set with every touch event, but nothing will happen when it expires.  So, the cleaner way to do this is to stop the timer from getting set in the first place.
    private void userActivity(long time, long timeoutOverride, boolean noChangeLights,
            int eventType, boolean force) {
        ...
        synchronized (mLocks) { 
            ...
            if (mLastEventTime <= time || force) {
                mLastEventTime = time;
                if ((mUserActivityAllowed && !mProximitySensorActive) || force) {
                    // Only turn on button backlights if a button was pressed
                    // and auto brightness is disabled
                    if (eventType == BUTTON_EVENT && !mUseSoftwareAutoBrightness) {
                        mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
                    } else {
                        // don't clear button/keyboard backlights when the screen is touched.
                        mUserState |= SCREEN_BRIGHT;
                    }
                    int uid = Binder.getCallingUid();
                    long ident = Binder.clearCallingIdentity();
                    try {
                        mBatteryStats.noteUserActivity(uid, eventType);
                    } catch (RemoteException e) {
                        // Ignore
                    } finally {
                        Binder.restoreCallingIdentity(ident);
                    }
                    mWakeLockState = mLocks.reactivateScreenLocksLocked();
                    setPowerState(mUserState | mWakeLockState, noChangeLights,
                            WindowManagerPolicy.OFF_BECAUSE_OF_USER);
                    setTimeoutLocked(time, timeoutOverride, SCREEN_BRIGHT);
                }
            }
        }
        if (mPolicy != null) {
            mPolicy.userActivity();
        }
    }
Comment out the setTimeoutLocked() call in line 44 of the above example, recompile and run.  PowerManagerService will still pick up on touch events and pass them to the battery management subsystem, but without the timer, setPowerState() doesn't get called until you tell it to.  Congratulations, you now have an insomniac Android!