Home | History | Annotate | Download | only in mtp
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.mtp;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.hardware.usb.UsbDevice;
     22 import android.hardware.usb.UsbDeviceConnection;
     23 import android.os.CancellationSignal;
     24 import android.os.ParcelFileDescriptor;
     25 
     26 import com.android.internal.util.Preconditions;
     27 
     28 import java.io.IOException;
     29 
     30 /**
     31  * This class represents an MTP or PTP device connected on the USB host bus. An application can
     32  * instantiate an object of this type, by referencing an attached {@link
     33  * android.hardware.usb.UsbDevice} and then use methods in this class to get information about the
     34  * device and objects stored on it, as well as open the connection and transfer data.
     35  */
     36 public final class MtpDevice {
     37 
     38     private static final String TAG = "MtpDevice";
     39 
     40     private final UsbDevice mDevice;
     41 
     42     static {
     43         System.loadLibrary("media_jni");
     44     }
     45 
     46     /**
     47      * MtpClient constructor
     48      *
     49      * @param device the {@link android.hardware.usb.UsbDevice} for the MTP or PTP device
     50      */
     51     public MtpDevice(UsbDevice device) {
     52         mDevice = device;
     53     }
     54 
     55     /**
     56      * Opens the MTP device.  Once the device is open it takes ownership of the
     57      * {@link android.hardware.usb.UsbDeviceConnection}.
     58      * The connection will be closed when you call {@link #close()}
     59      * The connection will also be closed if this method fails.
     60      *
     61      * @param connection an open {@link android.hardware.usb.UsbDeviceConnection} for the device
     62      * @return true if the device was successfully opened.
     63      */
     64     public boolean open(UsbDeviceConnection connection) {
     65         boolean result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
     66         if (!result) {
     67             connection.close();
     68         }
     69         return result;
     70     }
     71 
     72     /**
     73      * Closes all resources related to the MtpDevice object.
     74      * After this is called, the object can not be used until {@link #open} is called again
     75      * with a new {@link android.hardware.usb.UsbDeviceConnection}.
     76      */
     77     public void close() {
     78         native_close();
     79     }
     80 
     81     @Override
     82     protected void finalize() throws Throwable {
     83         try {
     84             native_close();
     85         } finally {
     86             super.finalize();
     87         }
     88     }
     89 
     90     /**
     91      * Returns the name of the USB device
     92      * This returns the same value as {@link android.hardware.usb.UsbDevice#getDeviceName}
     93      * for the device's {@link android.hardware.usb.UsbDevice}
     94      *
     95      * @return the device name
     96      */
     97     public String getDeviceName() {
     98         return mDevice.getDeviceName();
     99     }
    100 
    101     /**
    102      * Returns the USB ID of the USB device.
    103      * This returns the same value as {@link android.hardware.usb.UsbDevice#getDeviceId}
    104      * for the device's {@link android.hardware.usb.UsbDevice}
    105      *
    106      * @return the device ID
    107      */
    108     public int getDeviceId() {
    109         return mDevice.getDeviceId();
    110     }
    111 
    112     @Override
    113     public String toString() {
    114         return mDevice.getDeviceName();
    115     }
    116 
    117     /**
    118      * Returns the {@link MtpDeviceInfo} for this device
    119      *
    120      * @return the device info
    121      */
    122     public MtpDeviceInfo getDeviceInfo() {
    123         return native_get_device_info();
    124     }
    125 
    126     /**
    127      * Returns the list of IDs for all storage units on this device
    128      * Information about each storage unit can be accessed via {@link #getStorageInfo}.
    129      *
    130      * @return the list of storage IDs
    131      */
    132     public int[] getStorageIds() {
    133         return native_get_storage_ids();
    134     }
    135 
    136     /**
    137      * Returns the list of object handles for all objects on the given storage unit,
    138      * with the given format and parent.
    139      * Information about each object can be accessed via {@link #getObjectInfo}.
    140      *
    141      * @param storageId the storage unit to query
    142      * @param format the format of the object to return, or zero for all formats
    143      * @param objectHandle the parent object to query, -1 for the storage root,
    144      *     or zero for all objects
    145      * @return the object handles
    146      */
    147     public int[] getObjectHandles(int storageId, int format, int objectHandle) {
    148         return native_get_object_handles(storageId, format, objectHandle);
    149     }
    150 
    151     /**
    152      * Returns the data for an object as a byte array.
    153      * This call may block for an arbitrary amount of time depending on the size
    154      * of the data and speed of the devices.
    155      *
    156      * @param objectHandle handle of the object to read
    157      * @param objectSize the size of the object (this should match
    158      *      {@link MtpObjectInfo#getCompressedSize})
    159      * @return the object's data, or null if reading fails
    160      */
    161     public byte[] getObject(int objectHandle, int objectSize) {
    162         Preconditions.checkArgumentNonnegative(objectSize, "objectSize should not be negative");
    163         return native_get_object(objectHandle, objectSize);
    164     }
    165 
    166     /**
    167      * Obtains object bytes in the specified range and writes it to an array.
    168      * This call may block for an arbitrary amount of time depending on the size
    169      * of the data and speed of the devices.
    170      *
    171      * @param objectHandle handle of the object to read
    172      * @param offset Start index of reading range. It must be a non-negative value at most
    173      *     0xffffffff.
    174      * @param size Size of reading range. It must be a non-negative value at most Integer.MAX_VALUE
    175      *     or 0xffffffff. If 0xffffffff is specified, the method obtains the full bytes of object.
    176      * @param buffer Array to write data.
    177      * @return Size of bytes that are actually read.
    178      */
    179     public long getPartialObject(int objectHandle, long offset, long size, byte[] buffer)
    180             throws IOException {
    181         return native_get_partial_object(objectHandle, offset, size, buffer);
    182     }
    183 
    184     /**
    185      * Obtains object bytes in the specified range and writes it to an array.
    186      * This call may block for an arbitrary amount of time depending on the size
    187      * of the data and speed of the devices.
    188      *
    189      * This is a vender-extended operation supported by Android that enables us to pass
    190      * unsigned 64-bit offset. Check if the MTP device supports the operation by using
    191      * {@link MtpDeviceInfo#getOperationsSupported()}.
    192      *
    193      * @param objectHandle handle of the object to read
    194      * @param offset Start index of reading range. It must be a non-negative value.
    195      * @param size Size of reading range. It must be a non-negative value at most Integer.MAX_VALUE.
    196      * @param buffer Array to write data.
    197      * @return Size of bytes that are actually read.
    198      * @see MtpConstants#OPERATION_GET_PARTIAL_OBJECT_64
    199      */
    200     public long getPartialObject64(int objectHandle, long offset, long size, byte[] buffer)
    201             throws IOException {
    202         return native_get_partial_object_64(objectHandle, offset, size, buffer);
    203     }
    204 
    205     /**
    206      * Returns the thumbnail data for an object as a byte array.
    207      * The size and format of the thumbnail data can be determined via
    208      * {@link MtpObjectInfo#getThumbCompressedSize} and
    209      * {@link MtpObjectInfo#getThumbFormat}.
    210      * For typical devices the format is JPEG.
    211      *
    212      * @param objectHandle handle of the object to read
    213      * @return the object's thumbnail, or null if reading fails
    214      */
    215     public byte[] getThumbnail(int objectHandle) {
    216         return native_get_thumbnail(objectHandle);
    217     }
    218 
    219     /**
    220      * Retrieves the {@link MtpStorageInfo} for a storage unit.
    221      *
    222      * @param storageId the ID of the storage unit
    223      * @return the MtpStorageInfo
    224      */
    225     public MtpStorageInfo getStorageInfo(int storageId) {
    226         return native_get_storage_info(storageId);
    227     }
    228 
    229     /**
    230      * Retrieves the {@link MtpObjectInfo} for an object.
    231      *
    232      * @param objectHandle the handle of the object
    233      * @return the MtpObjectInfo
    234      */
    235     public MtpObjectInfo getObjectInfo(int objectHandle) {
    236         return native_get_object_info(objectHandle);
    237     }
    238 
    239     /**
    240      * Deletes an object on the device.  This call may block, since
    241      * deleting a directory containing many files may take a long time
    242      * on some devices.
    243      *
    244      * @param objectHandle handle of the object to delete
    245      * @return true if the deletion succeeds
    246      */
    247     public boolean deleteObject(int objectHandle) {
    248         return native_delete_object(objectHandle);
    249     }
    250 
    251     /**
    252      * Retrieves the object handle for the parent of an object on the device.
    253      *
    254      * @param objectHandle handle of the object to query
    255      * @return the parent's handle, or zero if it is in the root of the storage
    256      */
    257     public long getParent(int objectHandle) {
    258         return native_get_parent(objectHandle);
    259     }
    260 
    261     /**
    262      * Retrieves the ID of the storage unit containing the given object on the device.
    263      *
    264      * @param objectHandle handle of the object to query
    265      * @return the object's storage unit ID
    266      */
    267     public long getStorageId(int objectHandle) {
    268         return native_get_storage_id(objectHandle);
    269     }
    270 
    271     /**
    272      * Copies the data for an object to a file in external storage.
    273      * This call may block for an arbitrary amount of time depending on the size
    274      * of the data and speed of the devices.
    275      *
    276      * @param objectHandle handle of the object to read
    277      * @param destPath path to destination for the file transfer.
    278      *      This path should be in the external storage as defined by
    279      *      {@link android.os.Environment#getExternalStorageDirectory}
    280      * @return true if the file transfer succeeds
    281      */
    282     public boolean importFile(int objectHandle, String destPath) {
    283         return native_import_file(objectHandle, destPath);
    284     }
    285 
    286     /**
    287      * Copies the data for an object to a file descriptor.
    288      * This call may block for an arbitrary amount of time depending on the size
    289      * of the data and speed of the devices. The file descriptor is not closed
    290      * on completion, and must be done by the caller.
    291      *
    292      * @param objectHandle handle of the object to read
    293      * @param descriptor file descriptor to write the data to for the file transfer.
    294      * @return true if the file transfer succeeds
    295      */
    296     public boolean importFile(int objectHandle, ParcelFileDescriptor descriptor) {
    297         return native_import_file(objectHandle, descriptor.getFd());
    298     }
    299 
    300     /**
    301      * Copies the data for an object from a file descriptor.
    302      * This call may block for an arbitrary amount of time depending on the size
    303      * of the data and speed of the devices. The file descriptor is not closed
    304      * on completion, and must be done by the caller.
    305      *
    306      * @param objectHandle handle of the target file
    307      * @param size size of the file in bytes
    308      * @param descriptor file descriptor to read the data from.
    309      * @return true if the file transfer succeeds
    310      */
    311     public boolean sendObject(int objectHandle, long size, ParcelFileDescriptor descriptor) {
    312         return native_send_object(objectHandle, size, descriptor.getFd());
    313     }
    314 
    315     /**
    316      * Uploads an object metadata for a new entry. The {@link MtpObjectInfo} can be
    317      * created with the {@link MtpObjectInfo.Builder} class.
    318      *
    319      * The returned {@link MtpObjectInfo} has the new object handle field filled in.
    320      *
    321      * @param info metadata of the entry
    322      * @return object info of the created entry or null if the operation failed.
    323      */
    324     public MtpObjectInfo sendObjectInfo(MtpObjectInfo info) {
    325         return native_send_object_info(info);
    326     }
    327 
    328     /**
    329      * Reads an event from the device. It blocks the current thread until it gets an event.
    330      * It throws OperationCanceledException if it is cancelled by signal.
    331      *
    332      * @param signal signal for cancellation
    333      * @return obtained event
    334      * @throws IOException
    335      */
    336     public @NonNull MtpEvent readEvent(@Nullable CancellationSignal signal) throws IOException {
    337         final int handle = native_submit_event_request();
    338         Preconditions.checkState(handle >= 0, "Other thread is reading an event.");
    339 
    340         if (signal != null) {
    341             signal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
    342                 @Override
    343                 public void onCancel() {
    344                     native_discard_event_request(handle);
    345                 }
    346             });
    347         }
    348 
    349         try {
    350             return native_reap_event_request(handle);
    351         } finally {
    352             if (signal != null) {
    353                 signal.setOnCancelListener(null);
    354             }
    355         }
    356     }
    357 
    358     /**
    359      * Returns object size in 64-bit integer.
    360      *
    361      * Though MtpObjectInfo#getCompressedSize returns the object size in 32-bit unsigned integer,
    362      * this method returns the object size in 64-bit integer from the object property. Thus it can
    363      * fetch 4GB+ object size correctly. If the device does not support objectSize property, it
    364      * throws IOException.
    365      * @hide
    366      */
    367     public long getObjectSizeLong(int handle, int format) throws IOException {
    368         return native_get_object_size_long(handle, format);
    369     }
    370 
    371     // used by the JNI code
    372     private long mNativeContext;
    373 
    374     private native boolean native_open(String deviceName, int fd);
    375     private native void native_close();
    376     private native MtpDeviceInfo native_get_device_info();
    377     private native int[] native_get_storage_ids();
    378     private native MtpStorageInfo native_get_storage_info(int storageId);
    379     private native int[] native_get_object_handles(int storageId, int format, int objectHandle);
    380     private native MtpObjectInfo native_get_object_info(int objectHandle);
    381     private native byte[] native_get_object(int objectHandle, long objectSize);
    382     private native long native_get_partial_object(
    383             int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
    384     private native int native_get_partial_object_64(
    385             int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
    386     private native byte[] native_get_thumbnail(int objectHandle);
    387     private native boolean native_delete_object(int objectHandle);
    388     private native int native_get_parent(int objectHandle);
    389     private native int native_get_storage_id(int objectHandle);
    390     private native boolean native_import_file(int objectHandle, String destPath);
    391     private native boolean native_import_file(int objectHandle, int fd);
    392     private native boolean native_send_object(int objectHandle, long size, int fd);
    393     private native MtpObjectInfo native_send_object_info(MtpObjectInfo info);
    394     private native int native_submit_event_request() throws IOException;
    395     private native MtpEvent native_reap_event_request(int handle) throws IOException;
    396     private native void native_discard_event_request(int handle);
    397     private native long native_get_object_size_long(int handle, int format) throws IOException;
    398 }
    399