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