[go: nahoru, domu]

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
17package android.mtp;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.hardware.usb.UsbDevice;
22import android.hardware.usb.UsbDeviceConnection;
23import android.os.CancellationSignal;
24import android.os.ParcelFileDescriptor;
25
26import com.android.internal.util.Preconditions;
27
28import 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 */
36public 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