We now report hotplug events to the framework

Change-Id: I2d6b7787d39e5929485a551e4982498c5053c211
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index e631cca..1117f95 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -40,7 +40,8 @@
 class DisplayEventReceiver {
 public:
     enum {
-        DISPLAY_EVENT_VSYNC = 'vsyn'
+        DISPLAY_EVENT_VSYNC = 'vsyn',
+        DISPLAY_EVENT_HOTPLUG = 'plug'
     };
 
     struct Event {
@@ -54,9 +55,15 @@
             uint32_t count;
         };
 
+        struct Hotplug {
+            int32_t id;
+            bool connected;
+        };
+
         Header header;
         union {
             VSync vsync;
+            Hotplug hotplug;
         };
     };
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index caec250..09ac78d 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -305,7 +305,7 @@
     if (connected)
         queryDisplayProperties(disp);
 
-    // TODO: tell someone else about this
+    mEventHandler.onHotplugReceived(disp, bool(connected));
 }
 
 static const uint32_t DISPLAY_ATTRIBUTES[] = {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 4156332..ff39bc1 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -56,6 +56,7 @@
     class EventHandler {
         friend class HWComposer;
         virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0;
+        virtual void onHotplugReceived(int disp, bool connected) = 0;
     protected:
         virtual ~EventHandler() {}
     };
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 19e711e..6e7424e 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -106,19 +106,30 @@
 }
 
 
-void EventThread::onVSyncReceived(const wp<IBinder>&, nsecs_t timestamp) {
+void EventThread::onVSyncReceived(int type, nsecs_t timestamp) {
     Mutex::Autolock _l(mLock);
     mVSyncTimestamp = timestamp;
     mVSyncCount++;
     mCondition.broadcast();
 }
 
+void EventThread::onHotplugReceived(int type, bool connected) {
+    Mutex::Autolock _l(mLock);
+    DisplayEventReceiver::Event event;
+    event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
+    event.header.timestamp = systemTime();
+    event.hotplug.id = type;
+    event.hotplug.connected = connected;
+    mPendingEvents.add(event);
+    mCondition.broadcast();
+}
+
 bool EventThread::threadLoop() {
     DisplayEventReceiver::Event vsync;
     Vector< sp<EventThread::Connection> > signalConnections;
     signalConnections = waitForEvent(&vsync);
 
-    // dispatch vsync events to listeners...
+    // dispatch events to listeners...
     const size_t count = signalConnections.size();
     for (size_t i=0 ; i<count ; i++) {
         const sp<Connection>& conn(signalConnections[i]);
@@ -146,18 +157,29 @@
         DisplayEventReceiver::Event* event)
 {
     Mutex::Autolock _l(mLock);
-
-    size_t vsyncCount;
-    nsecs_t timestamp;
     Vector< sp<EventThread::Connection> > signalConnections;
 
     do {
-        // latch VSYNC event if any
+        bool eventPending = false;
         bool waitForVSync = false;
-        vsyncCount = mVSyncCount;
-        timestamp = mVSyncTimestamp;
+        size_t vsyncCount = mVSyncCount;
+        nsecs_t timestamp = mVSyncTimestamp;
         mVSyncTimestamp = 0;
 
+        if (timestamp) {
+            // we have a vsync event to dispatch
+            event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+            event->header.timestamp = timestamp;
+            event->vsync.count = vsyncCount;
+        } else {
+            eventPending = !mPendingEvents.isEmpty();
+            if (eventPending) {
+                // we have some other event to dispatch
+                *event = mPendingEvents[0];
+                mPendingEvents.removeAt(0);
+            }
+        }
+
         // find out connections waiting for events
         size_t count = mDisplayEventConnections.size();
         for (size_t i=0 ; i<count ; i++) {
@@ -179,6 +201,11 @@
                             // continuous event, and time to report it
                             signalConnections.add(connection);
                         }
+                    } else if (eventPending) {
+                        // we don't have a vsync event to process
+                        // (timestamp==0), but we have some pending
+                        // messages.
+                        signalConnections.add(connection);
                     }
                 }
             } else {
@@ -206,7 +233,7 @@
 
         // note: !timestamp implies signalConnections.isEmpty(), because we
         // don't populate signalConnections if there's no vsync pending
-        if (!timestamp) {
+        if (!timestamp && !eventPending) {
             // wait for something to happen
             if (waitForVSync) {
                 // This is where we spend most of our time, waiting
@@ -241,12 +268,6 @@
     // here we're guaranteed to have a timestamp and some connections to signal
     // (The connections might have dropped out of mDisplayEventConnections
     // while we were asleep, but we'll still have strong references to them.)
-
-    // fill in vsync event info
-    event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
-    event->header.timestamp = timestamp;
-    event->vsync.count = vsyncCount;
-
     return signalConnections;
 }
 
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index a92ba5c..1c6e637 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -76,7 +76,8 @@
     void onScreenAcquired();
 
     // called when receiving a vsync event
-    void onVSyncReceived(const wp<IBinder>& display, nsecs_t timestamp);
+    void onVSyncReceived(int type, nsecs_t timestamp);
+    void onHotplugReceived(int type, bool connected);
 
     Vector< sp<EventThread::Connection> > waitForEvent(
             DisplayEventReceiver::Event* event);
@@ -100,6 +101,7 @@
 
     // protected by mLock
     SortedVector< wp<Connection> > mDisplayEventConnections;
+    Vector< DisplayEventReceiver::Event > mPendingEvents;
     nsecs_t mVSyncTimestamp;
     bool mUseSoftwareVSync;
     size_t mVSyncCount;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index bd587f2..427e46f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -671,8 +671,21 @@
     }
     if (uint32_t(type) < DisplayDevice::NUM_DISPLAY_TYPES) {
         // we should only receive DisplayDevice::DisplayType from the vsync callback
-        const wp<IBinder>& token(mDefaultDisplays[type]);
-        mEventThread->onVSyncReceived(token, timestamp);
+        mEventThread->onVSyncReceived(type, timestamp);
+    }
+}
+
+void SurfaceFlinger::onHotplugReceived(int type, bool connected) {
+    if (mEventThread == NULL) {
+        // This is a temporary workaround for b/7145521.  A non-null pointer
+        // does not mean EventThread has finished initializing, so this
+        // is not a correct fix.
+        ALOGW("WARNING: EventThread not started, ignoring hotplug");
+        return;
+    }
+    if (uint32_t(type) < DisplayDevice::NUM_DISPLAY_TYPES) {
+        // we should only receive DisplayDevice::DisplayType from the vsync callback
+        mEventThread->onHotplugReceived(type, connected);
     }
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 80f5d4b..c9877b2 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -218,6 +218,7 @@
      * HWComposer::EventHandler interface
      */
     virtual void onVSyncReceived(int type, nsecs_t timestamp);
+    virtual void onHotplugReceived(int disp, bool connected);
 
     /* ------------------------------------------------------------------------
      * Message handling