Add new Source#getFilterData method to accept Trigger so that we can store duration from the source and trigger in the filter map.

Details:
- Also created a similar method for Source#getAggregatableAttributionSource
- Some minor improvements for FilterMap.

Bug: 295530374
Test: atest com.android.adservices.service.measurement.FilterMapTest
Change-Id: Iccf08f1aca62545ce3ee403cddb55fbe6048ea3f
diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/FilterMap.java b/adservices/service-core/java/com/android/adservices/service/measurement/FilterMap.java
index b0c36c3..17974af 100644
--- a/adservices/service-core/java/com/android/adservices/service/measurement/FilterMap.java
+++ b/adservices/service-core/java/com/android/adservices/service/measurement/FilterMap.java
@@ -77,6 +77,22 @@
     }
 
     /**
+     * Returns the long value given the key. {@code key} must be present and the value kind must be
+     * {@link FilterValue.Kind#LONG_VALUE}.
+     */
+    public long getLongValue(String key) {
+        return mAttributionFilterMapWithLongValue.get(key).longValue();
+    }
+
+    /**
+     * Returns the string list value given the key. {@code key} must be present and the value kind
+     * must be {@link FilterValue.Kind#STRING_LIST_VALUE}.
+     */
+    public List<String> getStringListValue(String key) {
+        return mAttributionFilterMapWithLongValue.get(key).stringListValue();
+    }
+
+    /**
      * Serializes the object into a {@link JSONObject}.
      *
      * @return serialized {@link JSONObject}.
@@ -148,6 +164,18 @@
             return this;
         }
 
+        /** Adds filter with long value. */
+        public Builder addLongValue(String key, long value) {
+            mBuilding.mAttributionFilterMapWithLongValue.put(key, FilterValue.ofLong(value));
+            return this;
+        }
+
+        /** Adds filter with string list value. */
+        public Builder addStringListValue(String key, List<String> value) {
+            mBuilding.mAttributionFilterMapWithLongValue.put(key, FilterValue.ofStringList(value));
+            return this;
+        }
+
         /**
          * See {@link FilterMap#getAttributionFilterMap()}.
          *
diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/Source.java b/adservices/service-core/java/com/android/adservices/service/measurement/Source.java
index 95b1565..d4029ba 100644
--- a/adservices/service-core/java/com/android/adservices/service/measurement/Source.java
+++ b/adservices/service-core/java/com/android/adservices/service/measurement/Source.java
@@ -49,6 +49,7 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
 
 /**
  * POJO for Source.
@@ -728,7 +729,10 @@
     /**
      * Returns the AggregatableAttributionSource object, which is constructed using the aggregate
      * source string and aggregate filter data string in Source.
+     *
+     * @deprecated use {@link #getAggregatableAttributionSourceV2(Trigger)} instead.
      */
