display: Add support for overscan compensation for ext display

- Read scan_info sys file node to check if TV underscans
- Apply action safe parameters to avoid overscan on ext display
- Store action safe width and height ratio using system  property
- Use these to calculate the destination position on the ext display
- Remove unsed ActionSafe Class

Change-Id: Id27e6fa20966fb13fc16aa7e237cacce8caeb642
CRs-fixed: 447367
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index b721195..2660c97 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -85,6 +85,7 @@
     openFrameBuffer(mHdmiFbNum);
     if(mFd == -1)
         return -1;
+    readCEUnderscanInfo();
     readResolution();
     // TODO: Move this to activate
     /* Used for changing the resolution
@@ -167,7 +168,7 @@
 
 ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1),
     mCurrentMode(-1), mConnected(0), mConnectedFbNum(0), mModeCount(0),
-    mHwcContext(ctx), mHdmiFbNum(-1), mWfdFbNum(-1)
+     mUnderscanSupported(false), mHwcContext(ctx), mHdmiFbNum(-1), mWfdFbNum(-1)
 {
     memset(&mVInfo, 0, sizeof(mVInfo));
     //Determine the fb index for external display devices.
@@ -193,7 +194,12 @@
 void ExternalDisplay::setActionSafeDimension(int w, int h) {
     ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
     Mutex::Autolock lock(mExtDispLock);
-    overlay::utils::ActionSafe::getInstance()->setDimension(w, h);
+    char actionsafeWidth[PROPERTY_VALUE_MAX];
+    char actionsafeHeight[PROPERTY_VALUE_MAX];
+    sprintf(actionsafeWidth, "%d", w);
+    property_set("hw.actionsafe.width", actionsafeWidth);
+    sprintf(actionsafeHeight, "%d", h);
+    property_set("hw.actionsafe.height", actionsafeHeight);
     setExternalDisplay(true, mHdmiFbNum);
 }
 
@@ -210,6 +216,75 @@
     }
 }
 
+void ExternalDisplay::readCEUnderscanInfo()
+{
+    int hdmiScanInfoFile = -1;
+    int len = -1;
+    char scanInfo[17];
+    char *ce_info_str = NULL;
+    const char token[] = ", \n";
+    int ce_info = -1;
+    char sysFsScanInfoFilePath[128];
+    sprintf(sysFsScanInfoFilePath, "/sys/devices/virtual/graphics/fb%d/"
+                                   "scan_info", mHdmiFbNum);
+
+    memset(scanInfo, 0, sizeof(scanInfo));
+    hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0);
+    if (hdmiScanInfoFile < 0) {
+        ALOGD_IF(DEBUG, "%s: scan_info file '%s' not found",
+                                __FUNCTION__, sysFsScanInfoFilePath);
+        return;
+    } else {
+        len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
+        ALOGD("%s: Scan Info string: %s length = %d",
+                 __FUNCTION__, scanInfo, len);
+        if (len <= 0) {
+            close(hdmiScanInfoFile);
+            ALOGE("%s: Scan Info file empty '%s'",
+                                __FUNCTION__, sysFsScanInfoFilePath);
+            return;
+        }
+        scanInfo[len] = '\0';  /* null terminate the string */
+    }
+    close(hdmiScanInfoFile);
+
+    /*
+     * The scan_info contains the three fields
+     * PT - preferred video format
+     * IT - video format
+     * CE video format - containing the underscan support information
+     */
+
+    /* PT */
+    ce_info_str = strtok(scanInfo, token);
+    if (ce_info_str) {
+        /* IT */
+        ce_info_str = strtok(NULL, token);
+        if (ce_info_str) {
+            /* CE */
+            ce_info_str = strtok(NULL, token);
+            if (ce_info_str)
+                ce_info = atoi(ce_info_str);
+        }
+    }
+
+    if (ce_info_str) {
+        // ce_info contains the underscan information
+        if (ce_info == EXT_SCAN_ALWAYS_UNDERSCANED ||
+            ce_info == EXT_SCAN_BOTH_SUPPORTED)
+            // if TV supported underscan, then driver will always underscan
+            // hence no need to apply action safe rectangle
+            mUnderscanSupported = true;
+    } else {
+        ALOGE("%s: scan_info string error", __FUNCTION__);
+    }
+
+    // Store underscan support info in a system property
+    const char* prop = (mUnderscanSupported) ? "1" : "0";
+    property_set("hw.underscan_supported", prop);
+    return;
+}
+
 ExternalDisplay::~ExternalDisplay()
 {
     closeFrameBuffer();
@@ -393,6 +468,10 @@
     memset(mEDIDModes, 0, sizeof(mEDIDModes));
     mModeCount = 0;
     mCurrentMode = -1;
+    mUnderscanSupported = false;
+    // Reset the underscan supported system property
+    const char* prop = "0";
+    property_set("hw.underscan_supported", prop);
 }
 
 int ExternalDisplay::getModeOrder(int mode)
