Bug 702256 - "[Gonk] Add DOM API for turning screen on/off and adjusting the screen's brightness" r=cjones,mounir
☠☠ backed out by d991d9770292 ☠ ☠
authorJustin Lebar <justin.lebar+bug>
Mon, 05 Dec 2011 01:07:00 +0800
changeset 83085 407fba8cbd5af2ef6a7a1adb597a38543876747c
parent 83084 03420089b4af22f32e1cb54f3904a74706416f34
child 83086 e8a2d4389e8fda88a630bebd7dbb9fb180443341
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones, mounir
bugs702256
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 702256 - "[Gonk] Add DOM API for turning screen on/off and adjusting the screen's brightness" r=cjones,mounir
dom/base/nsScreen.cpp
dom/base/nsScreen.h
dom/interfaces/base/nsIDOMScreen.idl
hal/Hal.cpp
hal/Hal.h
hal/android/AndroidHal.cpp
hal/fallback/FallbackHal.cpp
hal/linux/LinuxHal.cpp
hal/sandbox/PHal.ipdl
hal/sandbox/SandboxHal.cpp
widget/src/gonk/nsAppShell.cpp
--- a/dom/base/nsScreen.cpp
+++ b/dom/base/nsScreen.cpp
@@ -31,31 +31,53 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "nscore.h"
+#include "mozilla/Hal.h"
 #include "nsScreen.h"
 #include "nsIDocShell.h"
 #include "nsPresContext.h"
 #include "nsCOMPtr.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIInterfaceRequestorUtils.h"
+#include "nsIDocShellTreeItem.h"
 #include "nsLayoutUtils.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+
+/* static */ bool nsScreen::sInitialized = false;
+/* static */ bool nsScreen::sAllowScreenEnabledProperty = false;
+/* static */ bool nsScreen::sAllowScreenBrightnessProperty = false;
+
+/* static */ void
+nsScreen::Initialize()
+{
+  MOZ_ASSERT(!sInitialized);
+  sInitialized = true;
+  Preferences::AddBoolVarCache(&sAllowScreenEnabledProperty,
+                               "dom.screenEnabledProperty.enabled");
+  Preferences::AddBoolVarCache(&sAllowScreenBrightnessProperty,
+                               "dom.screenBrightnessProperty.enabled");
+}
 
 //
 //  Screen class implementation
 //
 nsScreen::nsScreen(nsIDocShell* aDocShell)
   : mDocShell(aDocShell)
 {
+  if (!sInitialized) {
+    Initialize();
+  }
 }
 
 nsScreen::~nsScreen()
 {
 }
 
 
 DOMCI_DATA(Screen, nsScreen)
@@ -232,8 +254,74 @@ nsScreen::GetAvailRect(nsRect& aRect)
 
   aRect.x = nsPresContext::AppUnitsToIntCSSPixels(aRect.x);
   aRect.y = nsPresContext::AppUnitsToIntCSSPixels(aRect.y);
   aRect.height = nsPresContext::AppUnitsToIntCSSPixels(aRect.height);
   aRect.width = nsPresContext::AppUnitsToIntCSSPixels(aRect.width);
 
   return NS_OK;
 }
