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

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

Integrate host to device file transfer with the media provider.



MTP file transfers happen in two stages.  The SendObjectInfo command sends
some information about the file and reserves an ObjectHandle for the new file.
The file transfer is then performed using the SendObject command.

To support this in the media provider, MtpDatabase.beginSendObject receives
the information from SendObjectInfo and creates an row for it in the MTP objects
table for the new file.  After the file transfer has completed, then
MtpDatabase.endSendObject is called.  In endSendObject, we run the media scanner
on the new file, which will add a row to the images, audio, video
or audio playlist table.

To avoid the media scanner creating a second row for the file in the MTP objects
table, we pass the ObjectHandle created in beginSendObject to the media scanner,
which then passes it to the media provider via the content values when it
performs its insert.

Change-Id: I1ebcc63d6bd4404b0d3a93c703a9d3c097381d3a
Signed-off-by: default avatarMike Lockwood <lockwood@android.com>
parent 19046b01
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -237,6 +237,14 @@ public final class MediaStore {
         * <P>Type: TEXT</P>
         */
        public static final String MIME_TYPE = "mime_type";

        /**
         * The MTP object handle of a newly transfered file.
         * Used internally by the MediaScanner
         * <P>Type: INTEGER</P>
         * @hide
         */
        public static final String MTP_OBJECT_HANDLE = "mtp_object_handle";
     }


+8 −0
Original line number Diff line number Diff line
@@ -107,6 +107,9 @@ public class MediaFile {
    // maps mime type to MTP format code
    private static HashMap<String, Integer> sMimeTypeToFormatMap
            = new HashMap<String, Integer>();
    // maps MTP format code to mime type
    private static HashMap<Integer, String> sFormatToMimeTypeMap
            = new HashMap<Integer, String>();

    static void addFileType(String extension, int fileType, String mimeType) {
        sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType));
@@ -117,6 +120,7 @@ public class MediaFile {
        addFileType(extension, fileType, mimeType);
        sFileTypeToFormatMap.put(extension, Integer.valueOf(mtpFormatCode));
        sMimeTypeToFormatMap.put(mimeType, Integer.valueOf(mtpFormatCode));
        sFormatToMimeTypeMap.put(mtpFormatCode, mimeType);
    }

    private static boolean isWMAEnabled() {
@@ -253,4 +257,8 @@ public class MediaFile {
        }
        return Mtp.Object.FORMAT_UNDEFINED;
    }

    public static String getMimeTypeForFormatCode(int formatCode) {
        return sFormatToMimeTypeMap.get(formatCode);
    }
}
+12 −0
Original line number Diff line number Diff line
@@ -305,6 +305,7 @@ public class MediaScanner
    private Uri mGenresUri;
    private Uri mPlaylistsUri;
    private boolean mProcessPlaylists, mProcessGenres;
    private int mMtpObjectHandle;

    // used when scanning the image database so we know whether we have to prune
    // old thumbnail files
@@ -625,6 +626,9 @@ public class MediaScanner
            map.put(MediaStore.MediaColumns.DATE_MODIFIED, mLastModified);
            map.put(MediaStore.MediaColumns.SIZE, mFileSize);
            map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType);
            if (mMtpObjectHandle != 0) {
                map.put(MediaStore.MediaColumns.MTP_OBJECT_HANDLE, mMtpObjectHandle);
            }

            if (MediaFile.isVideoFileType(mFileType)) {
                map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaStore.UNKNOWN_STRING));
