Bug 895665 - Gonk support for dev input audio jack events. r=mwu
authorMichael Vines <mvines@codeaurora.org>
Mon, 29 Jul 2013 21:27:48 -0700
changeset 140523 9262cbb74ed5b12b521b286f222cf42a699efdad
parent 140522 d47539d6c15fa0d06d4d2ce3995259bcacffaf38
child 140524 ead27e7569fe559182e2620cf24f75a234e596ad
push idunknown
push userunknown
push dateunknown
reviewersmwu
bugs895665
milestone25.0a1
Bug 895665 - Gonk support for dev input audio jack events. r=mwu
widget/gonk/nsAppShell.cpp
--- a/widget/gonk/nsAppShell.cpp
+++ b/widget/gonk/nsAppShell.cpp
@@ -47,16 +47,17 @@
 #include "nsWindow.h"
 #include "OrientationObserver.h"
 #include "GonkMemoryPressureMonitoring.h"
 
 #include "android/log.h"
 #include "libui/EventHub.h"
 #include "libui/InputReader.h"
 #include "libui/InputDispatcher.h"
+#include "cutils/properties.h"
 
 #include "GeckoProfiler.h"
 
 // Defines kKeyMapping and GetKeyNameIndex()
 #include "GonkKeyMapping.h"
 
 #define LOG(args...)                                            \
     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
@@ -73,16 +74,19 @@ using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::services;
 using namespace mozilla::widget;
 
 bool gDrawRequest = false;
 static nsAppShell *gAppShell = NULL;
 static int epollfd = 0;
 static int signalfds[2] = {0};
+static bool sDevInputAudioJack;
+static int32_t sHeadphoneState;
+static int32_t sMicrophoneState;
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsAppShell, nsBaseAppShell, nsIObserver)
 
 namespace mozilla {
 
 bool ProcessNextEvent()
 {
     return gAppShell->ProcessNextNativeEvent(true);
@@ -240,16 +244,51 @@ maybeSendKeyEvent(int keyCode, bool pres
     if (DOMKeyCode || DOMKeyNameIndex != KEY_NAME_INDEX_Unidentified) {
         sendKeyEvent(DOMKeyCode, DOMKeyNameIndex, pressed, timeMs);
     } else {
         VERBOSE_LOG("Got unknown key event code. type 0x%04x code 0x%04x value %d",
                     keyCode, pressed);
     }
 }
 
+class SwitchEventRunnable : public nsRunnable {
+public:
+    SwitchEventRunnable(hal::SwitchEvent& aEvent) : mEvent(aEvent)
+    {}
+
+    NS_IMETHOD Run()
+    {
+        hal::NotifySwitchChange(mEvent);
+        return NS_OK;
+    }
+private:
+    hal::SwitchEvent mEvent;
+};
+
+static void
+updateHeadphoneSwitch()
+{
+    hal::SwitchEvent event;
+
+    switch (sHeadphoneState) {
+    case AKEY_STATE_UP:
+        event.status() = hal::SWITCH_STATE_OFF;
+        break;
+    case AKEY_STATE_DOWN:
+        event.status() = sMicrophoneState == AKEY_STATE_DOWN ?
+            hal::SWITCH_STATE_HEADPHONE : hal::SWITCH_STATE_HEADSET;
+        break;
+    default:
+        return;
+    }
+
+    event.device() = hal::SWITCH_HEADPHONES;
+    NS_DispatchToMainThread(new SwitchEventRunnable(event));
+}
+
 class GeckoPointerController : public PointerControllerInterface {
     float mX;
     float mY;
     int32_t mButtonState;
     InputReaderConfiguration* mConfig;
 public:
     GeckoPointerController(InputReaderConfiguration* config)
         : mX(0)
@@ -548,16 +587,29 @@ GeckoInputDispatcher::notifyMotion(const
     }
     gAppShell->NotifyNativeEvent();
 }
 
 
 
 void GeckoInputDispatcher::notifySwitch(const NotifySwitchArgs* args)
 {
+    if (!sDevInputAudioJack)
+        return;
+
+    switch (args->switchCode) {
+    case SW_HEADPHONE_INSERT:
+        sHeadphoneState = args->switchValue;
+        updateHeadphoneSwitch();
+        break;
+    case SW_MICROPHONE_INSERT:
+        sMicrophoneState = args->switchValue;
+        updateHeadphoneSwitch();
+        break;
+    }
 }
 
 void GeckoInputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args)
 {
 }
 
 int32_t GeckoInputDispatcher::injectInputEvent(
     const InputEvent* event,
@@ -656,16 +708,22 @@ NS_IMETHODIMP
 nsAppShell::Observe(nsISupports* aSubject,
                     const char* aTopic,
                     const PRUnichar* aData)
 {
     if (strcmp(aTopic, "browser-ui-startup-complete")) {
         return nsBaseAppShell::Observe(aSubject, aTopic, aData);
     }
 
+    if (sDevInputAudioJack) {
+        sHeadphoneState  = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_HEADPHONE_INSERT);
+        sMicrophoneState = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_MICROPHONE_INSERT);
+        updateHeadphoneSwitch();
+    }
+
     mEnableDraw = true;
     NotifyEvent();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAppShell::Exit()
 {
@@ -675,16 +733,22 @@ nsAppShell::Exit()
         obsServ->RemoveObserver(this, "browser-ui-startup-complete");
     }
     return nsBaseAppShell::Exit();
 }
 
 void
 nsAppShell::InitInputDevices()
 {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.moz.devinputjack", value, "0");
+    sDevInputAudioJack = !strcmp(value, "1");
+    sHeadphoneState = AKEY_STATE_UNKNOWN;
+    sMicrophoneState = AKEY_STATE_UNKNOWN;
+
     mEventHub = new EventHub();
     mReaderPolicy = new GeckoInputReaderPolicy();
     mReaderPolicy->setDisplayInfo();
     mDispatcher = new GeckoInputDispatcher();
 
     mReader = new InputReader(mEventHub, mReaderPolicy, mDispatcher);
     mReaderThread = new InputReaderThread(mReader);