Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2013 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.media;
     18 
     19 import android.graphics.Bitmap;
     20 import android.media.session.MediaSession;
     21 import android.os.Bundle;
     22 import android.os.Parcelable;
     23 import android.util.Log;
     24 import android.util.SparseIntArray;
     25 
     26 /**
     27  * An abstract class for editing and storing metadata that can be published by
     28  * {@link RemoteControlClient}. See the {@link RemoteControlClient#editMetadata(boolean)}
     29  * method to instantiate a {@link RemoteControlClient.MetadataEditor} object.
     30  *
     31  * @deprecated Use {@link MediaMetadata} instead together with {@link MediaSession}.
     32  */
     33 @Deprecated public abstract class MediaMetadataEditor {
     34 
     35     private final static String TAG = "MediaMetadataEditor";
     36     /**
     37      * @hide
     38      */
     39     protected MediaMetadataEditor() {
     40     }
     41 
     42     // Public keys for metadata used by RemoteControlClient and RemoteController.
     43     // Note that these keys are defined here, and not in MediaMetadataRetriever
     44     // because they are not supported by the MediaMetadataRetriever features.
     45     /**
     46      * The metadata key for the content artwork / album art.
     47      */
     48     public final static int BITMAP_KEY_ARTWORK =
     49             RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK;
     50 
     51     /**
     52      * The metadata key for the content's average rating, not the user's rating.
     53      * The value associated with this key is a {@link Rating} instance.
     54      * @see #RATING_KEY_BY_USER
     55      */
     56     public final static int RATING_KEY_BY_OTHERS = 101;
     57 
     58     /**
     59      * The metadata key for the content's user rating.
     60      * The value associated with this key is a {@link Rating} instance.
     61      * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable
     62      * receiving user rating values through the
     63      * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface.
     64      */
     65     public final static int RATING_KEY_BY_USER = 0x10000001;
     66 
     67     /**
     68      * @hide
     69      * Editable key mask
     70      */
     71     public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF;
     72 
     73 
     74     /**
     75      * Applies all of the metadata changes that have been set since the MediaMetadataEditor instance
     76      * was created or since {@link #clear()} was called. Subclasses should synchronize on
     77      * {@code this} for thread safety.
     78      */
     79     public abstract void apply();
     80 
     81 
     82     /**
     83      * @hide
     84      * Mask of editable keys.
     85      */
     86     protected long mEditableKeys;
     87 
     88     /**
     89      * @hide
     90      */
     91     protected boolean mMetadataChanged = false;
     92 
     93     /**
     94      * @hide
     95      */
     96     protected boolean mApplied = false;
     97 
     98     /**
     99      * @hide
    100      */
    101     protected boolean mArtworkChanged = false;
    102 
    103     /**
    104      * @hide
    105      */
    106     protected Bitmap mEditorArtwork;
    107 
    108     /**
    109      * @hide
    110      */
    111     protected Bundle mEditorMetadata;
    112 
    113     /**
    114      * @hide
    115      */
    116     protected MediaMetadata.Builder mMetadataBuilder;
    117 
    118     /**
    119      * Clears all the pending metadata changes set since the MediaMetadataEditor instance was
    120      * created or since this method was last called.
    121      * Note that clearing the metadata doesn't reset the editable keys
    122      * (use {@link #removeEditableKeys()} instead).
    123      */
    124     public synchronized void clear() {
    125         if (mApplied) {
    126             Log.e(TAG, "Can't clear a previously applied MediaMetadataEditor");
    127             return;
    128         }
    129         mEditorMetadata.clear();
    130         mEditorArtwork = null;
    131         mMetadataBuilder = new MediaMetadata.Builder();
    132     }
    133 
    134     /**
    135      * Flags the given key as being editable.
    136      * This should only be used by metadata publishers, such as {@link RemoteControlClient},
    137      * which will declare the metadata field as eligible to be updated, with new values
    138      * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface.
    139      * @param key the type of metadata that can be edited. The supported key is
    140      *     {@link #RATING_KEY_BY_USER}.
    141      */
    142     public synchronized void addEditableKey(int key) {
    143         if (mApplied) {
    144             Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor");
    145             return;
    146         }
    147         // only one editable key at the moment, so we're not wasting memory on an array
    148         // of editable keys to check the validity of the key, just hardcode the supported key.
    149         if (key == RATING_KEY_BY_USER) {
    150             mEditableKeys |= (KEY_EDITABLE_MASK & key);
    151             mMetadataChanged = true;
    152         } else {
    153             Log.e(TAG, "Metadata key " + key + " cannot be edited");
    154         }
    155     }
    156 
    157     /**
    158      * Causes all metadata fields to be read-only.
    159      */
    160     public synchronized void removeEditableKeys() {
    161         if (mApplied) {
    162             Log.e(TAG, "Can't remove all editable keys of a previously applied MetadataEditor");
    163             return;
    164         }
    165         if (mEditableKeys != 0) {
    166             mEditableKeys = 0;
    167             mMetadataChanged = true;
    168         }
    169     }
    170 
    171     /**
    172      * Retrieves the keys flagged as editable.
    173      * @return null if there are no editable keys, or an array containing the keys.
    174      */
    175     public synchronized int[] getEditableKeys() {
    176         // only one editable key supported here
    177         if (mEditableKeys == RATING_KEY_BY_USER) {
    178             int[] keys = { RATING_KEY_BY_USER };
    179             return keys;
    180         } else {
    181             return null;
    182         }
    183     }
    184 
    185     /**
    186      * Adds textual information.
    187      * Note that none of the information added after {@link #apply()} has been called,
    188      * will be available to consumers of metadata stored by the MediaMetadataEditor.
    189      * @param key The identifier of a the metadata field to set. Valid values are
    190      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
    191      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
    192      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
    193      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
    194      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
    195      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
    196      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
    197      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
    198      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
    199      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
    200      * @param value The text for the given key, or {@code null} to signify there is no valid
    201      *      information for the field.
    202      * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
    203      *      calls together.
    204      */
    205     public synchronized MediaMetadataEditor putString(int key, String value)
    206             throws IllegalArgumentException {
    207         if (mApplied) {
    208             Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
    209             return this;
    210         }
    211         if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
    212             throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
    213         }
    214         mEditorMetadata.putString(String.valueOf(key), value);
    215         mMetadataChanged = true;
    216         return this;
    217     }
    218 
    219     /**
    220      * Adds numerical information.
    221      * Note that none of the information added after {@link #apply()} has been called
    222      * will be available to consumers of metadata stored by the MediaMetadataEditor.
    223      * @param key the identifier of a the metadata field to set. Valid values are
    224      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
    225      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
    226      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
    227      *      expressed in milliseconds),
    228      *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
    229      * @param value The long value for the given key
    230      * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
    231      *      calls together.
    232      * @throws IllegalArgumentException
    233      */
    234     public synchronized MediaMetadataEditor putLong(int key, long value)
    235             throws IllegalArgumentException {
    236         if (mApplied) {
    237             Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
    238             return this;
    239         }
    240         if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
    241             throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
    242         }
    243         mEditorMetadata.putLong(String.valueOf(key), value);
    244         mMetadataChanged = true;
    245         return this;
    246     }
    247 
    248     /**
    249      * Adds image.
    250      * @param key the identifier of the bitmap to set. The only valid value is
    251      *      {@link #BITMAP_KEY_ARTWORK}
    252      * @param bitmap The bitmap for the artwork, or null if there isn't any.
    253      * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
    254      *      calls together.
    255      * @throws IllegalArgumentException
    256      * @see android.graphics.Bitmap
    257      */
    258     public synchronized MediaMetadataEditor putBitmap(int key, Bitmap bitmap)
    259             throws IllegalArgumentException {
    260         if (mApplied) {
    261             Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
    262             return this;
    263         }
    264         if (key != BITMAP_KEY_ARTWORK) {
    265             throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
    266         }
    267         mEditorArtwork = bitmap;
    268         mArtworkChanged = true;
    269         return this;
    270     }
    271 
    272     /**
    273      * Adds information stored as an instance.
    274      * Note that none of the information added after {@link #apply()} has been called
    275      * will be available to consumers of metadata stored by the MediaMetadataEditor.
    276      * @param key the identifier of a the metadata field to set. Valid keys for a:
    277      *     <ul>
    278      *     <li>{@link Bitmap} object are {@link #BITMAP_KEY_ARTWORK},</li>
    279      *     <li>{@link String} object are the same as for {@link #putString(int, String)}</li>
    280      *     <li>{@link Long} object are the same as for {@link #putLong(int, long)}</li>
    281      *     <li>{@link Rating} object are {@link #RATING_KEY_BY_OTHERS}
    282      *         and {@link #RATING_KEY_BY_USER}.</li>
    283      *     </ul>
    284      * @param value the metadata to add.
    285      * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
    286      *      calls together.
    287      * @throws IllegalArgumentException
    288      */
    289     public synchronized MediaMetadataEditor putObject(int key, Object value)
    290             throws IllegalArgumentException {
    291         if (mApplied) {
    292             Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
    293             return this;
    294         }
    295         switch(METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
    296             case METADATA_TYPE_LONG:
    297                 if (value instanceof Long) {
    298                     return putLong(key, ((Long)value).longValue());
    299                 } else {
    300                     throw(new IllegalArgumentException("Not a non-null Long for key "+ key));
    301                 }
    302             case METADATA_TYPE_STRING:
    303                 if ((value == null) || (value instanceof String)) {
    304                     return putString(key, (String) value);
    305                 } else {
    306                     throw(new IllegalArgumentException("Not a String for key "+ key));
    307                 }
    308             case METADATA_TYPE_RATING:
    309                 mEditorMetadata.putParcelable(String.valueOf(key), (Parcelable)value);
    310                 mMetadataChanged = true;
    311                 break;
    312             case METADATA_TYPE_BITMAP:
    313                 if ((value == null) || (value instanceof Bitmap))  {
    314                     return putBitmap(key, (Bitmap) value);
    315                 } else {
    316                     throw(new IllegalArgumentException("Not a Bitmap for key "+ key));
    317                 }
    318             default:
    319                 throw(new IllegalArgumentException("Invalid key "+ key));
    320         }
    321         return this;
    322     }
    323 
    324 
    325     /**
    326      * Returns the long value for the key.
    327      * @param key one of the keys supported in {@link #putLong(int, long)}
    328      * @param defaultValue the value returned if the key is not present
    329      * @return the long value for the key, or the supplied default value if the key is not present
    330      * @throws IllegalArgumentException
    331      */
    332     public synchronized long getLong(int key, long defaultValue)
    333             throws IllegalArgumentException {
    334         if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
    335             throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
    336         }
    337         return mEditorMetadata.getLong(String.valueOf(key), defaultValue);
    338     }
    339 
    340     /**
    341      * Returns the {@link String} value for the key.
    342      * @param key one of the keys supported in {@link #putString(int, String)}
    343      * @param defaultValue the value returned if the key is not present
    344      * @return the {@link String} value for the key, or the supplied default value if the key is
    345      *     not present
    346      * @throws IllegalArgumentException
    347      */
    348     public synchronized String getString(int key, String defaultValue)
    349             throws IllegalArgumentException {
    350         if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
    351             throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
    352         }
    353         return mEditorMetadata.getString(String.valueOf(key), defaultValue);
    354     }
    355 
    356     /**
    357      * Returns the {@link Bitmap} value for the key.
    358      * @param key the {@link #BITMAP_KEY_ARTWORK} key
    359      * @param defaultValue the value returned if the key is not present
    360      * @return the {@link Bitmap} value for the key, or the supplied default value if the key is
    361      *     not present
    362      * @throws IllegalArgumentException
    363      */
    364     public synchronized Bitmap getBitmap(int key, Bitmap defaultValue)
    365             throws IllegalArgumentException {
    366         if (key != BITMAP_KEY_ARTWORK) {
    367             throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
    368         }
    369         return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
    370     }
    371 
    372     /**
    373      * Returns an object representation of the value for the key
    374      * @param key one of the keys supported in {@link #putObject(int, Object)}
    375      * @param defaultValue the value returned if the key is not present
    376      * @return the object for the key, as a {@link Long}, {@link Bitmap}, {@link String}, or
    377      *     {@link Rating} depending on the key value, or the supplied default value if the key is
    378      *     not present
    379      * @throws IllegalArgumentException
    380      */
    381     public synchronized Object getObject(int key, Object defaultValue)
    382             throws IllegalArgumentException {
    383         switch (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
    384             case METADATA_TYPE_LONG:
    385                 if (mEditorMetadata.containsKey(String.valueOf(key))) {
    386                     return mEditorMetadata.getLong(String.valueOf(key));
    387                 } else {
    388                     return defaultValue;
    389                 }
    390             case METADATA_TYPE_STRING:
    391                 if (mEditorMetadata.containsKey(String.valueOf(key))) {
    392                     return mEditorMetadata.getString(String.valueOf(key));
    393                 } else {
    394                     return defaultValue;
    395                 }
    396             case METADATA_TYPE_RATING:
    397                 if (mEditorMetadata.containsKey(String.valueOf(key))) {
    398                     return mEditorMetadata.getParcelable(String.valueOf(key));
    399                 } else {
    400                     return defaultValue;
    401                 }
    402             case METADATA_TYPE_BITMAP:
    403                 // only one key for Bitmap supported, value is not stored in mEditorMetadata Bundle
    404                 if (key == BITMAP_KEY_ARTWORK) {
    405                     return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
    406                 } // else: fall through to invalid key handling
    407             default:
    408                 throw(new IllegalArgumentException("Invalid key "+ key));
    409         }
    410     }
    411 
    412 
    413     /**
    414      * @hide
    415      */
    416     protected static final int METADATA_TYPE_INVALID = -1;
    417     /**
    418      * @hide
    419      */
    420     protected static final int METADATA_TYPE_LONG = 0;
    421 
    422     /**
    423      * @hide
    424      */
    425     protected static final int METADATA_TYPE_STRING = 1;
    426 
    427     /**
    428      * @hide
    429      */
    430     protected static final int METADATA_TYPE_BITMAP = 2;
    431 
    432     /**
    433      * @hide
    434      */
    435     protected static final int METADATA_TYPE_RATING = 3;
    436 
    437     /**
    438      * @hide
    439      */
    440     protected static final SparseIntArray METADATA_KEYS_TYPE;
    441 
    442     static {
    443         METADATA_KEYS_TYPE = new SparseIntArray(17);
    444         // NOTE: if adding to the list below, make sure you increment the array initialization size
    445         // keys with long values
    446         METADATA_KEYS_TYPE.put(
    447                 MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, METADATA_TYPE_LONG);
    448         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
    449         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_TYPE_LONG);
    450         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_TYPE_LONG);
    451         // keys with String values
    452         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_TYPE_STRING);
    453         METADATA_KEYS_TYPE.put(
    454                 MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, METADATA_TYPE_STRING);
    455         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_TYPE_STRING);
    456         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_TYPE_STRING);
    457         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_TYPE_STRING);
    458         METADATA_KEYS_TYPE.put(
    459                 MediaMetadataRetriever.METADATA_KEY_COMPILATION, METADATA_TYPE_STRING);
    460         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_TYPE_STRING);
    461         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_TYPE_STRING);
    462         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_TYPE_STRING);
    463         METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_TYPE_STRING);
    464         // keys with Bitmap values
    465         METADATA_KEYS_TYPE.put(BITMAP_KEY_ARTWORK, METADATA_TYPE_BITMAP);
    466         // keys with Rating values
    467         METADATA_KEYS_TYPE.put(RATING_KEY_BY_OTHERS, METADATA_TYPE_RATING);
    468         METADATA_KEYS_TYPE.put(RATING_KEY_BY_USER, METADATA_TYPE_RATING);
    469     }
    470 }
    471