зеркало из https://github.com/mozilla/gecko-dev.git
Bug 696041 - Battery API backend for linux with upower. r=karlt,cjones sr=roc
This commit is contained in:
Родитель
e248153a1f
Коммит
9e722c9ee8
|
@ -43,6 +43,7 @@ VPATH = \
|
|||
$(srcdir)/android \
|
||||
$(srcdir)/fallback \
|
||||
$(srcdir)/sandbox \
|
||||
$(srcdir)/linux \
|
||||
$(NULL)
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
@ -67,6 +68,11 @@ CPPSRCS = \
|
|||
|
||||
ifeq (Android,$(OS_TARGET))
|
||||
CPPSRCS += AndroidHal.cpp
|
||||
else ifeq (Linux,$(OS_TARGET))
|
||||
CPPSRCS += LinuxHal.cpp
|
||||
ifdef MOZ_ENABLE_DBUS
|
||||
CPPSRCS += UPowerClient.cpp
|
||||
endif
|
||||
else
|
||||
CPPSRCS += FallbackHal.cpp
|
||||
endif
|
||||
|
@ -74,3 +80,6 @@ endif
|
|||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
|
||||
CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* 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 "Hal.h"
|
||||
|
||||
#ifndef MOZ_ENABLE_DBUS
|
||||
#include <mozilla/dom/battery/Constants.h>
|
||||
#endif // !MOZ_ENABLE_DBUS
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
Vibrate(const nsTArray<uint32>& pattern)
|
||||
{}
|
||||
|
||||
#ifndef MOZ_ENABLE_DBUS
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
aBatteryInfo->level() = dom::battery::kDefaultLevel;
|
||||
aBatteryInfo->charging() = dom::battery::kDefaultCharging;
|
||||
}
|
||||
#endif // !MOZ_ENABLE_DBUS
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
|
|
@ -0,0 +1,409 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* 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 <mozilla/Hal.h>
|
||||
#include <dbus/dbus-glib.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
#include <mozilla/dom/battery/Constants.h>
|
||||
#include "nsAutoRef.h"
|
||||
|
||||
/*
|
||||
* Helper that manages the destruction of glib objects as soon as they leave
|
||||
* the current scope.
|
||||
*
|
||||
* We are specializing nsAutoRef class.
|
||||
*/
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
class nsAutoRefTraits<DBusGProxy> : public nsPointerRefTraits<DBusGProxy>
|
||||
{
|
||||
public:
|
||||
static void Release(DBusGProxy* ptr) { g_object_unref(ptr); }
|
||||
};
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
class nsAutoRefTraits<GHashTable> : public nsPointerRefTraits<GHashTable>
|
||||
{
|
||||
public:
|
||||
static void Release(GHashTable* ptr) { g_hash_table_unref(ptr); }
|
||||
};
|
||||
|
||||
using namespace mozilla::dom::battery;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
/**
|
||||
* This is the declaration of UPowerClient class. This class is listening and
|
||||
* communicating to upower daemon through DBus.
|
||||
* There is no header file because this class shouldn't be public.
|
||||
*/
|
||||
class UPowerClient
|
||||
{
|
||||
public:
|
||||
static UPowerClient* GetInstance();
|
||||
|
||||
void BeginListening();
|
||||
void StopListening();
|
||||
|
||||
float GetLevel();
|
||||
bool IsCharging();
|
||||
|
||||
~UPowerClient();
|
||||
|
||||
private:
|
||||
UPowerClient();
|
||||
|
||||
enum States {
|
||||
eState_Unknown = 0,
|
||||
eState_Charging,
|
||||
eState_Discharging,
|
||||
eState_Empty,
|
||||
eState_FullyCharged,
|
||||
eState_PendingCharge,
|
||||
eState_PendingDischarge
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the currently tracked device.
|
||||
* @return whether everything went ok.
|
||||
*/
|
||||
void UpdateTrackedDevice();
|
||||
|
||||
/**
|
||||
* Returns a hash table with the properties of aDevice.
|
||||
* Note: the caller has to unref the hash table.
|
||||
*/
|
||||
GHashTable* GetDeviceProperties(const gchar* aDevice);
|
||||
|
||||
/**
|
||||
* Using the device properties (aHashTable), this method updates the member
|
||||
* variable storing the values we care about.
|
||||
*/
|
||||
void UpdateSavedInfo(GHashTable* aHashTable);
|
||||
|
||||
/**
|
||||
* Callback used by 'DeviceChanged' signal.
|
||||
*/
|
||||
static void DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath,
|
||||
UPowerClient* aListener);
|
||||
|
||||
/**
|
||||
* Callback called when mDBusConnection gets a signal.
|
||||
*/
|
||||
static DBusHandlerResult ConnectionSignalFilter(DBusConnection* aConnection,
|
||||
DBusMessage* aMessage,
|
||||
void* aData);
|
||||
|
||||
// The DBus connection object.
|
||||
DBusGConnection* mDBusConnection;
|
||||
|
||||
// The DBus proxy object to upower.
|
||||
DBusGProxy* mUPowerProxy;
|
||||
|
||||
// The path of the tracked device.
|
||||
gchar* mTrackedDevice;
|
||||
|
||||
float mLevel;
|
||||
bool mCharging;
|
||||
|
||||
static UPowerClient* sInstance;
|
||||
|
||||
static const guint sDeviceTypeBattery = 2;
|
||||
};
|
||||
|
||||
/*
|
||||
* Implementation of mozilla::hal_impl::EnableBatteryNotifications,
|
||||
* mozilla::hal_impl::DisableBatteryNotifications,
|
||||
* and mozilla::hal_impl::GetCurrentBatteryInformation.
|
||||
*/
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{
|
||||
UPowerClient::GetInstance()->BeginListening();
|
||||
}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{
|
||||
UPowerClient::GetInstance()->StopListening();
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
UPowerClient* upowerClient = UPowerClient::GetInstance();
|
||||
|
||||
aBatteryInfo->level() = upowerClient->GetLevel();
|
||||
aBatteryInfo->charging() = upowerClient->IsCharging();
|
||||
}
|
||||
|
||||
/*
|
||||
* Following is the implementation of UPowerClient.
|
||||
*/
|
||||
|
||||
UPowerClient* UPowerClient::sInstance = nsnull;
|
||||
|
||||
/* static */ UPowerClient*
|
||||
UPowerClient::GetInstance()
|
||||
{
|
||||
if (!sInstance) {
|
||||
sInstance = new UPowerClient();
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
UPowerClient::UPowerClient()
|
||||
: mDBusConnection(nsnull)
|
||||
, mUPowerProxy(nsnull)
|
||||
, mTrackedDevice(nsnull)
|
||||
, mLevel(kDefaultLevel)
|
||||
, mCharging(kDefaultCharging)
|
||||
{
|
||||
}
|
||||
|
||||
UPowerClient::~UPowerClient()
|
||||
{
|
||||
NS_ASSERTION(!mDBusConnection && !mUPowerProxy && !mTrackedDevice,
|
||||
"The observers have not been correctly removed! "
|
||||
"(StopListening should have been called)");
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::BeginListening()
|
||||
{
|
||||
GError* error = nsnull;
|
||||
mDBusConnection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
|
||||
|
||||
if (!mDBusConnection) {
|
||||
g_printerr("Failed to open connection to bus: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
|
||||
DBusConnection* dbusConnection =
|
||||
dbus_g_connection_get_connection(mDBusConnection);
|
||||
|
||||
// Make sure we do not exit the entire program if DBus connection get lost.
|
||||
dbus_connection_set_exit_on_disconnect(dbusConnection, false);
|
||||
|
||||
// Listening to signals the DBus connection is going to get so we will know
|
||||
// when it is lost and we will be able to disconnect cleanly.
|
||||
dbus_connection_add_filter(dbusConnection, ConnectionSignalFilter, this,
|
||||
nsnull);
|
||||
|
||||
mUPowerProxy = dbus_g_proxy_new_for_name(mDBusConnection,
|
||||
"org.freedesktop.UPower",
|
||||
"/org/freedesktop/UPower",
|
||||
"org.freedesktop.UPower");
|
||||
|
||||
UpdateTrackedDevice();
|
||||
|
||||
/*
|
||||
* TODO: we should probably listen to DeviceAdded and DeviceRemoved signals.
|
||||
* If we do that, we would have to disconnect from those in StopListening.
|
||||
* It's not yet implemented because it requires testing hot plugging and
|
||||
* removal of a battery.
|
||||
*/
|
||||
dbus_g_proxy_add_signal(mUPowerProxy, "DeviceChanged", G_TYPE_STRING,
|
||||
G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal(mUPowerProxy, "DeviceChanged",
|
||||
G_CALLBACK (DeviceChanged), this, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::StopListening()
|
||||
{
|
||||
// If mDBusConnection isn't initialized, that means we are not really listening.
|
||||
if (!mDBusConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
dbus_connection_remove_filter(
|
||||
dbus_g_connection_get_connection(mDBusConnection),
|
||||
ConnectionSignalFilter, this);
|
||||
|
||||
dbus_g_proxy_disconnect_signal(mUPowerProxy, "DeviceChanged",
|
||||
G_CALLBACK (DeviceChanged), this);
|
||||
|
||||
g_free(mTrackedDevice);
|
||||
mTrackedDevice = nsnull;
|
||||
|
||||
g_object_unref(mUPowerProxy);
|
||||
mUPowerProxy = nsnull;
|
||||
|
||||
dbus_g_connection_unref(mDBusConnection);
|
||||
mDBusConnection = nsnull;
|
||||
|
||||
// We should now show the default values, not the latest we got.
|
||||
mLevel = kDefaultLevel;
|
||||
mCharging = kDefaultCharging;
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::UpdateTrackedDevice()
|
||||
{
|
||||
GType typeGPtrArray = dbus_g_type_get_collection("GPtrArray",
|
||||
DBUS_TYPE_G_OBJECT_PATH);
|
||||
GPtrArray* devices = nsnull;
|
||||
GError* error = nsnull;
|
||||
|
||||
// If that fails, that likely means upower isn't installed.
|
||||
if (!dbus_g_proxy_call(mUPowerProxy, "EnumerateDevices", &error, G_TYPE_INVALID,
|
||||
typeGPtrArray, &devices, G_TYPE_INVALID)) {
|
||||
g_printerr ("Error: %s\n", error->message);
|
||||
|
||||
mTrackedDevice = nsnull;
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are looking for the first device that is a battery.
|
||||
* TODO: we could try to combine more than one battery.
|
||||
*/
|
||||
for (guint i=0; i<devices->len; ++i) {
|
||||
gchar* devicePath = static_cast<gchar*>(g_ptr_array_index(devices, i));
|
||||
nsAutoRef<GHashTable> hashTable(GetDeviceProperties(devicePath));
|
||||
|
||||
if (g_value_get_uint(static_cast<const GValue*>(g_hash_table_lookup(hashTable, "Type"))) == sDeviceTypeBattery) {
|
||||
UpdateSavedInfo(hashTable);
|
||||
mTrackedDevice = devicePath;
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(devicePath);
|
||||
}
|
||||
|
||||
#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 22
|
||||
g_ptr_array_unref(devices);
|
||||
#else
|
||||
g_ptr_array_free(devices, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
UPowerClient::DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath, UPowerClient* aListener)
|
||||
{
|
||||
#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 16
|
||||
if (g_strcmp0(aObjectPath, aListener->mTrackedDevice)) {
|
||||
#else
|
||||
if (g_ascii_strcasecmp(aObjectPath, aListener->mTrackedDevice)) {
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoRef<GHashTable> hashTable(aListener->GetDeviceProperties(aObjectPath));
|
||||
aListener->UpdateSavedInfo(hashTable);
|
||||
|
||||
hal::NotifyBatteryChange(hal::BatteryInformation(aListener->mLevel, aListener->mCharging));
|
||||
}
|
||||
|
||||
/* static */ DBusHandlerResult
|
||||
UPowerClient::ConnectionSignalFilter(DBusConnection* aConnection,
|
||||
DBusMessage* aMessage, void* aData)
|
||||
{
|
||||
if (dbus_message_is_signal(aMessage, DBUS_INTERFACE_LOCAL, "Disconnected")) {
|
||||
static_cast<UPowerClient*>(aData)->StopListening();
|
||||
// We do not return DBUS_HANDLER_RESULT_HANDLED here because the connection
|
||||
// might be shared and some other filters might want to do something.
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
GHashTable*
|
||||
UPowerClient::GetDeviceProperties(const gchar* aDevice)
|
||||
{
|
||||
nsAutoRef<DBusGProxy> proxy(dbus_g_proxy_new_for_name(mDBusConnection,
|
||||
"org.freedesktop.UPower",
|
||||
aDevice,
|
||||
"org.freedesktop.DBus.Properties"));
|
||||
|
||||
GError* error = nsnull;
|
||||
GHashTable* hashTable = nsnull;
|
||||
GType typeGHashTable = dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
|
||||
G_TYPE_VALUE);
|
||||
if (!dbus_g_proxy_call(proxy, "GetAll", &error, G_TYPE_STRING,
|
||||
"org.freedesktop.UPower.Device", G_TYPE_INVALID,
|
||||
typeGHashTable, &hashTable, G_TYPE_INVALID)) {
|
||||
g_printerr("Error: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return hashTable;
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::UpdateSavedInfo(GHashTable* aHashTable)
|
||||
{
|
||||
mLevel = g_value_get_double(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "Percentage")))/100.f;
|
||||
|
||||
switch (g_value_get_uint(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "State")))) {
|
||||
case eState_Unknown:
|
||||
mCharging = kDefaultCharging;
|
||||
break;
|
||||
case eState_Charging:
|
||||
case eState_FullyCharged:
|
||||
case eState_PendingCharge:
|
||||
mCharging = true;
|
||||
break;
|
||||
case eState_Discharging:
|
||||
case eState_Empty:
|
||||
case eState_PendingDischarge:
|
||||
mCharging = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
UPowerClient::GetLevel()
|
||||
{
|
||||
return mLevel;
|
||||
}
|
||||
|
||||
bool
|
||||
UPowerClient::IsCharging()
|
||||
{
|
||||
return mCharging;
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
|
@ -185,11 +185,8 @@ EXTRA_DSO_LDOPTS += $(LIBCONIC_LIBS)
|
|||
endif
|
||||
|
||||
ifdef MOZ_ENABLE_DBUS
|
||||
EXTRA_DSO_LDOPTS += $(MOZ_DBUS_LIBS)
|
||||
ifdef MOZ_PLATFORM_MAEMO
|
||||
EXTRA_DSO_LDOPTS += $(MOZ_DBUS_GLIB_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
|
||||
EXTRA_DSO_LDOPTS += $(XLDFLAGS) $(XLIBS) $(XEXT_LIBS) $(XCOMPOSITE_LIBS) $(MOZ_PANGO_LIBS) $(MOZ_GTK2_LIBS) $(XT_LIBS) -lgthread-2.0
|
||||
|
|
Загрузка…
Ссылка в новой задаче