• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.server.adservices.data.topics;
18 
19 import static com.android.server.adservices.data.topics.TopicsTables.DUMMY_MODEL_VERSION;
20 
21 import android.adservices.topics.Topic;
22 import android.annotation.NonNull;
23 import android.content.ContentValues;
24 import android.content.Context;
25 import android.database.Cursor;
26 import android.database.SQLException;
27 import android.database.sqlite.SQLiteDatabase;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.server.adservices.LogUtil;
31 
32 import java.io.PrintWriter;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Objects;
36 import java.util.Set;
37 
38 /**
39  * Data Access Object for the Topics API in adservices system service.
40  *
41  * @hide
42  */
43 public class TopicsDao {
44     private static final Object LOCK = new Object();
45     private static TopicsDao sSingleton;
46 
47     private final TopicsDbHelper mTopicsDbHelper;
48 
49     /**
50      * It's only public to unit test.
51      *
52      * @param topicsDbHelper The database to query
53      */
54     @VisibleForTesting
TopicsDao(TopicsDbHelper topicsDbHelper)55     public TopicsDao(TopicsDbHelper topicsDbHelper) {
56         mTopicsDbHelper = topicsDbHelper;
57     }
58 
59     /** Returns an instance of the TopicsDAO given a context. */
60     @NonNull
getInstance(@onNull Context context)61     public static TopicsDao getInstance(@NonNull Context context) {
62         synchronized (LOCK) {
63             if (sSingleton == null) {
64                 sSingleton = new TopicsDao(TopicsDbHelper.getInstance(context));
65             }
66             return sSingleton;
67         }
68     }
69 
70     /**
71      * Record {@link Topic} which should be blocked to a specific user.
72      *
73      * @param topics {@link Topic}s to block.
74      * @param userIdentifier the user id to record the blocked topic
75      */
recordBlockedTopic(@onNull List<Topic> topics, int userIdentifier)76     public void recordBlockedTopic(@NonNull List<Topic> topics, int userIdentifier) {
77         Objects.requireNonNull(topics);
78         SQLiteDatabase db = mTopicsDbHelper.safeGetWritableDatabase();
79         if (db == null) {
80             return;
81         }
82 
83         for (Topic topic : topics) {
84             // Create a new map of values, where column names are the keys
85             ContentValues values = new ContentValues();
86             values.put(TopicsTables.BlockedTopicsContract.TOPIC, topic.getTopicId());
87             values.put(
88                     TopicsTables.BlockedTopicsContract.TAXONOMY_VERSION,
89                     topic.getTaxonomyVersion());
90             values.put(TopicsTables.BlockedTopicsContract.USER, userIdentifier);
91 
92             try {
93                 db.insert(
94                         TopicsTables.BlockedTopicsContract.TABLE, /* nullColumnHack */
95                         null,
96                         values);
97             } catch (SQLException e) {
98                 LogUtil.e("Failed to record blocked topic." + e.getMessage());
99             }
100         }
101     }
102 
103     /**
104      * Remove blocked {@link Topic}.
105      *
106      * @param topic blocked {@link Topic} to remove.
107      * @param userIdentifier the user id to remove the blocked topic
108      */
removeBlockedTopic(@onNull Topic topic, int userIdentifier)109     public void removeBlockedTopic(@NonNull Topic topic, int userIdentifier) {
110         Objects.requireNonNull(topic);
111         SQLiteDatabase db = mTopicsDbHelper.safeGetWritableDatabase();
112         if (db == null) {
113             return;
114         }
115 
116         // Where statement for: topics, taxonomyVersion
117         String whereClause =
118                 TopicsTables.BlockedTopicsContract.USER
119                         + " = ?"
120                         + " AND "
121                         + TopicsTables.BlockedTopicsContract.TOPIC
122                         + " = ?"
123                         + " AND "
124                         + TopicsTables.BlockedTopicsContract.TAXONOMY_VERSION
125                         + " = ?";
126         String[] whereArgs = {
127             String.valueOf(userIdentifier),
128             String.valueOf(topic.getTopicId()),
129             String.valueOf(topic.getTaxonomyVersion())
130         };
131 
132         try {
133             db.delete(TopicsTables.BlockedTopicsContract.TABLE, whereClause, whereArgs);
134         } catch (SQLException e) {
135             LogUtil.e("Failed to remove blocked topic." + e.getMessage());
136         }
137     }
138 
139     /**
140      * Get a {@link List} of {@link Topic}s which are blocked.
141      *
142      * @param userIdentifier the user id to get all blocked topics
143      * @return {@link List} a {@link List} of blocked {@link Topic}s.
144      */
145     @NonNull
retrieveAllBlockedTopics(int userIdentifier)146     public Set<Topic> retrieveAllBlockedTopics(int userIdentifier) {
147         SQLiteDatabase db = mTopicsDbHelper.safeGetReadableDatabase();
148         Set<Topic> blockedTopics = new HashSet<>();
149         if (db == null) {
150             return blockedTopics;
151         }
152 
153         String selection = TopicsTables.BlockedTopicsContract.USER + " = ?";
154         String[] selectionArgs = {String.valueOf(userIdentifier)};
155 
156         try (Cursor cursor =
157                 db.query(
158                         /* distinct= */ true,
159                         TopicsTables.BlockedTopicsContract.TABLE, // The table to query
160                         null, // Get all columns (null for all)
161                         selection,
162                         selectionArgs,
163                         null, // Don't group the rows
164                         null, // Don't filter by row groups
165                         null, // don't sort
166                         null // don't limit
167                         )) {
168             while (cursor.moveToNext()) {
169                 long taxonomyVersion =
170                         cursor.getLong(
171                                 cursor.getColumnIndexOrThrow(
172                                         TopicsTables.BlockedTopicsContract.TAXONOMY_VERSION));
173                 int topicInt =
174                         cursor.getInt(
175                                 cursor.getColumnIndexOrThrow(
176                                         TopicsTables.BlockedTopicsContract.TOPIC));
177                 Topic topic = new Topic(taxonomyVersion, DUMMY_MODEL_VERSION, topicInt);
178 
179                 blockedTopics.add(topic);
180             }
181         }
182 
183         return blockedTopics;
184     }
185 
186     /**
187      * Delete all blocked topics that belongs to a user.
188      *
189      * @param userIdentifier the user id to delete data for
190      */
clearAllBlockedTopicsOfUser(int userIdentifier)191     public void clearAllBlockedTopicsOfUser(int userIdentifier) {
192         SQLiteDatabase db = mTopicsDbHelper.safeGetWritableDatabase();
193         if (db == null) {
194             return;
195         }
196 
197         String whereClause = TopicsTables.BlockedTopicsContract.USER + " = ?";
198         String[] whereArgs = {
199             String.valueOf(userIdentifier),
200         };
201 
202         try {
203             db.delete(TopicsTables.BlockedTopicsContract.TABLE, whereClause, whereArgs);
204         } catch (SQLException e) {
205             LogUtil.e("Failed to remove all blocked topics." + e.getMessage());
206         }
207     }
208 
209     /** Dumps its internal state. */
dump(PrintWriter writer, String prefix, String[] args)210     public void dump(PrintWriter writer, String prefix, String[] args) {
211         mTopicsDbHelper.dump(writer, prefix, args);
212     }
213 }
214