Merge "QCamera3HWI: Add OIS keys to the results"
diff --git a/msm8998/QCamera2/Android.mk b/msm8998/QCamera2/Android.mk
index e01fdc8..f2d8d49 100755
--- a/msm8998/QCamera2/Android.mk
+++ b/msm8998/QCamera2/Android.mk
@@ -144,6 +144,7 @@
 LOCAL_SHARED_LIBRARIES += libqdMetaData libqservice libbinder
 LOCAL_SHARED_LIBRARIES += libbase libcutils libdl libhdrplusclient
 LOCAL_SHARED_LIBRARIES += libhidlbase libhwbinder libutils android.hardware.power@1.2
+LOCAL_SHARED_LIBRARIES += libtinyxml2
 ifeq ($(TARGET_TS_MAKEUP),true)
 LOCAL_SHARED_LIBRARIES += libts_face_beautify_hal libts_detected_face_hal
 endif
diff --git a/msm8998/QCamera2/HAL3/QCamera3HWI.cpp b/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
index c458a4d..0798377 100644
--- a/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
+++ b/msm8998/QCamera2/HAL3/QCamera3HWI.cpp
@@ -57,6 +57,9 @@
 #include "QCamera3VendorTags.h"
 #include "QCameraTrace.h"
 
+// XML parsing
+#include "tinyxml2.h"
+
 #include "HdrPlusClientUtils.h"
 
 extern "C" {
@@ -9571,6 +9574,34 @@
                       lens_shading_map_size,
                       sizeof(lens_shading_map_size)/sizeof(int32_t));
 
+    // Lens calibration for MOTION_TRACKING, back camera only
+    if (cameraId == 0) {
+
+        float poseRotation[4] = {1.0f, 0.f, 0.f, 0.f}; // quaternion rotation
+        float poseTranslation[3] = {0.0f, 0.f, 0.f}; // xyz translation, meters
+        uint8_t poseReference = ANDROID_LENS_POSE_REFERENCE_GYROSCOPE;
+        // TODO: b/70565622 - these should have better identity values as a fallback
+        float cameraIntrinsics[5] = {100.f, 100.f, 0.f, 1000, 1000}; // fx,fy,sx,cx,cy
+        float radialDistortion[6] = {1.f, 0.f, 0.f, 0.f, 0.f, 0.f}; // identity
+
+        bool success = readSensorCalibration(
+                gCamCapability[cameraId]->active_array_size.width,
+                poseRotation, poseTranslation, cameraIntrinsics, radialDistortion);
+        if (!success) {
+            ALOGE("Using identity lens calibration values");
+        }
+        staticInfo.update(ANDROID_LENS_POSE_ROTATION,
+                poseRotation, sizeof(poseRotation)/sizeof(float));
+        staticInfo.update(ANDROID_LENS_POSE_TRANSLATION,
+                poseTranslation, sizeof(poseTranslation)/sizeof(float));
+        staticInfo.update(ANDROID_LENS_INTRINSIC_CALIBRATION,
+                cameraIntrinsics, sizeof(cameraIntrinsics)/sizeof(float));
+        staticInfo.update(ANDROID_LENS_RADIAL_DISTORTION,
+                radialDistortion, sizeof(radialDistortion)/sizeof(float));
+        staticInfo.update(ANDROID_LENS_POSE_REFERENCE,
+                &poseReference, sizeof(poseReference));
+    }
+
     staticInfo.update(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
             gCamCapability[cameraId]->sensor_physical_size, SENSOR_PHYSICAL_SIZE_CNT);
 
@@ -10316,6 +10347,11 @@
     if (CAM_SENSOR_YUV != gCamCapability[cameraId]->sensor_type.sens_type) {
         available_capabilities.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
     }
+    // Only back camera supports MOTION_TRACKING
+    if (cameraId == 0) {
+        available_capabilities.add(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING);
+    }
+
     staticInfo.update(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
             available_capabilities.array(),
             available_capabilities.size());
@@ -10783,6 +10819,18 @@
     }
 #endif
 
