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

Commit 4a86977e authored by Tomasz Mikolajewski's avatar Tomasz Mikolajewski Committed by Android (Google) Code Review
Browse files

Merge "Add API for uploading files to MTP devices."

parents f5d7ce56 b0499059
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -18102,6 +18102,8 @@ package android.mtp {
    method public boolean importFile(int, java.lang.String);
    method public boolean importFile(int, android.os.ParcelFileDescriptor);
    method public boolean open(android.hardware.usb.UsbDeviceConnection);
    method public boolean sendObject(int, android.os.ParcelFileDescriptor);
    method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
  }
  public class MtpDeviceInfo {
@@ -18134,6 +18136,31 @@ package android.mtp {
    method public final int getThumbPixWidth();
  }
  public class MtpObjectInfo.Builder {
    ctor public MtpObjectInfo.Builder();
    ctor public MtpObjectInfo.Builder(android.mtp.MtpObjectInfo);
    method public android.mtp.MtpObjectInfo build();
    method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
    method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
    method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
    method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
    method public android.mtp.MtpObjectInfo.Builder setFormat(int);
    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
    method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
    method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
    method public android.mtp.MtpObjectInfo.Builder setParent(int);
    method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
    method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
    method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
  }
  public final class MtpStorageInfo {
    method public final java.lang.String getDescription();
    method public final long getFreeSpace();
+27 −0
Original line number Diff line number Diff line
@@ -19614,6 +19614,8 @@ package android.mtp {
    method public boolean importFile(int, java.lang.String);
    method public boolean importFile(int, android.os.ParcelFileDescriptor);
    method public boolean open(android.hardware.usb.UsbDeviceConnection);
    method public boolean sendObject(int, android.os.ParcelFileDescriptor);
    method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
  }
  public class MtpDeviceInfo {
@@ -19646,6 +19648,31 @@ package android.mtp {
    method public final int getThumbPixWidth();
  }
  public class MtpObjectInfo.Builder {
    ctor public MtpObjectInfo.Builder();
    ctor public MtpObjectInfo.Builder(android.mtp.MtpObjectInfo);
    method public android.mtp.MtpObjectInfo build();
    method public android.mtp.MtpObjectInfo.Builder setAssociationDesc(int);
    method public android.mtp.MtpObjectInfo.Builder setAssociationType(int);
    method public android.mtp.MtpObjectInfo.Builder setCompressedSize(int);
    method public android.mtp.MtpObjectInfo.Builder setDateCreated(long);
    method public android.mtp.MtpObjectInfo.Builder setDateModified(long);
    method public android.mtp.MtpObjectInfo.Builder setFormat(int);
    method public android.mtp.MtpObjectInfo.Builder setImagePixDepth(int);
    method public android.mtp.MtpObjectInfo.Builder setImagePixHeight(int);
    method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
    method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
    method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
    method public android.mtp.MtpObjectInfo.Builder setParent(int);
    method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
    method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
    method public android.mtp.MtpObjectInfo.Builder setStorageId(int);
    method public android.mtp.MtpObjectInfo.Builder setThumbCompressedSize(int);
    method public android.mtp.MtpObjectInfo.Builder setThumbFormat(int);
    method public android.mtp.MtpObjectInfo.Builder setThumbPixHeight(int);
    method public android.mtp.MtpObjectInfo.Builder setThumbPixWidth(int);
  }
  public final class MtpStorageInfo {
    method public final java.lang.String getDescription();
    method public final long getFreeSpace();
+29 −0
Original line number Diff line number Diff line
@@ -250,6 +250,33 @@ public final class MtpDevice {
        return native_import_file(objectHandle, descriptor.getFd());
    }

    /**
     * Copies the data for an object from a file descriptor.
     * This call may block for an arbitrary amount of time depending on the size
     * of the data and speed of the devices. The file descriptor is not closed
     * on completion, and must be done by the caller.
     *
     * @param objectHandle handle of the target file
     * @param descriptor file descriptor to read the data from.
     * @return true if the file transfer succeeds
     */
    public boolean sendObject(int objectHandle, ParcelFileDescriptor descriptor) {
        return native_send_object(objectHandle, descriptor.getFd());
    }

    /**
     * Uploads an object metadata for a new entry. The {@link MtpObjectInfo} can be
     * created with the {@link MtpObjectInfo.Builder} class.
     *
     * The returned {@link MtpObjectInfo} has the new object handle field filled in.
     *
     * @param info metadata of the entry
     * @return object info of the created entry
     */
    public MtpObjectInfo sendObjectInfo(MtpObjectInfo info) {
        return native_send_object_info(info);
    }

    // used by the JNI code
    private long mNativeContext;

@@ -267,4 +294,6 @@ public final class MtpDevice {
    private native long native_get_storage_id(int objectHandle);
    private native boolean native_import_file(int objectHandle, String destPath);
    private native boolean native_import_file(int objectHandle, int fd);
    private native boolean native_send_object(int objectHandle, int fd);
    private native MtpObjectInfo native_send_object_info(MtpObjectInfo info);
}
+151 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ public final class MtpObjectInfo {
    private long mDateModified;
    private String mKeywords;

    // only instantiated via JNI
    // only instantiated via JNI or via a builder
    private MtpObjectInfo() {
    }

@@ -252,4 +252,154 @@ public final class MtpObjectInfo {
    public final String getKeywords() {
        return mKeywords;
    }

    /**
     * Builds a new object info instance.
     */
    public class Builder {
        private MtpObjectInfo mObjectInfo;

        public Builder() {
            mObjectInfo = new MtpObjectInfo();
            mObjectInfo.mHandle = -1;
        }

        /**
         * Creates a builder on a copy of an existing object info.
         * All fields, except the object handle will be copied.
         *
         * @param objectInfo object info of an existing entry
         */
        public Builder(MtpObjectInfo objectInfo) {
            mObjectInfo = new MtpObjectInfo();
            mObjectInfo.mHandle = -1;
            mObjectInfo.mAssociationDesc = mObjectInfo.mAssociationDesc;
            mObjectInfo.mAssociationType = mObjectInfo.mAssociationType;
            mObjectInfo.mCompressedSize = mObjectInfo.mCompressedSize;
            mObjectInfo.mDateCreated = mObjectInfo.mDateCreated;
            mObjectInfo.mDateModified = mObjectInfo.mDateModified;
            mObjectInfo.mFormat = mObjectInfo.mFormat;
            mObjectInfo.mImagePixDepth = mObjectInfo.mImagePixDepth;
            mObjectInfo.mImagePixHeight = mObjectInfo.mImagePixHeight;
            mObjectInfo.mImagePixWidth = mObjectInfo.mImagePixWidth;
            mObjectInfo.mKeywords = mObjectInfo.mKeywords;
            mObjectInfo.mName = mObjectInfo.mName;
            mObjectInfo.mParent = mObjectInfo.mParent;
            mObjectInfo.mProtectionStatus = mObjectInfo.mProtectionStatus;
            mObjectInfo.mSequenceNumber = mObjectInfo.mSequenceNumber;
            mObjectInfo.mStorageId = mObjectInfo.mStorageId;
            mObjectInfo.mThumbCompressedSize = mObjectInfo.mThumbCompressedSize;
            mObjectInfo.mThumbFormat = mObjectInfo.mThumbFormat;
            mObjectInfo.mThumbPixHeight = mObjectInfo.mThumbPixHeight;
            mObjectInfo.mThumbPixWidth = mObjectInfo.mThumbPixWidth;
        }

        public Builder setAssociationDesc(int value) {
            mObjectInfo.mAssociationDesc = value;
            return this;
        }

        public Builder setAssociationType(int value) {
            mObjectInfo.mAssociationType = value;
            return this;
        }

        public Builder setCompressedSize(int value) {
            mObjectInfo.mCompressedSize = value;
            return this;
        }

        public Builder setDateCreated(long value) {
            mObjectInfo.mDateCreated = value;
            return this;
        }

        public Builder setDateModified(long value) {
            mObjectInfo.mDateModified = value;
            return this;
        }

        public Builder setFormat(int value) {
            mObjectInfo.mFormat = value;
            return this;
        }

        public Builder setImagePixDepth(int value) {
            mObjectInfo.mImagePixDepth = value;
            return this;
        }

        public Builder setImagePixHeight(int value) {
            mObjectInfo.mImagePixHeight = value;
            return this;
        }

        public Builder setImagePixWidth(int value) {
            mObjectInfo.mImagePixWidth = value;
            return this;
        }

        public Builder setKeywords(String value) {
            mObjectInfo.mKeywords = value;
            return this;
        }

        public Builder setName(String value) {
            mObjectInfo.mName = value;
            return this;
        }

        public Builder setParent(int value) {
            mObjectInfo.mParent = value;
            return this;
        }

        public Builder setProtectionStatus(int value) {
            mObjectInfo.mProtectionStatus = value;
            return this;
        }

        public Builder setSequenceNumber(int value) {
            mObjectInfo.mSequenceNumber = value;
            return this;
        }

        public Builder setStorageId(int value) {
            mObjectInfo.mStorageId = value;
            return this;
        }

        public Builder setThumbCompressedSize(int value) {
            mObjectInfo.mThumbCompressedSize = value;
            return this;
        }

        public Builder setThumbFormat(int value) {
            mObjectInfo.mThumbFormat = value;
            return this;
        }

        public Builder setThumbPixHeight(int value) {
            mObjectInfo.mThumbPixHeight = value;
            return this;
        }

        public Builder setThumbPixWidth(int value) {
            mObjectInfo.mThumbPixWidth = value;
            return this;
        }

        /**
         * Builds the object info instance. Once called, methods of the builder
         * must not be called anymore.
         *
         * @return the object info of the newly created file, or NULL in case
         *         of an error.
         */
        public MtpObjectInfo build() {
            MtpObjectInfo result = mObjectInfo;
            mObjectInfo = null;
            return result;
        }
    }
}
+130 −43
Original line number Diff line number Diff line
@@ -91,6 +91,55 @@ MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice)
    return (MtpDevice*)env->GetLongField(javaDevice, field_context);
}

void fill_jobject_from_object_info(JNIEnv* env, jobject object, MtpObjectInfo* objectInfo) {
    if (objectInfo->mHandle)
        env->SetIntField(object, field_objectInfo_handle, objectInfo->mHandle);
    if (objectInfo->mStorageID)
        env->SetIntField(object, field_objectInfo_storageId, objectInfo->mStorageID);
    if (objectInfo->mFormat)
        env->SetIntField(object, field_objectInfo_format, objectInfo->mFormat);
    if (objectInfo->mProtectionStatus)
        env->SetIntField(object, field_objectInfo_protectionStatus, objectInfo->mProtectionStatus);
    if (objectInfo->mCompressedSize)
        env->SetIntField(object, field_objectInfo_compressedSize, objectInfo->mCompressedSize);
    if (objectInfo->mThumbFormat)
        env->SetIntField(object, field_objectInfo_thumbFormat, objectInfo->mThumbFormat);
    if (objectInfo->mThumbCompressedSize) {
        env->SetIntField(object, field_objectInfo_thumbCompressedSize,
                objectInfo->mThumbCompressedSize);
    }
    if (objectInfo->mThumbPixWidth)
        env->SetIntField(object, field_objectInfo_thumbPixWidth, objectInfo->mThumbPixWidth);
    if (objectInfo->mThumbPixHeight)
        env->SetIntField(object, field_objectInfo_thumbPixHeight, objectInfo->mThumbPixHeight);
    if (objectInfo->mImagePixWidth)
        env->SetIntField(object, field_objectInfo_imagePixWidth, objectInfo->mImagePixWidth);
    if (objectInfo->mImagePixHeight)
        env->SetIntField(object, field_objectInfo_imagePixHeight, objectInfo->mImagePixHeight);
    if (objectInfo->mImagePixDepth)
        env->SetIntField(object, field_objectInfo_imagePixDepth, objectInfo->mImagePixDepth);
    if (objectInfo->mParent)
        env->SetIntField(object, field_objectInfo_parent, objectInfo->mParent);
    if (objectInfo->mAssociationType)
        env->SetIntField(object, field_objectInfo_associationType, objectInfo->mAssociationType);
    if (objectInfo->mAssociationDesc)
        env->SetIntField(object, field_objectInfo_associationDesc, objectInfo->mAssociationDesc);
    if (objectInfo->mSequenceNumber)
        env->SetIntField(object, field_objectInfo_sequenceNumber, objectInfo->mSequenceNumber);
    if (objectInfo->mName)
        env->SetObjectField(object, field_objectInfo_name, env->NewStringUTF(objectInfo->mName));
    if (objectInfo->mDateCreated)
        env->SetLongField(object, field_objectInfo_dateCreated, objectInfo->mDateCreated * 1000LL);
    if (objectInfo->mDateModified) {
        env->SetLongField(object, field_objectInfo_dateModified,
                objectInfo->mDateModified * 1000LL);
    }
    if (objectInfo->mKeywords) {
        env->SetObjectField(object, field_objectInfo_keywords,
            env->NewStringUTF(objectInfo->mKeywords));
    }
}

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

static jboolean
@@ -246,48 +295,7 @@ android_mtp_MtpDevice_get_object_info(JNIEnv *env, jobject thiz, jint objectID)
        return NULL;
    }

    if (objectInfo->mHandle)
        env->SetIntField(info, field_objectInfo_handle, objectInfo->mHandle);
    if (objectInfo->mStorageID)
        env->SetIntField(info, field_objectInfo_storageId, objectInfo->mStorageID);
    if (objectInfo->mFormat)
        env->SetIntField(info, field_objectInfo_format, objectInfo->mFormat);
    if (objectInfo->mProtectionStatus)
        env->SetIntField(info, field_objectInfo_protectionStatus, objectInfo->mProtectionStatus);
    if (objectInfo->mCompressedSize)
        env->SetIntField(info, field_objectInfo_compressedSize, objectInfo->mCompressedSize);
    if (objectInfo->mThumbFormat)
        env->SetIntField(info, field_objectInfo_thumbFormat, objectInfo->mThumbFormat);
    if (objectInfo->mThumbCompressedSize)
        env->SetIntField(info, field_objectInfo_thumbCompressedSize, objectInfo->mThumbCompressedSize);
    if (objectInfo->mThumbPixWidth)
        env->SetIntField(info, field_objectInfo_thumbPixWidth, objectInfo->mThumbPixWidth);
    if (objectInfo->mThumbPixHeight)
        env->SetIntField(info, field_objectInfo_thumbPixHeight, objectInfo->mThumbPixHeight);
    if (objectInfo->mImagePixWidth)
        env->SetIntField(info, field_objectInfo_imagePixWidth, objectInfo->mImagePixWidth);
    if (objectInfo->mImagePixHeight)
        env->SetIntField(info, field_objectInfo_imagePixHeight, objectInfo->mImagePixHeight);
    if (objectInfo->mImagePixDepth)
        env->SetIntField(info, field_objectInfo_imagePixDepth, objectInfo->mImagePixDepth);
    if (objectInfo->mParent)
        env->SetIntField(info, field_objectInfo_parent, objectInfo->mParent);
    if (objectInfo->mAssociationType)
        env->SetIntField(info, field_objectInfo_associationType, objectInfo->mAssociationType);
    if (objectInfo->mAssociationDesc)
        env->SetIntField(info, field_objectInfo_associationDesc, objectInfo->mAssociationDesc);
    if (objectInfo->mSequenceNumber)
        env->SetIntField(info, field_objectInfo_sequenceNumber, objectInfo->mSequenceNumber);
    if (objectInfo->mName)
        env->SetObjectField(info, field_objectInfo_name, env->NewStringUTF(objectInfo->mName));
    if (objectInfo->mDateCreated)
        env->SetLongField(info, field_objectInfo_dateCreated, objectInfo->mDateCreated * 1000LL);
    if (objectInfo->mDateModified)
        env->SetLongField(info, field_objectInfo_dateModified, objectInfo->mDateModified * 1000LL);
    if (objectInfo->mKeywords)
        env->SetObjectField(info, field_objectInfo_keywords,
            env->NewStringUTF(objectInfo->mKeywords));

    fill_jobject_from_object_info(env, info, objectInfo);
    delete objectInfo;
    return info;
}
@@ -403,6 +411,82 @@ android_mtp_MtpDevice_import_file_to_fd(JNIEnv *env, jobject thiz, jint object_i
        return JNI_FALSE;
}

static jboolean
android_mtp_MtpDevice_send_object(JNIEnv *env, jobject thiz, jint object_id, jint fd)
{
    MtpDevice* device = get_device_from_object(env, thiz);
    if (!device)
        return JNI_FALSE;
    MtpObjectInfo* object_info = device->getObjectInfo(object_id);
    if (!object_info)
        return JNI_FALSE;

    bool result = device->sendObject(object_info, fd);
    delete object_info;
    return result;
}

static jobject
android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info)
{
    MtpDevice* device = get_device_from_object(env, thiz);
    if (!device)
        return JNI_FALSE;

    // Updating existing objects is not supported.
    if (env->GetIntField(info, field_objectInfo_handle) != -1)
        return JNI_FALSE;

    MtpObjectInfo* object_info = new MtpObjectInfo(-1);
    object_info->mStorageID = env->GetIntField(info, field_objectInfo_storageId);
    object_info->mFormat = env->GetIntField(info, field_objectInfo_format);
    object_info->mProtectionStatus = env->GetIntField(info, field_objectInfo_protectionStatus);
    object_info->mCompressedSize = env->GetIntField(info, field_objectInfo_compressedSize);
    object_info->mThumbFormat = env->GetIntField(info, field_objectInfo_thumbFormat);
    object_info->mThumbCompressedSize =
            env->GetIntField(info, field_objectInfo_thumbCompressedSize);
    object_info->mThumbPixWidth = env->GetIntField(info, field_objectInfo_thumbPixWidth);
    object_info->mThumbPixHeight = env->GetIntField(info, field_objectInfo_thumbPixHeight);
    object_info->mImagePixWidth = env->GetIntField(info, field_objectInfo_imagePixWidth);
    object_info->mImagePixHeight = env->GetIntField(info, field_objectInfo_imagePixHeight);
    object_info->mImagePixDepth = env->GetIntField(info, field_objectInfo_imagePixDepth);
    object_info->mParent = env->GetIntField(info, field_objectInfo_parent);
    object_info->mAssociationType = env->GetIntField(info, field_objectInfo_associationType);
    object_info->mAssociationDesc = env->GetIntField(info, field_objectInfo_associationDesc);
    object_info->mSequenceNumber = env->GetIntField(info, field_objectInfo_sequenceNumber);

    jstring name_jstring = (jstring) env->GetObjectField(info, field_objectInfo_name);
    const char* name_string = env->GetStringUTFChars(name_jstring, NULL);
    object_info->mName = strdup(name_string);
    env->ReleaseStringUTFChars(name_jstring, name_string);

    object_info->mDateCreated = env->GetLongField(info, field_objectInfo_dateCreated) / 1000LL;
    object_info->mDateModified = env->GetLongField(info, field_objectInfo_dateModified) / 1000LL;

    jstring keywords_jstring = (jstring) env->GetObjectField(info, field_objectInfo_keywords);
    const char* keywords_string = env->GetStringUTFChars(keywords_jstring, NULL);
    object_info->mKeywords = strdup(keywords_string);
    env->ReleaseStringUTFChars(keywords_jstring, keywords_string);

    int object_handle = device->sendObjectInfo(object_info);
    if (object_handle == -1) {
        delete object_info;
        return NULL;
    }

    object_info->mHandle = object_handle;
    jobject result = env->NewObject(clazz_objectInfo, constructor_objectInfo);
    if (result == NULL) {
        ALOGE("Could not create a MtpObjectInfo object");
        delete object_info;
        return NULL;
    }

    fill_jobject_from_object_info(env, result, object_info);
    delete object_info;
    return result;
}

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

static JNINativeMethod gMethods[] = {
@@ -425,7 +509,10 @@ static JNINativeMethod gMethods[] = {
    {"native_get_storage_id",   "(I)J", (void *)android_mtp_MtpDevice_get_storage_id},
    {"native_import_file",      "(ILjava/lang/String;)Z",
                                        (void *)android_mtp_MtpDevice_import_file},
    {"native_import_file",      "(II)Z", (void *)android_mtp_MtpDevice_import_file_to_fd}
    {"native_import_file",      "(II)Z",(void *)android_mtp_MtpDevice_import_file_to_fd},
    {"native_send_object",      "(II)Z",(void *)android_mtp_MtpDevice_send_object},
    {"native_send_object_info", "(Landroid/mtp/MtpObjectInfo;)Landroid/mtp/MtpObjectInfo;",
                                        (void *)android_mtp_MtpDevice_send_object_info}
};

int register_android_mtp_MtpDevice(JNIEnv *env)