Merge change 7624
* changes:
Impl. of the metadata getters.
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index a345ef8..8dbe51a 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -20,10 +20,12 @@
import android.os.Parcel;
import android.util.Log;
+import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
-import java.util.Set;
import java.util.HashMap;
+import java.util.Set;
+import java.util.TimeZone;
/**
@@ -102,15 +104,20 @@
public static final Set<Integer> MATCH_NONE = Collections.EMPTY_SET;
public static final Set<Integer> MATCH_ALL = Collections.singleton(ANY);
- public static final int STRING_VAL = 1;
- public static final int INTEGER_VAL = 2;
- public static final int LONG_VAL = 3;
- public static final int DOUBLE_VAL = 4;
- public static final int TIMED_TEXT_VAL = 5;
- private static final int LAST_TYPE = 5;
+ public static final int STRING_VAL = 1;
+ public static final int INTEGER_VAL = 2;
+ public static final int BOOLEAN_VAL = 3;
+ public static final int LONG_VAL = 4;
+ public static final int DOUBLE_VAL = 5;
+ public static final int TIMED_TEXT_VAL = 6;
+ public static final int DATE_VAL = 7;
+ public static final int BYTE_ARRAY_VAL = 8;
+ // FIXME: misses a type for shared heap is missing (MemoryFile).
+ // FIXME: misses a type for bitmaps.
+ private static final int LAST_TYPE = 8;
private static final String TAG = "media.Metadata";
- private static final int kMetaHeaderSize = 8; // 8 bytes for the size + the marker
+ private static final int kMetaHeaderSize = 8; // size + marker
private static final int kMetaMarker = 0x4d455441; // 'M' 'E' 'T' 'A'
private static final int kRecordHeaderSize = 12; // size + id + type
@@ -122,21 +129,28 @@
// Used to look up if a key was present too.
// Key: Metadata ID
// Value: Offset of the metadata type field in the record.
- private final HashMap<Integer, Integer> mKeyToPosMap = new HashMap<Integer, Integer>();
+ private final HashMap<Integer, Integer> mKeyToPosMap =
+ new HashMap<Integer, Integer>();
/**
- * Helper class to hold a pair (time, text). Can be used to implement caption.
+ * Helper class to hold a triple (time, duration, text). Can be used to
+ * implement caption.
*/
public class TimedText {
private Date mTime;
+ private int mDuration; // millisec
private String mText;
- public TimedText(final Date time, final String text) {
+
+ public TimedText(Date time, int duration, String text) {
mTime = time;
+ mDuration = duration;
mText = text;
}
+
public String toString() {
StringBuilder res = new StringBuilder(80);
- res.append(mTime).append(":").append(mText);
+ res.append(mTime).append("-").append(mDuration)
+ .append(":").append(mText);
return res.toString();
}
}
@@ -300,44 +314,64 @@
return mKeyToPosMap.containsKey(metadataId);
}
- // Accessors
+ // Accessors.
+ // Caller must make sure the key is present using the {@code has}
+ // method otherwise a RuntimeException will occur.
+
public String getString(final int key) {
- // FIXME: Implement.
- return new String();
+ checkType(key, STRING_VAL);
+ return mParcel.readString();
}
public int getInt(final int key) {
- // FIXME: Implement.
- return 0;
+ checkType(key, INTEGER_VAL);
+ return mParcel.readInt();
+ }
+
+ public boolean getBoolean(final int key) {
+ checkType(key, BOOLEAN_VAL);
+ return mParcel.readInt() == 1;
}
public long getLong(final int key) {
- // FIXME: Implement.
- return 0;
+ checkType(key, LONG_VAL);
+ return mParcel.readLong();
}
public double getDouble(final int key) {
- // FIXME: Implement.
- return 0.0;
+ checkType(key, DOUBLE_VAL);
+ return mParcel.readDouble();
}
public byte[] getByteArray(final int key) {
- return new byte[0];
- }
-
- public Bitmap getBitmap(final int key) {
- // FIXME: Implement.
- return null;
+ checkType(key, BYTE_ARRAY_VAL);
+ return mParcel.createByteArray();
}
public Date getDate(final int key) {
- // FIXME: Implement.
- return new Date();
+ checkType(key, DATE_VAL);
+ final long timeSinceEpoch = mParcel.readLong();
+ final String timeZone = mParcel.readString();
+
+ if (timeZone.length() == 0) {
+ return new Date(timeSinceEpoch);
+ } else {
+ TimeZone tz = TimeZone.getTimeZone(timeZone);
+ Calendar cal = Calendar.getInstance(tz);
+
+ cal.setTimeInMillis(timeSinceEpoch);
+ return cal.getTime();
+ }
}
public TimedText getTimedText(final int key) {
- // FIXME: Implement.
- return new TimedText(new Date(0), "<missing>");
+ checkType(key, TIMED_TEXT_VAL);
+ final Date startTime = new Date(mParcel.readLong()); // epoch
+ final int duration = mParcel.readInt(); // millisec
+
+ return new TimedText(startTime,
+ duration,
+ mParcel.readString());
}
// @return the last available system metadata id. Ids are
@@ -360,4 +394,16 @@
}
return true;
}
+
+ // Check the type of the data match what is expected.
+ private void checkType(final int key, final int expectedType) {
+ final int pos = mKeyToPosMap.get(key);
+
+ mParcel.setDataPosition(pos);
+
+ final int type = mParcel.readInt();
+ if (type != expectedType) {
+ throw new IllegalStateException("Wrong type " + expectedType + " but got " + type);
+ }
+ }
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java
index f51b29e..576dddd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaPlayerMetadataParserTest.java
@@ -21,6 +21,9 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import java.util.Calendar;
+import java.util.Date;
+
/*
* Check the Java layer that parses serialized metadata in Parcel
* works as expected.
@@ -89,16 +92,6 @@
mParcel.writeInt(kMarker);
}
- // Insert a string record at the current position.
- private void writeStringRecord(int metadataId, String val) {
- final int start = mParcel.dataPosition();
- mParcel.writeInt(-1); // Placeholder for the length
- mParcel.writeInt(metadataId);
- mParcel.writeInt(Metadata.STRING_VAL);
- mParcel.writeString(val);
- adjustSize(start);
- }
-
// ----------------------------------------------------------------------
// START OF THE TESTS
@@ -133,7 +126,9 @@
assertParse();
}
+ // ----------------------------------------------------------------------
// RECORDS
+ // ----------------------------------------------------------------------
// A record header should be at least 12 bytes long
@SmallTest
@@ -223,4 +218,221 @@
assertFalse(mMetadata.has(Metadata.GENRE));
assertFalse(mMetadata.has(Metadata.firstCustomId()));
}
+
+ // ----------------------------------------------------------------------
+ // GETTERS
+ // ----------------------------------------------------------------------
+
+ // getString
+ @SmallTest
+ public void testGetString() throws Exception {
+ writeStringRecord(Metadata.TITLE, "a title");
+ writeStringRecord(Metadata.GENRE, "comedy");
+ adjustSize();
+ assertParse();
+
+ assertEquals("a title", mMetadata.getString(Metadata.TITLE));
+ assertEquals("comedy", mMetadata.getString(Metadata.GENRE));
+ }
+
+ // get an empty string.
+ @SmallTest
+ public void testGetEmptyString() throws Exception {
+ writeStringRecord(Metadata.TITLE, "");
+ adjustSize();
+ assertParse();
+
+ assertEquals("", mMetadata.getString(Metadata.TITLE));
+ }
+
+ // get a string when a NULL value was in the parcel
+ @SmallTest
+ public void testGetNullString() throws Exception {
+ writeStringRecord(Metadata.TITLE, null);
+ adjustSize();
+ assertParse();
+
+ assertEquals(null, mMetadata.getString(Metadata.TITLE));
+ }
+
+ // get a string when an integer is actually present
+ @SmallTest
+ public void testWrongType() throws Exception {
+ writeIntRecord(Metadata.DURATION, 5);
+ adjustSize();
+ assertParse();
+
+ try {
+ mMetadata.getString(Metadata.DURATION);
+ } catch (IllegalStateException ise) {
+ return;
+ }
+ fail("Exception was not thrown");
+ }
+
+ // getInt
+ @SmallTest
+ public void testGetInt() throws Exception {
+ writeIntRecord(Metadata.CD_TRACK_NUM, 1);
+ adjustSize();
+ assertParse();
+
+ assertEquals(1, mMetadata.getInt(Metadata.CD_TRACK_NUM));
+ }
+
+ // getBoolean
+ @SmallTest
+ public void testGetBoolean() throws Exception {
+ writeBooleanRecord(Metadata.DRM_CRIPPLED, true);
+ adjustSize();
+ assertParse();
+
+ assertEquals(true, mMetadata.getBoolean(Metadata.DRM_CRIPPLED));
+ }
+
+ // getLong
+ @SmallTest
+ public void testGetLong() throws Exception {
+ writeLongRecord(Metadata.DURATION, 1L);
+ adjustSize();
+ assertParse();
+
+ assertEquals(1L, mMetadata.getLong(Metadata.DURATION));
+ }
+
+ // getDouble
+ @SmallTest
+ public void testGetDouble() throws Exception {
+ writeDoubleRecord(Metadata.VIDEO_FRAME_RATE, 29.97);
+ adjustSize();
+ assertParse();
+
+ assertEquals(29.97, mMetadata.getDouble(Metadata.VIDEO_FRAME_RATE));
+ }
+
+ // getByteArray
+ @SmallTest
+ public void testGetByteArray() throws Exception {
+ byte data[] = new byte[]{1,2,3,4,5};
+
+ writeByteArrayRecord(Metadata.ALBUM_ART, data);
+ adjustSize();
+ assertParse();
+
+ byte res[] = mMetadata.getByteArray(Metadata.ALBUM_ART);
+ for (int i = 0; i < data.length; ++i) {
+ assertEquals(data[i], res[i]);
+ }
+ }
+
+ // getDate
+ @SmallTest
+ public void testGetDate() throws Exception {
+ writeDateRecord(Metadata.DATE, 0, "PST");
+ adjustSize();
+ assertParse();
+
+ assertEquals(new Date(0), mMetadata.getDate(Metadata.DATE));
+ }
+
+ // getTimedText
+ @SmallTest
+ public void testGetTimedText() throws Exception {
+ Date now = Calendar.getInstance().getTime();
+ writeTimedTextRecord(Metadata.CAPTION, now.getTime(),
+ 10, "Some caption");
+ adjustSize();
+ assertParse();
+
+ Metadata.TimedText caption = mMetadata.getTimedText(Metadata.CAPTION);
+ assertEquals("" + now + "-" + 10 + ":Some caption", caption.toString());
+ }
+
+ // ----------------------------------------------------------------------
+ // HELPERS TO APPEND RECORDS
+ // ----------------------------------------------------------------------
+
+ // Insert a string record at the current position.
+ private void writeStringRecord(int metadataId, String val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.STRING_VAL);
+ mParcel.writeString(val);
+ adjustSize(start);
+ }
+
+ // Insert an int record at the current position.
+ private void writeIntRecord(int metadataId, int val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.INTEGER_VAL);
+ mParcel.writeInt(val);
+ adjustSize(start);
+ }
+
+ // Insert a boolean record at the current position.
+ private void writeBooleanRecord(int metadataId, boolean val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.BOOLEAN_VAL);
+ mParcel.writeInt(val ? 1 : 0);
+ adjustSize(start);
+ }
+
+ // Insert a Long record at the current position.
+ private void writeLongRecord(int metadataId, long val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.LONG_VAL);
+ mParcel.writeLong(val);
+ adjustSize(start);
+ }
+
+ // Insert a Double record at the current position.
+ private void writeDoubleRecord(int metadataId, double val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.DOUBLE_VAL);
+ mParcel.writeDouble(val);
+ adjustSize(start);
+ }
+
+ // Insert a ByteArray record at the current position.
+ private void writeByteArrayRecord(int metadataId, byte[] val) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.BYTE_ARRAY_VAL);
+ mParcel.writeByteArray(val);
+ adjustSize(start);
+ }
+
+ // Insert a Date record at the current position.
+ private void writeDateRecord(int metadataId, long time, String tz) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.DATE_VAL);
+ mParcel.writeLong(time);
+ mParcel.writeString(tz);
+ adjustSize(start);
+ }
+
+ // Insert a TimedText record at the current position.
+ private void writeTimedTextRecord(int metadataId, long begin,
+ int duration, String text) {
+ final int start = mParcel.dataPosition();
+ mParcel.writeInt(-1); // Placeholder for the length
+ mParcel.writeInt(metadataId);
+ mParcel.writeInt(Metadata.TIMED_TEXT_VAL);
+ mParcel.writeLong(begin);
+ mParcel.writeInt(duration);
+ mParcel.writeString(text);
+ adjustSize(start);
+ }
}