blob: d0ef37c77055cbc4e3930952b28f48872871cb4c [file] [log] [blame]
Mike Lockwood8182e722010-12-30 15:38:45 -05001/*
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
Mike Lockwoodc4308f02011-03-01 08:04:54 -080019import android.hardware.usb.UsbDevice;
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050020import android.hardware.usb.UsbDeviceConnection;
Daichi Hirono0b494662015-09-10 20:38:15 +090021import android.os.CancellationSignal;
Tomasz Mikolajewski74d4ff82015-08-04 18:34:03 +090022import android.os.ParcelFileDescriptor;
Mike Lockwood8182e722010-12-30 15:38:45 -050023
Daichi Hirono2dd48252016-01-12 15:46:41 +090024import com.android.internal.util.Preconditions;
25
Daichi Hirono52da3ad2015-12-24 17:52:10 +090026import java.io.IOException;
27
Mike Lockwood8182e722010-12-30 15:38:45 -050028/**
Scott Main0cdd9f72011-05-05 15:53:44 -070029 * This class represents an MTP or PTP device connected on the USB host bus. An application can
30 * instantiate an object of this type, by referencing an attached {@link
31 * android.hardware.usb.UsbDevice} and then use methods in this class to get information about the
32 * device and objects stored on it, as well as open the connection and transfer data.
Mike Lockwood8182e722010-12-30 15:38:45 -050033 */
34public final class MtpDevice {
35
36 private static final String TAG = "MtpDevice";
37
38 private final UsbDevice mDevice;
39
40 static {
41 System.loadLibrary("media_jni");
42 }
43
Mike Lockwood540380f2011-02-09 21:48:53 -050044 /**
45 * MtpClient constructor
46 *
Mike Lockwoodc4308f02011-03-01 08:04:54 -080047 * @param device the {@link android.hardware.usb.UsbDevice} for the MTP or PTP device
Mike Lockwood540380f2011-02-09 21:48:53 -050048 */
Mike Lockwood8182e722010-12-30 15:38:45 -050049 public MtpDevice(UsbDevice device) {
50 mDevice = device;
51 }
52
Mike Lockwood540380f2011-02-09 21:48:53 -050053 /**
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050054 * Opens the MTP device. Once the device is open it takes ownership of the
Daichi Hirono0b494662015-09-10 20:38:15 +090055 * {@link android.hardware.usb.UsbDeviceConnection}.
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050056 * The connection will be closed when you call {@link #close()}
57 * The connection will also be closed if this method fails.
Mike Lockwood540380f2011-02-09 21:48:53 -050058 *
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050059 * @param connection an open {@link android.hardware.usb.UsbDeviceConnection} for the device
Mike Lockwood540380f2011-02-09 21:48:53 -050060 * @return true if the device was successfully opened.
61 */
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050062 public boolean open(UsbDeviceConnection connection) {
63 boolean result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
64 if (!result) {
65 connection.close();
Mike Lockwood8182e722010-12-30 15:38:45 -050066 }
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050067 return result;
Mike Lockwood8182e722010-12-30 15:38:45 -050068 }
69
Mike Lockwood540380f2011-02-09 21:48:53 -050070 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -040071 * Closes all resources related to the MtpDevice object.
72 * After this is called, the object can not be used until {@link #open} is called again
73 * with a new {@link android.hardware.usb.UsbDeviceConnection}.
Mike Lockwood540380f2011-02-09 21:48:53 -050074 */
Mike Lockwood8182e722010-12-30 15:38:45 -050075 public void close() {
Mike Lockwood8182e722010-12-30 15:38:45 -050076 native_close();
77 }
78
79 @Override
80 protected void finalize() throws Throwable {
Mike Lockwood8182e722010-12-30 15:38:45 -050081 try {
82 native_close();
83 } finally {
84 super.finalize();
85 }
86 }
87
Mike Lockwood540380f2011-02-09 21:48:53 -050088 /**
89 * Returns the name of the USB device
Mike Lockwood11dd5ae2011-04-01 14:00:08 -040090 * This returns the same value as {@link android.hardware.usb.UsbDevice#getDeviceName}
91 * for the device's {@link android.hardware.usb.UsbDevice}
Mike Lockwood540380f2011-02-09 21:48:53 -050092 *
93 * @return the device name
94 */
Mike Lockwood8182e722010-12-30 15:38:45 -050095 public String getDeviceName() {
96 return mDevice.getDeviceName();
97 }
98
Mike Lockwood540380f2011-02-09 21:48:53 -050099 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400100 * Returns the USB ID of the USB device.
101 * This returns the same value as {@link android.hardware.usb.UsbDevice#getDeviceId}
102 * for the device's {@link android.hardware.usb.UsbDevice}
Mike Lockwood540380f2011-02-09 21:48:53 -0500103 *
104 * @return the device ID
105 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500106 public int getDeviceId() {
107 return mDevice.getDeviceId();
108 }
109
110 @Override
111 public String toString() {
112 return mDevice.getDeviceName();
113 }
114
Mike Lockwood540380f2011-02-09 21:48:53 -0500115 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400116 * Returns the {@link MtpDeviceInfo} for this device
Mike Lockwood540380f2011-02-09 21:48:53 -0500117 *
118 * @return the device info
119 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500120 public MtpDeviceInfo getDeviceInfo() {
121 return native_get_device_info();
122 }
123
Mike Lockwood540380f2011-02-09 21:48:53 -0500124 /**
125 * Returns the list of IDs for all storage units on this device
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400126 * Information about each storage unit can be accessed via {@link #getStorageInfo}.
Mike Lockwood540380f2011-02-09 21:48:53 -0500127 *
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400128 * @return the list of storage IDs
Mike Lockwood540380f2011-02-09 21:48:53 -0500129 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500130 public int[] getStorageIds() {
131 return native_get_storage_ids();
132 }
133
Mike Lockwood540380f2011-02-09 21:48:53 -0500134 /**
135 * Returns the list of object handles for all objects on the given storage unit,
136 * with the given format and parent.
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400137 * Information about each object can be accessed via {@link #getObjectInfo}.
Mike Lockwood540380f2011-02-09 21:48:53 -0500138 *
139 * @param storageId the storage unit to query
140 * @param format the format of the object to return, or zero for all formats
Daichi Hirono660727c2015-06-12 10:45:08 +0900141 * @param objectHandle the parent object to query, -1 for the storage root,
142 * or zero for all objects
Mike Lockwood540380f2011-02-09 21:48:53 -0500143 * @return the object handles
144 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500145 public int[] getObjectHandles(int storageId, int format, int objectHandle) {
146 return native_get_object_handles(storageId, format, objectHandle);
147 }
148
Mike Lockwood540380f2011-02-09 21:48:53 -0500149 /**
150 * Returns the data for an object as a byte array.
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400151 * This call may block for an arbitrary amount of time depending on the size
152 * of the data and speed of the devices.
Mike Lockwood540380f2011-02-09 21:48:53 -0500153 *
154 * @param objectHandle handle of the object to read
155 * @param objectSize the size of the object (this should match
Daichi Hironoe0e66542016-01-15 14:42:53 +0900156 * {@link MtpObjectInfo#getCompressedSize})
Mike Lockwood540380f2011-02-09 21:48:53 -0500157 * @return the object's data, or null if reading fails
158 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500159 public byte[] getObject(int objectHandle, int objectSize) {
Daichi Hironoe0e66542016-01-15 14:42:53 +0900160 Preconditions.checkArgumentNonnegative(objectSize, "objectSize should not be negative");
Mike Lockwood8182e722010-12-30 15:38:45 -0500161 return native_get_object(objectHandle, objectSize);
162 }
163
Mike Lockwood540380f2011-02-09 21:48:53 -0500164 /**
Daichi Hirono52da3ad2015-12-24 17:52:10 +0900165 * Obtains object bytes in the specified range and writes it to an array.
166 * This call may block for an arbitrary amount of time depending on the size
167 * of the data and speed of the devices.
168 *
169 * @param objectHandle handle of the object to read
Daichi Hirono2dd48252016-01-12 15:46:41 +0900170 * @param offset Start index of reading range. It must be a non-negative value at most
171 * 0xffffffff.
172 * @param size Size of reading range. It must be a non-negative value at most 0xffffffff. If
173 * 0xffffffff is specified, the method obtains the full bytes of object.
Daichi Hirono52da3ad2015-12-24 17:52:10 +0900174 * @param buffer Array to write data.
175 * @return Size of bytes that are actually read.
176 */
Daichi Hirono2dd48252016-01-12 15:46:41 +0900177 public long getPartialObject(int objectHandle, long offset, long size, byte[] buffer)
Daichi Hirono52da3ad2015-12-24 17:52:10 +0900178 throws IOException {
179 return native_get_partial_object(objectHandle, offset, size, buffer);
180 }
181
182 /**
Daichi Hirono038832b2016-01-22 19:34:25 +0900183 * Obtains object bytes in the specified range and writes it to an array.
184 * This call may block for an arbitrary amount of time depending on the size
185 * of the data and speed of the devices.
186 *
187 * This is a vender-extended operation supported by Android that enables us to pass
188 * unsigned 64-bit offset. Check if the MTP device supports the operation by using
189 * {@link MtpDeviceInfo#getOperationsSupported()}.
190 *
191 * @param objectHandle handle of the object to read
192 * @param offset Start index of reading range. It must be a non-negative value.
193 * @param size Size of reading range. It must be a non-negative value at most 0xffffffff.
194 * @param buffer Array to write data.
195 * @return Size of bytes that are actually read.
196 * @see MtpConstants#OPERATION_GET_PARTIAL_OBJECT_64
197 */
198 public long getPartialObject64(int objectHandle, long offset, long size, byte[] buffer)
199 throws IOException {
200 return native_get_partial_object_64(objectHandle, offset, size, buffer);
201 }
202
203 /**
Mike Lockwood540380f2011-02-09 21:48:53 -0500204 * Returns the thumbnail data for an object as a byte array.
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400205 * The size and format of the thumbnail data can be determined via
206 * {@link MtpObjectInfo#getThumbCompressedSize} and
207 * {@link MtpObjectInfo#getThumbFormat}.
208 * For typical devices the format is JPEG.
Mike Lockwood540380f2011-02-09 21:48:53 -0500209 *
210 * @param objectHandle handle of the object to read
211 * @return the object's thumbnail, or null if reading fails
212 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500213 public byte[] getThumbnail(int objectHandle) {
214 return native_get_thumbnail(objectHandle);
215 }
216
Mike Lockwood540380f2011-02-09 21:48:53 -0500217 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400218 * Retrieves the {@link MtpStorageInfo} for a storage unit.
Mike Lockwood540380f2011-02-09 21:48:53 -0500219 *
220 * @param storageId the ID of the storage unit
221 * @return the MtpStorageInfo
222 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500223 public MtpStorageInfo getStorageInfo(int storageId) {
224 return native_get_storage_info(storageId);
225 }
226
Mike Lockwood540380f2011-02-09 21:48:53 -0500227 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400228 * Retrieves the {@link MtpObjectInfo} for an object.
Mike Lockwood540380f2011-02-09 21:48:53 -0500229 *
230 * @param objectHandle the handle of the object
231 * @return the MtpObjectInfo
232 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500233 public MtpObjectInfo getObjectInfo(int objectHandle) {
234 return native_get_object_info(objectHandle);
235 }
236
Mike Lockwood540380f2011-02-09 21:48:53 -0500237 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400238 * Deletes an object on the device. This call may block, since
239 * deleting a directory containing many files may take a long time
240 * on some devices.
Mike Lockwood540380f2011-02-09 21:48:53 -0500241 *
242 * @param objectHandle handle of the object to delete
243 * @return true if the deletion succeeds
244 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500245 public boolean deleteObject(int objectHandle) {
246 return native_delete_object(objectHandle);
247 }
248
Mike Lockwood540380f2011-02-09 21:48:53 -0500249 /**
250 * Retrieves the object handle for the parent of an object on the device.
251 *
252 * @param objectHandle handle of the object to query
253 * @return the parent's handle, or zero if it is in the root of the storage
254 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500255 public long getParent(int objectHandle) {
256 return native_get_parent(objectHandle);
257 }
258
Mike Lockwood540380f2011-02-09 21:48:53 -0500259 /**
260 * Retrieves the ID of the storage unit containing the given object on the device.
261 *
262 * @param objectHandle handle of the object to query
263 * @return the object's storage unit ID
264 */
Mike Lockwood62cfeeb2011-03-11 18:39:03 -0500265 public long getStorageId(int objectHandle) {
Mike Lockwood8182e722010-12-30 15:38:45 -0500266 return native_get_storage_id(objectHandle);
267 }
268
Mike Lockwood540380f2011-02-09 21:48:53 -0500269 /**
270 * Copies the data for an object to a file in external storage.
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400271 * This call may block for an arbitrary amount of time depending on the size
272 * of the data and speed of the devices.
Mike Lockwood540380f2011-02-09 21:48:53 -0500273 *
274 * @param objectHandle handle of the object to read
275 * @param destPath path to destination for the file transfer.
276 * This path should be in the external storage as defined by
277 * {@link android.os.Environment#getExternalStorageDirectory}
278 * @return true if the file transfer succeeds
279 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500280 public boolean importFile(int objectHandle, String destPath) {
281 return native_import_file(objectHandle, destPath);
282 }
283
Tomasz Mikolajewski74d4ff82015-08-04 18:34:03 +0900284 /**
285 * Copies the data for an object to a file descriptor.
286 * This call may block for an arbitrary amount of time depending on the size
287 * of the data and speed of the devices. The file descriptor is not closed
288 * on completion, and must be done by the caller.
289 *
290 * @param objectHandle handle of the object to read
291 * @param descriptor file descriptor to write the data to for the file transfer.
292 * @return true if the file transfer succeeds
293 */
294 public boolean importFile(int objectHandle, ParcelFileDescriptor descriptor) {
295 return native_import_file(objectHandle, descriptor.getFd());
296 }
297
Tomasz Mikolajewskib0499052015-08-06 19:13:09 +0900298 /**
299 * Copies the data for an object from 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 target file
Tomasz Mikolajewskib80a3cf2015-08-24 16:10:51 +0900305 * @param size size of the file in bytes
Tomasz Mikolajewskib0499052015-08-06 19:13:09 +0900306 * @param descriptor file descriptor to read the data from.
307 * @return true if the file transfer succeeds
308 */
Daichi Hironoe0e66542016-01-15 14:42:53 +0900309 public boolean sendObject(int objectHandle, long size, ParcelFileDescriptor descriptor) {
Tomasz Mikolajewskib80a3cf2015-08-24 16:10:51 +0900310 return native_send_object(objectHandle, size, descriptor.getFd());
Tomasz Mikolajewskib0499052015-08-06 19:13:09 +0900311 }
312
313 /**
314 * Uploads an object metadata for a new entry. The {@link MtpObjectInfo} can be
315 * created with the {@link MtpObjectInfo.Builder} class.
316 *
317 * The returned {@link MtpObjectInfo} has the new object handle field filled in.
318 *
319 * @param info metadata of the entry
320 * @return object info of the created entry
321 */
322 public MtpObjectInfo sendObjectInfo(MtpObjectInfo info) {
323 return native_send_object_info(info);
324 }
325
Daichi Hirono0b494662015-09-10 20:38:15 +0900326 /**
327 * Reads an event from the device. It blocks the current thread until it gets an event.
328 * It throws OperationCanceledException if it is cancelled by signal.
329 *
330 * @param signal signal for cancellation
331 * @return obtained event
332 */
333 public MtpEvent readEvent(CancellationSignal signal) {
334 final int handle = native_submit_event_request();
335
336 if (handle < 0) {
337 throw new IllegalStateException("Other thread is reading an event.");
338 }
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
Daichi Hirono787821b2016-03-24 21:05:51 +0900358 /**
359 * Returns object size in 64-bit integer.
360 *
Daichi Hirono1337deb2016-03-28 08:53:15 +0900361 * 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.
Daichi Hirono787821b2016-03-24 21:05:51 +0900365 * @hide
366 */
367 public long getObjectSizeLong(int handle, int format) throws IOException {
368 return native_get_object_size_long(handle, format);
369 }
370
Mike Lockwood8182e722010-12-30 15:38:45 -0500371 // used by the JNI code
Ashok Bhate2e59322013-12-17 19:04:19 +0000372 private long mNativeContext;
Mike Lockwood8182e722010-12-30 15:38:45 -0500373
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);
Daichi Hironoe0e66542016-01-15 14:42:53 +0900381 private native byte[] native_get_object(int objectHandle, long objectSize);
Daichi Hirono2dd48252016-01-12 15:46:41 +0900382 private native long native_get_partial_object(
383 int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
Daichi Hirono038832b2016-01-22 19:34:25 +0900384 private native int native_get_partial_object_64(
385 int objectHandle, long offset, long objectSize, byte[] buffer) throws IOException;
Mike Lockwood8182e722010-12-30 15:38:45 -0500386 private native byte[] native_get_thumbnail(int objectHandle);
387 private native boolean native_delete_object(int objectHandle);
Daichi Hironoe0e66542016-01-15 14:42:53 +0900388 private native int native_get_parent(int objectHandle);
389 private native int native_get_storage_id(int objectHandle);
Mike Lockwood8182e722010-12-30 15:38:45 -0500390 private native boolean native_import_file(int objectHandle, String destPath);
Tomasz Mikolajewski74d4ff82015-08-04 18:34:03 +0900391 private native boolean native_import_file(int objectHandle, int fd);
Daichi Hironoe0e66542016-01-15 14:42:53 +0900392 private native boolean native_send_object(int objectHandle, long size, int fd);
Tomasz Mikolajewskib0499052015-08-06 19:13:09 +0900393 private native MtpObjectInfo native_send_object_info(MtpObjectInfo info);
Daichi Hirono0b494662015-09-10 20:38:15 +0900394 private native int native_submit_event_request();
395 private native MtpEvent native_reap_event_request(int handle);
396 private native void native_discard_event_request(int handle);
Daichi Hirono787821b2016-03-24 21:05:51 +0900397 private native long native_get_object_size_long(int handle, int format) throws IOException;
Mike Lockwood8182e722010-12-30 15:38:45 -0500398}