blob: f9f4c5dc0d6252450ef8e18fb777d5e48a1720d5 [file] [log] [blame]
Alan Viverette3da604b2020-06-10 18:34:39 +00001/*
2 * Copyright (C) 2007 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
17package android.content;
18
19import android.annotation.Nullable;
20import android.compat.annotation.UnsupportedAppUsage;
21import android.os.Parcel;
22import android.os.Parcelable;
23import android.util.ArrayMap;
24import android.util.Log;
25
26import com.android.internal.util.Preconditions;
27
28import java.util.ArrayList;
29import java.util.HashMap;
30import java.util.Map;
31import java.util.Objects;
32import java.util.Set;
33
34/**
35 * This class is used to store a set of values that the {@link ContentResolver}
36 * can process.
37 */
38public final class ContentValues implements Parcelable {
39 public static final String TAG = "ContentValues";
40
41 /**
42 * @hide
43 * @deprecated kept around for lame people doing reflection
44 */
45 @Deprecated
46 @UnsupportedAppUsage
47 private HashMap<String, Object> mValues;
48
49 private final ArrayMap<String, Object> mMap;
50
51 /**
52 * Creates an empty set of values using the default initial size
53 */
54 public ContentValues() {
55 mMap = new ArrayMap<>();
56 }
57
58 /**
59 * Creates an empty set of values using the given initial size
60 *
61 * @param size the initial size of the set of values
62 */
63 public ContentValues(int size) {
64 Preconditions.checkArgumentNonnegative(size);
65 mMap = new ArrayMap<>(size);
66 }
67
68 /**
69 * Creates a set of values copied from the given set
70 *
71 * @param from the values to copy
72 */
73 public ContentValues(ContentValues from) {
74 Objects.requireNonNull(from);
75 mMap = new ArrayMap<>(from.mMap);
76 }
77
78 /**
79 * @hide
80 * @deprecated kept around for lame people doing reflection
81 */
82 @Deprecated
83 @UnsupportedAppUsage
84 private ContentValues(HashMap<String, Object> from) {
85 mMap = new ArrayMap<>();
86 mMap.putAll(from);
87 }
88
89 /** {@hide} */
90 private ContentValues(Parcel in) {
91 mMap = new ArrayMap<>(in.readInt());
92 in.readArrayMap(mMap, null);
93 }
94
95 @Override
96 public boolean equals(Object object) {
97 if (!(object instanceof ContentValues)) {
98 return false;
99 }
100 return mMap.equals(((ContentValues) object).mMap);
101 }
102
103 /** {@hide} */
104 public ArrayMap<String, Object> getValues() {
105 return mMap;
106 }
107
108 @Override
109 public int hashCode() {
110 return mMap.hashCode();
111 }
112
113 /**
114 * Adds a value to the set.
115 *
116 * @param key the name of the value to put
117 * @param value the data for the value to put
118 */
119 public void put(String key, String value) {
120 mMap.put(key, value);
121 }
122
123 /**
124 * Adds all values from the passed in ContentValues.
125 *
126 * @param other the ContentValues from which to copy
127 */
128 public void putAll(ContentValues other) {
129 mMap.putAll(other.mMap);
130 }
131
132 /**
133 * Adds a value to the set.
134 *
135 * @param key the name of the value to put
136 * @param value the data for the value to put
137 */
138 public void put(String key, Byte value) {
139 mMap.put(key, value);
140 }
141
142 /**
143 * Adds a value to the set.
144 *
145 * @param key the name of the value to put
146 * @param value the data for the value to put
147 */
148 public void put(String key, Short value) {
149 mMap.put(key, value);
150 }
151
152 /**
153 * Adds a value to the set.
154 *
155 * @param key the name of the value to put
156 * @param value the data for the value to put
157 */
158 public void put(String key, Integer value) {
159 mMap.put(key, value);
160 }
161
162 /**
163 * Adds a value to the set.
164 *
165 * @param key the name of the value to put
166 * @param value the data for the value to put
167 */
168 public void put(String key, Long value) {
169 mMap.put(key, value);
170 }
171
172 /**
173 * Adds a value to the set.
174 *
175 * @param key the name of the value to put
176 * @param value the data for the value to put
177 */
178 public void put(String key, Float value) {
179 mMap.put(key, value);
180 }
181
182 /**
183 * Adds a value to the set.
184 *
185 * @param key the name of the value to put
186 * @param value the data for the value to put
187 */
188 public void put(String key, Double value) {
189 mMap.put(key, value);
190 }
191
192 /**
193 * Adds a value to the set.
194 *
195 * @param key the name of the value to put
196 * @param value the data for the value to put
197 */
198 public void put(String key, Boolean value) {
199 mMap.put(key, value);
200 }
201
202 /**
203 * Adds a value to the set.
204 *
205 * @param key the name of the value to put
206 * @param value the data for the value to put
207 */
208 public void put(String key, byte[] value) {
209 mMap.put(key, value);
210 }
211
212 /**
213 * Adds a null value to the set.
214 *
215 * @param key the name of the value to make null
216 */
217 public void putNull(String key) {
218 mMap.put(key, null);
219 }
220
221 /** {@hide} */
222 public void putObject(@Nullable String key, @Nullable Object value) {
223 if (value == null) {
224 putNull(key);
225 } else if (value instanceof String) {
226 put(key, (String) value);
227 } else if (value instanceof Byte) {
228 put(key, (Byte) value);
229 } else if (value instanceof Short) {
230 put(key, (Short) value);
231 } else if (value instanceof Integer) {
232 put(key, (Integer) value);
233 } else if (value instanceof Long) {
234 put(key, (Long) value);
235 } else if (value instanceof Float) {
236 put(key, (Float) value);
237 } else if (value instanceof Double) {
238 put(key, (Double) value);
239 } else if (value instanceof Boolean) {
240 put(key, (Boolean) value);
241 } else if (value instanceof byte[]) {
242 put(key, (byte[]) value);
243 } else {
244 throw new IllegalArgumentException("Unsupported type " + value.getClass());
245 }
246 }
247
248 /**
249 * Returns the number of values.
250 *
251 * @return the number of values
252 */
253 public int size() {
254 return mMap.size();
255 }
256
257 /**
258 * Indicates whether this collection is empty.
259 *
260 * @return true iff size == 0
261 */
262 public boolean isEmpty() {
263 return mMap.isEmpty();
264 }
265
266 /**
267 * Remove a single value.
268 *
269 * @param key the name of the value to remove
270 */
271 public void remove(String key) {
272 mMap.remove(key);
273 }
274
275 /**
276 * Removes all values.
277 */
278 public void clear() {
279 mMap.clear();
280 }
281
282 /**
283 * Returns true if this object has the named value.
284 *
285 * @param key the value to check for
286 * @return {@code true} if the value is present, {@code false} otherwise
287 */
288 public boolean containsKey(String key) {
289 return mMap.containsKey(key);
290 }
291
292 /**
293 * Gets a value. Valid value types are {@link String}, {@link Boolean},
294 * {@link Number}, and {@code byte[]} implementations.
295 *
296 * @param key the value to get
297 * @return the data for the value, or {@code null} if the value is missing or if {@code null}
298 * was previously added with the given {@code key}
299 */
300 public Object get(String key) {
301 return mMap.get(key);
302 }
303
304 /**
305 * Gets a value and converts it to a String.
306 *
307 * @param key the value to get
308 * @return the String for the value
309 */
310 public String getAsString(String key) {
311 Object value = mMap.get(key);
312 return value != null ? value.toString() : null;
313 }
314
315 /**
316 * Gets a value and converts it to a Long.
317 *
318 * @param key the value to get
319 * @return the Long value, or {@code null} if the value is missing or cannot be converted
320 */
321 public Long getAsLong(String key) {
322 Object value = mMap.get(key);
323 try {
324 return value != null ? ((Number) value).longValue() : null;
325 } catch (ClassCastException e) {
326 if (value instanceof CharSequence) {
327 try {
328 return Long.valueOf(value.toString());
329 } catch (NumberFormatException e2) {
330 Log.e(TAG, "Cannot parse Long value for " + value + " at key " + key);
331 return null;
332 }
333 } else {
334 Log.e(TAG, "Cannot cast value for " + key + " to a Long: " + value, e);
335 return null;
336 }
337 }
338 }
339
340 /**
341 * Gets a value and converts it to an Integer.
342 *
343 * @param key the value to get
344 * @return the Integer value, or {@code null} if the value is missing or cannot be converted
345 */
346 public Integer getAsInteger(String key) {
347 Object value = mMap.get(key);
348 try {
349 return value != null ? ((Number) value).intValue() : null;
350 } catch (ClassCastException e) {
351 if (value instanceof CharSequence) {
352 try {
353 return Integer.valueOf(value.toString());
354 } catch (NumberFormatException e2) {
355 Log.e(TAG, "Cannot parse Integer value for " + value + " at key " + key);
356 return null;
357 }
358 } else {
359 Log.e(TAG, "Cannot cast value for " + key + " to a Integer: " + value, e);
360 return null;
361 }
362 }
363 }
364
365 /**
366 * Gets a value and converts it to a Short.
367 *
368 * @param key the value to get
369 * @return the Short value, or {@code null} if the value is missing or cannot be converted
370 */
371 public Short getAsShort(String key) {
372 Object value = mMap.get(key);
373 try {
374 return value != null ? ((Number) value).shortValue() : null;
375 } catch (ClassCastException e) {
376 if (value instanceof CharSequence) {
377 try {
378 return Short.valueOf(value.toString());
379 } catch (NumberFormatException e2) {
380 Log.e(TAG, "Cannot parse Short value for " + value + " at key " + key);
381 return null;
382 }
383 } else {
384 Log.e(TAG, "Cannot cast value for " + key + " to a Short: " + value, e);
385 return null;
386 }
387 }
388 }
389
390 /**
391 * Gets a value and converts it to a Byte.
392 *
393 * @param key the value to get
394 * @return the Byte value, or {@code null} if the value is missing or cannot be converted
395 */
396 public Byte getAsByte(String key) {
397 Object value = mMap.get(key);
398 try {
399 return value != null ? ((Number) value).byteValue() : null;
400 } catch (ClassCastException e) {
401 if (value instanceof CharSequence) {
402 try {
403 return Byte.valueOf(value.toString());
404 } catch (NumberFormatException e2) {
405 Log.e(TAG, "Cannot parse Byte value for " + value + " at key " + key);
406 return null;
407 }
408 } else {
409 Log.e(TAG, "Cannot cast value for " + key + " to a Byte: " + value, e);
410 return null;
411 }
412 }
413 }
414
415 /**
416 * Gets a value and converts it to a Double.
417 *
418 * @param key the value to get
419 * @return the Double value, or {@code null} if the value is missing or cannot be converted
420 */
421 public Double getAsDouble(String key) {
422 Object value = mMap.get(key);
423 try {
424 return value != null ? ((Number) value).doubleValue() : null;
425 } catch (ClassCastException e) {
426 if (value instanceof CharSequence) {
427 try {
428 return Double.valueOf(value.toString());
429 } catch (NumberFormatException e2) {
430 Log.e(TAG, "Cannot parse Double value for " + value + " at key " + key);
431 return null;
432 }
433 } else {
434 Log.e(TAG, "Cannot cast value for " + key + " to a Double: " + value, e);
435 return null;
436 }
437 }
438 }
439
440 /**
441 * Gets a value and converts it to a Float.
442 *
443 * @param key the value to get
444 * @return the Float value, or {@code null} if the value is missing or cannot be converted
445 */
446 public Float getAsFloat(String key) {
447 Object value = mMap.get(key);
448 try {
449 return value != null ? ((Number) value).floatValue() : null;
450 } catch (ClassCastException e) {
451 if (value instanceof CharSequence) {
452 try {
453 return Float.valueOf(value.toString());
454 } catch (NumberFormatException e2) {
455 Log.e(TAG, "Cannot parse Float value for " + value + " at key " + key);
456 return null;
457 }
458 } else {
459 Log.e(TAG, "Cannot cast value for " + key + " to a Float: " + value, e);
460 return null;
461 }
462 }
463 }
464
465 /**
466 * Gets a value and converts it to a Boolean.
467 *
468 * @param key the value to get
469 * @return the Boolean value, or {@code null} if the value is missing or cannot be converted
470 */
471 public Boolean getAsBoolean(String key) {
472 Object value = mMap.get(key);
473 try {
474 return (Boolean) value;
475 } catch (ClassCastException e) {
476 if (value instanceof CharSequence) {
477 // Note that we also check against 1 here because SQLite's internal representation
478 // for booleans is an integer with a value of 0 or 1. Without this check, boolean
479 // values obtained via DatabaseUtils#cursorRowToContentValues will always return
480 // false.
481 return Boolean.valueOf(value.toString()) || "1".equals(value);
482 } else if (value instanceof Number) {
483 return ((Number) value).intValue() != 0;
484 } else {
485 Log.e(TAG, "Cannot cast value for " + key + " to a Boolean: " + value, e);
486 return null;
487 }
488 }
489 }
490
491 /**
492 * Gets a value that is a byte array. Note that this method will not convert
493 * any other types to byte arrays.
494 *
495 * @param key the value to get
496 * @return the {@code byte[]} value, or {@code null} is the value is missing or not a
497 * {@code byte[]}
498 */
499 public byte[] getAsByteArray(String key) {
500 Object value = mMap.get(key);
501 if (value instanceof byte[]) {
502 return (byte[]) value;
503 } else {
504 return null;
505 }
506 }
507
508 /**
509 * Returns a set of all of the keys and values
510 *
511 * @return a set of all of the keys and values
512 */
513 public Set<Map.Entry<String, Object>> valueSet() {
514 return mMap.entrySet();
515 }
516
517 /**
518 * Returns a set of all of the keys
519 *
520 * @return a set of all of the keys
521 */
522 public Set<String> keySet() {
523 return mMap.keySet();
524 }
525
526 public static final @android.annotation.NonNull Parcelable.Creator<ContentValues> CREATOR =
527 new Parcelable.Creator<ContentValues>() {
528 @Override
529 public ContentValues createFromParcel(Parcel in) {
530 return new ContentValues(in);
531 }
532
533 @Override
534 public ContentValues[] newArray(int size) {
535 return new ContentValues[size];
536 }
537 };
538
539 @Override
540 public int describeContents() {
541 return 0;
542 }
543
544 @Override
545 public void writeToParcel(Parcel parcel, int flags) {
546 parcel.writeInt(mMap.size());
547 parcel.writeArrayMap(mMap);
548 }
549
550 /**
551 * Unsupported, here until we get proper bulk insert APIs.
552 * {@hide}
553 */
554 @Deprecated
555 @UnsupportedAppUsage
556 public void putStringArrayList(String key, ArrayList<String> value) {
557 mMap.put(key, value);
558 }
559
560 /**
561 * Unsupported, here until we get proper bulk insert APIs.
562 * {@hide}
563 */
564 @SuppressWarnings("unchecked")
565 @Deprecated
566 @UnsupportedAppUsage
567 public ArrayList<String> getStringArrayList(String key) {
568 return (ArrayList<String>) mMap.get(key);
569 }
570
571 /**
572 * Returns a string containing a concise, human-readable description of this object.
573 * @return a printable representation of this object.
574 */
575 @Override
576 public String toString() {
577 StringBuilder sb = new StringBuilder();
578 for (String name : mMap.keySet()) {
579 String value = getAsString(name);
580 if (sb.length() > 0) sb.append(" ");
581 sb.append(name + "=" + value);
582 }
583 return sb.toString();
584 }
585
586 /** {@hide} */
587 public static boolean isSupportedValue(Object value) {
588 if (value == null) {
589 return true;
590 } else if (value instanceof String) {
591 return true;
592 } else if (value instanceof Byte) {
593 return true;
594 } else if (value instanceof Short) {
595 return true;
596 } else if (value instanceof Integer) {
597 return true;
598 } else if (value instanceof Long) {
599 return true;
600 } else if (value instanceof Float) {
601 return true;
602 } else if (value instanceof Double) {
603 return true;
604 } else if (value instanceof Boolean) {
605 return true;
606 } else if (value instanceof byte[]) {
607 return true;
608 } else {
609 return false;
610 }
611 }
612}