summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2010-09-26 12:35:51 -0400
committerMike Lockwood <lockwood@android.com>2010-09-27 13:16:53 -0400
commitae078f7dacdc719d045c2d19bbce019599fec64e (patch)
treeb3dd3061c7e3822621c92cbec055ec03678e0e61 /media
parentbdb05df757847ebf343ad332f319a97f7482957c (diff)
downloadframeworks_base-ae078f7dacdc719d045c2d19bbce019599fec64e.zip
frameworks_base-ae078f7dacdc719d045c2d19bbce019599fec64e.tar.gz
frameworks_base-ae078f7dacdc719d045c2d19bbce019599fec64e.tar.bz2
MTP: Implement extra object properties for audio, video and image files
Read-only support at this point. BUG: 2869730 Change-Id: I424ba760c8f5f4af394bd65276f19438fa6da6cb Signed-off-by: Mike Lockwood <lockwood@android.com>
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/MtpDatabase.java303
-rw-r--r--media/jni/android_media_MtpDatabase.cpp33
2 files changed, 290 insertions, 46 deletions
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 403ed58..630d7112e 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -25,8 +25,9 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.MediaStore.Audio;
-import android.provider.MediaStore.MediaColumns;
import android.provider.MediaStore.Files;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.MediaColumns;
import android.provider.Mtp;
import android.util.Log;
@@ -278,8 +279,9 @@ public class MtpDatabase {
return null;
}
- private int[] getSupportedObjectProperties(int handle) {
- return new int[] {
+ static final int[] FILE_PROPERTIES = {
+ // NOTE must match beginning of AUDIO_PROPERTIES, VIDEO_PROPERTIES
+ // and IMAGE_PROPERTIES below
MtpConstants.PROPERTY_STORAGE_ID,
MtpConstants.PROPERTY_OBJECT_FORMAT,
MtpConstants.PROPERTY_PROTECTION_STATUS,
@@ -289,7 +291,93 @@ public class MtpDatabase {
MtpConstants.PROPERTY_PARENT_OBJECT,
MtpConstants.PROPERTY_PERSISTENT_UID,
MtpConstants.PROPERTY_NAME,
- };
+ MtpConstants.PROPERTY_DATE_ADDED,
+ };
+
+ static final int[] AUDIO_PROPERTIES = {
+ // NOTE must match FILE_PROPERTIES above
+ MtpConstants.PROPERTY_STORAGE_ID,
+ MtpConstants.PROPERTY_OBJECT_FORMAT,
+ MtpConstants.PROPERTY_PROTECTION_STATUS,
+ MtpConstants.PROPERTY_OBJECT_SIZE,
+ MtpConstants.PROPERTY_OBJECT_FILE_NAME,
+ MtpConstants.PROPERTY_DATE_MODIFIED,
+ MtpConstants.PROPERTY_PARENT_OBJECT,
+ MtpConstants.PROPERTY_PERSISTENT_UID,
+ MtpConstants.PROPERTY_NAME,
+ MtpConstants.PROPERTY_DISPLAY_NAME,
+ MtpConstants.PROPERTY_DATE_ADDED,
+
+ // audio specific properties
+ MtpConstants.PROPERTY_ARTIST,
+ MtpConstants.PROPERTY_ALBUM_NAME,
+ MtpConstants.PROPERTY_ALBUM_ARTIST,
+ MtpConstants.PROPERTY_TRACK,
+ MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE,
+ MtpConstants.PROPERTY_DURATION,
+ MtpConstants.PROPERTY_GENRE,
+ MtpConstants.PROPERTY_COMPOSER,
+ };
+
+ static final int[] VIDEO_PROPERTIES = {
+ // NOTE must match FILE_PROPERTIES above
+ MtpConstants.PROPERTY_STORAGE_ID,
+ MtpConstants.PROPERTY_OBJECT_FORMAT,
+ MtpConstants.PROPERTY_PROTECTION_STATUS,
+ MtpConstants.PROPERTY_OBJECT_SIZE,
+ MtpConstants.PROPERTY_OBJECT_FILE_NAME,
+ MtpConstants.PROPERTY_DATE_MODIFIED,
+ MtpConstants.PROPERTY_PARENT_OBJECT,
+ MtpConstants.PROPERTY_PERSISTENT_UID,
+ MtpConstants.PROPERTY_NAME,
+ MtpConstants.PROPERTY_DISPLAY_NAME,
+ MtpConstants.PROPERTY_DATE_ADDED,
+
+ // video specific properties
+ MtpConstants.PROPERTY_ARTIST,
+ MtpConstants.PROPERTY_ALBUM_NAME,
+ MtpConstants.PROPERTY_DURATION,
+ MtpConstants.PROPERTY_DESCRIPTION,
+ };
+
+ static final int[] IMAGE_PROPERTIES = {
+ // NOTE must match FILE_PROPERTIES above
+ MtpConstants.PROPERTY_STORAGE_ID,
+ MtpConstants.PROPERTY_OBJECT_FORMAT,
+ MtpConstants.PROPERTY_PROTECTION_STATUS,
+ MtpConstants.PROPERTY_OBJECT_SIZE,
+ MtpConstants.PROPERTY_OBJECT_FILE_NAME,
+ MtpConstants.PROPERTY_DATE_MODIFIED,
+ MtpConstants.PROPERTY_PARENT_OBJECT,
+ MtpConstants.PROPERTY_PERSISTENT_UID,
+ MtpConstants.PROPERTY_NAME,
+ MtpConstants.PROPERTY_DISPLAY_NAME,
+ MtpConstants.PROPERTY_DATE_ADDED,
+
+ // image specific properties
+ MtpConstants.PROPERTY_DESCRIPTION,
+ };
+
+ private int[] getSupportedObjectProperties(int format) {
+ switch (format) {
+ case MtpConstants.FORMAT_MP3:
+ case MtpConstants.FORMAT_WAV:
+ case MtpConstants.FORMAT_WMA:
+ case MtpConstants.FORMAT_OGG:
+ case MtpConstants.FORMAT_AAC:
+ return AUDIO_PROPERTIES;
+ case MtpConstants.FORMAT_MPEG:
+ case MtpConstants.FORMAT_3GP_CONTAINER:
+ case MtpConstants.FORMAT_WMV:
+ return VIDEO_PROPERTIES;
+ case MtpConstants.FORMAT_EXIF_JPEG:
+ case MtpConstants.FORMAT_GIF:
+ case MtpConstants.FORMAT_PNG:
+ case MtpConstants.FORMAT_BMP:
+ return IMAGE_PROPERTIES;
+ default:
+ return FILE_PROPERTIES;
+ }
}
private int[] getSupportedDeviceProperties() {
@@ -299,17 +387,90 @@ public class MtpDatabase {
};
}
+ private String queryString(int id, String column) {
+ Cursor c = null;
+ try {
+ // for now we are only reading properties from the "objects" table
+ c = mMediaProvider.query(mObjectsUri,
+ new String [] { Files.FileColumns._ID, column },
+ ID_WHERE, new String[] { Integer.toString(id) }, null);
+ if (c != null && c.moveToNext()) {
+ return c.getString(1);
+ } else {
+ return "";
+ }
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ private String queryGenre(int id) {
+ Cursor c = null;
+ try {
+ Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
+ c = mMediaProvider.query(uri,
+ new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
+ null, null, null);
+ if (c != null && c.moveToNext()) {
+ return c.getString(1);
+ } else {
+ return "";
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "queryGenre exception", e);
+ return null;
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ private boolean queryInt(int id, String column, long[] outValue) {
+ Cursor c = null;
+ try {
+ // for now we are only reading properties from the "objects" table
+ c = mMediaProvider.query(mObjectsUri,
+ new String [] { Files.FileColumns._ID, column },
+ ID_WHERE, new String[] { Integer.toString(id) }, null);
+ if (c != null && c.moveToNext()) {
+ outValue[0] = c.getLong(1);
+ return true;
+ }
+ return false;
+ } catch (Exception e) {
+ return false;
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ private String nameFromPath(String path) {
+ // extract name from full path
+ int start = 0;
+ int lastSlash = path.lastIndexOf('/');
+ if (lastSlash >= 0) {
+ start = lastSlash + 1;
+ }
+ int end = path.length();
+ if (end - start > 255) {
+ end = start + 255;
+ }
+ return path.substring(start, end);
+ }
+
private int getObjectProperty(int handle, int property,
long[] outIntValue, char[] outStringValue) {
Log.d(TAG, "getObjectProperty: " + property);
String column = null;
boolean isString = false;
- // temporary hack
- if (property == MtpConstants.PROPERTY_NAME) {
- property = MtpConstants.PROPERTY_OBJECT_FILE_NAME;
- }
-
switch (property) {
case MtpConstants.PROPERTY_STORAGE_ID:
outIntValue[0] = mStorageID;
@@ -325,12 +486,46 @@ public class MtpDatabase {
column = Files.FileColumns.SIZE;
break;
case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
- column = Files.FileColumns.DATA;
- isString = true;
- break;
+ // special case - need to extract file name from full path
+ String value = queryString(handle, Files.FileColumns.DATA);
+ if (value != null) {
+ value = nameFromPath(value);
+ value.getChars(0, value.length(), outStringValue, 0);
+ outStringValue[value.length()] = 0;
+ return MtpConstants.RESPONSE_OK;
+ } else {
+ return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+ case MtpConstants.PROPERTY_NAME:
+ // first try title
+ String name = queryString(handle, MediaColumns.TITLE);
+ // then try name
+ if (name == null) {
+ name = queryString(handle, Audio.PlaylistsColumns.NAME);
+ }
+ // if title and name fail, extract name from full path
+ if (name == null) {
+ name = queryString(handle, Files.FileColumns.DATA);
+ if (name != null) {
+ name = nameFromPath(name);
+ }
+ }
+ if (name != null) {
+ name.getChars(0, name.length(), outStringValue, 0);
+ outStringValue[name.length()] = 0;
+ return MtpConstants.RESPONSE_OK;
+ } else {
+ return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
+ }
case MtpConstants.PROPERTY_DATE_MODIFIED:
column = Files.FileColumns.DATE_MODIFIED;
break;
+ case MtpConstants.PROPERTY_DATE_ADDED:
+ column = Files.FileColumns.DATE_ADDED;
+ break;
+ case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
+ column = Audio.AudioColumns.YEAR;
+ break;
case MtpConstants.PROPERTY_PARENT_OBJECT:
column = Files.FileColumns.PARENT;
break;
@@ -341,44 +536,64 @@ public class MtpDatabase {
puid += handle;
outIntValue[0] = puid;
return MtpConstants.RESPONSE_OK;
+ case MtpConstants.PROPERTY_DURATION:
+ column = Audio.AudioColumns.DURATION;
+ break;
+ case MtpConstants.PROPERTY_TRACK:
+ if (queryInt(handle, Audio.AudioColumns.TRACK, outIntValue)) {
+ // track is stored in lower 3 decimal digits
+ outIntValue[0] %= 1000;
+ return MtpConstants.RESPONSE_OK;
+ } else {
+ return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+ case MtpConstants.PROPERTY_DISPLAY_NAME:
+ column = MediaColumns.DISPLAY_NAME;
+ isString = true;
+ break;
+ case MtpConstants.PROPERTY_ARTIST:
+ column = Audio.AudioColumns.ARTIST;
+ isString = true;
+ break;
+ case MtpConstants.PROPERTY_ALBUM_NAME:
+ column = Audio.AudioColumns.ALBUM;
+ isString = true;
+ break;
+ case MtpConstants.PROPERTY_ALBUM_ARTIST:
+ column = Audio.AudioColumns.ALBUM_ARTIST;
+ isString = true;
+ break;
+ case MtpConstants.PROPERTY_GENRE:
+ String genre = queryGenre(handle);
+ if (genre != null) {
+ genre.getChars(0, genre.length(), outStringValue, 0);
+ outStringValue[genre.length()] = 0;
+ return MtpConstants.RESPONSE_OK;
+ } else {
+ return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+ case MtpConstants.PROPERTY_COMPOSER:
+ column = Audio.AudioColumns.COMPOSER;
+ isString = true;
+ break;
+ case MtpConstants.PROPERTY_DESCRIPTION:
+ column = Images.ImageColumns.DESCRIPTION;
+ isString = true;
+ break;
default:
return MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
}
- Cursor c = null;
- try {
- // for now we are only reading properties from the "objects" table
- c = mMediaProvider.query(mObjectsUri,
- new String [] { Files.FileColumns._ID, column },
- ID_WHERE, new String[] { Integer.toString(handle) }, null);
- if (c != null && c.moveToNext()) {
- if (isString) {
- String value = c.getString(1);
- int start = 0;
-
- if (property == MtpConstants.PROPERTY_OBJECT_FILE_NAME) {
- // extract name from full path
- int lastSlash = value.lastIndexOf('/');
- if (lastSlash >= 0) {
- start = lastSlash + 1;
- }
- }
- int end = value.length();
- if (end - start > 255) {
- end = start + 255;
- }
- value.getChars(start, end, outStringValue, 0);
- outStringValue[end - start] = 0;
- } else {
- outIntValue[0] = c.getLong(1);
- }
+ if (isString) {
+ String value = queryString(handle, column);
+ if (value != null) {
+ value.getChars(0, value.length(), outStringValue, 0);
+ outStringValue[value.length()] = 0;
return MtpConstants.RESPONSE_OK;
}
- } catch (Exception e) {
- return MtpConstants.RESPONSE_GENERAL_ERROR;
- } finally {
- if (c != null) {
- c.close();
+ } else {
+ if (queryInt(handle, column, outIntValue)) {
+ return MtpConstants.RESPONSE_OK;
}
}
// query failed if we get here
diff --git a/media/jni/android_media_MtpDatabase.cpp b/media/jni/android_media_MtpDatabase.cpp
index b5f4856..10ad29d 100644
--- a/media/jni/android_media_MtpDatabase.cpp
+++ b/media/jni/android_media_MtpDatabase.cpp
@@ -342,14 +342,21 @@ MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
jlong longValue = longValues[0];
env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
- // special case MTP_PROPERTY_DATE_MODIFIED, which is a string to MTP
+ // special case date properties, which are strings to MTP
// but stored internally as a uint64
- if (property == MTP_PROPERTY_DATE_MODIFIED) {
+ if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
char date[20];
formatDateTime(longValue, date, sizeof(date));
packet.putString(date);
return MTP_RESPONSE_OK;
}
+ // release date is stored internally as just the year
+ if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) {
+ char date[20];
+ snprintf(date, sizeof(date), "%04lld0101T000000", longValue);
+ packet.putString(date);
+ return MTP_RESPONSE_OK;
+ }
switch (type) {
case MTP_TYPE_INT8:
@@ -680,6 +687,17 @@ static const PropertyTableEntry kObjectPropertyTable[] = {
{ MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 },
{ MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 },
{ MTP_PROPERTY_NAME, MTP_TYPE_STR },
+ { MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR },
+ { MTP_PROPERTY_DATE_ADDED, MTP_TYPE_STR },
+ { MTP_PROPERTY_ARTIST, MTP_TYPE_STR },
+ { MTP_PROPERTY_ALBUM_NAME, MTP_TYPE_STR },
+ { MTP_PROPERTY_ALBUM_ARTIST, MTP_TYPE_STR },
+ { MTP_PROPERTY_TRACK, MTP_TYPE_UINT16 },
+ { MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR },
+ { MTP_PROPERTY_GENRE, MTP_TYPE_STR },
+ { MTP_PROPERTY_COMPOSER, MTP_TYPE_STR },
+ { MTP_PROPERTY_DURATION, MTP_TYPE_UINT32 },
+ { MTP_PROPERTY_DESCRIPTION, MTP_TYPE_STR },
};
static const PropertyTableEntry kDevicePropertyTable[] = {
@@ -754,10 +772,12 @@ MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
switch (property) {
case MTP_PROPERTY_OBJECT_FORMAT:
case MTP_PROPERTY_PROTECTION_STATUS:
+ case MTP_PROPERTY_TRACK:
result = new MtpProperty(property, MTP_TYPE_UINT16);
break;
case MTP_PROPERTY_STORAGE_ID:
case MTP_PROPERTY_PARENT_OBJECT:
+ case MTP_PROPERTY_DURATION:
result = new MtpProperty(property, MTP_TYPE_UINT32);
break;
case MTP_PROPERTY_OBJECT_SIZE:
@@ -769,6 +789,15 @@ MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
case MTP_PROPERTY_NAME:
case MTP_PROPERTY_OBJECT_FILE_NAME:
case MTP_PROPERTY_DATE_MODIFIED:
+ case MTP_PROPERTY_DISPLAY_NAME:
+ case MTP_PROPERTY_DATE_ADDED:
+ case MTP_PROPERTY_ARTIST:
+ case MTP_PROPERTY_ALBUM_NAME:
+ case MTP_PROPERTY_ALBUM_ARTIST:
+ case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
+ case MTP_PROPERTY_GENRE:
+ case MTP_PROPERTY_COMPOSER:
+ case MTP_PROPERTY_DESCRIPTION:
result = new MtpProperty(property, MTP_TYPE_STR);
break;
}