summaryrefslogtreecommitdiffstats
path: root/media/mtp
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2010-07-02 14:03:31 -0400
committerMike Lockwood <lockwood@android.com>2010-07-02 14:14:06 -0400
commit0250361b110267a139cc0865ff7d2f13b4d63bdf (patch)
treea2a5f01424d963c2b24d2fca8e2c59095ce404f8 /media/mtp
parentfc20aab463f527ab3b0664986f0381a86b375884 (diff)
downloadframeworks_av-0250361b110267a139cc0865ff7d2f13b4d63bdf.zip
frameworks_av-0250361b110267a139cc0865ff7d2f13b4d63bdf.tar.gz
frameworks_av-0250361b110267a139cc0865ff7d2f13b4d63bdf.tar.bz2
MTP: Make MtpDatabase class abstract so we can have multiple implementations
Rename existing test database to MtpSqliteDatabase This is the first step in transitioning to using the media provider database Change-Id: I5f36c854c6e76a79137c267b000a52ced803776c Signed-off-by: Mike Lockwood <lockwood@android.com>
Diffstat (limited to 'media/mtp')
-rw-r--r--media/mtp/Android.mk12
-rw-r--r--media/mtp/MtpDatabase.cpp504
-rw-r--r--media/mtp/MtpDatabase.h94
-rw-r--r--media/mtp/MtpServer.cpp4
-rw-r--r--media/mtp/MtpServer.h4
-rw-r--r--media/mtp/MtpSqliteDatabase.cpp564
-rw-r--r--media/mtp/MtpSqliteDatabase.h96
-rw-r--r--media/mtp/SqliteDatabase.h4
-rw-r--r--media/mtp/scantest.cpp4
9 files changed, 715 insertions, 571 deletions
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index 3c9909b..13a6430 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -32,6 +32,7 @@ LOCAL_SRC_FILES:= \
MtpRequestPacket.cpp \
MtpResponsePacket.cpp \
MtpServer.cpp \
+ MtpSqliteDatabase.cpp \
MtpStorageInfo.cpp \
MtpStringBuffer.cpp \
MtpStorage.cpp \
@@ -70,18 +71,9 @@ include $(CLEAR_VARS)
LOCAL_MODULE := scantest
LOCAL_SRC_FILES:= \
scantest.cpp \
- MtpMediaScanner.cpp \
- MtpDatabase.cpp \
- MtpDataPacket.cpp \
- MtpPacket.cpp \
- MtpStringBuffer.cpp \
- MtpUtils.cpp \
- SqliteDatabase.cpp \
- SqliteStatement.cpp \
-#LOCAL_STATIC_LIBRARIES := libusbhost
-#LOCAL_LDLIBS := -lpthread
+LOCAL_STATIC_LIBRARIES := libmtp
LOCAL_C_INCLUDES := external/sqlite/dist
LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright libmedia
diff --git a/media/mtp/MtpDatabase.cpp b/media/mtp/MtpDatabase.cpp
index 0f9b898..eabd993 100644
--- a/media/mtp/MtpDatabase.cpp
+++ b/media/mtp/MtpDatabase.cpp
@@ -18,196 +18,14 @@
#include "MtpDebug.h"
#include "MtpDatabase.h"
-#include "MtpDataPacket.h"
-#include "MtpUtils.h"
-#include "SqliteDatabase.h"
-#include "SqliteStatement.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sqlite3.h>
+#include "MtpTypes.h"
+#include "mtp.h"
namespace android {
-#define FILE_ID_COLUMN 1
-#define FILE_PATH_COLUMN 2
-#define FILE_FORMAT_COLUMN 3
-#define FILE_PARENT_COLUMN 4
-#define FILE_STORAGE_COLUMN 5
-#define FILE_SIZE_COLUMN 6
-#define FILE_MODIFIED_COLUMN 7
-
-#define AUDIO_ID_COLUMN 1
-#define AUDIO_TITLE_COLUMN 2
-#define AUDIO_ARTIST_COLUMN 3
-#define AUDIO_ALBUM_COLUMN 4
-#define AUDIO_ALBUM_ARTIST_COLUMN 5
-#define AUDIO_GENRE_COLUMN 6
-#define AUDIO_COMPOSER_COLUMN 7
-#define AUDIO_TRACK_NUMBER_COLUMN 8
-#define AUDIO_YEAR_COLUMN 9
-#define AUDIO_DURATION_COLUMN 10
-#define AUDIO_USE_COUNT_COLUMN 11
-#define AUDIO_SAMPLE_RATE_COLUMN 12
-#define AUDIO_NUM_CHANNELS_COLUMN 13
-#define AUDIO_AUDIO_WAVE_CODEC_COLUMN 14
-#define AUDIO_AUDIO_BIT_RATE_COLUMN 15
-
-#define FILE_TABLE_CREATE "CREATE TABLE IF NOT EXISTS files (" \
- "_id INTEGER PRIMARY KEY," \
- "path TEXT," \
- "format INTEGER," \
- "parent INTEGER," \
- "storage INTEGER," \
- "size INTEGER," \
- "date_modified INTEGER" \
- ");"
-
-#define AUDIO_TABLE_CREATE "CREATE TABLE IF NOT EXISTS audio (" \
- "id INTEGER PRIMARY KEY," \
- "title TEXT," \
- "artist TEXT," \
- "album TEXT," \
- "album_artist TEXT," \
- "genre TEXT," \
- "composer TEXT," \
- "track_number INTEGER," \
- "year INTEGER," \
- "duration INTEGER," \
- "use_count INTEGER," \
- "sample_rate INTEGER," \
- "num_channels INTEGER," \
- "audio_wave_codec TEXT," \
- "audio_bit_rate INTEGER" \
- ");"
-
-#define PATH_INDEX_CREATE "CREATE INDEX IF NOT EXISTS path_index on files(path);"
-
-#define FILE_ID_QUERY "SELECT _id,format FROM files WHERE path = ?;"
-#define FILE_PATH_QUERY "SELECT path,size FROM files WHERE _id = ?"
-
-#define GET_OBJECT_INFO_QUERY "SELECT storage,format,parent,path,size,date_modified FROM files WHERE _id = ?;"
-#define FILE_INSERT "INSERT INTO files VALUES(?,?,?,?,?,?,?);"
-#define FILE_DELETE "DELETE FROM files WHERE _id = ?;"
-
-#define AUDIO_INSERT "INSERT INTO audio VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);"
-#define AUDIO_DELETE "DELETE FROM audio WHERE id = ?;"
-
-struct PropertyTableEntry {
- MtpObjectProperty property;
- int type;
- const char* columnName;
-};
-
-static const PropertyTableEntry kPropertyTable[] = {
- { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, "parent" },
- { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, "storage" },
- { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT32, "format" },
- { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, "path" },
- { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, "size" },
- { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, "date_modified" },
-};
-
-static bool getPropertyInfo(MtpObjectProperty property, int& type, const char*& columnName) {
- int count = sizeof(kPropertyTable) / sizeof(kPropertyTable[0]);
- const PropertyTableEntry* entry = kPropertyTable;
- for (int i = 0; i < count; i++, entry++) {
- if (entry->property == property) {
- type = entry->type;
- columnName = entry->columnName;
- return true;
- }
- }
- return false;
-}
-
-
-
-MtpDatabase::MtpDatabase()
- : mFileIdQuery(NULL),
- mFilePathQuery(NULL),
- mObjectInfoQuery(NULL),
- mFileInserter(NULL),
- mFileDeleter(NULL),
- mAudioInserter(NULL),
- mAudioDeleter(NULL)
-{
-}
-
MtpDatabase::~MtpDatabase() {
}
-bool MtpDatabase::open(const char* path, bool create) {
- if (!SqliteDatabase::open(path, create))
- return false;
-
- // create tables and indices if necessary
- if (!exec(FILE_TABLE_CREATE)) {
- LOGE("could not create file table");
- return false;
- }
- if (!exec(PATH_INDEX_CREATE)) {
- LOGE("could not path index on file table");
- return false;
- }
- if (!exec(AUDIO_TABLE_CREATE)) {
- LOGE("could not create file table");
- return false;
- }
-
- if (!mFileIdQuery) {
- mFileIdQuery = new SqliteStatement(this);
- if (!mFileIdQuery->prepare(FILE_ID_QUERY)) {
- LOGE("could not compile FILE_ID_QUERY");
- exit(-1);
- }
- }
- if (!mFilePathQuery) {
- mFilePathQuery = new SqliteStatement(this);
- if (!mFilePathQuery->prepare(FILE_PATH_QUERY)) {
- LOGE("could not compile FILE_PATH_QUERY");
- exit(-1);
- }
- }
- if (!mObjectInfoQuery) {
- mObjectInfoQuery = new SqliteStatement(this);
- if (!mObjectInfoQuery->prepare(GET_OBJECT_INFO_QUERY)) {
- LOGE("could not compile GET_OBJECT_INFO_QUERY");
- exit(-1);
- }
- }
- if (!mFileInserter) {
- mFileInserter = new SqliteStatement(this);
- if (!mFileInserter->prepare(FILE_INSERT)) {
- LOGE("could not compile FILE_INSERT\n");
- exit(-1);
- }
- }
- if (!mFileDeleter) {
- mFileDeleter = new SqliteStatement(this);
- if (!mFileDeleter->prepare(FILE_DELETE)) {
- LOGE("could not compile FILE_DELETE\n");
- exit(-1);
- }
- }
- if (!mAudioInserter) {
- mAudioInserter = new SqliteStatement(this);
- if (!mAudioInserter->prepare(AUDIO_INSERT)) {
- LOGE("could not compile AUDIO_INSERT\n");
- exit(-1);
- }
- }
- if (!mAudioDeleter) {
- mAudioDeleter = new SqliteStatement(this);
- if (!mAudioDeleter->prepare(AUDIO_DELETE)) {
- LOGE("could not compile AUDIO_DELETE\n");
- exit(-1);
- }
- }
-
- return true;
-}
-
uint32_t MtpDatabase::getTableForFile(MtpObjectFormat format) {
switch (format) {
case MTP_FORMAT_AIFF:
@@ -260,322 +78,4 @@ uint32_t MtpDatabase::getTableForFile(MtpObjectFormat format) {
}
}
-MtpObjectHandle MtpDatabase::getObjectHandle(const char* path) {
- mFileIdQuery->reset();
- mFileIdQuery->bind(1, path);
- if (mFileIdQuery->step()) {
- int row = mFileIdQuery->getColumnInt(0);
- if (row > 0) {
- MtpObjectFormat format = mFileIdQuery->getColumnInt(1);
- row |= getTableForFile(format);
- return row;
- }
- }
-
- return 0;
-}
-
-MtpObjectHandle MtpDatabase::addFile(const char* path,
- MtpObjectFormat format,
- MtpObjectHandle parent,
- MtpStorageID storage,
- uint64_t size,
- time_t modified) {
- mFileInserter->bind(FILE_PATH_COLUMN, path);
- mFileInserter->bind(FILE_FORMAT_COLUMN, format);
- mFileInserter->bind(FILE_PARENT_COLUMN, parent);
- mFileInserter->bind(FILE_STORAGE_COLUMN, storage);
- mFileInserter->bind(FILE_SIZE_COLUMN, size);
- mFileInserter->bind(FILE_MODIFIED_COLUMN, modified);
- mFileInserter->step();
- mFileInserter->reset();
- int result = lastInsertedRow();
- return (result <= 0 ? kInvalidObjectHandle : result);
-}
-
-MtpObjectHandle MtpDatabase::addAudioFile(MtpObjectHandle handle) {
- mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
- mAudioInserter->step();
- mAudioInserter->reset();
- int result = lastInsertedRow();
- handle |= kObjectHandleTableAudio;
- return (result > 0 ? handle : kInvalidObjectHandle);
-}
-
-MtpObjectHandle MtpDatabase::addAudioFile(MtpObjectHandle handle,
- const char* title,
- const char* artist,
- const char* album,
- const char* albumArtist,
- const char* genre,
- const char* composer,
- const char* mimeType,
- int track,
- int year,
- int duration) {
- mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
- if (title) mAudioInserter->bind(AUDIO_TITLE_COLUMN, title);
- if (artist) mAudioInserter->bind(AUDIO_ARTIST_COLUMN, artist);
- if (album) mAudioInserter->bind(AUDIO_ALBUM_COLUMN, album);
- if (albumArtist) mAudioInserter->bind(AUDIO_ALBUM_ARTIST_COLUMN, albumArtist);
- if (genre) mAudioInserter->bind(AUDIO_GENRE_COLUMN, genre);
- if (composer) mAudioInserter->bind(AUDIO_COMPOSER_COLUMN, composer);
- if (track) mAudioInserter->bind(AUDIO_TRACK_NUMBER_COLUMN, track);
- if (year) mAudioInserter->bind(AUDIO_YEAR_COLUMN, year);
- if (duration) mAudioInserter->bind(AUDIO_DURATION_COLUMN, duration);
- mAudioInserter->step();
- mAudioInserter->reset();
- int result = lastInsertedRow();
- if (result <= 0)
- return kInvalidObjectHandle;
- result |= kObjectHandleTableAudio;
- return result;
-}
-
-MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
- MtpObjectFormat format,
- MtpObjectHandle parent) {
- bool whereStorage = (storageID != 0xFFFFFFFF);
- bool whereFormat = (format != 0);
- bool whereParent = (parent != 0);
- char intBuffer[20];
-
- MtpString query("SELECT _id,format FROM files");
- if (whereStorage || whereFormat || whereParent)
- query += " WHERE";
- if (whereStorage) {
- snprintf(intBuffer, sizeof(intBuffer), "%d", storageID);
- query += " storage = ";
- query += intBuffer;
- }
- if (whereFormat) {
- snprintf(intBuffer, sizeof(intBuffer), "%d", format);
- if (whereStorage)
- query += " AND";
- query += " format = ";
- query += intBuffer;
- }
- if (whereParent) {
- if (parent != MTP_PARENT_ROOT)
- parent &= kObjectHandleIndexMask;
- snprintf(intBuffer, sizeof(intBuffer), "%d", parent);
- if (whereStorage || whereFormat)
- query += " AND";
- query += " parent = ";
- query += intBuffer;
- }
- query += ";";
-
- SqliteStatement stmt(this);
- LOGV("%s", (const char *)query);
- stmt.prepare(query);
-
- MtpObjectHandleList* list = new MtpObjectHandleList();
- while (!stmt.isDone()) {
- if (stmt.step()) {
- int index = stmt.getColumnInt(0);
- LOGV("stmt.getColumnInt returned %d", index);
- if (index > 0) {
- MtpObjectFormat format = stmt.getColumnInt(1);
- index |= getTableForFile(format);
- list->push(index);
- }
- }
- }
- LOGV("list size: %d", list->size());
- return list;
-}
-
-
-MtpResponseCode MtpDatabase::getObjectProperty(MtpObjectHandle handle,
- MtpObjectProperty property,
- MtpDataPacket& packet) {
- int type;
- const char* columnName;
- char intBuffer[20];
-
- if (handle != MTP_PARENT_ROOT)
- handle &= kObjectHandleIndexMask;
-
- if (!getPropertyInfo(property, type, columnName))
- return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
- snprintf(intBuffer, sizeof(intBuffer), "%d", handle);
-
- MtpString query("SELECT ");
- query += columnName;
- query += " FROM files WHERE _id = ";
- query += intBuffer;
- query += ";";
-
- SqliteStatement stmt(this);
- LOGV("%s", (const char *)query);
- stmt.prepare(query);
-
- if (!stmt.step())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
-
- switch (type) {
- case MTP_TYPE_INT8:
- packet.putInt8(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_UINT8:
- packet.putUInt8(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_INT16:
- packet.putInt16(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_UINT16:
- packet.putUInt16(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_INT32:
- packet.putInt32(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_UINT32:
- packet.putUInt32(stmt.getColumnInt(0));
- break;
- case MTP_TYPE_INT64:
- packet.putInt64(stmt.getColumnInt64(0));
- break;
- case MTP_TYPE_UINT64:
- packet.putUInt64(stmt.getColumnInt64(0));
- break;
- case MTP_TYPE_STR:
- packet.putString(stmt.getColumnString(0));
- break;
- default:
- LOGE("unsupported object type\n");
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
- }
- return MTP_RESPONSE_OK;
-}
-
-MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
- MtpDataPacket& packet) {
- char date[20];
-
- if (handle != MTP_PARENT_ROOT)
- handle &= kObjectHandleIndexMask;
-
- mObjectInfoQuery->reset();
- mObjectInfoQuery->bind(1, handle);
- if (!mObjectInfoQuery->step())
- return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
-
- MtpStorageID storageID = mObjectInfoQuery->getColumnInt(0);
- MtpObjectFormat format = mObjectInfoQuery->getColumnInt(1);
- MtpObjectHandle parent = mObjectInfoQuery->getColumnInt(2);
- // extract name from path. do we want a separate database entry for this?
- const char* name = mObjectInfoQuery->getColumnString(3);
- const char* lastSlash = strrchr(name, '/');
- if (lastSlash)
- name = lastSlash + 1;
- int64_t size = mObjectInfoQuery->getColumnInt64(4);
- time_t modified = mObjectInfoQuery->getColumnInt(5);
- int associationType = (format == MTP_FORMAT_ASSOCIATION ?
- MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
- MTP_ASSOCIATION_TYPE_UNDEFINED);
-
- LOGV("storageID: %d, format: %d, parent: %d", storageID, format, parent);
-
- packet.putUInt32(storageID);
- packet.putUInt16(format);
- packet.putUInt16(0); // protection status
- packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
- packet.putUInt16(0); // thumb format
- packet.putUInt32(0); // thumb compressed size
- packet.putUInt32(0); // thumb pix width
- packet.putUInt32(0); // thumb pix height
- packet.putUInt32(0); // image pix width
- packet.putUInt32(0); // image pix height
- packet.putUInt32(0); // image bit depth
- packet.putUInt32(parent);
- packet.putUInt16(associationType);
- packet.putUInt32(0); // association desc
- packet.putUInt32(0); // sequence number
- packet.putString(name); // file name
- packet.putEmptyString();
- formatDateTime(modified, date, sizeof(date));
- packet.putString(date); // date modified
- packet.putEmptyString(); // keywords
-
- return MTP_RESPONSE_OK;
-}
-
-bool MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
- MtpString& filePath,
- int64_t& fileLength) {
- if (handle != MTP_PARENT_ROOT)
- handle &= kObjectHandleIndexMask;
- mFilePathQuery->reset();
- mFilePathQuery->bind(1, handle);
- if (!mFilePathQuery->step())
- return false;
-
- const char* path = mFilePathQuery->getColumnString(0);
- if (!path)
- return false;
- filePath = path;
- fileLength = mFilePathQuery->getColumnInt64(1);
- return true;
-}
-
-bool MtpDatabase::deleteFile(MtpObjectHandle handle) {
- uint32_t table = handle & kObjectHandleTableMask;
- handle &= kObjectHandleIndexMask;
- mFileDeleter->bind(1, handle);
- mFileDeleter->step();
- mFileDeleter->reset();
- if (table == kObjectHandleTableAudio) {
- mAudioDeleter->bind(1, handle);
- mAudioDeleter->step();
- mAudioDeleter->reset();
- }
-
- return true;
-}
-
-MtpObjectHandle* MtpDatabase::getFileList(int& outCount) {
- MtpObjectHandle* result = NULL;
- int count = 0;
- SqliteStatement stmt(this);
- stmt.prepare("SELECT count(*) FROM files;");
-
- MtpObjectHandleList* list = new MtpObjectHandleList();
- if (stmt.step())
- count = stmt.getColumnInt(0);
-
- if (count > 0) {
- result = new MtpObjectHandle[count];
- memset(result, 0, count * sizeof(*result));
- SqliteStatement stmt2(this);
- stmt2.prepare("SELECT _id,format FROM files;");
-
- for (int i = 0; i < count; i++) {
- if (!stmt2.step()) {
- LOGW("getFileList ended early");
- count = i;
- break;
- }
- MtpObjectHandle handle = stmt2.getColumnInt(0);
- MtpObjectFormat format = stmt2.getColumnInt(1);
- handle |= getTableForFile(format);
- result[i] = handle;
- }
- }
- outCount = count;
- return result;
-}
-
-/*
- for getObjectPropDesc
-
- packet.putUInt16(property);
- packet.putUInt16(dataType);
- packet.putUInt8(getSet);
- // default value DTS
- packet.putUInt32(groupCode);
- packet.putUInt8(formFlag);
- // form, variable
-*/
-
} // namespace android
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index 51d5fb1..0c70d9f 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -23,65 +23,57 @@
namespace android {
class MtpDataPacket;
-class SqliteStatement;
-
-class MtpDatabase : public SqliteDatabase {
-private:
- SqliteStatement* mFileIdQuery;
- SqliteStatement* mFilePathQuery;
- SqliteStatement* mObjectInfoQuery;
- SqliteStatement* mFileInserter;
- SqliteStatement* mFileDeleter;
- SqliteStatement* mAudioInserter;
- SqliteStatement* mAudioDeleter;
+class MtpDatabase {
public:
- MtpDatabase();
- virtual ~MtpDatabase();
-
- static uint32_t getTableForFile(MtpObjectFormat format);
-
- bool open(const char* path, bool create);
- MtpObjectHandle getObjectHandle(const char* path);
- MtpObjectHandle addFile(const char* path,
+ virtual ~MtpDatabase();
+
+ static uint32_t getTableForFile(MtpObjectFormat format);
+
+ virtual MtpObjectHandle getObjectHandle(const char* path) = 0;
+ virtual MtpObjectHandle addFile(const char* path,
+ MtpObjectFormat format,
+ MtpObjectHandle parent,
+ MtpStorageID storage,
+ uint64_t size,
+ time_t modified) = 0;
+
+ virtual MtpObjectHandle addAudioFile(MtpObjectHandle id) = 0;
+
+ virtual MtpObjectHandle addAudioFile(MtpObjectHandle id,
+ const char* title,
+ const char* artist,
+ const char* album,
+ const char* albumArtist,
+ const char* genre,
+ const char* composer,
+ const char* mimeType,
+ int track,
+ int year,
+ int duration) = 0;
+
+ virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
MtpObjectFormat format,
- MtpObjectHandle parent,
- MtpStorageID storage,
- uint64_t size,
- time_t modified);
-
- MtpObjectHandle addAudioFile(MtpObjectHandle id);
-
- MtpObjectHandle addAudioFile(MtpObjectHandle id,
- const char* title,
- const char* artist,
- const char* album,
- const char* albumArtist,
- const char* genre,
- const char* composer,
- const char* mimeType,
- int track,
- int year,
- int duration);
-
- MtpObjectHandleList* getObjectList(MtpStorageID storageID,
- MtpObjectFormat format,
- MtpObjectHandle parent);
+ MtpObjectHandle parent) = 0;
- MtpResponseCode getObjectProperty(MtpObjectHandle handle,
- MtpObjectProperty property,
- MtpDataPacket& packet);
+ virtual MtpResponseCode getObjectProperty(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet) = 0;
- MtpResponseCode getObjectInfo(MtpObjectHandle handle,
- MtpDataPacket& packet);
+ virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
+ MtpDataPacket& packet) = 0;
- bool getObjectFilePath(MtpObjectHandle handle,
- MtpString& filePath,
- int64_t& fileLength);
- bool deleteFile(MtpObjectHandle handle);
+ virtual bool getObjectFilePath(MtpObjectHandle handle,
+ MtpString& filePath,
+ int64_t& fileLength) = 0;
+ virtual bool deleteFile(MtpObjectHandle handle) = 0;
// helper for media scanner
- MtpObjectHandle* getFileList(int& outCount);
+ virtual MtpObjectHandle* getFileList(int& outCount) = 0;
+
+ virtual void beginTransaction() = 0;
+ virtual void commitTransaction() = 0;
+ virtual void rollbackTransaction() = 0;
};
}; // namespace android
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 0b99cb1..cc6fdad 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -25,9 +25,9 @@
#include <cutils/properties.h>
#include "MtpDebug.h"
-#include "MtpDatabase.h"
#include "MtpProperty.h"
#include "MtpServer.h"
+#include "MtpSqliteDatabase.h"
#include "MtpStorage.h"
#include "MtpStringBuffer.h"
@@ -122,7 +122,7 @@ MtpServer::MtpServer(int fd, const char* databasePath)
mSendObjectHandle(kInvalidObjectHandle),
mSendObjectFileSize(0)
{
- mDatabase = new MtpDatabase();
+ mDatabase = new MtpSqliteDatabase();
mDatabase->open(databasePath, true);
initObjectProperties();
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 40329c5..42261a9 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -27,7 +27,7 @@
namespace android {
class MtpStorage;
-class MtpDatabase;
+class MtpSqliteDatabase;
class MtpProperty;
class MtpServer {
@@ -39,7 +39,7 @@ private:
// path to our sqlite3 database
const char* mDatabasePath;
- MtpDatabase* mDatabase;
+ MtpSqliteDatabase* mDatabase;
// current session ID
MtpSessionID mSessionID;
diff --git a/media/mtp/MtpSqliteDatabase.cpp b/media/mtp/MtpSqliteDatabase.cpp
new file mode 100644
index 0000000..fa3bdfe
--- /dev/null
+++ b/media/mtp/MtpSqliteDatabase.cpp
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "MtpSqliteDatabase"
+
+#include "MtpDebug.h"
+#include "MtpSqliteDatabase.h"
+#include "MtpDataPacket.h"
+#include "MtpUtils.h"
+#include "SqliteDatabase.h"
+#include "SqliteStatement.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sqlite3.h>
+
+namespace android {
+
+#define FILE_ID_COLUMN 1
+#define FILE_PATH_COLUMN 2
+#define FILE_FORMAT_COLUMN 3
+#define FILE_PARENT_COLUMN 4
+#define FILE_STORAGE_COLUMN 5
+#define FILE_SIZE_COLUMN 6
+#define FILE_MODIFIED_COLUMN 7
+
+#define AUDIO_ID_COLUMN 1
+#define AUDIO_TITLE_COLUMN 2
+#define AUDIO_ARTIST_COLUMN 3
+#define AUDIO_ALBUM_COLUMN 4
+#define AUDIO_ALBUM_ARTIST_COLUMN 5
+#define AUDIO_GENRE_COLUMN 6
+#define AUDIO_COMPOSER_COLUMN 7
+#define AUDIO_TRACK_NUMBER_COLUMN 8
+#define AUDIO_YEAR_COLUMN 9
+#define AUDIO_DURATION_COLUMN 10
+#define AUDIO_USE_COUNT_COLUMN 11
+#define AUDIO_SAMPLE_RATE_COLUMN 12
+#define AUDIO_NUM_CHANNELS_COLUMN 13
+#define AUDIO_AUDIO_WAVE_CODEC_COLUMN 14
+#define AUDIO_AUDIO_BIT_RATE_COLUMN 15
+
+#define FILE_TABLE_CREATE "CREATE TABLE IF NOT EXISTS files (" \
+ "_id INTEGER PRIMARY KEY," \
+ "path TEXT," \
+ "format INTEGER," \
+ "parent INTEGER," \
+ "storage INTEGER," \
+ "size INTEGER," \
+ "date_modified INTEGER" \
+ ");"
+
+#define AUDIO_TABLE_CREATE "CREATE TABLE IF NOT EXISTS audio (" \
+ "id INTEGER PRIMARY KEY," \
+ "title TEXT," \
+ "artist TEXT," \
+ "album TEXT," \
+ "album_artist TEXT," \
+ "genre TEXT," \
+ "composer TEXT," \
+ "track_number INTEGER," \
+ "year INTEGER," \
+ "duration INTEGER," \
+ "use_count INTEGER," \
+ "sample_rate INTEGER," \
+ "num_channels INTEGER," \
+ "audio_wave_codec TEXT," \
+ "audio_bit_rate INTEGER" \
+ ");"
+
+#define PATH_INDEX_CREATE "CREATE INDEX IF NOT EXISTS path_index on files(path);"
+
+#define FILE_ID_QUERY "SELECT _id,format FROM files WHERE path = ?;"
+#define FILE_PATH_QUERY "SELECT path,size FROM files WHERE _id = ?"
+
+#define GET_OBJECT_INFO_QUERY "SELECT storage,format,parent,path,size,date_modified FROM files WHERE _id = ?;"
+#define FILE_INSERT "INSERT INTO files VALUES(?,?,?,?,?,?,?);"
+#define FILE_DELETE "DELETE FROM files WHERE _id = ?;"
+
+#define AUDIO_INSERT "INSERT INTO audio VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);"
+#define AUDIO_DELETE "DELETE FROM audio WHERE id = ?;"
+
+struct PropertyTableEntry {
+ MtpObjectProperty property;
+ int type;
+ const char* columnName;
+};
+
+static const PropertyTableEntry kPropertyTable[] = {
+ { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32, "parent" },
+ { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32, "storage" },
+ { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT32, "format" },
+ { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR, "path" },
+ { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64, "size" },
+ { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR, "date_modified" },
+};
+
+static bool getPropertyInfo(MtpObjectProperty property, int& type, const char*& columnName) {
+ int count = sizeof(kPropertyTable) / sizeof(kPropertyTable[0]);
+ const PropertyTableEntry* entry = kPropertyTable;
+ for (int i = 0; i < count; i++, entry++) {
+ if (entry->property == property) {
+ type = entry->type;
+ columnName = entry->columnName;
+ return true;
+ }
+ }
+ return false;
+}
+
+MtpSqliteDatabase::MtpSqliteDatabase()
+ : mDatabase(NULL),
+ mFileIdQuery(NULL),
+ mFilePathQuery(NULL),
+ mObjectInfoQuery(NULL),
+ mFileInserter(NULL),
+ mFileDeleter(NULL),
+ mAudioInserter(NULL),
+ mAudioDeleter(NULL)
+{
+}
+
+MtpSqliteDatabase::~MtpSqliteDatabase() {
+ delete mDatabase;
+ delete mFileIdQuery;
+ delete mFilePathQuery;
+ delete mObjectInfoQuery;
+ delete mFileInserter;
+ delete mFileDeleter;
+ delete mAudioInserter;
+ delete mAudioDeleter;
+}
+
+bool MtpSqliteDatabase::open(const char* path, bool create) {
+ mDatabase = new SqliteDatabase;
+
+ if (!mDatabase->open(path, create))
+ goto fail;
+
+ // create tables and indices if necessary
+ if (!mDatabase->exec(FILE_TABLE_CREATE)) {
+ LOGE("could not create file table");
+ goto fail;
+ }
+ if (!mDatabase->exec(PATH_INDEX_CREATE)) {
+ LOGE("could not path index on file table");
+ goto fail;
+ }
+ if (!mDatabase->exec(AUDIO_TABLE_CREATE)) {
+ LOGE("could not create file table");
+ goto fail;
+ }
+
+ if (!mFileIdQuery) {
+ mFileIdQuery = new SqliteStatement(mDatabase);
+ if (!mFileIdQuery->prepare(FILE_ID_QUERY)) {
+ LOGE("could not compile FILE_ID_QUERY");
+ goto fail;
+ }
+ }
+ if (!mFilePathQuery) {
+ mFilePathQuery = new SqliteStatement(mDatabase);
+ if (!mFilePathQuery->prepare(FILE_PATH_QUERY)) {
+ LOGE("could not compile FILE_PATH_QUERY");
+ goto fail;
+ }
+ }
+ if (!mObjectInfoQuery) {
+ mObjectInfoQuery = new SqliteStatement(mDatabase);
+ if (!mObjectInfoQuery->prepare(GET_OBJECT_INFO_QUERY)) {
+ LOGE("could not compile GET_OBJECT_INFO_QUERY");
+ goto fail;
+ }
+ }
+ if (!mFileInserter) {
+ mFileInserter = new SqliteStatement(mDatabase);
+ if (!mFileInserter->prepare(FILE_INSERT)) {
+ LOGE("could not compile FILE_INSERT\n");
+ goto fail;
+ }
+ }
+ if (!mFileDeleter) {
+ mFileDeleter = new SqliteStatement(mDatabase);
+ if (!mFileDeleter->prepare(FILE_DELETE)) {
+ LOGE("could not compile FILE_DELETE\n");
+ goto fail;
+ }
+ }
+ if (!mAudioInserter) {
+ mAudioInserter = new SqliteStatement(mDatabase);
+ if (!mAudioInserter->prepare(AUDIO_INSERT)) {
+ LOGE("could not compile AUDIO_INSERT\n");
+ goto fail;
+ }
+ }
+ if (!mAudioDeleter) {
+ mAudioDeleter = new SqliteStatement(mDatabase);
+ if (!mAudioDeleter->prepare(AUDIO_DELETE)) {
+ LOGE("could not compile AUDIO_DELETE\n");
+ goto fail;
+ }
+ }
+
+ return true;
+
+fail:
+ delete mDatabase;
+ delete mFileIdQuery;
+ delete mFilePathQuery;
+ delete mObjectInfoQuery;
+ delete mFileInserter;
+ delete mFileDeleter;
+ delete mAudioInserter;
+ delete mAudioDeleter;
+ mDatabase = NULL;
+ mFileIdQuery = NULL;
+ mFilePathQuery = NULL;
+ mObjectInfoQuery = NULL;
+ mFileInserter = NULL;
+ mFileDeleter = NULL;
+ mAudioInserter = NULL;
+ mAudioDeleter = NULL;
+ return false;
+}
+
+void MtpSqliteDatabase::close() {
+ if (mDatabase) {
+ mDatabase->close();
+ mDatabase = NULL;
+ }
+}
+
+MtpObjectHandle MtpSqliteDatabase::getObjectHandle(const char* path) {
+ mFileIdQuery->reset();
+ mFileIdQuery->bind(1, path);
+ if (mFileIdQuery->step()) {
+ int row = mFileIdQuery->getColumnInt(0);
+ if (row > 0) {
+ MtpObjectFormat format = mFileIdQuery->getColumnInt(1);
+ row |= getTableForFile(format);
+ return row;
+ }
+ }
+
+ return 0;
+}
+
+MtpObjectHandle MtpSqliteDatabase::addFile(const char* path,
+ MtpObjectFormat format,
+ MtpObjectHandle parent,
+ MtpStorageID storage,
+ uint64_t size,
+ time_t modified) {
+ mFileInserter->bind(FILE_PATH_COLUMN, path);
+ mFileInserter->bind(FILE_FORMAT_COLUMN, format);
+ mFileInserter->bind(FILE_PARENT_COLUMN, parent);
+ mFileInserter->bind(FILE_STORAGE_COLUMN, storage);
+ mFileInserter->bind(FILE_SIZE_COLUMN, size);
+ mFileInserter->bind(FILE_MODIFIED_COLUMN, modified);
+ mFileInserter->step();
+ mFileInserter->reset();
+ int result = mDatabase->lastInsertedRow();
+ return (result <= 0 ? kInvalidObjectHandle : result);
+}
+
+MtpObjectHandle MtpSqliteDatabase::addAudioFile(MtpObjectHandle handle) {
+ mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
+ mAudioInserter->step();
+ mAudioInserter->reset();
+ int result = mDatabase->lastInsertedRow();
+ handle |= kObjectHandleTableAudio;
+ return (result > 0 ? handle : kInvalidObjectHandle);
+}
+
+MtpObjectHandle MtpSqliteDatabase::addAudioFile(MtpObjectHandle handle,
+ const char* title,
+ const char* artist,
+ const char* album,
+ const char* albumArtist,
+ const char* genre,
+ const char* composer,
+ const char* mimeType,
+ int track,
+ int year,
+ int duration) {
+ mAudioInserter->bind(AUDIO_ID_COLUMN, handle);
+ if (title) mAudioInserter->bind(AUDIO_TITLE_COLUMN, title);
+ if (artist) mAudioInserter->bind(AUDIO_ARTIST_COLUMN, artist);
+ if (album) mAudioInserter->bind(AUDIO_ALBUM_COLUMN, album);
+ if (albumArtist) mAudioInserter->bind(AUDIO_ALBUM_ARTIST_COLUMN, albumArtist);
+ if (genre) mAudioInserter->bind(AUDIO_GENRE_COLUMN, genre);
+ if (composer) mAudioInserter->bind(AUDIO_COMPOSER_COLUMN, composer);
+ if (track) mAudioInserter->bind(AUDIO_TRACK_NUMBER_COLUMN, track);
+ if (year) mAudioInserter->bind(AUDIO_YEAR_COLUMN, year);
+ if (duration) mAudioInserter->bind(AUDIO_DURATION_COLUMN, duration);
+ mAudioInserter->step();
+ mAudioInserter->reset();
+ int result = mDatabase->lastInsertedRow();
+ if (result <= 0)
+ return kInvalidObjectHandle;
+ result |= kObjectHandleTableAudio;
+ return result;
+}
+
+MtpObjectHandleList* MtpSqliteDatabase::getObjectList(MtpStorageID storageID,
+ MtpObjectFormat format,
+ MtpObjectHandle parent) {
+ bool whereStorage = (storageID != 0xFFFFFFFF);
+ bool whereFormat = (format != 0);
+ bool whereParent = (parent != 0);
+ char intBuffer[20];
+
+ MtpString query("SELECT _id,format FROM files");
+ if (whereStorage || whereFormat || whereParent)
+ query += " WHERE";
+ if (whereStorage) {
+ snprintf(intBuffer, sizeof(intBuffer), "%d", storageID);
+ query += " storage = ";
+ query += intBuffer;
+ }
+ if (whereFormat) {
+ snprintf(intBuffer, sizeof(intBuffer), "%d", format);
+ if (whereStorage)
+ query += " AND";
+ query += " format = ";
+ query += intBuffer;
+ }
+ if (whereParent) {
+ if (parent != MTP_PARENT_ROOT)
+ parent &= kObjectHandleIndexMask;
+ snprintf(intBuffer, sizeof(intBuffer), "%d", parent);
+ if (whereStorage || whereFormat)
+ query += " AND";
+ query += " parent = ";
+ query += intBuffer;
+ }
+ query += ";";
+
+ SqliteStatement stmt(mDatabase);
+ LOGV("%s", (const char *)query);
+ stmt.prepare(query);
+
+ MtpObjectHandleList* list = new MtpObjectHandleList();
+ while (!stmt.isDone()) {
+ if (stmt.step()) {
+ int index = stmt.getColumnInt(0);
+ LOGV("stmt.getColumnInt returned %d", index);
+ if (index > 0) {
+ MtpObjectFormat format = stmt.getColumnInt(1);
+ index |= getTableForFile(format);
+ list->push(index);
+ }
+ }
+ }
+ LOGV("list size: %d", list->size());
+ return list;
+}
+
+
+MtpResponseCode MtpSqliteDatabase::getObjectProperty(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet) {
+ int type;
+ const char* columnName;
+ char intBuffer[20];
+
+ if (handle != MTP_PARENT_ROOT)
+ handle &= kObjectHandleIndexMask;
+
+ if (!getPropertyInfo(property, type, columnName))
+ return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE;
+ snprintf(intBuffer, sizeof(intBuffer), "%d", handle);
+
+ MtpString query("SELECT ");
+ query += columnName;
+ query += " FROM files WHERE _id = ";
+ query += intBuffer;
+ query += ";";
+
+ SqliteStatement stmt(mDatabase);
+ LOGV("%s", (const char *)query);
+ stmt.prepare(query);
+
+ if (!stmt.step())
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+
+ switch (type) {
+ case MTP_TYPE_INT8:
+ packet.putInt8(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_UINT8:
+ packet.putUInt8(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_INT16:
+ packet.putInt16(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_UINT16:
+ packet.putUInt16(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_INT32:
+ packet.putInt32(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_UINT32:
+ packet.putUInt32(stmt.getColumnInt(0));
+ break;
+ case MTP_TYPE_INT64:
+ packet.putInt64(stmt.getColumnInt64(0));
+ break;
+ case MTP_TYPE_UINT64:
+ packet.putUInt64(stmt.getColumnInt64(0));
+ break;
+ case MTP_TYPE_STR:
+ packet.putString(stmt.getColumnString(0));
+ break;
+ default:
+ LOGE("unsupported object type\n");
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpSqliteDatabase::getObjectInfo(MtpObjectHandle handle,
+ MtpDataPacket& packet) {
+ char date[20];
+
+ if (handle != MTP_PARENT_ROOT)
+ handle &= kObjectHandleIndexMask;
+
+ mObjectInfoQuery->reset();
+ mObjectInfoQuery->bind(1, handle);
+ if (!mObjectInfoQuery->step())
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+
+ MtpStorageID storageID = mObjectInfoQuery->getColumnInt(0);
+ MtpObjectFormat format = mObjectInfoQuery->getColumnInt(1);
+ MtpObjectHandle parent = mObjectInfoQuery->getColumnInt(2);
+ // extract name from path. do we want a separate database entry for this?
+ const char* name = mObjectInfoQuery->getColumnString(3);
+ const char* lastSlash = strrchr(name, '/');
+ if (lastSlash)
+ name = lastSlash + 1;
+ int64_t size = mObjectInfoQuery->getColumnInt64(4);
+ time_t modified = mObjectInfoQuery->getColumnInt(5);
+ int associationType = (format == MTP_FORMAT_ASSOCIATION ?
+ MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
+ MTP_ASSOCIATION_TYPE_UNDEFINED);
+
+ LOGV("storageID: %d, format: %d, parent: %d", storageID, format, parent);
+
+ packet.putUInt32(storageID);
+ packet.putUInt16(format);
+ packet.putUInt16(0); // protection status
+ packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
+ packet.putUInt16(0); // thumb format
+ packet.putUInt32(0); // thumb compressed size
+ packet.putUInt32(0); // thumb pix width
+ packet.putUInt32(0); // thumb pix height
+ packet.putUInt32(0); // image pix width
+ packet.putUInt32(0); // image pix height
+ packet.putUInt32(0); // image bit depth
+ packet.putUInt32(parent);
+ packet.putUInt16(associationType);
+ packet.putUInt32(0); // association desc
+ packet.putUInt32(0); // sequence number
+ packet.putString(name); // file name
+ packet.putEmptyString();
+ formatDateTime(modified, date, sizeof(date));
+ packet.putString(date); // date modified
+ packet.putEmptyString(); // keywords
+
+ return MTP_RESPONSE_OK;
+}
+
+bool MtpSqliteDatabase::getObjectFilePath(MtpObjectHandle handle,
+ MtpString& filePath,
+ int64_t& fileLength) {
+ if (handle != MTP_PARENT_ROOT)
+ handle &= kObjectHandleIndexMask;
+ mFilePathQuery->reset();
+ mFilePathQuery->bind(1, handle);
+ if (!mFilePathQuery->step())
+ return false;
+
+ const char* path = mFilePathQuery->getColumnString(0);
+ if (!path)
+ return false;
+ filePath = path;
+ fileLength = mFilePathQuery->getColumnInt64(1);
+ return true;
+}
+
+bool MtpSqliteDatabase::deleteFile(MtpObjectHandle handle) {
+ uint32_t table = handle & kObjectHandleTableMask;
+ handle &= kObjectHandleIndexMask;
+ mFileDeleter->bind(1, handle);
+ mFileDeleter->step();
+ mFileDeleter->reset();
+ if (table == kObjectHandleTableAudio) {
+ mAudioDeleter->bind(1, handle);
+ mAudioDeleter->step();
+ mAudioDeleter->reset();
+ }
+
+ return true;
+}
+
+MtpObjectHandle* MtpSqliteDatabase::getFileList(int& outCount) {
+ MtpObjectHandle* result = NULL;
+ int count = 0;
+ SqliteStatement stmt(mDatabase);
+ stmt.prepare("SELECT count(*) FROM files;");
+
+ MtpObjectHandleList* list = new MtpObjectHandleList();
+ if (stmt.step())
+ count = stmt.getColumnInt(0);
+
+ if (count > 0) {
+ result = new MtpObjectHandle[count];
+ memset(result, 0, count * sizeof(*result));
+ SqliteStatement stmt2(mDatabase);
+ stmt2.prepare("SELECT _id,format FROM files;");
+
+ for (int i = 0; i < count; i++) {
+ if (!stmt2.step()) {
+ LOGW("getFileList ended early");
+ count = i;
+ break;
+ }
+ MtpObjectHandle handle = stmt2.getColumnInt(0);
+ MtpObjectFormat format = stmt2.getColumnInt(1);
+ handle |= getTableForFile(format);
+ result[i] = handle;
+ }
+ }
+ outCount = count;
+ return result;
+}
+
+void MtpSqliteDatabase::beginTransaction() {
+ mDatabase->beginTransaction();
+}
+
+void MtpSqliteDatabase::commitTransaction() {
+ mDatabase->commitTransaction();
+}
+
+void MtpSqliteDatabase::rollbackTransaction() {
+ mDatabase->rollbackTransaction();
+}
+
+} // namespace android
diff --git a/media/mtp/MtpSqliteDatabase.h b/media/mtp/MtpSqliteDatabase.h
new file mode 100644
index 0000000..74626a8
--- /dev/null
+++ b/media/mtp/MtpSqliteDatabase.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef _MTP_SQLITE_DATABASE_H
+#define _MTP_SQLITE_DATABASE_H
+
+#include "MtpTypes.h"
+#include "MtpDatabase.h"
+
+class SqliteDatabase;
+
+namespace android {
+
+class MtpDataPacket;
+class SqliteStatement;
+
+class MtpSqliteDatabase : public MtpDatabase {
+private:
+ SqliteDatabase* mDatabase;
+ SqliteStatement* mFileIdQuery;
+ SqliteStatement* mFilePathQuery;
+ SqliteStatement* mObjectInfoQuery;
+ SqliteStatement* mFileInserter;
+ SqliteStatement* mFileDeleter;
+ SqliteStatement* mAudioInserter;
+ SqliteStatement* mAudioDeleter;
+
+public:
+ MtpSqliteDatabase();
+ virtual ~MtpSqliteDatabase();
+
+ bool open(const char* path, bool create);
+ void close();
+
+ virtual MtpObjectHandle getObjectHandle(const char* path);
+ virtual MtpObjectHandle addFile(const char* path,
+ MtpObjectFormat format,
+ MtpObjectHandle parent,
+ MtpStorageID storage,
+ uint64_t size,
+ time_t modified);
+
+ virtual MtpObjectHandle addAudioFile(MtpObjectHandle id);
+
+ virtual MtpObjectHandle addAudioFile(MtpObjectHandle id,
+ const char* title,
+ const char* artist,
+ const char* album,
+ const char* albumArtist,
+ const char* genre,
+ const char* composer,
+ const char* mimeType,
+ int track,
+ int year,
+ int duration);
+
+ virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
+ MtpObjectFormat format,
+ MtpObjectHandle parent);
+
+ virtual MtpResponseCode getObjectProperty(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet);
+
+ virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
+ MtpDataPacket& packet);
+
+ virtual bool getObjectFilePath(MtpObjectHandle handle,
+ MtpString& filePath,
+ int64_t& fileLength);
+ virtual bool deleteFile(MtpObjectHandle handle);
+
+ // helper for media scanner
+ virtual MtpObjectHandle* getFileList(int& outCount);
+
+ virtual void beginTransaction();
+ virtual void commitTransaction();
+ virtual void rollbackTransaction();
+};
+
+}; // namespace android
+
+#endif // _MTP_SQLITE_DATABASE_H
diff --git a/media/mtp/SqliteDatabase.h b/media/mtp/SqliteDatabase.h
index 56dd9dd..7d008f9 100644
--- a/media/mtp/SqliteDatabase.h
+++ b/media/mtp/SqliteDatabase.h
@@ -29,8 +29,8 @@ public:
SqliteDatabase();
virtual ~SqliteDatabase();
- virtual bool open(const char* path, bool create);
- virtual void close();
+ bool open(const char* path, bool create);
+ void close();
bool exec(const char* sql);
int lastInsertedRow();
diff --git a/media/mtp/scantest.cpp b/media/mtp/scantest.cpp
index f910bb6..3702a5d 100644
--- a/media/mtp/scantest.cpp
+++ b/media/mtp/scantest.cpp
@@ -16,7 +16,7 @@
#include <stdio.h>
-#include "MtpDatabase.h"
+#include "MtpSqliteDatabase.h"
#include "MtpMediaScanner.h"
using namespace android;
@@ -27,7 +27,7 @@ int main(int argc, char* argv[]) {
return -1;
}
- MtpDatabase* database = new MtpDatabase();
+ MtpSqliteDatabase* database = new MtpSqliteDatabase();
database->open("scantest.db", true);
MtpMediaScanner scanner(1, argv[1], database);