+    @Deprecated
     public Optional<AggregatableAttributionSource> getAggregatableAttributionSource()
             throws JSONException {
         if (mAggregatableAttributionSource == null) {
@@ -757,6 +761,30 @@
         return mAggregatableAttributionSource;
     }
 
+    /**
+     * Returns the AggregatableAttributionSource object, which is constructed using the aggregate
+     * source string and aggregate filter data string in Source.
+     */
+    public Optional<AggregatableAttributionSource> getAggregatableAttributionSourceV2(
+            @NonNull Trigger trigger) throws JSONException {
+        if (mAggregateSource == null) {
+            return Optional.empty();
+        }
+        JSONObject jsonObject = new JSONObject(mAggregateSource);
+        TreeMap<String, BigInteger> aggregateSourceMap = new TreeMap<>();
+        for (String key : jsonObject.keySet()) {
+            // Remove "0x" prefix.
+            String hexString = jsonObject.getString(key).substring(2);
+            BigInteger bigInteger = new BigInteger(hexString, 16);
+            aggregateSourceMap.put(key, bigInteger);
+        }
+        return Optional.of(
+                new AggregatableAttributionSource.Builder()
+                        .setAggregatableSource(aggregateSourceMap)
+                        .setFilterMap(getFilterData(trigger))
+                        .build());
+    }
+
     /** Returns the registration id. */
     @Nullable
     public String getRegistrationId() {
@@ -902,7 +930,10 @@
     /**
      * Generates AggregatableFilterData from aggregate filter string in Source, including an entry
      * for source type.
+     *
+     * @deprecated use {@link #getFilterData(Trigger)} instead.
      */
+    @Deprecated
     public FilterMap getFilterData() throws JSONException {
         if (mFilterData != null) {
             return mFilterData;
@@ -922,6 +953,21 @@
         return mFilterData;
     }
 
+    /**
+     * Generates AggregatableFilterData from aggregate filter string in Source, including entries
+     * for source type and duration from source to trigger.
+     */
+    public FilterMap getFilterData(@NonNull Trigger trigger) throws JSONException {
+        return new FilterMap.Builder()
+                .buildFilterDataV2(new JSONObject(mFilterDataString))
+                .addStringListValue(
+                        "source_type", Collections.singletonList(mSourceType.getValue()))
+                .addLongValue(
+                        FilterMap.LOOKBACK_WINDOW,
+                        TimeUnit.MILLISECONDS.toSeconds(trigger.getTriggerTime() - mEventTime))
+                .build();
+    }
+
     @Nullable
     public UnsignedLong getSharedDebugKey() {
         return mSharedDebugKey;
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/FilterMapTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/FilterMapTest.java
index 8a9c347..0eb7452 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/FilterMapTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/FilterMapTest.java
@@ -16,6 +16,8 @@
 
 package com.android.adservices.service.measurement;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
@@ -107,6 +109,23 @@
         assertEquals(expected, actual);
     }
 
+    @Test
+    public void testAddLongValue() {
+        assertThat(new FilterMap.Builder().addLongValue("a", 1L).build().getLongValue("a"))
+                .isEqualTo(1L);
+    }
+
+    @Test
+    public void testAddStringListValue() {
+        List<String> stringList = Arrays.asList("123", "456");
+        assertThat(
+                        new FilterMap.Builder()
+                                .addStringListValue("a", stringList)
+                                .build()
+                                .getStringListValue("a"))
+                .isEqualTo(stringList);
+    }
+
     private FilterMap createExample() {
         Map<String, List<String>> attributionFilterMap = new HashMap<>();
         attributionFilterMap.put("type", Arrays.asList("1", "2", "3", "4"));
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/SourceTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/SourceTest.java
index 3def290..4f922b3 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/SourceTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/SourceTest.java
@@ -16,6 +16,8 @@
 
 package com.android.adservices.service.measurement;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -780,6 +782,45 @@
     }
 
     @Test
+    public void testAggregatableAttributionSourceWithTrigger_addsLookbackWindow() throws Exception {
+        JSONObject aggregatableSource = new JSONObject();
+        aggregatableSource.put("campaignCounts", "0x159");
+        aggregatableSource.put("geoValue", "0x5");
+
+        JSONObject filterMapJson = new JSONObject();
+        filterMapJson.put("conversion", new JSONArray(Collections.singletonList("electronics")));
+
+        final Source source =
+                SourceFixture.getMinimalValidSourceBuilder()
+                        .setAggregateSource(aggregatableSource.toString())
+                        .setFilterData(filterMapJson.toString())
+                        .build();
+
+        Trigger trigger = TriggerFixture.getValidTrigger();
+        Optional<AggregatableAttributionSource> aggregatableAttributionSource =
+                source.getAggregatableAttributionSourceV2(trigger);
+        assertThat(aggregatableAttributionSource.isPresent()).isTrue();
+        assertThat(aggregatableAttributionSource.get().getAggregatableSource())
+                .containsExactly(
+                        "campaignCounts",
+                        new BigInteger("159", 16),
+                        "geoValue",
+                        new BigInteger("5", 16));
+        assertThat(
+                        aggregatableAttributionSource
+                                .get()
+                                .getFilterMap()
+                                .getAttributionFilterMapWithLongValue())
+                .containsExactly(
+                        "conversion",
+                        FilterValue.ofStringList(Collections.singletonList("electronics")),
+                        "source_type",
+                        FilterValue.ofStringList(Collections.singletonList("event")),
+                        FilterMap.LOOKBACK_WINDOW,
+                        FilterValue.ofLong(8640000L));
+    }
+
+    @Test
     public void testTriggerDataCardinality() {
         Source eventSource =
                 SourceFixture.getMinimalValidSourceBuilder()
@@ -809,7 +850,7 @@
     }
 
     @Test
-    public void testParseFilterData_nonEmpty() throws JSONException {
+    public void testGetFilterData_nonEmpty() throws JSONException {
         JSONObject filterMapJson = new JSONObject();
         filterMapJson.put("conversion", new JSONArray(Collections.singletonList("electronics")));
         filterMapJson.put("product", new JSONArray(Arrays.asList("1234", "2345")));
@@ -824,12 +865,37 @@
                 filterMap.getAttributionFilterMap().get("conversion"));
         assertEquals(Arrays.asList("1234", "2345"),
                 filterMap.getAttributionFilterMap().get("product"));
-        assertEquals(Collections.singletonList("navigation"),
+        assertEquals(
+                Collections.singletonList("navigation"),
                 filterMap.getAttributionFilterMap().get("source_type"));
     }
 
     @Test
-    public void testParseFilterData_nullFilterData() throws JSONException {
+    public void testGetFilterData_withTrigger_addsLookbackWindow() throws JSONException {
+        JSONObject filterMapJson = new JSONObject();
+        filterMapJson.put("conversion", new JSONArray(List.of("electronics")));
+        filterMapJson.put("product", new JSONArray(List.of("1234", "2345")));
+        Source source =
+                SourceFixture.getMinimalValidSourceBuilder()
+                        .setSourceType(Source.SourceType.NAVIGATION)
+                        .setFilterData(filterMapJson.toString())
+                        .build();
+        Trigger trigger = TriggerFixture.getValidTrigger();
+        FilterMap filterMap = source.getFilterData(trigger);
+        assertThat(filterMap.getAttributionFilterMapWithLongValue())
+                .containsExactly(
+                        "conversion",
+                        FilterValue.ofStringList(List.of("electronics")),
+                        "product",
+                        FilterValue.ofStringList(List.of("1234", "2345")),
+                        "source_type",
+                        FilterValue.ofStringList(List.of("navigation")),
+                        FilterMap.LOOKBACK_WINDOW,
+                        FilterValue.ofLong(8640000L));
+    }
+
+    @Test
+    public void testGetFilterData_nullFilterData() throws JSONException {
         Source source =
                 SourceFixture.getMinimalValidSourceBuilder()
                         .setSourceType(Source.SourceType.EVENT)
@@ -841,7 +907,7 @@
     }
 
     @Test
-    public void testParseFilterData_emptyFilterData() throws JSONException {
+    public void testGetFilterData_emptyFilterData() throws JSONException {
         Source source =
                 SourceFixture.getMinimalValidSourceBuilder()
                         .setSourceType(Source.SourceType.EVENT)