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