+
+namespace {
+
+bool
+IsChromeType(nsIDocShell *aDocShell)
+{
+  nsCOMPtr<nsIDocShellTreeItem> ds = do_QueryInterface(aDocShell);
+  if (!ds) {
+    return false;
+  }
+
+  PRInt32 itemType;
+  ds->GetItemType(&itemType);
+  return itemType == nsIDocShellTreeItem::typeChrome;
+}
+
+} // anonymous namespace
+
+nsresult
+nsScreen::GetMozEnabled(bool *aEnabled)
+{
+  if (!sAllowScreenEnabledProperty || !IsChromeType(mDocShell)) {
+    *aEnabled = true;
+    return NS_OK;
+  }
+
+  *aEnabled = hal::GetScreenEnabled();
+  return NS_OK;
+}
+
+nsresult
+nsScreen::SetMozEnabled(bool aEnabled)
+{
+  if (!sAllowScreenEnabledProperty || !IsChromeType(mDocShell)) {
+    return NS_OK;
+  }
+
+  // TODO bug 707589: When the screen's state changes, all visible windows
+  // should fire a visibility change event.
+  hal::SetScreenEnabled(aEnabled);
+  return NS_OK;
+}
+
+nsresult
+nsScreen::GetMozBrightness(double *aBrightness)
+{
+  if (!sAllowScreenBrightnessProperty || !IsChromeType(mDocShell)) {
+    *aBrightness = 1;
+    return NS_OK;
+  }
+
+  *aBrightness = hal::GetScreenBrightness();
+  return NS_OK;
+}
+
+nsresult
+nsScreen::SetMozBrightness(double aBrightness)
+{
+  if (!sAllowScreenBrightnessProperty || !IsChromeType(mDocShell)) {
+    return NS_OK;
+  }
+
+  NS_ENSURE_TRUE(0 <= aBrightness && aBrightness <= 1, NS_ERROR_INVALID_ARG);
+  hal::SetScreenBrightness(aBrightness);
+  return NS_OK;
+}
--- a/dom/base/nsScreen.h
+++ b/dom/base/nsScreen.h
@@ -59,11 +59,18 @@ public:
   NS_DECL_NSIDOMSCREEN
 
 protected:
   nsDeviceContext* GetDeviceContext();
   nsresult GetRect(nsRect& aRect);
   nsresult GetAvailRect(nsRect& aRect);
 
   nsIDocShell* mDocShell; // Weak Reference
+
+private:
+  static bool sInitialized;
+  static bool sAllowScreenEnabledProperty;
+  static bool sAllowScreenBrightnessProperty;
+
+  static void Initialize();
 };
 
 #endif /* nsScreen_h___ */
--- a/dom/interfaces/base/nsIDOMScreen.idl
+++ b/dom/interfaces/base/nsIDOMScreen.idl
@@ -34,22 +34,45 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "domstubs.idl"
 
-[scriptable, uuid(77947960-b4af-11d2-bd93-00805f8ae3f4)]
+[scriptable, uuid(4507e43f-097c-452a-bfc4-dbb99748f6fd)]
 interface nsIDOMScreen : nsISupports
 {
   readonly attribute long             top;
   readonly attribute long             left;
   readonly attribute long             width;
   readonly attribute long             height;
   readonly attribute long             pixelDepth;
   readonly attribute long             colorDepth;
   readonly attribute long             availWidth;
   readonly attribute long             availHeight;
   readonly attribute long             availLeft;
   readonly attribute long             availTop;
+
+  /**
+   * Is the device's screen currently enabled?  This attribute controls the
+   * device's screen, so setting it to false will turn off the screen.
+   */
+  attribute boolean mozEnabled;
+
+  /**
+   * How bright is the screen's backlight, on a scale from 0 (very dim) to 1
+   * (full brightness)?  Setting this attribute modifies the screen's
+   * brightness.
+   *
+   * You can read and write this attribute even when the screen is disabled,
+   * but the backlight is off while the screen is disabled.
+   *
+   * If you write a value of X into this attribute, the attribute may not have
+   * the same value X when you later read it.  Most screens don't support as
+   * many different brightness levels as there are doubles between 0 and 1, so
+   * we may reduce the value's precision before storing it.
+   *
+   * @throw NS_ERROR_INVALID_ARG if brightness is not in the range [0, 1].
+   */
+  attribute double mozBrightness;
 };
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -61,16 +61,25 @@ using namespace mozilla::services;
   do {                                            \
     if (InSandbox()) {                            \
       hal_sandbox::_call;                         \
     } else {                                      \
       hal_impl::_call;                            \
     }                                             \
   } while (0)
 
