Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d0782678 authored by Mike Lockwood's avatar Mike Lockwood
Browse files

MTP: More prototyping work:



New media scanner test program
Media scanner now cleans up after files that no longer exist
Separate database table for audio files
Extract metadata from audio files with libstagefright

Change-Id: I2bd0fe877836c741658e72fcfeb89c11be0d9b41
Signed-off-by: default avatarMike Lockwood <lockwood@android.com>
parent f6e9a082
Loading
Loading
Loading
Loading
+29 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ LOCAL_SRC_FILES:= \
                  MtpDatabase.cpp                       \
                  MtpDataPacket.cpp                     \
                  MtpDebug.cpp                          \
                  MtpMediaScanner.cpp                   \
                  MtpPacket.cpp                         \
                  MtpRequestPacket.cpp                  \
                  MtpResponsePacket.cpp                 \
@@ -40,7 +41,7 @@ LOCAL_C_INCLUDES := external/sqlite/dist

LOCAL_CFLAGS := -DMTP_DEVICE

LOCAL_SHARED_LIBRARIES := libutils libsqlite
LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright

include $(BUILD_EXECUTABLE)

@@ -70,4 +71,31 @@ LOCAL_LDFLAGS := -g

include $(BUILD_HOST_EXECUTABLE)

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_C_INCLUDES := external/sqlite/dist
LOCAL_SHARED_LIBRARIES := libutils libsqlite libstagefright


LOCAL_CFLAGS := -g
LOCAL_LDFLAGS := -g

include $(BUILD_EXECUTABLE)

endif
 No newline at end of file
+284 −97
Original line number Diff line number Diff line
@@ -20,38 +20,74 @@
#include "SqliteStatement.h"

#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>

