hwc: Allow HWC to support Virtual Display

  This change allows virtual display to be composed
  by HWC for supporting Google WFD App + QCOM WFD stack.

Change-Id: If8892230256e72fa34e3fb5ae715c3ad8cbd5b64
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 6b8f4e3..752aaa2 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -35,6 +35,21 @@
 
 #define HWC_UEVENT_THREAD_NAME "hwcUeventThread"
 
+/* External Display states */
+enum {
+    EXTERNAL_OFFLINE = 0,
+    EXTERNAL_ONLINE,
+    EXTERNAL_PAUSE,
+    EXTERNAL_RESUME
+};
+
+static bool isHDMI(const char* str)
+{
+    if(strcasestr("change@/devices/virtual/switch/hdmi", str))
+        return true;
+    return false;
+}
+
 static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
 {
     int vsync = 0;
@@ -48,7 +63,6 @@
                            qdutils::COMPOSITION_TYPE_MDP |
                            qdutils::COMPOSITION_TYPE_C2D)) {
         usecopybit = true;
-
     }
 
     if(!strcasestr("change@/devices/virtual/switch/hdmi", str) &&
@@ -56,19 +70,35 @@
         ALOGD_IF(UEVENT_DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__);
         return;
     }
-
     int connected = -1; // initial value - will be set to  1/0 based on hotplug
+    int extDpyNum = HWC_DISPLAY_EXTERNAL;
+    char property[PROPERTY_VALUE_MAX];
+    if((property_get("persist.sys.wfd.virtual", property, NULL) > 0) &&
+            (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+             (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+        // This means we are using Google API to trigger WFD Display
+        extDpyNum = HWC_DISPLAY_VIRTUAL;
+
+    }
+
+    int dpy = isHDMI(str) ? HWC_DISPLAY_EXTERNAL : extDpyNum;
+
+    // update extDpyNum
+    ctx->mExtDisplay->setExtDpyNum(dpy);
+
     // parse HDMI/WFD switch state for connect/disconnect
     // for HDMI:
     // The event will be of the form:
     // change@/devices/virtual/switch/hdmi ACTION=change
     // SWITCH_STATE=1 or SWITCH_STATE=0
-
     while(*str) {
         if (!strncmp(str, "SWITCH_STATE=", strlen("SWITCH_STATE="))) {
             connected = atoi(str + strlen("SWITCH_STATE="));
             //Disabled until SF calls unblank
             ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
+            //Ignored for Virtual Displays
+            //ToDo: we can do this in a much better way
+            ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = true;
             break;
         }
         str += strlen(str) + 1;
@@ -76,32 +106,63 @@
             break;
     }
 
-    if(connected != -1) { //either we got switch_state connected or disconnect
-        ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = connected;
-        if (connected) {
-            ctx->mExtDispConfiguring = true;
-            ctx->mExtDisplay->processUEventOnline(udata);
-            ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL] =
-                IFBUpdate::getObject(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].xres,
-                HWC_DISPLAY_EXTERNAL);
-            if(usecopybit)
-                ctx->mCopyBit[HWC_DISPLAY_EXTERNAL] = new CopyBit();
-        } else {
-            ctx->mExtDisplay->processUEventOffline(udata);
-            if(ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL]) {
+    switch(connected) {
+        case EXTERNAL_OFFLINE:
+            {   // disconnect event
+                ctx->mExtDisplay->processUEventOffline(udata);
+                if(ctx->mFBUpdate[dpy]) {
+                    Locker::Autolock _l(ctx->mExtSetLock);
+                    delete ctx->mFBUpdate[dpy];
+                    ctx->mFBUpdate[dpy] = NULL;
+                }
+                if(ctx->mCopyBit[dpy]){
+                    Locker::Autolock _l(ctx->mExtSetLock);
+                    delete ctx->mCopyBit[dpy];
+                    ctx->mCopyBit[dpy] = NULL;
+                }
+                ALOGD("%s sending hotplug: connected = %d and dpy:%d",
+                      __FUNCTION__, connected, dpy);
+                ctx->dpyAttr[dpy].connected = false;
                 Locker::Autolock _l(ctx->mExtSetLock);
-                delete ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL];
-                ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL] = NULL;
+                //hwc comp could be on
+                ctx->proc->hotplug(ctx->proc, dpy, connected);
+                break;
             }
-            if(ctx->mCopyBit[HWC_DISPLAY_EXTERNAL]){
-                Locker::Autolock _l(ctx->mExtSetLock);
-                delete ctx->mCopyBit[HWC_DISPLAY_EXTERNAL];
-                ctx->mCopyBit[HWC_DISPLAY_EXTERNAL] = NULL;
+        case EXTERNAL_ONLINE:
+            {   // connect case
+                ctx->mExtDispConfiguring = true;
+                ctx->mExtDisplay->processUEventOnline(udata);
+                ctx->mFBUpdate[dpy] =
+                        IFBUpdate::getObject(ctx->dpyAttr[dpy].xres, dpy);
+                ctx->dpyAttr[dpy].isPause = false;
+                if(usecopybit)
+                    ctx->mCopyBit[dpy] = new CopyBit();
+                ALOGD("%s sending hotplug: connected = %d", __FUNCTION__,
+                        connected);
+                ctx->dpyAttr[dpy].connected = true;
+                Locker::Autolock _l(ctx->mExtSetLock); //hwc comp could be on
+                ctx->proc->hotplug(ctx->proc, dpy, connected);
+                break;
             }
-        }
-        ALOGD("%s sending hotplug: connected = %d", __FUNCTION__, connected);
-        Locker::Autolock _l(ctx->mExtSetLock); //hwc comp could be on
-        ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL, connected);
+        case EXTERNAL_PAUSE:
+            {   // pause case
+                ALOGD("%s Received Pause event",__FUNCTION__);
+                ctx->dpyAttr[dpy].isActive = true;
+                ctx->dpyAttr[dpy].isPause = true;
+                break;
+            }
+        case EXTERNAL_RESUME:
+            {  // resume case
+                ALOGD("%s Received resume event",__FUNCTION__);
+                ctx->dpyAttr[dpy].isActive = true;
+                ctx->dpyAttr[dpy].isPause = false;
+                break;
+            }
+        default:
+            {
+                ALOGE("ignore event and connected:%d",connected);
+                break;
+            }
     }
 }