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