libjpegrecoverymap: XMP updates.

Actually write out MinContentBoost in the XMP. Also move XMP for
RecoveryMap:* elements into the secondary image Item, to match updates
to the ghdr spec. Update XMP test for min content boost.

Bug: 264715926
Test: tests pass
Change-Id: I8e32755ef3852511ee2e89949fcb7a3cd61d0507
diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h
index 3a0f67d..581806c 100644
--- a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h
+++ b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h
@@ -56,6 +56,7 @@
  * below is an example of the XMP metadata that this function generates where
  * secondary_image_length = 1000
  * max_content_boost = 8.0
+ * min_content_boost = 0.5
  *
  * <x:xmpmeta
  *   xmlns:x="adobe:ns:meta/"
@@ -70,16 +71,17 @@
  *         <rdf:Seq>
  *           <rdf:li>
  *             <Container:Item
- *              Item:Semantic="Primary"
- *              Item:Mime="image/jpeg"
- *              RecoveryMap:Version="1"
- *              RecoveryMap:MaxContentBoost="8.0"/>
+ *               Item:Semantic="Primary"
+ *               Item:Mime="image/jpeg"/>
  *           </rdf:li>
  *           <rdf:li>
  *             <Container:Item
  *               Item:Semantic="RecoveryMap"
  *               Item:Mime="image/jpeg"
- *               Item:Length="1000"/>
+ *               Item:Length="1000"
+ *               RecoveryMap:Version="1"
+ *               RecoveryMap:MaxContentBoost="8.0"
+ *               RecoveryMap:MinContentBoost="0.5"/>
  *           </rdf:li>
  *         </rdf:Seq>
  *       </Container:Directory>
diff --git a/libs/jpegrecoverymap/jpegrutils.cpp b/libs/jpegrecoverymap/jpegrutils.cpp
index bcca91a..49526c8 100644
--- a/libs/jpegrecoverymap/jpegrutils.cpp
+++ b/libs/jpegrecoverymap/jpegrutils.cpp
@@ -95,6 +95,8 @@
             if (context.BuildTokenValue(&val)) {
                 if (!val.compare(maxContentBoostAttrName)) {
                     lastAttributeName = maxContentBoostAttrName;
+                } else if (!val.compare(minContentBoostAttrName)) {
+                    lastAttributeName = minContentBoostAttrName;
                 } else {
                     lastAttributeName = "";
                 }
@@ -109,6 +111,8 @@
             if (context.BuildTokenValue(&val, true)) {
                 if (!lastAttributeName.compare(maxContentBoostAttrName)) {
                     maxContentBoostStr = val;
+                } else if (!lastAttributeName.compare(minContentBoostAttrName)) {
+                    minContentBoostStr = val;
                 }
             }
         }
@@ -130,10 +134,27 @@
         }
     }
 
+    bool getMinContentBoost(float* min_content_boost) {
+        if (gContainerItemState == Done) {
+            stringstream ss(minContentBoostStr);
+            float val;
+            if (ss >> val) {
+                *min_content_boost = val;
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
 private:
     static const string gContainerItemName;
     static const string maxContentBoostAttrName;
     string              maxContentBoostStr;
+    static const string minContentBoostAttrName;
+    string              minContentBoostStr;
     string              lastAttributeName;
     ParseState          gContainerItemState;
 };
@@ -169,10 +190,12 @@
 
 // RecoveryMap XMP constants - element and attribute names
 const string kMapMaxContentBoost  = Name(kRecoveryMapPrefix, "MaxContentBoost");
+const string kMapMinContentBoost  = Name(kRecoveryMapPrefix, "MinContentBoost");
 const string kMapVersion          = Name(kRecoveryMapPrefix, "Version");
 
 // RecoveryMap XMP constants - names for XMP handlers
 const string XMPXmlHandler::maxContentBoostAttrName = kMapMaxContentBoost;
+const string XMPXmlHandler::minContentBoostAttrName = kMapMinContentBoost;
 
 bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata) {
     string nameSpace = "http://ns.adobe.com/xap/1.0/\0";
@@ -213,6 +236,10 @@
         return false;
     }
 
+    if (!handler.getMinContentBoost(&metadata->minContentBoost)) {
+        return false;
+    }
+
     return true;
 }
 
@@ -235,13 +262,14 @@
   size_t item_depth = writer.StartWritingElements(kLiItem);
   writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticPrimary);
   writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg);
-  writer.WriteAttributeNameAndValue(kMapVersion, metadata.version);
-  writer.WriteAttributeNameAndValue(kMapMaxContentBoost, metadata.maxContentBoost);
   writer.FinishWritingElementsToDepth(item_depth);
   writer.StartWritingElements(kLiItem);
   writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticRecoveryMap);
   writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg);
   writer.WriteAttributeNameAndValue(kItemLength, secondary_image_length);
+  writer.WriteAttributeNameAndValue(kMapVersion, metadata.version);
+  writer.WriteAttributeNameAndValue(kMapMaxContentBoost, metadata.maxContentBoost);
+  writer.WriteAttributeNameAndValue(kMapMinContentBoost, metadata.minContentBoost);
   writer.FinishWriting();
 
   return ss.str();
diff --git a/libs/jpegrecoverymap/tests/jpegr_test.cpp b/libs/jpegrecoverymap/tests/jpegr_test.cpp
index c0347e3..7a3133d 100644
--- a/libs/jpegrecoverymap/tests/jpegr_test.cpp
+++ b/libs/jpegrecoverymap/tests/jpegr_test.cpp
@@ -176,6 +176,7 @@
 TEST_F(JpegRTest, writeXmpThenRead) {
   jpegr_metadata metadata_expected;
   metadata_expected.maxContentBoost = 1.25;
+  metadata_expected.minContentBoost = 0.75;
   int length_expected = 1000;
   const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0";
   const int nameSpaceLength = nameSpace.size() + 1;  // need to count the null terminator
@@ -192,6 +193,7 @@
   jpegr_metadata metadata_read;
   EXPECT_TRUE(getMetadataFromXMP(xmpData.data(), xmpData.size(), &metadata_read));
   ASSERT_EQ(metadata_expected.maxContentBoost, metadata_read.maxContentBoost);
+  ASSERT_EQ(metadata_expected.minContentBoost, metadata_read.minContentBoost);
 }
 
 /* Test Encode API-0 and decode */
@@ -496,4 +498,4 @@
   benchmark.BenchmarkApplyRecoveryMap(&mRawYuv420Image, &map, &metadata, &dest);
 }
 
-} // namespace android::recoverymap
\ No newline at end of file
+} // namespace android::recoverymap