1 /* 2 * Copyright (C) 2024 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.providers.media.photopicker.v2.sqlite; 18 19 import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE; 20 21 import static com.android.providers.media.photopicker.data.PickerDbFacade.KEY_DATE_TAKEN_MS; 22 import static com.android.providers.media.photopicker.data.PickerDbFacade.KEY_DURATION_MS; 23 import static com.android.providers.media.photopicker.data.PickerDbFacade.KEY_ID; 24 import static com.android.providers.media.photopicker.data.PickerDbFacade.KEY_MIME_TYPE; 25 import static com.android.providers.media.photopicker.data.PickerDbFacade.KEY_SIZE_BYTES; 26 import static com.android.providers.media.photopicker.data.PickerDbFacade.KEY_STANDARD_MIME_TYPE_EXTENSION; 27 28 import static java.util.Objects.requireNonNull; 29 30 import android.provider.CloudMediaProviderContract; 31 32 import androidx.annotation.NonNull; 33 import androidx.annotation.Nullable; 34 import androidx.annotation.VisibleForTesting; 35 36 import java.util.Arrays; 37 import java.util.Objects; 38 39 /** 40 * Helper class that keeps track of Picker related Constants. 41 */ 42 public class PickerSQLConstants { 43 public static final int DEFAULT_SEARCH_SUGGESTIONS_LIMIT = 50; 44 public static final int DEFAULT_SEARCH_HISTORY_SUGGESTIONS_LIMIT = 3; 45 public static String EXTRA_SEARCH_REQUEST_ID = "search_request_id"; 46 public static String EXTRA_SEARCH_PROVIDER_AUTHORITIES = "search_provider_authorities"; 47 static final String COUNT_COLUMN = "Count"; 48 49 /** 50 * An enum that holds the table names in Picker DB 51 */ 52 public enum Table { 53 MEDIA, 54 ALBUM_MEDIA, 55 SEARCH_REQUEST, 56 SEARCH_RESULT_MEDIA, 57 SEARCH_HISTORY, 58 SEARCH_SUGGESTION, 59 MEDIA_SETS, 60 MEDIA_IN_MEDIA_SETS 61 } 62 63 /** 64 * An enum that holds the columns names for the Available Providers query response. 65 */ 66 public enum AvailableProviderResponse { 67 AUTHORITY("authority"), 68 MEDIA_SOURCE("media_source"), 69 UID("uid"), 70 DISPLAY_NAME("display_name"); 71 72 private final String mColumnName; 73 AvailableProviderResponse(String columnName)74 AvailableProviderResponse(String columnName) { 75 this.mColumnName = columnName; 76 } 77 getColumnName()78 public String getColumnName() { 79 return mColumnName; 80 } 81 } 82 83 public enum CollectionInfoResponse { 84 AUTHORITY("authority"), 85 COLLECTION_ID("collection_id"), 86 ACCOUNT_NAME("account_name"); 87 88 private final String mColumnName; 89 CollectionInfoResponse(String columnName)90 CollectionInfoResponse(String columnName) { 91 this.mColumnName = columnName; 92 } 93 getColumnName()94 public String getColumnName() { 95 return mColumnName; 96 } 97 } 98 99 /** 100 * An enum that holds the DB columns names and projections for the Album SQL query response. 101 */ 102 public enum AlbumResponse { 103 ALBUM_ID(CloudMediaProviderContract.AlbumColumns.ID), 104 PICKER_ID("picker_id"), 105 AUTHORITY("authority"), 106 DATE_TAKEN(CloudMediaProviderContract.AlbumColumns.DATE_TAKEN_MILLIS), 107 ALBUM_NAME(CloudMediaProviderContract.AlbumColumns.DISPLAY_NAME), 108 UNWRAPPED_COVER_URI("unwrapped_cover_uri"), 109 COVER_MEDIA_SOURCE("media_source"); 110 111 private final String mColumnName; 112 AlbumResponse(@onNull String columnName)113 AlbumResponse(@NonNull String columnName) { 114 requireNonNull(columnName); 115 this.mColumnName = columnName; 116 } 117 getColumnName()118 public String getColumnName() { 119 return mColumnName; 120 } 121 } 122 123 /** 124 * @param columnName Input album column name. 125 * @return Corresponding enum AlbumResponse to the given column name. 126 * @throws IllegalArgumentException if the column name does not correspond to a AlbumResponse 127 * enum. 128 */ mapColumnNameToAlbumResponseColumn(String columnName)129 public static AlbumResponse mapColumnNameToAlbumResponseColumn(String columnName) 130 throws IllegalArgumentException { 131 for (AlbumResponse albumResponseColumn : AlbumResponse.values()) { 132 if (albumResponseColumn.getColumnName().equalsIgnoreCase(columnName)) { 133 return albumResponseColumn; 134 } 135 } 136 throw new IllegalArgumentException(columnName + " does not exist. Available data: " 137 + Arrays.toString(PickerSQLConstants.AlbumResponse.values())); 138 } 139 140 /** 141 * An enum that holds the DB columns names and projected names for the Media SQL query response. 142 */ 143 public enum MediaResponse { 144 MEDIA_ID(CloudMediaProviderContract.MediaColumns.ID), 145 AUTHORITY(CloudMediaProviderContract.MediaColumns.AUTHORITY), 146 MEDIA_SOURCE("media_source"), 147 WRAPPED_URI("wrapped_uri"), 148 UNWRAPPED_URI("unwrapped_uri"), 149 PICKER_ID(KEY_ID, "picker_id"), 150 DATE_TAKEN_MS(KEY_DATE_TAKEN_MS, CloudMediaProviderContract.MediaColumns.DATE_TAKEN_MILLIS), 151 SIZE_IN_BYTES(KEY_SIZE_BYTES, CloudMediaProviderContract.MediaColumns.SIZE_BYTES), 152 MIME_TYPE(KEY_MIME_TYPE, CloudMediaProviderContract.MediaColumns.MIME_TYPE), 153 STANDARD_MIME_TYPE(KEY_STANDARD_MIME_TYPE_EXTENSION, 154 CloudMediaProviderContract.MediaColumns.STANDARD_MIME_TYPE_EXTENSION), 155 DURATION_MS(KEY_DURATION_MS, CloudMediaProviderContract.MediaColumns.DURATION_MILLIS), 156 IS_PRE_GRANTED("is_pre_granted"); 157 158 @Nullable 159 private final String mColumnName; 160 @NonNull 161 private final String mProjectedName; 162 MediaResponse(@onNull String dbColumnName, @NonNull String projectedName)163 MediaResponse(@NonNull String dbColumnName, @NonNull String projectedName) { 164 this.mColumnName = dbColumnName; 165 this.mProjectedName = projectedName; 166 } 167 MediaResponse(@onNull String projectedName)168 MediaResponse(@NonNull String projectedName) { 169 this.mColumnName = null; 170 this.mProjectedName = projectedName; 171 } 172 173 @Nullable getColumnName()174 public String getColumnName() { 175 return mColumnName; 176 } 177 178 @NonNull getProjectedName()179 public String getProjectedName() { 180 return mProjectedName; 181 } 182 } 183 184 public enum MediaResponseExtras { 185 PREV_PAGE_ID("prev_page_picker_id"), 186 PREV_PAGE_DATE_TAKEN("prev_page_date_taken"), 187 NEXT_PAGE_ID("next_page_picker_id"), 188 NEXT_PAGE_DATE_TAKEN("next_page_date_taken"), 189 ITEMS_BEFORE_COUNT("items_before_count"); 190 191 private final String mKey; 192 MediaResponseExtras(String key)193 MediaResponseExtras(String key) { 194 mKey = key; 195 } 196 getKey()197 public String getKey() { 198 return mKey; 199 } 200 } 201 202 public enum SearchRequestTableColumns { 203 SEARCH_REQUEST_ID("_id"), 204 LOCAL_SYNC_RESUME_KEY("local_sync_resume_key"), 205 LOCAL_AUTHORITY("local_authority"), 206 CLOUD_SYNC_RESUME_KEY("cloud_sync_resume_key"), 207 CLOUD_AUTHORITY("cloud_authority"), 208 SEARCH_TEXT("search_text"), 209 MEDIA_SET_ID("media_set_id"), 210 SUGGESTION_TYPE("suggestion_type"), 211 SUGGESTION_AUTHORITY("suggestion_authority"), 212 MIME_TYPES("mime_types"); 213 214 private final String mColumnName; 215 SearchRequestTableColumns(@onNull String columnName)216 SearchRequestTableColumns(@NonNull String columnName) { 217 mColumnName = columnName; 218 } 219 getColumnName()220 public String getColumnName() { 221 return mColumnName; 222 } 223 } 224 225 @VisibleForTesting(otherwise = PACKAGE_PRIVATE) 226 public enum SearchResultMediaTableColumns { 227 PICKER_ID("_id"), 228 SEARCH_REQUEST_ID("search_request_id"), 229 LOCAL_ID("local_id"), 230 CLOUD_ID("cloud_id"); 231 232 private final String mColumnName; 233 SearchResultMediaTableColumns(@onNull String columnName)234 SearchResultMediaTableColumns(@NonNull String columnName) { 235 mColumnName = columnName; 236 } 237 getColumnName()238 public String getColumnName() { 239 return mColumnName; 240 } 241 } 242 243 244 @VisibleForTesting(otherwise = PACKAGE_PRIVATE) 245 public enum SearchHistoryTableColumns { 246 PICKER_ID("_id"), 247 AUTHORITY("authority"), 248 SEARCH_TEXT("search_text"), 249 MEDIA_SET_ID("media_set_id"), 250 COVER_MEDIA_ID("cover_media_id"), 251 CREATION_TIME_MS("creation_time_ms"); 252 253 private final String mColumnName; 254 SearchHistoryTableColumns(@onNull String columnName)255 SearchHistoryTableColumns(@NonNull String columnName) { 256 mColumnName = columnName; 257 } 258 getColumnName()259 public String getColumnName() { 260 return mColumnName; 261 } 262 } 263 264 @VisibleForTesting(otherwise = PACKAGE_PRIVATE) 265 public enum SearchSuggestionsTableColumns { 266 PICKER_ID("_id"), 267 AUTHORITY("authority"), 268 SEARCH_TEXT("search_text"), 269 MEDIA_SET_ID("media_set_id"), 270 COVER_MEDIA_ID("cover_media_id"), 271 SUGGESTION_TYPE("suggestion_type"), 272 CREATION_TIME_MS("creation_time_ms"); 273 274 private final String mColumnName; 275 SearchSuggestionsTableColumns(@onNull String columnName)276 SearchSuggestionsTableColumns(@NonNull String columnName) { 277 mColumnName = columnName; 278 } 279 getColumnName()280 public String getColumnName() { 281 return mColumnName; 282 } 283 } 284 285 public enum MediaSetsTableColumns { 286 PICKER_ID("_id"), 287 CATEGORY_ID("category_id"), 288 MEDIA_SET_ID("media_set_id"), 289 DISPLAY_NAME("display_name"), 290 COVER_ID("cover_id"), 291 MEDIA_SET_AUTHORITY("media_set_authority"), 292 MIME_TYPE_FILTER("mime_type_filter"), 293 MEDIA_IN_MEDIA_SET_SYNC_RESUME_KEY("media_in_media_set_sync_resume_key"); 294 295 private final String mColumnName; 296 MediaSetsTableColumns(@onNull String columnName)297 MediaSetsTableColumns(@NonNull String columnName) { 298 Objects.requireNonNull(columnName); 299 mColumnName = columnName; 300 } 301 getColumnName()302 public String getColumnName() { 303 return mColumnName; 304 } 305 } 306 307 308 public enum SearchSuggestionsResponseColumns { 309 AUTHORITY("authority"), 310 MEDIA_SET_ID("media_set_id"), 311 SEARCH_TEXT("display_text"), 312 COVER_MEDIA_URI("cover_media_uri"), 313 SUGGESTION_TYPE("suggestion_type"); 314 315 private final String mProjection; 316 SearchSuggestionsResponseColumns(@onNull String projection)317 SearchSuggestionsResponseColumns(@NonNull String projection) { 318 mProjection = projection; 319 } 320 getProjection()321 public String getProjection() { 322 return mProjection; 323 } 324 } 325 326 public enum MediaInMediaSetsTableColumns { 327 PICKER_ID("_id"), 328 LOCAL_ID("local_id"), 329 CLOUD_ID("cloud_id"), 330 MEDIA_SETS_PICKER_ID("media_set_picker_id"); 331 332 private final String mColumnName; 333 MediaInMediaSetsTableColumns(@onNull String columnName)334 MediaInMediaSetsTableColumns(@NonNull String columnName) { 335 Objects.requireNonNull(columnName); 336 mColumnName = columnName; 337 } 338 getColumnName()339 public String getColumnName() { 340 return mColumnName; 341 } 342 } 343 344 public enum MediaGroupResponseColumns { 345 /** Type of media group - Album, Category or MediaSet. This cannot be null. */ 346 MEDIA_GROUP("media_group"), 347 /** Identifier received from CMP. This cannot be null. */ 348 GROUP_ID("group_id"), 349 /** Identifier used in Picker Backend, if any. */ 350 PICKER_ID("picker_id"), 351 /** Display name for the group, if any. */ 352 DISPLAY_NAME("display_name"), 353 /** Source provider's authority. */ 354 AUTHORITY("authority"), 355 /** Cover image Uri for the group. */ 356 UNWRAPPED_COVER_URI("unwrapped_cover_uri"), 357 /** Additional cover image Uri for the category. */ 358 ADDITIONAL_UNWRAPPED_COVER_URI_1("additional_cover_uri_1"), 359 /** Additional cover image Uri for the category. */ 360 ADDITIONAL_UNWRAPPED_COVER_URI_2("additional_cover_uri_2"), 361 /** Additional cover image Uri for the category. */ 362 ADDITIONAL_UNWRAPPED_COVER_URI_3("additional_cover_uri_3"), 363 /** If the media group is category, this will be populated with the category type. */ 364 CATEGORY_TYPE("category_type"), 365 /** True, if the media category is leaf category which contains media sets, 366 * otherwise false. */ 367 IS_LEAF_CATEGORY("is_leaf_category"); 368 369 private final String mColumnName; 370 MediaGroupResponseColumns(@onNull String columnName)371 MediaGroupResponseColumns(@NonNull String columnName) { 372 Objects.requireNonNull(columnName); 373 mColumnName = columnName; 374 } 375 getColumnName()376 public String getColumnName() { 377 return mColumnName; 378 } 379 } 380 } 381