@@ -1227,6 +1231,14 @@ public class MediaScanner
        }
    }

    public Uri scanMtpFile(String path, String volumeName, int objectHandle, int format) {
        String mimeType = MediaFile.getMimeTypeForFormatCode(format);
        mMtpObjectHandle = objectHandle;
        Uri result = scanSingleFile(path, volumeName, mimeType);
        mMtpObjectHandle = 0;
        return result;
    }

    // returns the number of matching file/directory names, starting from the right
    private int matchPaths(String path1, String path2) {
        int result = 0;
+32 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.media;

import android.content.Context;
import android.content.ContentValues;
import android.content.IContentProvider;
import android.database.Cursor;
import android.net.Uri;
@@ -57,6 +58,8 @@ public class MtpDatabase {
    private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
                                            + MtpObjects.ObjectColumns.FORMAT + "=?";

    private final MediaScanner mMediaScanner;

    static {
        System.loadLibrary("media_jni");
    }
@@ -67,6 +70,7 @@ public class MtpDatabase {
        mMediaProvider = context.getContentResolver().acquireProvider("media");
        mVolumeName = volumeName;
        mObjectsUri = MtpObjects.getContentUri(volumeName);
        mMediaScanner = new MediaScanner(context);
    }

    @Override
@@ -74,10 +78,35 @@ public class MtpDatabase {
        native_finalize();
    }

    private int addFile(String path, int format, int parent,
    private int beginSendObject(String path, int format, int parent,
                         int storage, long size, long modified) {
        Log.d(TAG, "addFile " + path);
        return 0;
        ContentValues values = new ContentValues();
        values.put(MtpObjects.ObjectColumns.DATA, path);
        values.put(MtpObjects.ObjectColumns.FORMAT, format);
        values.put(MtpObjects.ObjectColumns.PARENT, parent);
        // storage is ignored for now
        values.put(MtpObjects.ObjectColumns.SIZE, size);
        values.put(MtpObjects.ObjectColumns.DATE_MODIFIED, modified);

        try {
            Uri uri = mMediaProvider.insert(mObjectsUri, values);
            if (uri != null) {
                return Integer.parseInt(uri.getPathSegments().get(2));
            } else {
                return -1;
            }
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException in beginSendObject", e);
            return -1;
        }
    }

    private void endSendObject(String path, int handle, int format, boolean succeeded) {
        if (succeeded) {
            Uri uri = mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
        } else {
            deleteFile(handle);
        }
    }

    private int[] getObjectList(int storageID, int format, int parent) {
+25 −7
Original line number Diff line number Diff line
@@ -36,7 +36,8 @@ using namespace android;

// ----------------------------------------------------------------------------

static jmethodID method_addFile;
static jmethodID method_beginSendObject;
static jmethodID method_endSendObject;
static jmethodID method_getObjectList;
static jmethodID method_getObjectProperty;
static jmethodID method_getObjectInfo;
@@ -62,13 +63,18 @@ public:
    virtual                         ~MyMtpDatabase();
    void                            cleanup(JNIEnv *env);

    virtual MtpObjectHandle         addFile(const char* path,
    virtual MtpObjectHandle         beginSendObject(const char* path,
                                            MtpObjectFormat format,
                                            MtpObjectHandle parent,
                                            MtpStorageID storage,
                                            uint64_t size,
                                            time_t modified);

    virtual void                    endSendObject(const char* path,
                                            MtpObjectHandle handle,
                                            MtpObjectFormat format,
                                            bool succeeded);

    virtual MtpObjectHandleList*    getObjectList(MtpStorageID storageID,
                                    MtpObjectFormat format,
                                    MtpObjectHandle parent);
@@ -135,17 +141,24 @@ void MyMtpDatabase::cleanup(JNIEnv *env) {
MyMtpDatabase::~MyMtpDatabase() {
}

MtpObjectHandle MyMtpDatabase::addFile(const char* path,
MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
                                            MtpObjectFormat format,
                                            MtpObjectHandle parent,
                                            MtpStorageID storage,
                                            uint64_t size,
                                            time_t modified) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    return env->CallIntMethod(mDatabase, method_addFile, env->NewStringUTF(path),
    return env->CallIntMethod(mDatabase, method_beginSendObject, env->NewStringUTF(path),
                (jint)format, (jint)parent, (jint)storage, (jlong)size, (jlong)modified);
}

void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
                                MtpObjectFormat format, bool succeeded) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    env->CallVoidMethod(mDatabase, method_endSendObject, env->NewStringUTF(path),
                        (jint)handle, (jint)format, (jboolean)succeeded);
}

MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
                                    MtpObjectFormat format,
                                    MtpObjectHandle parent) {
@@ -397,9 +410,14 @@ int register_android_media_MtpDatabase(JNIEnv *env)
        LOGE("Can't find android/media/MtpDatabase");
        return -1;
    }
    method_addFile = env->GetMethodID(clazz, "addFile", "(Ljava/lang/String;IIIJJ)I");
    if (method_addFile == NULL) {
        LOGE("Can't find addFile");
    method_beginSendObject = env->GetMethodID(clazz, "beginSendObject", "(Ljava/lang/String;IIIJJ)I");
    if (method_beginSendObject == NULL) {
        LOGE("Can't find beginSendObject");
        return -1;
    }
    method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V");
    if (method_endSendObject == NULL) {
        LOGE("Can't find endSendObject");
        return -1;
    }
    method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
Loading