namespace android {

#define ID_COLUMN       1
#define PATH_COLUMN     2
#define FORMAT_COLUMN   3
#define PARENT_COLUMN   4
#define STORAGE_COLUMN  5
#define SIZE_COLUMN     6
#define CREATED_COLUMN  7
#define MODIFIED_COLUMN 8

#define TABLE_CREATE    "CREATE TABLE IF NOT EXISTS files ("    \
#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_created 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 FROM files WHERE 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_created,date_modified FROM files WHERE _id = ?;"
#define FILE_INSERT     "INSERT INTO files VALUES(?,?,?,?,?,?,?,?);"
#define FILE_DELETE     "DELETE FROM files WHERE path = ?;"
#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;
@@ -65,7 +101,6 @@ static const PropertyTableEntry kPropertyTable[] = {
    {   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_CREATED,      MTP_TYPE_STR,       "date_created"  },
    {   MTP_PROPERTY_DATE_MODIFIED,     MTP_TYPE_STR,       "date_modified" },
};

@@ -83,11 +118,14 @@ static bool getPropertyInfo(MtpObjectProperty property, int& type, const char*&
}



MtpDatabase::MtpDatabase()
    :   mFileIdQuery(NULL),
        mObjectInfoQuery(NULL),
        mFileInserter(NULL),
        mFileDeleter(NULL)
        mFileDeleter(NULL),
        mAudioInserter(NULL),
        mAudioDeleter(NULL)
{
}

@@ -98,66 +136,195 @@ bool MtpDatabase::open(const char* path, bool create) {
    if (!SqliteDatabase::open(path, create))
        return false;

    // create the table if necessary
    if (!exec(TABLE_CREATE)) {
        fprintf(stderr, "could not create table\n");
    // create tables and indices if necessary
    if (!exec(FILE_TABLE_CREATE)) {
        fprintf(stderr, "could not create file table\n");
        return false;
    }
    if (!exec(PATH_INDEX_CREATE)) {
        fprintf(stderr, "could not path index\n");
        fprintf(stderr, "could not path index on file table\n");
        return false;
    }
    return true;
    if (!exec(AUDIO_TABLE_CREATE)) {
        fprintf(stderr, "could not create file table\n");
        return false;
    }

MtpObjectHandle MtpDatabase::addFile(const char* path,
                                    MtpObjectFormat format,
                                    MtpObjectHandle parent,
                                    MtpStorageID storage,
                                    uint64_t size,
                                    time_t created,
                                    time_t modified) {

    // first check to see if the file exists
    if (mFileIdQuery)
        mFileIdQuery->reset();
    else {
    if (!mFileIdQuery) {
        mFileIdQuery = new SqliteStatement(this);
        if (!mFileIdQuery->prepare(FILE_ID_QUERY)) {
            fprintf(stderr, "could not compile FILE_ID_QUERY\n");
            delete mFileIdQuery;
            mFileIdQuery = NULL;
            return kInvalidObjectHandle;
            exit(-1);
        }
    }
    if (!mFilePathQuery) {
        mFilePathQuery = new SqliteStatement(this);
        if (!mFilePathQuery->prepare(FILE_PATH_QUERY)) {
            fprintf(stderr, "could not compile FILE_PATH_QUERY\n");
            exit(-1);
        }
    }
    if (!mObjectInfoQuery) {
        mObjectInfoQuery = new SqliteStatement(this);
        if (!mObjectInfoQuery->prepare(GET_OBJECT_INFO_QUERY)) {
            fprintf(stderr, "could not compile GET_OBJECT_INFO_QUERY\n");
            exit(-1);
        }
    }
    if (!mFileInserter) {
        mFileInserter = new SqliteStatement(this);
        if (!mFileInserter->prepare(FILE_INSERT)) {
            fprintf(stderr, "could not compile FILE_INSERT\n");
            exit(-1);
        }
    }
    if (!mFileDeleter) {
        mFileDeleter = new SqliteStatement(this);
        if (!mFileDeleter->prepare(FILE_DELETE)) {
            fprintf(stderr, "could not compile FILE_DELETE\n");
            exit(-1);
        }
    }
    if (!mAudioInserter) {
        mAudioInserter = new SqliteStatement(this);
        if (!mAudioInserter->prepare(AUDIO_INSERT)) {
            fprintf(stderr, "could not compile AUDIO_INSERT\n");
            exit(-1);
        }
    }
    if (!mAudioDeleter) {
        mAudioDeleter = new SqliteStatement(this);
        if (!mAudioDeleter->prepare(AUDIO_DELETE)) {
            fprintf(stderr, "could not compile AUDIO_DELETE\n");
            exit(-1);
        }
    }

    return true;
}

uint32_t MtpDatabase::getTableForFile(MtpObjectFormat format) {
    switch (format) {
        case MTP_FORMAT_AIFF:
        case MTP_FORMAT_WAV:
        case MTP_FORMAT_MP3:
        case MTP_FORMAT_FLAC:
        case MTP_FORMAT_UNDEFINED_AUDIO:
        case MTP_FORMAT_WMA:
        case MTP_FORMAT_OGG:
        case MTP_FORMAT_AAC:
        case MTP_FORMAT_AUDIBLE:
            return kObjectHandleTableAudio;
        case MTP_FORMAT_AVI:
        case MTP_FORMAT_MPEG:
        case MTP_FORMAT_ASF:
        case MTP_FORMAT_UNDEFINED_VIDEO:
        case MTP_FORMAT_WMV:
        case MTP_FORMAT_MP4_CONTAINER:
        case MTP_FORMAT_MP2:
        case MTP_FORMAT_3GP_CONTAINER:
            return kObjectHandleTableVideo;
        case MTP_FORMAT_DEFINED:
        case MTP_FORMAT_EXIF_JPEG:
        case MTP_FORMAT_TIFF_EP:
        case MTP_FORMAT_FLASHPIX:
        case MTP_FORMAT_BMP:
        case MTP_FORMAT_CIFF:
        case MTP_FORMAT_GIF:
        case MTP_FORMAT_JFIF:
        case MTP_FORMAT_CD:
        case MTP_FORMAT_PICT:
        case MTP_FORMAT_PNG:
        case MTP_FORMAT_TIFF:
        case MTP_FORMAT_TIFF_IT:
        case MTP_FORMAT_JP2:
        case MTP_FORMAT_JPX:
        case MTP_FORMAT_WINDOWS_IMAGE_FORMAT:
            return kObjectHandleTableImage;
        case MTP_FORMAT_ABSTRACT_AUDIO_PLAYLIST:
        case MTP_FORMAT_ABSTRACT_AV_PLAYLIST:
        case MTP_FORMAT_ABSTRACT_VIDEO_PLAYLIST:
        case MTP_FORMAT_WPL_PLAYLIST:
        case MTP_FORMAT_M3U_PLAYLIST:
        case MTP_FORMAT_MPL_PLAYLIST:
        case MTP_FORMAT_ASX_PLAYLIST:
        case MTP_FORMAT_PLS_PLAYLIST:
            return kObjectHandleTablePlaylist;
        default:
            return kObjectHandleTableFile;
    }
}

MtpObjectHandle MtpDatabase::getObjectHandle(const char* path) {
    mFileIdQuery->reset();
    mFileIdQuery->bind(1, path);
    if (mFileIdQuery->step()) {
        int row = mFileIdQuery->getColumnInt(0);
        if (row > 0)
        if (row > 0) {
            MtpObjectFormat format = mFileIdQuery->getColumnInt(1);
            row |= getTableForFile(format);
            return row;
        }

    if (!mFileInserter) {
        mFileInserter = new SqliteStatement(this);
        if (!mFileInserter->prepare(FILE_INSERT)) {
            fprintf(stderr, "could not compile FILE_INSERT\n");
            delete mFileInserter;
            mFileInserter = NULL;
            return kInvalidObjectHandle;
    }

    return 0;
}
    mFileInserter->bind(PATH_COLUMN, path);
    mFileInserter->bind(FORMAT_COLUMN, format);
    mFileInserter->bind(PARENT_COLUMN, parent);
    mFileInserter->bind(STORAGE_COLUMN, storage);
    mFileInserter->bind(SIZE_COLUMN, size);
    mFileInserter->bind(CREATED_COLUMN, created);
    mFileInserter->bind(MODIFIED_COLUMN, modified);

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 row = lastInsertedRow();
    return (row > 0 ? row : kInvalidObjectHandle);
    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,
@@ -168,7 +335,7 @@ MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
    bool                whereParent = (parent != 0);
    char                intBuffer[20];

    MtpString  query("SELECT _id FROM files");
    MtpString  query("SELECT _id,format FROM files");
    if (whereStorage || whereFormat || whereParent)
        query += " WHERE";
    if (whereStorage) {
@@ -184,6 +351,8 @@ MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
        query += intBuffer;
    }
    if (whereParent) {
        if (parent != MTP_PARENT_ROOT)
            parent &= kObjectHandleIndexMask;
        snprintf(intBuffer, sizeof(intBuffer), "%d", parent);
        if (whereStorage || whereFormat)
            query += " AND";
@@ -201,14 +370,18 @@ MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
        if (stmt.step()) {
            int index = stmt.getColumnInt(0);
            printf("stmt.getColumnInt returned %d\n", index);
            if (index > 0)
            if (index > 0) {
                MtpObjectFormat format = stmt.getColumnInt(1);
                index |= getTableForFile(format);
                list->push(index);
            }
        }
    }
    printf("list size: %d\n", list->size());
    return list;
}


MtpResponseCode MtpDatabase::getObjectProperty(MtpObjectHandle handle,
                                    MtpObjectProperty property,
                                    MtpDataPacket& packet) {
@@ -216,6 +389,9 @@ MtpResponseCode MtpDatabase::getObjectProperty(MtpObjectHandle handle,
    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);
@@ -272,18 +448,10 @@ MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
                                        MtpDataPacket& packet) {
    char    date[20];

    if (mObjectInfoQuery)
        mObjectInfoQuery->reset();
    else {
        mObjectInfoQuery = new SqliteStatement(this);
        if (!mObjectInfoQuery->prepare(GET_OBJECT_INFO_QUERY)) {
            fprintf(stderr, "could not compile FILE_ID_QUERY\n");
            delete mObjectInfoQuery;
            mObjectInfoQuery = NULL;
            return MTP_RESPONSE_GENERAL_ERROR;
        }
    }
    if (handle != MTP_PARENT_ROOT)
        handle &= kObjectHandleIndexMask;

    mObjectInfoQuery->reset();
    mObjectInfoQuery->bind(1, handle);
    if (!mObjectInfoQuery->step())
        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
@@ -297,8 +465,7 @@ MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
    if (lastSlash)
        name = lastSlash + 1;
    int64_t size = mObjectInfoQuery->getColumnInt64(4);
    time_t created = mObjectInfoQuery->getColumnInt(5);
    time_t modified = mObjectInfoQuery->getColumnInt(6);
    time_t modified = mObjectInfoQuery->getColumnInt(5);
    int associationType = (format == MTP_FORMAT_ASSOCIATION ?
                            MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
                            MTP_ASSOCIATION_TYPE_UNDEFINED);
@@ -321,8 +488,7 @@ MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
    packet.putUInt32(0);   // association desc
    packet.putUInt32(0);   // sequence number
    packet.putString(name);   // file name
    formatDateTime(created, date, sizeof(date));
    packet.putString(date);   // date created
    packet.putEmptyString();
    formatDateTime(modified, date, sizeof(date));
    packet.putString(date);   // date modified
    packet.putEmptyString();   // keywords
@@ -333,18 +499,9 @@ MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
bool MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
                                    MtpString& filePath,
                                    int64_t& fileLength) {
    if (mFilePathQuery)
    if (handle != MTP_PARENT_ROOT)
        handle &= kObjectHandleIndexMask;
    mFilePathQuery->reset();
    else {
        mFilePathQuery = new SqliteStatement(this);
        if (!mFilePathQuery->prepare(FILE_PATH_QUERY)) {
            fprintf(stderr, "could not compile FILE_ID_QUERY\n");
            delete mFilePathQuery;
            mFilePathQuery = NULL;
            return kInvalidObjectHandle;
        }
    }

    mFilePathQuery->bind(1, handle);
    if (!mFilePathQuery->step())
        return false;
@@ -358,22 +515,52 @@ bool MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
}

bool MtpDatabase::deleteFile(MtpObjectHandle handle) {
    if (!mFileDeleter) {
        mFileDeleter = new SqliteStatement(this);
        if (!mFileDeleter->prepare(FILE_DELETE)) {
            fprintf(stderr, "could not compile FILE_DELETE\n");
            delete mFileDeleter;
            mFileDeleter = NULL;
            return false;
        }
    }
printf("deleteFile %d\n", 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()) {
                printf("getFileList ended early\n");
                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

+22 −1
Original line number Diff line number Diff line
@@ -33,20 +33,38 @@ private:
    SqliteStatement*        mObjectInfoQuery;
    SqliteStatement*        mFileInserter;
    SqliteStatement*        mFileDeleter;
    SqliteStatement*        mAudioInserter;
    SqliteStatement*        mAudioDeleter;

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,
                                    MtpObjectFormat format,
                                    MtpObjectHandle parent,
                                    MtpStorageID storage,
                                    uint64_t size,
                                    time_t created,
                                    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);
@@ -62,6 +80,9 @@ public:
                                    MtpString& filePath,
                                    int64_t& fileLength);
    bool                    deleteFile(MtpObjectHandle handle);

    // helper for media scanner
    MtpObjectHandle*        getFileList(int& outCount);
};

}; // namespace android
+377 −0

File added.

Preview size limit exceeded, changes collapsed.

+56 −0
Original line number Diff line number Diff line
/*
 * 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_MEDIA_SCANNER_H
#define _MTP_MEDIA_SCANNER_H

struct stat;

namespace android {

class MtpDatabase;
class SqliteStatement;
class MediaScanner;
class MtpMediaScannerClient;

class MtpMediaScanner {
private:
    MtpStorageID            mStorageID;
    const char*             mFilePath;
    MtpDatabase*            mDatabase;
    MediaScanner*           mMediaScanner;
    MtpMediaScannerClient*  mMediaScannerClient;

    // for garbage collecting missing files
    MtpObjectHandle*        mFileList;
    int                     mFileCount;

public:
                            MtpMediaScanner(MtpStorageID id, const char* filePath, MtpDatabase* db);
    virtual                 ~MtpMediaScanner();

    bool                    scanFiles();

private:
    MtpObjectFormat         getFileFormat(const char* path, uint32_t& table);
    int                     scanDirectory(const char* path, MtpObjectHandle parent);
    void                    scanFile(const char* path, MtpObjectHandle parent, struct stat& statbuf);
    void                    markFile(MtpObjectHandle handle);
};

}; // namespace android

#endif // _MTP_MEDIA_SCANNER_H
Loading