+#define RETURN_PROXY_IF_SANDBOXED(_call)          \
+  do {                                            \
+    if (InSandbox()) {                            \
+      return hal_sandbox::_call;                  \
+    } else {                                      \
+      return hal_impl::_call;                     \
+    }                                             \
+  } while (0)
+
 namespace mozilla {
 namespace hal {
 
 PRLogModuleInfo *sHalLog = PR_LOG_DEFINE("hal");
 
 namespace {
 
 void
@@ -272,17 +281,17 @@ CancelVibrate(const WindowIdentifier &id
   else if (*gLastIDToVibrate == id.AsArray()) {
     // Don't forward our ID to hal_impl. It doesn't need it, and we
     // don't want it to be tempted to read it.  The empty identifier
     // will assert if it's used.
     HAL_LOG(("CancelVibrate: Forwarding to hal_impl."));
     hal_impl::CancelVibrate(WindowIdentifier());
   }
 }
- 
+
 class BatteryObserversManager
 {
 public:
   void AddObserver(BatteryObserver* aObserver) {
     if (!mObservers) {
       mObservers = new ObserverList<BatteryInformation>();
     }
 
@@ -367,10 +376,34 @@ GetCurrentBatteryInformation(BatteryInfo
 void NotifyBatteryChange(const BatteryInformation& aBatteryInfo)
 {
   AssertMainThread();
 
   sBatteryObservers.CacheBatteryInformation(aBatteryInfo);
   sBatteryObservers.Broadcast(aBatteryInfo);
 }
 
+bool GetScreenEnabled()
+{
+  AssertMainThread();
+  RETURN_PROXY_IF_SANDBOXED(GetScreenEnabled());
+}
+
+void SetScreenEnabled(bool enabled)
+{
+  AssertMainThread();
+  PROXY_IF_SANDBOXED(SetScreenEnabled(enabled));
+}
+
+double GetScreenBrightness()
+{
+  AssertMainThread();
+  RETURN_PROXY_IF_SANDBOXED(GetScreenBrightness());
+}
+
+void SetScreenBrightness(double brightness)
+{
+  AssertMainThread();
+  PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0)));
+}
+
 } // namespace hal
 } // namespace mozilla
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -252,16 +252,49 @@ void DisableBatteryNotifications();
 void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
 
 /**
  * Notify of a change in the battery state.
  * @param aBatteryInfo The new battery information.
  */
 void NotifyBatteryChange(const hal::BatteryInformation& aBatteryInfo);
 
+/**
+ * Determine whether the device's screen is currently enabled.
+ */
+bool GetScreenEnabled();
+
+/**
+ * Enable or disable the device's screen.
+ *
+ * Note that it may take a few seconds for the screen to turn on or off.
+ */
+void SetScreenEnabled(bool enabled);
+
+/**
+ * Get the brightness of the device's screen's backlight, on a scale from 0
+ * (very dim) to 1 (full blast).
+ *
+ * If the display is currently disabled, this returns the brightness the
+ * backlight will have when the display is re-enabled.
+ */
+double GetScreenBrightness();
+
+/**
+ * Set the brightness of the device's screen's backlight, on a scale from 0
+ * (very dimm) to 1 (full blast).  Values larger than 1 are treated like 1, and
+ * values smaller than 0 are treated like 0.
+ *
+ * Note that we may reduce the resolution of the given brightness value before
+ * sending it to the screen.  Therefore if you call SetScreenBrightness(x)
+ * followed by GetScreenBrightness(), the value returned by
+ * GetScreenBrightness() may not be exactly x.
+ */
+void SetScreenBrightness(double brightness);
+
 } // namespace MOZ_HAL_NAMESPACE
 } // namespace mozilla
 
 #ifdef MOZ_DEFINED_HAL_NAMESPACE
 # undef MOZ_DEFINED_HAL_NAMESPACE
 # undef MOZ_HAL_NAMESPACE
 #endif
 
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -100,11 +100,31 @@ GetCurrentBatteryInformation(hal::Batter
   AndroidBridge* bridge = AndroidBridge::Bridge();
   if (!bridge) {
     return;
   }
 
   bridge->GetCurrentBatteryInformation(aBatteryInfo);
 }
 
+bool
+GetScreenEnabled()
+{
+  return true;
+}
+
+void
+SetScreenEnabled(bool enabled)
+{}
+
+double
+GetScreenBrightness()
+{
+  return 1;
+}
+
+void
+SetScreenBrightness(double brightness)
+{}
+
 } // hal_impl
 } // mozilla
 
