From 7e4e561bc717a6eea4e0d06ec4173ad27420425f Mon Sep 17 00:00:00 2001 From: Romain Guy Date: Mon, 5 Mar 2012 14:37:29 -0800 Subject: [PATCH] Ignore draw requests when the display is off When WindowManagerService's events are enabled/disabled, the state of the display is dispatched to the known windows. This allows ViewRootImpl to ignore draw requests until the screen is turned back on. This can potentially lead to significant battery savings. For instance, a launcher widget showing a repeating animation will cause the CPU and the GPU to wake up regularly without this change. (Change submitted by Intel and merged manually) Change-Id: I7f93b0e60c3e6de1705f619e80860c36b1cdb978 --- core/java/android/view/IWindow.aidl | 1 + core/java/android/view/View.java | 2 + core/java/android/view/ViewRootImpl.java | 38 ++++++++++++++++++- .../android/internal/view/BaseIWindow.java | 3 ++ .../server/wm/WindowManagerService.java | 16 ++++++++ 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index 715fa7b4eacb4..acb13877c7a44 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -49,6 +49,7 @@ oneway interface IWindow { boolean reportDraw, in Configuration newConfig); void dispatchAppVisibility(boolean visible); void dispatchGetNewSurface(); + void dispatchScreenStatus(boolean on); /** * Tell the window that it is either gaining or losing focus. Keep it up diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 49f6023d1b3ba..1a6c97bd176c7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -14845,6 +14845,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal boolean mHardwareAccelerationRequested; HardwareRenderer mHardwareRenderer; + boolean mScreenOn; + /** * Scale factor used by the compatibility mode */ diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index e0d07635c1e87..3bc867c2a7387 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -46,6 +46,7 @@ import android.os.LatencyTimer; import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; +import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; @@ -390,6 +391,9 @@ public final class ViewRootImpl implements ViewParent, mProfileRendering = Boolean.parseBoolean( SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false")); mChoreographer = Choreographer.getInstance(); + + PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mAttachInfo.mScreenOn = powerManager.isScreenOn(); } /** @@ -757,6 +761,16 @@ public final class ViewRootImpl implements ViewParent, scheduleTraversals(); } + void handleScreenStatusChange(boolean on) { + if (on != mAttachInfo.mScreenOn) { + mAttachInfo.mScreenOn = on; + if (on) { + mFullRedrawNeeded = true; + scheduleTraversals(); + } + } + } + /** * {@inheritDoc} */ @@ -1886,6 +1900,8 @@ public final class ViewRootImpl implements ViewParent, } private void performDraw() { + if (!mAttachInfo.mScreenOn) return; + final long drawStartTime; if (ViewDebug.DEBUG_LATENCY) { drawStartTime = System.nanoTime(); @@ -2018,8 +2034,7 @@ public final class ViewRootImpl implements ViewParent, } if (!dirty.isEmpty() || mIsAnimating) { - if (mAttachInfo.mHardwareRenderer != null - && mAttachInfo.mHardwareRenderer.isEnabled()) { + if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { // Draw with hardware renderer. mIsAnimating = false; mHardwareYOffset = yoff; @@ -2485,6 +2500,7 @@ public final class ViewRootImpl implements ViewParent, private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 21; private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 22; private final static int MSG_PROCESS_INPUT_EVENTS = 23; + private final static int MSG_DISPATCH_SCREEN_STATUS = 24; final class ViewRootHandler extends Handler { @Override @@ -2741,6 +2757,11 @@ public final class ViewRootImpl implements ViewParent, .findAccessibilityNodeInfosByTextUiThread(msg); } } break; + case MSG_DISPATCH_SCREEN_STATUS: { + if (mView != null) { + handleScreenStatusChange(msg.arg1 == 1); + } + } break; } } } @@ -4025,6 +4046,12 @@ public final class ViewRootImpl implements ViewParent, mHandler.sendMessage(msg); } + public void dispatchScreenStatusChange(boolean on) { + Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATUS); + msg.arg1 = on ? 1 : 0; + mHandler.sendMessage(msg); + } + public void dispatchGetNewSurface() { Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE); mHandler.sendMessage(msg); @@ -4226,6 +4253,13 @@ public final class ViewRootImpl implements ViewParent, } } + public void dispatchScreenStatus(boolean on) { + final ViewRootImpl viewAncestor = mViewAncestor.get(); + if (viewAncestor != null) { + viewAncestor.dispatchScreenStatusChange(on); + } + } + public void dispatchGetNewSurface() { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index b22770093014d..e695f8efbcb86 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -49,6 +49,9 @@ public class BaseIWindow extends IWindow.Stub { public void dispatchGetNewSurface() { } + public void dispatchScreenStatus(boolean on) { + } + public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) { } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 1c5a70fdaef3b..023f97dbb1d42 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -6347,6 +6347,8 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mWindowMap) { mInputMonitor.setEventDispatchingLw(enabled); } + + sendScreenStatusToClients(); } /** @@ -6570,6 +6572,20 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.systemReady(); } + private void sendScreenStatusToClients() { + final ArrayList windows = mWindows; + final int count = windows.size(); + boolean on = mPowerManager.isScreenOn(); + for (int i = count - 1; i >= 0; i--) { + WindowState win = mWindows.get(i); + try { + win.mClient.dispatchScreenStatus(on); + } catch (RemoteException e) { + // Ignored + } + } + } + // This is an animation that does nothing: it just immediately finishes // itself every time it is called. It is used as a stub animation in cases // where we want to synchronize multiple things that may be animating.