+    if (cameraId == 0) {
+        int32_t lensCalibrationKeys[] = {
+            ANDROID_LENS_POSE_ROTATION,
+            ANDROID_LENS_POSE_TRANSLATION,
+            ANDROID_LENS_POSE_REFERENCE,
+            ANDROID_LENS_INTRINSIC_CALIBRATION,
+            ANDROID_LENS_RADIAL_DISTORTION,
+        };
+        available_characteristics_keys.appendArray(lensCalibrationKeys,
+                sizeof(lensCalibrationKeys) / sizeof(lensCalibrationKeys[0]));
+    }
+
     if (0 <= indexPD) {
         int32_t depthKeys[] = {
                 ANDROID_DEPTH_MAX_DEPTH_SAMPLES,
@@ -11585,6 +11633,18 @@
         focusMode = ANDROID_CONTROL_AF_MODE_OFF;
         optStabMode = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
         break;
+      case CAMERA3_TEMPLATE_MOTION_TRACKING_PREVIEW:
+      case CAMERA3_TEMPLATE_MOTION_TRACKING_BEST:
+        edge_mode = ANDROID_EDGE_MODE_FAST;
+        noise_red_mode = ANDROID_NOISE_REDUCTION_MODE_FAST;
+        shading_mode = ANDROID_SHADING_MODE_FAST;
+        hot_pixel_mode = ANDROID_HOT_PIXEL_MODE_FAST;
+        tonemap_mode = ANDROID_TONEMAP_MODE_FAST;
+        cacMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST;
+        controlIntent = ANDROID_CONTROL_CAPTURE_INTENT_MOTION_TRACKING;
+        focusMode = ANDROID_CONTROL_AF_MODE_OFF;
+        optStabMode = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
+        break;
       default:
         edge_mode = ANDROID_EDGE_MODE_FAST;
         noise_red_mode = ANDROID_NOISE_REDUCTION_MODE_FAST;
@@ -11737,6 +11797,10 @@
 
     /*focus distance*/
     float focus_distance = 0.0;
+    if (type == CAMERA3_TEMPLATE_MOTION_TRACKING_PREVIEW ||
+            type == CAMERA3_TEMPLATE_MOTION_TRACKING_BEST) {
+        focus_distance = 0.1f;
+    }
     settings.update(ANDROID_LENS_FOCUS_DISTANCE, &focus_distance, 1);
 
     /*target fps range: use maximum range for picture, and maximum fixed range for video*/
@@ -15993,6 +16057,191 @@
     pthread_mutex_unlock(&mMutex);
 }
 
+bool QCamera3HardwareInterface::readSensorCalibration(
+        int activeArrayWidth,
+        float poseRotation[4], float poseTranslation[3],
+        float cameraIntrinsics[5], float radialDistortion[6]) {
+
+    const char* calibrationPath = "/persist/sensors/calibration/calibration.xml";
+
+    using namespace tinyxml2;
+
+    XMLDocument calibrationXml;
+    XMLError err = calibrationXml.LoadFile(calibrationPath);
+    if (err != XML_SUCCESS) {
+        ALOGE("Unable to load calibration file '%s'. Error: %s",
+                calibrationPath, XMLDocument::ErrorIDToName(err));
+        return false;
+    }
+    XMLElement *rig = calibrationXml.FirstChildElement("rig");
+    if (rig == nullptr) {
+        ALOGE("No 'rig' in calibration file");
+        return false;
+    }
+    XMLElement *cam = rig->FirstChildElement("camera");
+    XMLElement *camModel = nullptr;
+    while (cam != nullptr) {
+        camModel = cam->FirstChildElement("camera_model");
+        if (camModel == nullptr) {
+            ALOGE("No 'camera_model' in calibration file");
+            return false;
+        }
+        int modelIndex = camModel->IntAttribute("index", -1);
+        // Model index "0" has the calibration we need
+        if (modelIndex == 0) {
+            break;
+        }
+        cam = cam->NextSiblingElement("camera");
+    }
+    if (cam == nullptr) {
+        ALOGE("No 'camera' in calibration file");
+        return false;
+    }
+    const char *modelType = camModel->Attribute("type");
+    if (modelType == nullptr || strcmp(modelType,"calibu_fu_fv_u0_v0_k1_k2_k3")) {
+        ALOGE("Camera model is unknown type %s",
+                modelType ? modelType : "NULL");
+        return false;
+    }
+    XMLElement *modelWidth = camModel->FirstChildElement("width");
+    if (modelWidth == nullptr || modelWidth->GetText() == nullptr) {
+        ALOGE("No camera model width in calibration file");
+        return false;
+    }
+    int width = atoi(modelWidth->GetText());
+    XMLElement *modelHeight = camModel->FirstChildElement("height");
+    if (modelHeight == nullptr || modelHeight->GetText() == nullptr) {
+        ALOGE("No camera model height in calibration file");
+        return false;
+    }
+    int height = atoi(modelHeight->GetText());
+    if (width <= 0 || height <= 0) {
+        ALOGE("Bad model width or height in calibration file: %d x %d", width, height);
+        return false;
+    }
+    ALOGI("Width: %d, Height: %d", width, height);
+
+    XMLElement *modelParams = camModel->FirstChildElement("params");
+    if (modelParams == nullptr) {
+        ALOGE("No camera model params in calibration file");
+        return false;
+    }
+    const char* paramText = modelParams->GetText();
+    if (paramText == nullptr) {
+        ALOGE("No parameters in params element in calibration file");
+        return false;
+    }
+    ALOGI("Parameters: %s", paramText);
+
+    // Parameter string is of the form "[ float; float; float ...]"
+    float params[7];
+    bool success = parseStringArray(paramText, params, 7);
+    if (!success) {
+        ALOGE("Malformed camera parameter string in calibration file");
+        return false;
+    }
+
+    XMLElement *extCalib = rig->FirstChildElement("extrinsic_calibration");
+    while (extCalib != nullptr) {
+        int id = extCalib->IntAttribute("frame_B_id", -1);
+        if (id == 0) {
+            break;
+        }
+        extCalib = extCalib->NextSiblingElement("extrinsic_calibration");
+    }
+    if (extCalib == nullptr) {
+        ALOGE("No 'extrinsic_calibration' in calibration file");
+        return false;
+    }
+
+    XMLElement *q = extCalib->FirstChildElement("A_q_B");
+    if (q == nullptr || q->GetText() == nullptr) {
+        ALOGE("No extrinsic quarternion in calibration file");
+        return false;
+    }
+    float rotation[4];
+    success = parseStringArray(q->GetText(), rotation, 4);
+    if (!success) {
+        ALOGE("Malformed extrinsic quarternion string in calibration file");
+        return false;
+    }
+
+    XMLElement *p = extCalib->FirstChildElement("A_p_B");
+    if (p == nullptr || p->GetText() == nullptr) {
+        ALOGE("No extrinsic translation in calibration file");
+        return false;
+    }
+    float position[3];
+    success = parseStringArray(p->GetText(), position, 3);
+    if (!success) {
+        ALOGE("Malformed extrinsic position string in calibration file");
+        return false;
+    }
+
+    // Map from width x height to active array
+    float scaleFactor = static_cast<float>(activeArrayWidth) / width;
+
+    cameraIntrinsics[0] = params[0] * scaleFactor; // fu -> f_x
+    cameraIntrinsics[1] = params[1] * scaleFactor; // fv -> f_y
+    cameraIntrinsics[2] = params[2] * scaleFactor; // u0 -> c_x
+    cameraIntrinsics[3] = params[3] * scaleFactor; // v0 -> c_y
+    cameraIntrinsics[4] = 0; // s = 0
+
+    radialDistortion[0] = 1; // k_0 = 1
+    radialDistortion[1] = params[4]; // k1 -> k_1
+    radialDistortion[2] = params[5]; // k2 -> k_2
+    radialDistortion[3] = params[6]; // k3 -> k_3
+    radialDistortion[4] = 0; // k_4 = 0
+    radialDistortion[5] = 0; // k_5 = 0
+
+    for (int i = 0; i < 4; i++) {
+        poseRotation[i] = rotation[i];
+    }
+    for (int i = 0; i < 3; i++) {
+        poseTranslation[i] = position[i];
+    }
+
+    ALOGI("Intrinsics: %f, %f, %f, %f, %f", cameraIntrinsics[0],
+            cameraIntrinsics[1], cameraIntrinsics[2],
+            cameraIntrinsics[3], cameraIntrinsics[4]);
+    ALOGI("Distortion: %f, %f, %f, %f, %f, %f",
+            radialDistortion[0], radialDistortion[1], radialDistortion[2], radialDistortion[3],
+            radialDistortion[4], radialDistortion[5]);
+    ALOGI("Pose rotation: %f, %f, %f, %f",
+            poseRotation[0], poseRotation[1], poseRotation[2], poseRotation[3]);
+    ALOGI("Pose translation: %f, %f, %f",
+            poseTranslation[0], poseTranslation[1], poseTranslation[2]);
+
+    return true;
+}
+
+bool QCamera3HardwareInterface::parseStringArray(const char *str, float *dest, int count) {
+    size_t idx = 0;
+    size_t len = strlen(str);
+    for (; idx < len; idx++) {
+        if (str[idx] == '[') break;
+    }
+    const char *startParam = str + idx + 1;
+    if (startParam >= str + len) {
+        ALOGE("Malformed array: %s", str);
+        return false;
+    }
+    char *endParam = nullptr;
+    for (int i = 0; i < count; i++) {
+        dest[i] = strtod(startParam, &endParam);
+        if (startParam == endParam) {
+            ALOGE("Malformed array, index %d: %s", i, str);
+            return false;
+        }
+        startParam = endParam + 1;
+        if (startParam >= str + len) {
+            ALOGE("Malformed array, index %d: %s", i, str);
+            return false;
+        }
+    }
+    return true;
+}
+
 ShutterDispatcher::ShutterDispatcher(QCamera3HardwareInterface *parent) :
         mParent(parent) {}
 
diff --git a/msm8998/QCamera2/HAL3/QCamera3HWI.h b/msm8998/QCamera2/HAL3/QCamera3HWI.h
index 528920b..13f3c0e 100644
--- a/msm8998/QCamera2/HAL3/QCamera3HWI.h
+++ b/msm8998/QCamera2/HAL3/QCamera3HWI.h
@@ -904,6 +904,16 @@
 
     // Thread to handle callbacks from HDR+ client. Protected by gHdrPlusClientLock.
     sp<QCamera3HdrPlusListenerThread> mQCamera3HdrPlusListenerThread;
+
+    // Read sensor calibration XML file for lens calibration fields. On failure to read
+    // the file, leaves passed-in values unchanged and returns false.
+    static bool readSensorCalibration(int activeArrayWidth,
+            float poseRotation[4], float poseTranslation[3],
+            float cameraIntrinsics[5], float radialDistortion[6]);
+
+    // Parse a string of form " [ x; y; z ...]" into a floating-point array.
+    // Returns false on parse error
+    static bool parseStringArray(const char *str, float *dest, int count);
 };
 
 }; // namespace qcamera