static jobject android_mtp_MtpDevice_get_storage_info(JNIEnv *env, jobject thiz, jint storageID) { MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; MtpStorageInfo* storageInfo = device->getStorageInfo(storageID); if (!storageInfo) return NULL; jobject info = env->NewObject(clazz_storageInfo, constructor_storageInfo); if (info == NULL) { ALOGE("Could not create a MtpStorageInfo object"); delete storageInfo; return NULL; } if (storageInfo->mStorageID) env->SetIntField(info, field_storageInfo_storageId, storageInfo->mStorageID); if (storageInfo->mMaxCapacity) env->SetLongField(info, field_storageInfo_maxCapacity, storageInfo->mMaxCapacity); if (storageInfo->mFreeSpaceBytes) env->SetLongField(info, field_storageInfo_freeSpace, storageInfo->mFreeSpaceBytes); if (storageInfo->mStorageDescription) env->SetObjectField(info, field_storageInfo_description, env->NewStringUTF(storageInfo->mStorageDescription)); if (storageInfo->mVolumeIdentifier) env->SetObjectField(info, field_storageInfo_volumeIdentifier, env->NewStringUTF(storageInfo->mVolumeIdentifier)); delete storageInfo; return info; }
static jlong android_mtp_MtpDevice_get_storage_id(JNIEnv *env, jobject thiz, jint object_id) { MtpDevice* device = get_device_from_object(env, thiz); if (device) return (jlong)device->getStorageID(object_id); else return -1; }
static jlong android_mtp_MtpDevice_get_parent(JNIEnv *env, jobject thiz, jint object_id) { MtpDevice* device = get_device_from_object(env, thiz); if (device) return device->getParent(object_id); else return -1; }
static jboolean android_mtp_MtpDevice_delete_object(JNIEnv *env, jobject thiz, jint object_id) { MtpDevice* device = get_device_from_object(env, thiz); if (device) return device->deleteObject(object_id); else return NULL; }
static jboolean android_mtp_MtpDevice_delete_object(JNIEnv *env, jobject thiz, jint object_id) { MtpDevice* device = get_device_from_object(env, thiz); if (device && device->deleteObject(object_id)) { return JNI_TRUE; } else { return JNI_FALSE; } }
static void android_mtp_MtpDevice_close(JNIEnv *env, jobject thiz) { MtpDevice* device = get_device_from_object(env, thiz); if (device) { device->close(); delete device; env->SetLongField(thiz, field_context, 0); } }
static jboolean android_mtp_MtpDevice_import_file(JNIEnv *env, jobject thiz, jint object_id, jstring dest_path) { MtpDevice* device = get_device_from_object(env, thiz); if (device) { const char *destPathStr = env->GetStringUTFChars(dest_path, NULL); if (destPathStr == NULL) { return JNI_FALSE; } jboolean result = device->readObject(object_id, destPathStr, AID_SDCARD_RW, 0664); env->ReleaseStringUTFChars(dest_path, destPathStr); return result; } return JNI_FALSE; }
static jbyteArray android_mtp_MtpDevice_get_thumbnail(JNIEnv *env, jobject thiz, jint objectID) { MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; int length; void* thumbnail = device->getThumbnail(objectID, length); if (! thumbnail) return NULL; jbyteArray array = env->NewByteArray(length); env->SetByteArrayRegion(array, 0, length, (const jbyte *)thumbnail); free(thumbnail); return array; }
static jintArray android_mtp_MtpDevice_get_storage_ids(JNIEnv *env, jobject thiz) { MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; MtpStorageIDList* storageIDs = device->getStorageIDs(); if (!storageIDs) return NULL; int length = storageIDs->size(); jintArray array = env->NewIntArray(length); // FIXME is this cast safe? env->SetIntArrayRegion(array, 0, length, (const jint *)storageIDs->array()); delete storageIDs; return array; }
static jintArray android_mtp_MtpDevice_get_object_handles(JNIEnv *env, jobject thiz, jint storageID, jint format, jint objectID) { MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; MtpObjectHandleList* handles = device->getObjectHandles(storageID, format, objectID); if (!handles) return NULL; int length = handles->size(); jintArray array = env->NewIntArray(length); // FIXME is this cast safe? env->SetIntArrayRegion(array, 0, length, (const jint *)handles->array()); delete handles; return array; }
static jbyteArray android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jint objectSize) { MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; jbyteArray array = env->NewByteArray(objectSize); if (!array) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return NULL; } get_object_callback_data data; data.env = env; data.array = array; if (device->readObject(objectID, get_object_callback, objectSize, &data)) return array; return NULL; }
static jobject android_mtp_MtpDevice_get_device_info(JNIEnv *env, jobject thiz) { MtpDevice* device = get_device_from_object(env, thiz); if (!device) { ALOGD("android_mtp_MtpDevice_get_device_info device is null"); return NULL; } MtpDeviceInfo* deviceInfo = device->getDeviceInfo(); if (!deviceInfo) { ALOGD("android_mtp_MtpDevice_get_device_info deviceInfo is null"); return NULL; } jobject info = env->NewObject(clazz_deviceInfo, constructor_deviceInfo); if (info == NULL) { ALOGE("Could not create a MtpDeviceInfo object"); delete deviceInfo; return NULL; } if (deviceInfo->mManufacturer) env->SetObjectField(info, field_deviceInfo_manufacturer, env->NewStringUTF(deviceInfo->mManufacturer)); if (deviceInfo->mModel) env->SetObjectField(info, field_deviceInfo_model, env->NewStringUTF(deviceInfo->mModel)); if (deviceInfo->mVersion) env->SetObjectField(info, field_deviceInfo_version, env->NewStringUTF(deviceInfo->mVersion)); if (deviceInfo->mSerial) env->SetObjectField(info, field_deviceInfo_serialNumber, env->NewStringUTF(deviceInfo->mSerial)); delete deviceInfo; return info; }
static jobject android_mtp_MtpDevice_get_object_info(JNIEnv *env, jobject thiz, jint objectID) { MtpDevice* device = get_device_from_object(env, thiz); if (!device) return NULL; MtpObjectInfo* objectInfo = device->getObjectInfo(objectID); if (!objectInfo) return NULL; jobject info = env->NewObject(clazz_objectInfo, constructor_objectInfo); if (info == NULL) { ALOGE("Could not create a MtpObjectInfo object"); delete objectInfo; 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)); delete objectInfo; return info; }
MtpDevice* MtpDevice::open(const char* deviceName, int fd) { struct usb_device *device = usb_device_new(deviceName, fd); if (!device) { ALOGE("usb_device_new failed for %s", deviceName); return NULL; } struct usb_descriptor_header* desc; struct usb_descriptor_iter iter; usb_descriptor_iter_init(device, &iter); while ((desc = usb_descriptor_iter_next(&iter)) != NULL) { if (desc->bDescriptorType == USB_DT_INTERFACE) { struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc; if (interface->bInterfaceClass == USB_CLASS_STILL_IMAGE && interface->bInterfaceSubClass == 1 && // Still Image Capture interface->bInterfaceProtocol == 1) // Picture Transfer Protocol (PIMA 15470) { char* manufacturerName = usb_device_get_manufacturer_name(device); char* productName = usb_device_get_product_name(device); ALOGD("Found camera: \"%s\" \"%s\"\n", manufacturerName, productName); free(manufacturerName); free(productName); } else if (interface->bInterfaceClass == 0xFF && interface->bInterfaceSubClass == 0xFF && interface->bInterfaceProtocol == 0) { char* interfaceName = usb_device_get_string(device, interface->iInterface); if (!interfaceName) { continue; } else if (strcmp(interfaceName, "MTP")) { free(interfaceName); continue; } free(interfaceName); // Looks like an android style MTP device char* manufacturerName = usb_device_get_manufacturer_name(device); char* productName = usb_device_get_product_name(device); ALOGD("Found MTP device: \"%s\" \"%s\"\n", manufacturerName, productName); free(manufacturerName); free(productName); } #if 0 else { // look for special cased devices based on vendor/product ID // we are doing this mainly for testing purposes uint16_t vendor = usb_device_get_vendor_id(device); uint16_t product = usb_device_get_product_id(device); if (!isMtpDevice(vendor, product)) { // not an MTP or PTP device continue; } // request MTP OS string and descriptor // some music players need to see this before entering MTP mode. char buffer[256]; memset(buffer, 0, sizeof(buffer)); int ret = usb_device_control_transfer(device, USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_STANDARD, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | 0xEE, 0, buffer, sizeof(buffer), 0); printf("usb_device_control_transfer returned %d errno: %d\n", ret, errno); if (ret > 0) { printf("got MTP string %s\n", buffer); ret = usb_device_control_transfer(device, USB_DIR_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR, 1, 0, 4, buffer, sizeof(buffer), 0); printf("OS descriptor got %d\n", ret); } else { printf("no MTP string\n"); } } #endif // if we got here, then we have a likely MTP or PTP device // interface should be followed by three endpoints struct usb_endpoint_descriptor *ep; struct usb_endpoint_descriptor *ep_in_desc = NULL; struct usb_endpoint_descriptor *ep_out_desc = NULL; struct usb_endpoint_descriptor *ep_intr_desc = NULL; for (int i = 0; i < 3; i++) { ep = (struct usb_endpoint_descriptor *)usb_descriptor_iter_next(&iter); if (!ep || ep->bDescriptorType != USB_DT_ENDPOINT) { ALOGE("endpoints not found\n"); usb_device_close(device); return NULL; } if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ep_in_desc = ep; else ep_out_desc = ep; } else if (ep->bmAttributes == USB_ENDPOINT_XFER_INT && ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { ep_intr_desc = ep; } } if (!ep_in_desc || !ep_out_desc || !ep_intr_desc) { ALOGE("endpoints not found\n"); usb_device_close(device); return NULL; } if (usb_device_claim_interface(device, interface->bInterfaceNumber)) { ALOGE("usb_device_claim_interface failed errno: %d\n", errno); usb_device_close(device); return NULL; } MtpDevice* mtpDevice = new MtpDevice(device, interface->bInterfaceNumber, ep_in_desc, ep_out_desc, ep_intr_desc); mtpDevice->initialize(); return mtpDevice; } } usb_device_close(device); ALOGE("device not found"); return NULL; }