diff --git a/libexternal/external.h b/libexternal/external.h
index d85ce44..baf3598 100644
--- a/libexternal/external.h
+++ b/libexternal/external.h
@@ -28,6 +28,13 @@
 
 namespace qhwc {
 
+//Type of scanning of EDID(Video Capability Data Block)
+enum external_scansupport_type {
+    EXT_SCAN_NOT_SUPPORTED      = 0,
+    EXT_SCAN_ALWAYS_OVERSCANED  = 1,
+    EXT_SCAN_ALWAYS_UNDERSCANED = 2,
+    EXT_SCAN_BOTH_SUPPORTED     = 3
+};
 
 class ExternalDisplay
 {
@@ -36,6 +43,7 @@
     ~ExternalDisplay();
     int getModeCount() const;
     void getEDIDModes(int *out) const;
+    bool isCEUnderscanSupported() { return mUnderscanSupported; }
     void setExternalDisplay(bool connected, int extFbNum = 0);
     bool isExternalConnected() { return mConnected;};
     bool post();
@@ -46,6 +54,7 @@
     void processUEventOffline(const char *str);
 
 private:
+    void readCEUnderscanInfo();
     bool readResolution();
     int  parseResolution(char* edidStr, int* edidModes);
     void setResolution(int ID);
@@ -78,6 +87,7 @@
     char mEDIDs[128];
     int mEDIDModes[64];
     int mModeCount;
+    bool mUnderscanSupported;
     hwc_context_t *mHwcContext;
     fb_var_screeninfo mVInfo;
     int mHdmiFbNum;
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 18f75eb..a0dbbe3 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -104,6 +104,9 @@
                 displayFrame.top,
                 displayFrame.right - displayFrame.left,
                 displayFrame.bottom - displayFrame.top);
+        // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
+        if(mDpy)
+            getActionSafePosition(ctx, mDpy, dpos.x, dpos.y, dpos.w, dpos.h);
         ov.setPosition(dpos, dest);
 
         ret = true;
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index e1f413c..ee7c25d 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -148,6 +148,55 @@
     va_end(varargs);
 }
 
+/* Calculates the destination position based on the action safe rectangle */
+void getActionSafePosition(hwc_context_t *ctx, int dpy, uint32_t& x,
+                           uint32_t& y, uint32_t& w, uint32_t& h) {
+
+    // if external supports underscan, do nothing
+    // it will be taken care in the driver
+    if(ctx->mExtDisplay->isCEUnderscanSupported())
+        return;
+
+    float wRatio = 1.0;
+    float hRatio = 1.0;
+    float xRatio = 1.0;
+    float yRatio = 1.0;
+
+    float fbWidth = ctx->dpyAttr[dpy].xres;
+    float fbHeight = ctx->dpyAttr[dpy].yres;
+
+    float asX = 0;
+    float asY = 0;
+    float asW = fbWidth;
+    float asH= fbHeight;
+    char value[PROPERTY_VALUE_MAX];
+
+    // Apply action safe parameters
+    property_get("hw.actionsafe.width", value, "0");
+    int asWidthRatio = atoi(value);
+    property_get("hw.actionsafe.height", value, "0");
+    int asHeightRatio = atoi(value);
+    // based on the action safe ratio, get the Action safe rectangle
+    asW = fbWidth * (1.0f -  asWidthRatio / 100.0f);
+    asH = fbHeight * (1.0f -  asHeightRatio / 100.0f);
+    asX = (fbWidth - asW) / 2;
+    asY = (fbHeight - asH) / 2;
+
+    // calculate the position ratio
+    xRatio = (float)x/fbWidth;
+    yRatio = (float)y/fbHeight;
+    wRatio = (float)w/fbWidth;
+    hRatio = (float)h/fbHeight;
+
+    //Calculate the position...
+    x = (xRatio * asW) + asX;
+    y = (yRatio * asH) + asY;
+    w = (wRatio * asW);
+    h = (hRatio * asH);
+
+    return;
+}
+
 static inline bool isAlphaScaled(hwc_layer_1_t const* layer) {
     int dst_w, dst_h, src_w, src_h;
 
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 9692986..c66f7ff 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -136,6 +136,10 @@
 //Helper function to dump logs
 void dumpsys_log(android::String8& buf, const char* fmt, ...);
 
+/* Calculates the destination position based on the action safe rectangle */
+void getActionSafePosition(hwc_context_t *ctx, int dpy, uint32_t& x,
+                                        uint32_t& y, uint32_t& w, uint32_t& h);
+
 //Sync point impl.
 int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
                                                     int fd);
diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp
index 0c0a40d..6abc7ae 100644
--- a/libhwcomposer/hwc_video.cpp
+++ b/libhwcomposer/hwc_video.cpp
@@ -171,6 +171,10 @@
             displayFrame.top,
             displayFrame.right - displayFrame.left,
             displayFrame.bottom - displayFrame.top);
+    // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
+    if(dpy)
+        getActionSafePosition(ctx, dpy, dpos.x, dpos.y, dpos.w, dpos.h);
+
     ov.setPosition(dpos, dest);
 
     if (!ov.commit(dest)) {
diff --git a/liboverlay/overlayCtrl.cpp b/liboverlay/overlayCtrl.cpp
index 03d2564..2cbf1c5 100644
--- a/liboverlay/overlayCtrl.cpp
+++ b/liboverlay/overlayCtrl.cpp
@@ -79,8 +79,6 @@
     return true;
 }
 
-utils::ActionSafe* utils::ActionSafe::sActionSafe = NULL;
-
 utils::FrameBufferInfo* utils::FrameBufferInfo::sFBInfoInstance = 0;
 
 void Ctrl::dump() const {
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index cbacf7f..449d2fa 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -245,28 +245,6 @@
     uint32_t size;
 };
 
-class ActionSafe {
-private:
-    ActionSafe() : mWidth(0.0f), mHeight(0.0f) { };
-    float mWidth;
-    float mHeight;
-    static ActionSafe *sActionSafe;
-public:
-    ~ActionSafe() { };
-    static ActionSafe* getInstance() {
-        if(!sActionSafe) {
-            sActionSafe = new ActionSafe();
-        }
-        return sActionSafe;
-    }
-    void setDimension(int w, int h) {
-        mWidth = (float)w;
-        mHeight = (float)h;
-    }
-    float getWidth() { return mWidth; }
-    float getHeight() { return mHeight; }
-};
-
 enum { MAX_PATH_LEN = 256 };
 
 /**