471 lines
19 KiB
Java
471 lines
19 KiB
Java
/*
|
|
* 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:
|
|
* <ul>
|
|
* <li>{@link Bitmap} object are {@link #BITMAP_KEY_ARTWORK},</li>
|
|
* <li>{@link String} object are the same as for {@link #putString(int, String)}</li>
|
|
* <li>{@link Long} object are the same as for {@link #putLong(int, long)}</li>
|
|
* <li>{@link Rating} object are {@link #RATING_KEY_BY_OTHERS}
|
|
* and {@link #RATING_KEY_BY_USER}.</li>
|
|
* </ul>
|
|
* @param value the metadata to add.
|
|
* @return Returns a reference to the same MediaMetadataEditor object, so you can chain put
|
|
* calls together.
|
|
* @throws IllegalArgumentException
|
|
*/
|
|
public synchronized MediaMetadataEditor putObject(int key, Object value)
|
|
throws IllegalArgumentException {
|
|
if (mApplied) {
|
|
Log.e(TAG, "Can't edit a previously applied MediaMetadataEditor");
|
|
return this;
|
|
}
|
|
switch(METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
|
|
case METADATA_TYPE_LONG:
|
|
if (value instanceof Long) {
|
|
return putLong(key, ((Long)value).longValue());
|
|
} else {
|
|
throw(new IllegalArgumentException("Not a non-null Long for key "+ key));
|
|
}
|
|
case METADATA_TYPE_STRING:
|
|
if ((value == null) || (value instanceof String)) {
|
|
return putString(key, (String) value);
|
|
} else {
|
|
throw(new IllegalArgumentException("Not a String for key "+ key));
|
|
}
|
|
case METADATA_TYPE_RATING:
|
|
mEditorMetadata.putParcelable(String.valueOf(key), (Parcelable)value);
|
|
mMetadataChanged = true;
|
|
break;
|
|
case METADATA_TYPE_BITMAP:
|
|
if ((value == null) || (value instanceof Bitmap)) {
|
|
return putBitmap(key, (Bitmap) value);
|
|
} else {
|
|
throw(new IllegalArgumentException("Not a Bitmap for key "+ key));
|
|
}
|
|
default:
|
|
throw(new IllegalArgumentException("Invalid key "+ key));
|
|
}
|
|
return this;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the long value for the key.
|
|
* @param key one of the keys supported in {@link #putLong(int, long)}
|
|
* @param defaultValue the value returned if the key is not present
|
|
* @return the long value for the key, or the supplied default value if the key is not present
|
|
* @throws IllegalArgumentException
|
|
*/
|
|
public synchronized long getLong(int key, long defaultValue)
|
|
throws IllegalArgumentException {
|
|
if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_LONG) {
|
|
throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
|
|
}
|
|
return mEditorMetadata.getLong(String.valueOf(key), defaultValue);
|
|
}
|
|
|
|
/**
|
|
* Returns the {@link String} value for the key.
|
|
* @param key one of the keys supported in {@link #putString(int, String)}
|
|
* @param defaultValue the value returned if the key is not present
|
|
* @return the {@link String} value for the key, or the supplied default value if the key is
|
|
* not present
|
|
* @throws IllegalArgumentException
|
|
*/
|
|
public synchronized String getString(int key, String defaultValue)
|
|
throws IllegalArgumentException {
|
|
if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) != METADATA_TYPE_STRING) {
|
|
throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
|
|
}
|
|
return mEditorMetadata.getString(String.valueOf(key), defaultValue);
|
|
}
|
|
|
|
/**
|
|
* Returns the {@link Bitmap} value for the key.
|
|
* @param key the {@link #BITMAP_KEY_ARTWORK} key
|
|
* @param defaultValue the value returned if the key is not present
|
|
* @return the {@link Bitmap} value for the key, or the supplied default value if the key is
|
|
* not present
|
|
* @throws IllegalArgumentException
|
|
*/
|
|
public synchronized Bitmap getBitmap(int key, Bitmap defaultValue)
|
|
throws IllegalArgumentException {
|
|
if (key != BITMAP_KEY_ARTWORK) {
|
|
throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
|
|
}
|
|
return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
|
|
}
|
|
|
|
/**
|
|
* Returns an object representation of the value for the key
|
|
* @param key one of the keys supported in {@link #putObject(int, Object)}
|
|
* @param defaultValue the value returned if the key is not present
|
|
* @return the object for the key, as a {@link Long}, {@link Bitmap}, {@link String}, or
|
|
* {@link Rating} depending on the key value, or the supplied default value if the key is
|
|
* not present
|
|
* @throws IllegalArgumentException
|
|
*/
|
|
public synchronized Object getObject(int key, Object defaultValue)
|
|
throws IllegalArgumentException {
|
|
switch (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID)) {
|
|
case METADATA_TYPE_LONG:
|
|
if (mEditorMetadata.containsKey(String.valueOf(key))) {
|
|
return mEditorMetadata.getLong(String.valueOf(key));
|
|
} else {
|
|
return defaultValue;
|
|
}
|
|
case METADATA_TYPE_STRING:
|
|
if (mEditorMetadata.containsKey(String.valueOf(key))) {
|
|
return mEditorMetadata.getString(String.valueOf(key));
|
|
} else {
|
|
return defaultValue;
|
|
}
|
|
case METADATA_TYPE_RATING:
|
|
if (mEditorMetadata.containsKey(String.valueOf(key))) {
|
|
return mEditorMetadata.getParcelable(String.valueOf(key));
|
|
} else {
|
|
return defaultValue;
|
|
}
|
|
case METADATA_TYPE_BITMAP:
|
|
// only one key for Bitmap supported, value is not stored in mEditorMetadata Bundle
|
|
if (key == BITMAP_KEY_ARTWORK) {
|
|
return (mEditorArtwork != null ? mEditorArtwork : defaultValue);
|
|
} // else: fall through to invalid key handling
|
|
default:
|
|
throw(new IllegalArgumentException("Invalid key "+ key));
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
protected static final int METADATA_TYPE_INVALID = -1;
|
|
/**
|
|
* @hide
|
|
*/
|
|
protected static final int METADATA_TYPE_LONG = 0;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
protected static final int METADATA_TYPE_STRING = 1;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
protected static final int METADATA_TYPE_BITMAP = 2;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
protected static final int METADATA_TYPE_RATING = 3;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
protected static final SparseIntArray METADATA_KEYS_TYPE;
|
|
|
|
static {
|
|
METADATA_KEYS_TYPE = new SparseIntArray(17);
|
|
// NOTE: if adding to the list below, make sure you increment the array initialization size
|
|
// keys with long values
|
|
METADATA_KEYS_TYPE.put(
|
|
MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, METADATA_TYPE_LONG);
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_TYPE_LONG);
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_TYPE_LONG);
|
|
// keys with String values
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_TYPE_STRING);
|
|
METADATA_KEYS_TYPE.put(
|
|
MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, METADATA_TYPE_STRING);
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_TYPE_STRING);
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_TYPE_STRING);
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_TYPE_STRING);
|
|
METADATA_KEYS_TYPE.put(
|
|
MediaMetadataRetriever.METADATA_KEY_COMPILATION, METADATA_TYPE_STRING);
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_TYPE_STRING);
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_TYPE_STRING);
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_TYPE_STRING);
|
|
METADATA_KEYS_TYPE.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_TYPE_STRING);
|
|
// keys with Bitmap values
|
|
METADATA_KEYS_TYPE.put(BITMAP_KEY_ARTWORK, METADATA_TYPE_BITMAP);
|
|
// keys with Rating values
|
|
METADATA_KEYS_TYPE.put(RATING_KEY_BY_OTHERS, METADATA_TYPE_RATING);
|
|
METADATA_KEYS_TYPE.put(RATING_KEY_BY_USER, METADATA_TYPE_RATING);
|
|
}
|
|
}
|