--- a/hal/fallback/FallbackHal.cpp
+++ b/hal/fallback/FallbackHal.cpp
@@ -64,10 +64,30 @@ DisableBatteryNotifications()
 void
 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
 {
   aBatteryInfo->level() = dom::battery::kDefaultLevel;
   aBatteryInfo->charging() = dom::battery::kDefaultCharging;
   aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
 }
 
+bool
+GetScreenEnabled()
+{
+  return true;
+}
+
+void
+SetScreenEnabled(bool enabled)
+{}
+
+double
+GetScreenBrightness()
+{
+  return 1;
+}
+
+void
+SetScreenBrightness(double brightness)
+{}
+
 } // hal_impl
 } // namespace mozilla
--- a/hal/linux/LinuxHal.cpp
+++ b/hal/linux/LinuxHal.cpp
@@ -65,11 +65,31 @@ void
 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
 {
   aBatteryInfo->level() = dom::battery::kDefaultLevel;
   aBatteryInfo->charging() = dom::battery::kDefaultCharging;
   aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
 }
 #endif // !MOZ_ENABLE_DBUS
 
+bool
+GetScreenEnabled()
+{
+  return true;
+}
+
+void
+SetScreenEnabled(bool enabled)
+{}
+
+double
+GetScreenBrightness()
+{
+  return 1;
+}
+
+void
+SetScreenBrightness(double brightness)
+{}
+
 } // hal_impl
 } // mozilla
 
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -62,13 +62,19 @@ parent:
     Vibrate(uint32[] pattern, uint64[] id, PBrowser browser);
     CancelVibrate(uint64[] id, PBrowser browser);
 
     EnableBatteryNotifications();
     DisableBatteryNotifications();
     sync GetCurrentBatteryInformation()
       returns (BatteryInformation aBatteryInfo);
 
+    sync GetScreenEnabled() returns (bool enabled);
+    SetScreenEnabled(bool enabled);
+
+    sync GetScreenBrightness() returns (double brightness);
+    SetScreenBrightness(double brightness);
+
     __delete__();
 };
 
 } // namespace hal
 } // namespace mozilla
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -99,16 +99,44 @@ DisableBatteryNotifications()
 }
 
 void
 GetCurrentBatteryInformation(BatteryInformation* aBatteryInfo)
 {
   Hal()->SendGetCurrentBatteryInformation(aBatteryInfo);
 }
 
