1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.adservices.service.customaudience;
18 
19 import static android.adservices.common.AdFilters.APP_INSTALL_FIELD_NAME;
20 import static android.adservices.common.AdFilters.FREQUENCY_CAP_FIELD_NAME;
21 
22 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.AD_COUNTERS_KEY;
23 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.AD_FILTERS_KEY;
24 
25 import android.adservices.common.AdFilters;
26 import android.adservices.common.AppInstallFilters;
27 import android.adservices.common.FrequencyCapFilters;
28 
29 import com.android.adservices.LoggerFactory;
30 import com.android.adservices.data.common.DBAdData;
31 
32 import org.json.JSONArray;
33 import org.json.JSONException;
34 import org.json.JSONObject;
35 
36 import java.util.HashSet;
37 import java.util.Set;
38 /** Factory for ReadFiltersFromJsonStrategys */
39 public class ReadFiltersFromJsonStrategyFactory {
40     private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger();
41 
42     private static class FilteringEnabledStrategy implements ReadFiltersFromJsonStrategy {
43         private final ReadFrequencyCapFiltersFromJsonStrategy
44                 mReadFrequencyCapFiltersFromJsonStrategy;
45         private final ReadAppInstallFiltersFromJsonStrategy mReadAppInstallFiltersFromJsonStrategy;
46 
FilteringEnabledStrategy( boolean frequencyCapFilteringEnabled, boolean appInstallFilteringEnabled)47         FilteringEnabledStrategy(
48                 boolean frequencyCapFilteringEnabled, boolean appInstallFilteringEnabled) {
49             if (frequencyCapFilteringEnabled) {
50                 mReadFrequencyCapFiltersFromJsonStrategy =
51                         new FrequencyCapFilteringEnabledStrategy();
52             } else {
53                 mReadFrequencyCapFiltersFromJsonStrategy =
54                         new FrequencyCapFilteringDisabledStrategy();
55             }
56 
57             if (appInstallFilteringEnabled) {
58                 mReadAppInstallFiltersFromJsonStrategy = new AppInstallFilteringEnabledStrategy();
59             } else {
60                 mReadAppInstallFiltersFromJsonStrategy = new AppInstallFilteringDisabledStrategy();
61             }
62         }
63 
64         /**
65          * Adds filtering fields to the provided AdData builder.
66          *
67          * @param adDataBuilder the AdData builder to modify.
68          * @param adDataJsonObj the AdData JSON to extract from
69          * @throws JSONException if the key is found but the schema is incorrect
70          * @throws NullPointerException if the key found by the field is null
71          */
72         @Override
readFilters(DBAdData.Builder adDataBuilder, JSONObject adDataJsonObj)73         public void readFilters(DBAdData.Builder adDataBuilder, JSONObject adDataJsonObj)
74                 throws JSONException, NullPointerException, IllegalArgumentException {
75             mReadFrequencyCapFiltersFromJsonStrategy.readAdCounterKeys(
76                     adDataJsonObj, adDataBuilder);
77             AdFilters adFilters = null;
78             if (adDataJsonObj.has(AD_FILTERS_KEY)) {
79                 AdFilters.Builder builder = new AdFilters.Builder();
80                 JSONObject adFiltersObject = adDataJsonObj.getJSONObject(AD_FILTERS_KEY);
81                 mReadFrequencyCapFiltersFromJsonStrategy.readFrequencyCapFilters(
82                         adFiltersObject, builder);
83                 mReadAppInstallFiltersFromJsonStrategy.readAppInstallFilters(
84                         adFiltersObject, builder);
85                 adFilters = builder.build();
86             }
87             adDataBuilder.setAdFilters(adFilters);
88         }
89     }
90 
91     private static class FilteringDisabledStrategy implements ReadFiltersFromJsonStrategy {
92         /**
93          * Does nothing.
94          *
95          * @param adDataBuilder unused
96          * @param adDataJsonObj unused
97          */
98         @Override
readFilters(DBAdData.Builder adDataBuilder, JSONObject adDataJsonObj)99         public void readFilters(DBAdData.Builder adDataBuilder, JSONObject adDataJsonObj) {}
100     }
101 
102     private static class FrequencyCapFilteringEnabledStrategy
103             implements ReadFrequencyCapFiltersFromJsonStrategy {
104 
105         @Override
readAdCounterKeys(JSONObject json, DBAdData.Builder adDataBuilder)106         public void readAdCounterKeys(JSONObject json, DBAdData.Builder adDataBuilder)
107                 throws JSONException {
108             Set<Integer> adCounterKeys = new HashSet<>();
109             if (json.has(AD_COUNTERS_KEY)) {
110                 JSONArray counterKeys = json.getJSONArray(AD_COUNTERS_KEY);
111                 for (int i = 0; i < counterKeys.length(); i++) {
112                     adCounterKeys.add(counterKeys.getInt(i));
113                 }
114             }
115             adDataBuilder.setAdCounterKeys(adCounterKeys);
116         }
117 
118         @Override
readFrequencyCapFilters(JSONObject json, AdFilters.Builder builder)119         public void readFrequencyCapFilters(JSONObject json, AdFilters.Builder builder)
120                 throws JSONException {
121             if (json.has(FREQUENCY_CAP_FIELD_NAME)) {
122                 builder.setFrequencyCapFilters(
123                         FrequencyCapFilters.fromJson(json.getJSONObject(FREQUENCY_CAP_FIELD_NAME)));
124             }
125         }
126     }
127 
128     private static class FrequencyCapFilteringDisabledStrategy
129             implements ReadFrequencyCapFiltersFromJsonStrategy {
130 
131         @Override
readAdCounterKeys(JSONObject json, DBAdData.Builder adDataBuilder)132         public void readAdCounterKeys(JSONObject json, DBAdData.Builder adDataBuilder)
133                 throws JSONException {
134             sLogger.v("Frequency cap filtering is disabled, reading fcap filters is a no op");
135         }
136 
137         @Override
readFrequencyCapFilters(JSONObject json, AdFilters.Builder builder)138         public void readFrequencyCapFilters(JSONObject json, AdFilters.Builder builder)
139                 throws JSONException {
140             sLogger.v("Frequency cap filtering is disabled, reading fcap filters is a no op");
141         }
142     }
143 
144     private static class AppInstallFilteringEnabledStrategy
145             implements ReadAppInstallFiltersFromJsonStrategy {
146 
147         @Override
readAppInstallFilters(JSONObject json, AdFilters.Builder builder)148         public void readAppInstallFilters(JSONObject json, AdFilters.Builder builder)
149                 throws JSONException {
150             if (json.has(APP_INSTALL_FIELD_NAME)) {
151                 builder.setAppInstallFilters(
152                         AppInstallFilters.fromJson(json.getJSONObject(APP_INSTALL_FIELD_NAME)));
153             }
154         }
155     }
156 
157     private static class AppInstallFilteringDisabledStrategy
158             implements ReadAppInstallFiltersFromJsonStrategy {
159 
160         @Override
readAppInstallFilters(JSONObject json, AdFilters.Builder builder)161         public void readAppInstallFilters(JSONObject json, AdFilters.Builder builder)
162                 throws JSONException {
163             sLogger.v("App install filtering is disabled, reading app install filters is a no op");
164         }
165     }
166 
167     /**
168      * Returns the appropriate ReadFiltersFromJsonStrategy based whether filtering is enabled
169      *
170      * @param frequencyCapFilteringEnabled Should be true if frequency cap filtering is enabled.
171      * @param appInstallFilteringEnabled Should be true if app install filtering is enabled.
172      * @return An implementation of ReadFiltersFromJsonStrategy
173      */
getStrategy( boolean frequencyCapFilteringEnabled, boolean appInstallFilteringEnabled)174     public static ReadFiltersFromJsonStrategy getStrategy(
175             boolean frequencyCapFilteringEnabled, boolean appInstallFilteringEnabled) {
176         if (frequencyCapFilteringEnabled || appInstallFilteringEnabled) {
177             return new FilteringEnabledStrategy(
178                     frequencyCapFilteringEnabled, appInstallFilteringEnabled);
179         }
180         return new FilteringDisabledStrategy();
181     }
182 }
183