Bug 736939 - Audio routing support. r=cjones, a=b2g-only
--- a/hal/Hal.cpp
+++ b/hal/Hal.cpp
@@ -591,10 +591,88 @@ LockScreenOrientation(const dom::ScreenO
void
UnlockScreenOrientation()
{
AssertMainThread();
PROXY_IF_SANDBOXED(UnlockScreenOrientation());
}
+void
+EnableSwitchNotifications(hal::SwitchDevice aDevice) {
+ AssertMainThread();
+ PROXY_IF_SANDBOXED(EnableSwitchNotifications(aDevice));
+}
+
+void
+DisableSwitchNotifications(hal::SwitchDevice aDevice) {
+ AssertMainThread();
+ PROXY_IF_SANDBOXED(DisableSwitchNotifications(aDevice));
+}
+
+hal::SwitchState GetCurrentSwitchState(hal::SwitchDevice aDevice)
+{
+ AssertMainThread();
+ RETURN_PROXY_IF_SANDBOXED(GetCurrentSwitchState(aDevice));
+}
+
+typedef mozilla::ObserverList<SwitchEvent> SwitchObserverList;
+
+static SwitchObserverList *sSwitchObserverLists = NULL;
+
+static SwitchObserverList&
+GetSwitchObserverList(hal::SwitchDevice aDevice) {
+ MOZ_ASSERT(0 <= aDevice && aDevice < NUM_SWITCH_DEVICE);
+ if (sSwitchObserverLists == NULL) {
+ sSwitchObserverLists = new SwitchObserverList[NUM_SWITCH_DEVICE];
+ }
+ return sSwitchObserverLists[aDevice];
+}
+
+static void
+ReleaseObserversIfNeeded() {
+ for (int i = 0; i < NUM_SWITCH_DEVICE; i++) {
+ if (sSwitchObserverLists[i].Length() != 0)
+ return;
+ }
+
+ //The length of every list is 0, no observer in the list.
+ delete [] sSwitchObserverLists;
+ sSwitchObserverLists = NULL;
+}
+
+void
+RegisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver)
+{
+ AssertMainThread();
+ SwitchObserverList& observer = GetSwitchObserverList(aDevice);
+ observer.AddObserver(aObserver);
+ if (observer.Length() == 1) {
+ EnableSwitchNotifications(aDevice);
+ }
+}
+
+void
+UnregisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aObserver)
+{
+ AssertMainThread();
+ SwitchObserverList& observer = GetSwitchObserverList(aDevice);
+ observer.RemoveObserver(aObserver);
+ if (observer.Length() == 0) {
+ DisableSwitchNotifications(aDevice);
+ ReleaseObserversIfNeeded();
+ }
+}
+
+void
+NotifySwitchChange(const hal::SwitchEvent& aEvent)
+{
+ // When callback this notification, main thread may call unregister function
+ // first. We should check if this pointer is valid.
+ if (!sSwitchObserverLists)
+ return;
+
+ SwitchObserverList& observer = GetSwitchObserverList(aEvent.device());
+ observer.Broadcast(aEvent);
+}
+
} // namespace hal
} // namespace mozilla
--- a/hal/Hal.h
+++ b/hal/Hal.h
@@ -340,16 +340,41 @@ void NotifyScreenOrientationChange(const
*/
bool LockScreenOrientation(const dom::ScreenOrientation& aOrientation);
/**
* Unlock the screen orientation.
*/
void UnlockScreenOrientation();
+/**
+ * Register an observer for the switch of given SwitchDevice.
+ *
+ * The observer will receive data whenever the data generated by the
+ * given switch.
+ */
+void RegisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aSwitchObserver);
+
+/**
+ * Unregister an observer for the switch of given SwitchDevice.
+ */
+void UnregisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aSwitchObserver);
+
+/**
+ * Notify the state of the switch.
+ *
+ * This API is internal to hal; clients shouldn't call it directly.
+ */
+void NotifySwitchChange(const hal::SwitchEvent& aEvent);
+
+/**
+ * Get current switch information.
+ */
+hal::SwitchState GetCurrentSwitchState(hal::SwitchDevice aDevice);
+
} // namespace MOZ_HAL_NAMESPACE
} // namespace mozilla
#ifdef MOZ_DEFINED_HAL_NAMESPACE
# undef MOZ_DEFINED_HAL_NAMESPACE
# undef MOZ_HAL_NAMESPACE
#endif
--- a/hal/HalInternal.h
+++ b/hal/HalInternal.h
@@ -82,12 +82,22 @@ void DisableNetworkNotifications();
*/
void EnableScreenOrientationNotifications();
/**
* Disables screen orientation notifications from the backend.
*/
void DisableScreenOrientationNotifications();
+/**
+ * Enable switch notifications from the backend
+ */
+void EnableSwitchNotifications(hal::SwitchDevice aDevice);
+
+/**
+ * Disable switch notifications from the backend
+ */
+void DisableSwitchNotifications(hal::SwitchDevice aDevice);
+
} // namespace MOZ_HAL_NAMESPACE
} // namespace mozilla
#endif // mozilla_HalInternal_h
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -32,16 +32,32 @@ enum LightMode {
eHalLightMode_Sensor = 1 // brightness is managed by a light sensor
};
enum FlashMode {
eHalLightFlash_None = 0,
eHalLightFlash_Timed = 1, // timed flashing. Use flashOnMS and flashOffMS for timing
eHalLightFlash_Hardware = 2 // hardware assisted flashing
};
+class SwitchEvent;
+
+enum SwitchDevice {
+ SWITCH_DEVICE_UNKNOWN = -1,
+ SWITCH_HEADPHONES,
+ NUM_SWITCH_DEVICE
+};
+
+enum SwitchState {
+ SWITCH_STATE_UNKNOWN = -1,
+ SWITCH_STATE_ON,
+ SWITCH_STATE_OFF,
+ NUM_SWITCH_STATE
+};
+
+typedef Observer<SwitchEvent> SwitchObserver;
} // namespace hal
} // namespace mozilla
namespace mozilla {
namespace hal {
/**
* Used by ModifyWakeLock
@@ -92,11 +108,32 @@ struct ParamTraits<mozilla::hal::FlashMo
*/
template <>
struct ParamTraits<mozilla::hal::WakeLockControl>
: public EnumSerializer<mozilla::hal::WakeLockControl,
mozilla::hal::WAKE_LOCK_REMOVE_ONE,
mozilla::hal::WAKE_LOCK_ADD_ONE>
{};
+/**
+ * Serializer for SwitchState
+ */
+template <>
+struct ParamTraits<mozilla::hal::SwitchState>:
+ public EnumSerializer<mozilla::hal::SwitchState,
+ mozilla::hal::SWITCH_STATE_UNKNOWN,
+ mozilla::hal::NUM_SWITCH_STATE> {
+};
+
+/**
+ * Serializer for SwitchDevice
+ */
+template <>
+struct ParamTraits<mozilla::hal::SwitchDevice>:
+ public EnumSerializer<mozilla::hal::SwitchDevice,
+ mozilla::hal::SWITCH_DEVICE_UNKNOWN,
+ mozilla::hal::NUM_SWITCH_DEVICE> {
+};
+
+
} // namespace IPC
#endif // mozilla_hal_Types_h
--- a/hal/Makefile.in
+++ b/hal/Makefile.in
@@ -80,16 +80,17 @@ CPPSRCS += \
AndroidSensor.cpp \
$(NULL)
else ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += \
GonkHal.cpp \
Power.cpp \
GonkSensor.cpp \
UeventPoller.cpp \
+ GonkSwitch.cpp \
$(NULL)
else ifeq (Linux,$(OS_TARGET))
CPPSRCS += \
LinuxHal.cpp \
FallbackSensor.cpp \
Power.cpp \
$(NULL)
ifdef MOZ_ENABLE_DBUS
@@ -116,16 +117,17 @@ CPPSRCS += \
$(NULL)
endif
ifneq (gonk,$(MOZ_WIDGET_TOOLKIT)) #{
CPPSRCS += \
FallbackLights.cpp \
FallbackTime.cpp \
FallbackWakeLocks.cpp \
+ FallbackSwitch.cpp \
$(NULL)
endif #}
# Screen Orientation backend
ifneq (android,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += ScreenOrientationFallback.cpp
endif
new file mode 100644
--- /dev/null
+++ b/hal/fallback/FallbackSwitch.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Hal.h"
+
+using namespace mozilla::hal;
+
+namespace mozilla {
+namespace hal_impl {
+
+void
+EnableSwitchNotifications(SwitchDevice aDevice)
+{
+}
+
+void
+DisableSwitchNotifications(SwitchDevice aDevice)
+{
+}
+
+SwitchState
+GetCurrentSwitchState(SwitchDevice aDevice) {
+ return SWITCH_STATE_UNKNOWN;
+}
+
+} // namespace hal_impl
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/hal/gonk/GonkSwitch.cpp
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <android/log.h>
+#include <sysutils/NetlinkEvent.h>
+
+#include "base/message_loop.h"
+
+#include "Hal.h"
+#include "nsXULAppAPI.h"
+#include "UeventPoller.h"
+
+using namespace mozilla::hal;
+
+#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkSwitch" , ## args)
+
+namespace mozilla {
+namespace hal_impl {
+
+struct {const char* name; SwitchDevice device; } kSwitchNameMap[] = {
+ { "h2w", SWITCH_HEADPHONES },
+ { NULL, SWITCH_DEVICE_UNKNOWN },
+};
+
+static SwitchDevice
+NameToDevice(const char* name) {
+ for (int i = 0; kSwitchNameMap[i].device != SWITCH_DEVICE_UNKNOWN; i++) {
+ if (strcmp(name, kSwitchNameMap[i].name) == 0) {
+ return kSwitchNameMap[i].device;
+ }
+ }
+ return SWITCH_DEVICE_UNKNOWN;
+}
+
+class SwitchEventRunnable : public nsRunnable
+{
+public:
+ SwitchEventRunnable(SwitchEvent& event) : mEvent(event) {}
+
+ NS_IMETHOD Run() {
+ NotifySwitchChange(mEvent);
+ return NS_OK;
+ }
+private:
+ SwitchEvent mEvent;
+};
+
+class SwitchEventObserver : public IUeventObserver
+{
+public:
+ SwitchEventObserver() : mEnableNum(0) {
+ InternalInit();
+ }
+ ~SwitchEventObserver() {}
+
+ int GetEnableCount() {
+ return mEnableNum;
+ }
+
+ void EnableSwitch(SwitchDevice aDevice) {
+ mEventInfo[aDevice].mEnable = true;
+ mEnableNum++;
+ }
+
+ void DisableSwitch(SwitchDevice aDevice) {
+ mEventInfo[aDevice].mEnable = false;
+ mEnableNum--;
+ }
+
+ void Notify(const NetlinkEvent& event) {
+ const char* name;
+ const char* state;
+
+ SwitchDevice device = ProcessEvent(event, &name, &state);
+ if (device == SWITCH_DEVICE_UNKNOWN) {
+ return;
+ }
+
+ EventInfo& info = mEventInfo[device];
+ info.mEvent.status() = atoi(state) == 0 ? SWITCH_STATE_OFF : SWITCH_STATE_ON;
+ if (info.mEnable) {
+ NS_DispatchToMainThread(new SwitchEventRunnable(info.mEvent));
+ }
+ }
+
+ SwitchState GetCurrentInformation(SwitchDevice aDevice) {
+ return mEventInfo[aDevice].mEvent.status();
+ }
+
+private:
+ class EventInfo {
+ public:
+ EventInfo() : mEnable(false) {}
+ SwitchEvent mEvent;
+ bool mEnable;
+ };
+
+ EventInfo mEventInfo[NUM_SWITCH_DEVICE];
+ size_t mEnableNum;
+
+ void InternalInit() {
+ for (int i = 0; i < NUM_SWITCH_DEVICE; i++) {
+ mEventInfo[i].mEvent.device() = kSwitchNameMap[i].device;
+ mEventInfo[i].mEvent.status() = SWITCH_STATE_UNKNOWN;
+ }
+ }
+
+ bool GetEventInfo(const NetlinkEvent& event, const char** name, const char** state) {
+ //working around the android code not being const-correct
+ NetlinkEvent *e = const_cast<NetlinkEvent*>(&event);
+ const char* subsystem = e->getSubsystem();
+
+ if (!subsystem || strcmp(subsystem, "switch")) {
+ return false;
+ }
+
+ *name = e->findParam("SWITCH_NAME");
+ *state = e->findParam("SWITCH_STATE");
+
+ if (!*name || !*state) {
+ return false;
+ }
+ return true;
+ }
+
+ SwitchDevice ProcessEvent(const NetlinkEvent& event, const char** name, const char** state) {
+ bool rv = GetEventInfo(event, name, state);
+ NS_ENSURE_TRUE(rv, SWITCH_DEVICE_UNKNOWN);
+ return NameToDevice(*name);
+ }
+};
+
+SwitchEventObserver* sSwitchObserver;
+
+static void
+InitializeResourceIfNeed()
+{
+ if (!sSwitchObserver) {
+ sSwitchObserver = new SwitchEventObserver();
+ RegisterUeventListener(sSwitchObserver);
+ }
+}
+
+static void
+ReleaseResourceIfNeed()
+{
+ if (sSwitchObserver->GetEnableCount() == 0) {
+ UnregisterUeventListener(sSwitchObserver);
+ delete sSwitchObserver;
+ sSwitchObserver = NULL;
+ }
+}
+
+static void
+EnableSwitchNotificationsIOThread(SwitchDevice aDevice)
+{
+ InitializeResourceIfNeed();
+ sSwitchObserver->EnableSwitch(aDevice);
+}
+
+void
+EnableSwitchNotifications(SwitchDevice aDevice)
+{
+ XRE_GetIOMessageLoop()->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(EnableSwitchNotificationsIOThread, aDevice));
+}
+
+static void
+DisableSwitchNotificationsIOThread(SwitchDevice aDevice)
+{
+ MOZ_ASSERT(sSwitchObserver->GetEnableCount());
+ sSwitchObserver->DisableSwitch(aDevice);
+ ReleaseResourceIfNeed();
+}
+
+void
+DisableSwitchNotifications(SwitchDevice aDevice)
+{
+ XRE_GetIOMessageLoop()->PostTask(
+ FROM_HERE,
+ NewRunnableFunction(DisableSwitchNotificationsIOThread, aDevice));
+}
+
+SwitchState
+GetCurrentSwitchState(SwitchDevice aDevice)
+{
+ MOZ_ASSERT(sSwitchObserver && sSwitchObserver->GetEnableCount());
+ return sSwitchObserver->GetCurrentInformation(aDevice);
+}
+
+} // hal_impl
+} //mozilla
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -47,16 +47,18 @@ include "mozilla/dom/ScreenOrientation.h
using PRTime;
using mozilla::hal::FlashMode;
using mozilla::hal::LightType;
using mozilla::hal::LightMode;
using mozilla::hal::SensorType;
using mozilla::hal::SensorAccuracyType;
using mozilla::hal::WakeLockControl;
using mozilla::dom::ScreenOrientation;
+using mozilla::hal::SwitchState;
+using mozilla::hal::SwitchDevice;
namespace mozilla {
namespace hal {
struct BatteryInformation {
double level;
bool charging;
double remainingTime;
@@ -77,16 +79,21 @@ namespace hal {
float[] values;
SensorAccuracyType accuracy;
};
struct NetworkInformation {
double bandwidth;
bool canBeMetered;
};
+
+ struct SwitchEvent {
+ SwitchDevice device;
+ SwitchState status;
+ };
}
namespace hal {
struct WakeLockInformation {
uint32_t numLocks;
uint32_t numHidden;
nsString topic;
};
@@ -97,16 +104,17 @@ namespace hal_sandbox {
sync protocol PHal {
manager PContent;
child:
NotifyBatteryChange(BatteryInformation aBatteryInfo);
NotifyNetworkChange(NetworkInformation aNetworkInfo);
NotifyWakeLockChange(WakeLockInformation aWakeLockInfo);
NotifyScreenOrientationChange(ScreenOrientation aScreenOrientation);
+ NotifySwitchChange(SwitchEvent aEvent);
parent:
Vibrate(uint32[] pattern, uint64[] id, PBrowser browser);
CancelVibrate(uint64[] id, PBrowser browser);
EnableBatteryNotifications();
DisableBatteryNotifications();
sync GetCurrentBatteryInformation()
@@ -145,16 +153,21 @@ parent:
EnableScreenOrientationNotifications();
DisableScreenOrientationNotifications();
sync GetCurrentScreenOrientation()
returns (ScreenOrientation aScreenOrientation);
sync LockScreenOrientation(ScreenOrientation aOrientation)
returns (bool allowed);
UnlockScreenOrientation();
+
+ EnableSwitchNotifications(SwitchDevice aDevice);
+ DisableSwitchNotifications(SwitchDevice aDevice);
+ sync GetCurrentSwitchState(SwitchDevice aDevice)
+ returns (SwitchState aState);
child:
NotifySensorChange(SensorData aSensorData);
parent:
EnableSensorNotifications(SensorType aSensor);
DisableSensorNotifications(SensorType aSensor);
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -235,22 +235,43 @@ ModifyWakeLock(const nsAString &aTopic,
}
void
GetWakeLockInfo(const nsAString &aTopic, WakeLockInformation *aWakeLockInfo)
{
Hal()->SendGetWakeLockInfo(nsString(aTopic), aWakeLockInfo);
}
+void
+EnableSwitchNotifications(SwitchDevice aDevice)
+{
+ Hal()->SendEnableSwitchNotifications(aDevice);
+}
+
+void
+DisableSwitchNotifications(SwitchDevice aDevice)
+{
+ Hal()->SendDisableSwitchNotifications(aDevice);
+}
+
+SwitchState
+GetCurrentSwitchState(SwitchDevice aDevice)
+{
+ SwitchState state;
+ Hal()->SendGetCurrentSwitchState(aDevice, &state);
+ return state;
+}
+
class HalParent : public PHalParent
, public BatteryObserver
, public NetworkObserver
, public ISensorObserver
, public WakeLockObserver
, public ScreenOrientationObserver
+ , public SwitchObserver
{
public:
NS_OVERRIDE virtual bool
RecvVibrate(const InfallibleTArray<unsigned int>& pattern,
const InfallibleTArray<uint64> &id,
PBrowserParent *browserParent)
{
// Check whether browserParent is active. We should have already
@@ -496,16 +517,42 @@ public:
hal::GetWakeLockInfo(aTopic, aWakeLockInfo);
return true;
}
void Notify(const WakeLockInformation& aWakeLockInfo)
{
unused << SendNotifyWakeLockChange(aWakeLockInfo);
}
+
+ NS_OVERRIDE virtual bool
+ RecvEnableSwitchNotifications(const SwitchDevice& aDevice)
+ {
+ hal::RegisterSwitchObserver(aDevice, this);
+ return true;
+ }
+
+ NS_OVERRIDE virtual bool
+ RecvDisableSwitchNotifications(const SwitchDevice& aDevice)
+ {
+ hal::UnregisterSwitchObserver(aDevice, this);
+ return true;
+ }
+
+ void Notify(const SwitchEvent& aSwitchEvent)
+ {
+ unused << SendNotifySwitchChange(aSwitchEvent);
+ }
+
+ NS_OVERRIDE virtual bool
+ RecvGetCurrentSwitchState(const SwitchDevice& aDevice, hal::SwitchState *aState)
+ {
+ *aState = hal::GetCurrentSwitchState(aDevice);
+ return true;
+ }
};
class HalChild : public PHalChild {
public:
NS_OVERRIDE virtual bool
RecvNotifyBatteryChange(const BatteryInformation& aBatteryInfo) {
hal::NotifyBatteryChange(aBatteryInfo);
return true;
@@ -526,16 +573,22 @@ public:
return true;
}
NS_OVERRIDE virtual bool
RecvNotifyScreenOrientationChange(const ScreenOrientation& aScreenOrientation) {
hal::NotifyScreenOrientationChange(aScreenOrientation);
return true;
}
+
+ NS_OVERRIDE virtual bool
+ RecvNotifySwitchChange(const mozilla::hal::SwitchEvent& aEvent) {
+ hal::NotifySwitchChange(aEvent);
+ return true;
+ }
};
bool
HalChild::RecvNotifySensorChange(const hal::SensorData &aSensorData) {
hal::NotifySensorChange(aSensorData);
return true;
}