+bool
+GetScreenEnabled()
+{
+  bool enabled = false;
+  Hal()->SendGetScreenEnabled(&enabled);
+  return enabled;
+}
+
+void
+SetScreenEnabled(bool enabled)
+{
+  Hal()->SendSetScreenEnabled(enabled);
+}
+
+double
+GetScreenBrightness()
+{
+  double brightness = 0;
+  Hal()->SendGetScreenBrightness(&brightness);
+  return brightness;
+}
+
+void
+SetScreenBrightness(double brightness)
+{
+  Hal()->SendSetScreenBrightness(brightness);
+}
+
 class HalParent : public PHalParent
                 , public BatteryObserver {
 public:
   NS_OVERRIDE virtual bool
   RecvVibrate(const InfallibleTArray<unsigned int>& pattern,
               const InfallibleTArray<uint64> &id,
               PBrowserParent *browserParent)
   {
@@ -162,16 +190,44 @@ public:
   RecvGetCurrentBatteryInformation(BatteryInformation* aBatteryInfo) {
     hal::GetCurrentBatteryInformation(aBatteryInfo);
     return true;
   }
 
   void Notify(const BatteryInformation& aBatteryInfo) {
     unused << SendNotifyBatteryChange(aBatteryInfo);
   }
+
+  NS_OVERRIDE virtual bool
+  RecvGetScreenEnabled(bool *enabled)
+  {
+    *enabled = hal::GetScreenEnabled();
+    return true;
+  }
+
+  NS_OVERRIDE virtual bool
+  RecvSetScreenEnabled(const bool &enabled)
+  {
+    hal::SetScreenEnabled(enabled);
+    return true;
+  }
+
+  NS_OVERRIDE virtual bool
+  RecvGetScreenBrightness(double *brightness)
+  {
+    *brightness = hal::GetScreenBrightness();
+    return true;
+  }
+
+  NS_OVERRIDE virtual bool
+  RecvSetScreenBrightness(const double &brightness)
+  {
+    hal::SetScreenBrightness(brightness);
+    return true;
+  }
 };
 
 class HalChild : public PHalChild {
 public:
   NS_OVERRIDE virtual bool
   RecvNotifyBatteryChange(const BatteryInformation& aBatteryInfo) {
     hal::NotifyBatteryChange(aBatteryInfo);
     return true;
--- a/widget/src/gonk/nsAppShell.cpp
+++ b/widget/src/gonk/nsAppShell.cpp
@@ -239,40 +239,16 @@ sendKeyEvent(PRUint32 keyCode, bool keyD
 static void
 sendSpecialKeyEvent(nsIAtom *command, const struct timeval &time)
 {
     nsCommandEvent event(true, nsGkAtoms::onAppCommand, command, NULL);
     event.time = timevalToMS(time);
     nsWindow::DispatchInputEvent(event);
 }
 
-static int screenFd = -1;
-static bool sScreenOn = true;
-
-static void
-handlePowerKeyPressed()
-{
-    if (screenFd == -1) {
-        screenFd = open("/sys/power/state", O_RDWR);
-        if (screenFd < 0) {
-            LOG("Unable to open /sys/power/state.");
-            return;
-        }
-    }
-
-    // No idea why the screen-off string is "mem" rather than "off".
-    const char *state = sScreenOn ? "mem" : "on";
-    if (write(screenFd, state, strlen(state)) < 0) {
-        LOG("Unable to write to /sys/power/state.");
-        return;
-    }
-
-    sScreenOn = !sScreenOn;
-}
-
 static void
 keyHandler(int fd, FdHandler *data)
 {
     input_event events[16];
     ssize_t bytesRead = read(fd, events, sizeof(events));
     if (bytesRead < 0) {
         LOG("Error reading in keyHandler");
         return;
@@ -294,23 +270,16 @@ keyHandler(int fd, FdHandler *data)
         }
 
         if (e.value != 0 && e.value != 1) {
             LOG("Got unknown key event value. type 0x%04x code 0x%04x value %d",
                 e.type, e.code, e.value);
             continue;
         }
 
-        if (!sScreenOn && e.code != KEY_POWER) {
-            LOG("Ignoring key event, because the screen is off. "
-                "type 0x%04x code 0x%04x value %d",
-                e.type, e.code, e.value);
-            continue;
-        }
-
         bool pressed = e.value == 1;
         const char* upOrDown = pressed ? "pressed" : "released";
         switch (e.code) {
         case KEY_BACK:
             sendKeyEvent(NS_VK_ESCAPE, pressed, e.time);
             break;
         case KEY_MENU:
             if (!pressed)
@@ -319,22 +288,17 @@ keyHandler(int fd, FdHandler *data)
         case KEY_SEARCH:
             if (pressed)
                 sendSpecialKeyEvent(nsGkAtoms::Search, e.time);
             break;
         case KEY_HOME:
             sendKeyEvent(NS_VK_HOME, pressed, e.time);
             break;
         case KEY_POWER:
-            LOG("Power key %s", upOrDown);
-            // Ideally, we'd send a NS_VK_SLEEP event here and let the front-end
-            // sort out what to do.  But for now, let's just turn off the screen
-            // ourselves.
-            if (pressed)
-                handlePowerKeyPressed();
+            sendKeyEvent(NS_VK_SLEEP, pressed, e.time);
             break;
         case KEY_VOLUMEUP:
             if (pressed)
                 sendSpecialKeyEvent(nsGkAtoms::VolumeUp, e.time);
             break;
         case KEY_VOLUMEDOWN:
             if (pressed)
                 sendSpecialKeyEvent(nsGkAtoms::VolumeDown, e.time);