/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.media; import android.graphics.Bitmap; import android.media.session.MediaSession; import android.os.Bundle; import android.os.Parcelable; import android.util.Log; import android.util.SparseIntArray; /** * An abstract class for editing and storing metadata that can be published by * {@link RemoteControlClient}. See the {@link RemoteControlClient#editMetadata(boolean)} * method to instantiate a {@link RemoteControlClient.MetadataEditor} object. * * @deprecated Use {@link MediaMetadata} instead together with {@link MediaSession}. */ @Deprecated public abstract class MediaMetadataEditor { private final static String TAG = "MediaMetadataEditor"; /** * @hide */ protected MediaMetadataEditor() { } // Public keys for metadata used by RemoteControlClient and RemoteController. // Note that these keys are defined here, and not in MediaMetadataRetriever // because they are not supported by the MediaMetadataRetriever features. /** * The metadata key for the content artwork / album art. */ public final static int BITMAP_KEY_ARTWORK = RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK; /** * The metadata key for the content's average rating, not the user's rating. * The value associated with this key is a {@link Rating} instance. * @see #RATING_KEY_BY_USER */ public final static int RATING_KEY_BY_OTHERS = 101; /** * The metadata key for the content's user rating. * The value associated with this key is a {@link Rating} instance. * This key can be flagged as "editable" (with {@link #addEditableKey(int)}) to enable * receiving user rating values through the * {@link android.media.RemoteControlClient.OnMetadataUpdateListener} interface. */ public final static int RATING_KEY_BY_USER = 0x10000001; /** * @hide * Editable key mask */ public final static int KEY_EDITABLE_MASK = 0x1FFFFFFF; /** * Applies all of the metadata changes that have been set since the MediaMetadataEditor instance * was created or since {@link #clear()} was called. Subclasses should synchronize on * {@code this} for thread safety. */ public abstract void apply(); /** * @hide * Mask of editable keys. */ protected long mEditableKeys; /** * @hide */ protected boolean mMetadataChanged = false; /** * @hide */ protected boolean mApplied = false; /** * @hide */ protected boolean mArtworkChanged = false; /** * @hide */ protected Bitmap mEditorArtwork; /** * @hide */ protected Bundle mEditorMetadata; /** * @hide */ protected MediaMetadata.Builder mMetadataBuilder; /** * Clears all the pending metadata changes set since the MediaMetadataEditor instance was * created or since this method was last called. * Note that clearing the metadata doesn't reset the editable keys * (use {@link #removeEditableKeys()} instead). */ public synchronized void clear() { if (mApplied) { Log.e(TAG, "Can't clear a previously applied MediaMetadataEditor"); return; } mEditorMetadata.clear(); mEditorArtwork = null; mMetadataBuilder = new MediaMetadata.Builder(); } /** * Flags the given key as being editable. * This should only be used by metadata publishers, such as {@link RemoteControlClient}, * which will declare the metadata field as eligible to be updated, with new values * received through the {@link RemoteControlClient.OnMetadataUpdateListener} interface. * @param key the type of metadata that can be edited. The supported key is * {@link #RATING_KEY_BY_USER}. */ public synchronized void addEditableKey(int key) { if (mApplied) { Log.e(TAG, "Can't change editable keys of a previously applied MetadataEditor"); return; } // only one editable key at the moment, so we're not wasting memory on an array // of editable keys to check the validity of the key, just hardcode the supported key. if (key == RATING_KEY_BY_USER) { mEditableKeys |= (KEY_EDITABLE_MASK & key); mMetadataChanged = true; } else { Log.e(TAG, "Metadata key " + key + " cannot be edited"); } } /** * Causes all metadata fields to be read-only. */ public synchronized void removeEditableKeys() { if (mApplied) { Log.e(TAG, "Can't remove all editable keys of a previously applied MetadataEditor"); return; } if (mEditableKeys != 0) { mEditableKeys = 0; mMetadataChanged = true; } } /** * Retrieves the keys flagged as editable. * @return null if there are no editable keys, or an array containing the keys. */ public synchronized int[] getEditableKeys() { // only one editable key supported here if (mEditableKeys == RATING_KEY_BY_USER) { int[] keys = { RATING_KEY_BY_USER }; return keys; } else { return null; } } /** * Adds textual information. * Note that none of the information added after {@link #apply()} has been called, * will be available to consumers of metadata stored by the MediaMetadataEditor. * @param key The identifier of a the metadata field to set. Valid values are * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}. * @param value The text for the given key, or {@code null} to signify there is no valid * information for the field. * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put * calls together. */ public synchronized MediaMetadataEditor putString(int key, String value) throws IllegalArgumentException { if (mApplied) { Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor"); return this; } if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) { throw(new IllegalArgumentException("Invalid type 'String' for key "+ key)); } mEditorMetadata.putString(String.valueOf(key), value); mMetadataChanged = true; return this; } /** * Adds numerical information. * Note that none of the information added after {@link #apply()} has been called * will be available to consumers of metadata stored by the MediaMetadataEditor. * @param key the identifier of a the metadata field to set. Valid values are * {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER}, * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value * expressed in milliseconds), * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}. * @param value The long value for the given key * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put * calls together. * @throws IllegalArgumentException */ public synchronized MediaMetadataEditor putLong(int key, long value) throws IllegalArgumentException { if (mApplied) { Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor"); return this; } if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) { throw(new IllegalArgumentException("Invalid type 'long' for key "+ key)); } mEditorMetadata.putLong(String.valueOf(key), value); mMetadataChanged = true; return this; } /** * Adds image. * @param key the identifier of the bitmap to set. The only valid value is * {@link #BITMAP_KEY_ARTWORK} * @param bitmap The bitmap for the artwork, or null if there isn't any. * @return Returns a reference to the same MediaMetadataEditor object, so you can chain put * calls together. * @throws IllegalArgumentException * @see android.graphics.Bitmap */ public synchronized MediaMetadataEditor putBitmap(int key, Bitmap bitmap) throws IllegalArgumentException { if (mApplied) { Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor"); return this; } if (key != BITMAP_KEY_ARTWORK) { throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key)); } mEditorArtwork = bitmap; mArtworkChanged = true; return this; } /** * Adds information stored as an instance. * Note that none of the information added after {@link #apply()} has been called * will be available to consumers of metadata stored by the MediaMetadataEditor. * @param key the identifier of a the metadata field to set. Valid keys for a: *