blob: 4082778986c62b0df081849e9a80077c5eb1ee02 [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
Daichi Hirono60fa3612016-04-19 12:50:34 +090019import android.annotation.NonNull;
20import android.annotation.Nullable;
Mike Lockwoodc4308f02011-03-01 08:04:54 -080021import android.hardware.usb.UsbDevice;
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050022import android.hardware.usb.UsbDeviceConnection;
Daichi Hirono0b494662015-09-10 20:38:15 +090023import android.os.CancellationSignal;
Tomasz Mikolajewski74d4ff82015-08-04 18:34:03 +090024import android.os.ParcelFileDescriptor;
Mike Lockwood8182e722010-12-30 15:38:45 -050025
Daichi Hirono2dd48252016-01-12 15:46:41 +090026import com.android.internal.util.Preconditions;
27
Daichi Hirono52da3ad2015-12-24 17:52:10 +090028import java.io.IOException;
29
Mike Lockwood8182e722010-12-30 15:38:45 -050030/**
Scott Main0cdd9f72011-05-05 15:53:44 -070031 * 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.
Mike Lockwood8182e722010-12-30 15:38:45 -050035 */
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
Mike Lockwood540380f2011-02-09 21:48:53 -050046 /**
47 * MtpClient constructor
48 *
Mike Lockwoodc4308f02011-03-01 08:04:54 -080049 * @param device the {@link android.hardware.usb.UsbDevice} for the MTP or PTP device
Mike Lockwood540380f2011-02-09 21:48:53 -050050 */
Mike Lockwood8182e722010-12-30 15:38:45 -050051 public MtpDevice(UsbDevice device) {
52 mDevice = device;
53 }
54
Mike Lockwood540380f2011-02-09 21:48:53 -050055 /**
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050056 * Opens the MTP device. Once the device is open it takes ownership of the
Daichi Hirono0b494662015-09-10 20:38:15 +090057 * {@link android.hardware.usb.UsbDeviceConnection}.
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050058 * The connection will be closed when you call {@link #close()}
59 * The connection will also be closed if this method fails.
Mike Lockwood540380f2011-02-09 21:48:53 -050060 *
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050061 * @param connection an open {@link android.hardware.usb.UsbDeviceConnection} for the device
Mike Lockwood540380f2011-02-09 21:48:53 -050062 * @return true if the device was successfully opened.
63 */
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050064 public boolean open(UsbDeviceConnection connection) {
65 boolean result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor());
66 if (!result) {
67 connection.close();
Mike Lockwood8182e722010-12-30 15:38:45 -050068 }
Mike Lockwoodacc29cc2011-03-11 08:18:08 -050069 return result;
Mike Lockwood8182e722010-12-30 15:38:45 -050070 }
71
Mike Lockwood540380f2011-02-09 21:48:53 -050072 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -040073 * 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}.
Mike Lockwood540380f2011-02-09 21:48:53 -050076 */
Mike Lockwood8182e722010-12-30 15:38:45 -050077 public void close() {
Mike Lockwood8182e722010-12-30 15:38:45 -050078 native_close();
79 }
80
81 @Override
82 protected void finalize() throws Throwable {
Mike Lockwood8182e722010-12-30 15:38:45 -050083 try {
84 native_close();
85 } finally {
86 super.finalize();
87 }
88 }
89
Mike Lockwood540380f2011-02-09 21:48:53 -050090 /**
91 * Returns the name of the USB device
Mike Lockwood11dd5ae2011-04-01 14:00:08 -040092 * This returns the same value as {@link android.hardware.usb.UsbDevice#getDeviceName}
93 * for the device's {@link android.hardware.usb.UsbDevice}
Mike Lockwood540380f2011-02-09 21:48:53 -050094 *
95 * @return the device name
96 */
Mike Lockwood8182e722010-12-30 15:38:45 -050097 public String getDeviceName() {
98 return mDevice.getDeviceName();
99 }
100
Mike Lockwood540380f2011-02-09 21:48:53 -0500101 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400102 * 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}
Mike Lockwood540380f2011-02-09 21:48:53 -0500105 *
106 * @return the device ID
107 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500108 public int getDeviceId() {
109 return mDevice.getDeviceId();
110 }
111
112 @Override
113 public String toString() {
114 return mDevice.getDeviceName();
115 }
116
Mike Lockwood540380f2011-02-09 21:48:53 -0500117 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400118 * Returns the {@link MtpDeviceInfo} for this device
Mike Lockwood540380f2011-02-09 21:48:53 -0500119 *
120 * @return the device info
121 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500122 public MtpDeviceInfo getDeviceInfo() {
123 return native_get_device_info();
124 }
125
Mike Lockwood540380f2011-02-09 21:48:53 -0500126 /**
127 * Returns the list of IDs for all storage units on this device
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400128 * Information about each storage unit can be accessed via {@link #getStorageInfo}.
Mike Lockwood540380f2011-02-09 21:48:53 -0500129 *
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400130 * @return the list of storage IDs
Mike Lockwood540380f2011-02-09 21:48:53 -0500131 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500132 public int[] getStorageIds() {
133 return native_get_storage_ids();
134 }
135
Mike Lockwood540380f2011-02-09 21:48:53 -0500136 /**
137 * Returns the list of object handles for all objects on the given storage unit,
138 * with the given format and parent.
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400139 * Information about each object can be accessed via {@link #getObjectInfo}.
Mike Lockwood540380f2011-02-09 21:48:53 -0500140 *
141 * @param storageId the storage unit to query
142 * @param format the format of the object to return, or zero for all formats
Daichi Hirono660727c2015-06-12 10:45:08 +0900143 * @param objectHandle the parent object to query, -1 for the storage root,
144 * or zero for all objects
Mike Lockwood540380f2011-02-09 21:48:53 -0500145 * @return the object handles
146 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500147 public int[] getObjectHandles(int storageId, int format, int objectHandle) {
148 return native_get_object_handles(storageId, format, objectHandle);
149 }
150
Mike Lockwood540380f2011-02-09 21:48:53 -0500151 /**
152 * Returns the data for an object as a byte array.
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400153 * This call may block for an arbitrary amount of time depending on the size
154 * of the data and speed of the devices.
Mike Lockwood540380f2011-02-09 21:48:53 -0500155 *
156 * @param objectHandle handle of the object to read
157 * @param objectSize the size of the object (this should match
Daichi Hironoe0e66542016-01-15 14:42:53 +0900158 * {@link MtpObjectInfo#getCompressedSize})
Mike Lockwood540380f2011-02-09 21:48:53 -0500159 * @return the object's data, or null if reading fails
160 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500161 public byte[] getObject(int objectHandle, int objectSize) {
Daichi Hironoe0e66542016-01-15 14:42:53 +0900162 Preconditions.checkArgumentNonnegative(objectSize, "objectSize should not be negative");
Mike Lockwood8182e722010-12-30 15:38:45 -0500163 return native_get_object(objectHandle, objectSize);
164 }
165
Mike Lockwood540380f2011-02-09 21:48:53 -0500166 /**
Daichi Hirono52da3ad2015-12-24 17:52:10 +0900167 * 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
Daichi Hirono2dd48252016-01-12 15:46:41 +0900172 * @param offset Start index of reading range. It must be a non-negative value at most
173 * 0xffffffff.
Daichi Hirono399df702016-04-13 11:07:44 +0900174 * @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.
Daichi Hirono52da3ad2015-12-24 17:52:10 +0900176 * @param buffer Array to write data.
177 * @return Size of bytes that are actually read.
178 */
Daichi Hirono2dd48252016-01-12 15:46:41 +0900179 public long getPartialObject(int objectHandle, long offset, long size, byte[] buffer)
Daichi Hirono52da3ad2015-12-24 17:52:10 +0900180 throws IOException {
181 return native_get_partial_object(objectHandle, offset, size, buffer);
182 }
183
184 /**
Daichi Hirono038832b2016-01-22 19:34:25 +0900185 * 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.
Daichi Hirono399df702016-04-13 11:07:44 +0900195 * @param size Size of reading range. It must be a non-negative value at most Integer.MAX_VALUE.
Daichi Hirono038832b2016-01-22 19:34:25 +0900196 * @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 /**
Mike Lockwood540380f2011-02-09 21:48:53 -0500206 * Returns the thumbnail data for an object as a byte array.
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400207 * 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.
Mike Lockwood540380f2011-02-09 21:48:53 -0500211 *
212 * @param objectHandle handle of the object to read
213 * @return the object's thumbnail, or null if reading fails
214 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500215 public byte[] getThumbnail(int objectHandle) {
216 return native_get_thumbnail(objectHandle);
217 }
218
Mike Lockwood540380f2011-02-09 21:48:53 -0500219 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400220 * Retrieves the {@link MtpStorageInfo} for a storage unit.
Mike Lockwood540380f2011-02-09 21:48:53 -0500221 *
222 * @param storageId the ID of the storage unit
223 * @return the MtpStorageInfo
224 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500225 public MtpStorageInfo getStorageInfo(int storageId) {
226 return native_get_storage_info(storageId);
227 }
228
Mike Lockwood540380f2011-02-09 21:48:53 -0500229 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400230 * Retrieves the {@link MtpObjectInfo} for an object.
Mike Lockwood540380f2011-02-09 21:48:53 -0500231 *
232 * @param objectHandle the handle of the object
233 * @return the MtpObjectInfo
234 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500235 public MtpObjectInfo getObjectInfo(int objectHandle) {
236 return native_get_object_info(objectHandle);
237 }
238
Mike Lockwood540380f2011-02-09 21:48:53 -0500239 /**
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400240 * 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.
Mike Lockwood540380f2011-02-09 21:48:53 -0500243 *
244 * @param objectHandle handle of the object to delete
245 * @return true if the deletion succeeds
246 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500247 public boolean deleteObject(int objectHandle) {
248 return native_delete_object(objectHandle);
249 }
250
Mike Lockwood540380f2011-02-09 21:48:53 -0500251 /**
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 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500257 public long getParent(int objectHandle) {
258 return native_get_parent(objectHandle);
259 }
260
Mike Lockwood540380f2011-02-09 21:48:53 -0500261 /**
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 */
Mike Lockwood62cfeeb2011-03-11 18:39:03 -0500267 public long getStorageId(int objectHandle) {
Mike Lockwood8182e722010-12-30 15:38:45 -0500268 return native_get_storage_id(objectHandle);
269 }
270
Mike Lockwood540380f2011-02-09 21:48:53 -0500271 /**
272 * Copies the data for an object to a file in external storage.
Mike Lockwood11dd5ae2011-04-01 14:00:08 -0400273 * This call may block for an arbitrary amount of time depending on the size
274 * of the data and speed of the devices.
Mike Lockwood540380f2011-02-09 21:48:53 -0500275 *
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 */
Mike Lockwood8182e722010-12-30 15:38:45 -0500282 public boolean importFile(int objectHandle, String destPath) {
283 return native_import_file(objectHandle, destPath);
284 }
285
Tomasz Mikolajewski74d4ff82015-08-04 18:34:03 +0900286 /**
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
Tomasz Mikolajewskib0499052015-08-06 19:13:09 +0900300 /**
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
Tomasz Mikolajewskib80a3cf2015-08-24 16:10:51 +0900307 * @param size size of the file in bytes
Tomasz Mikolajewskib0499052015-08-06 19:13:09 +0900308 * @param descriptor file descriptor to read the data from.
309 * @return true if the file transfer succeeds
310 */
Daichi Hironoe0e66542016-01-15 14:42:53 +0900311 public boolean sendObject(int objectHandle, long size, ParcelFileDescriptor descriptor) {
Tomasz Mikolajewskib80a3cf2015-08-24 16:10:51 +0900312 return native_send_object(objectHandle, size, descriptor.getFd());
Tomasz Mikolajewskib0499052015-08-06 19:13:09 +0900313 }
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
Daichi Hirono399df702016-04-13 11:07:44 +0900322 * @return object info of the created entry or null if the operation failed.
Tomasz Mikolajewskib0499052015-08-06 19:13:09 +0900323 */
324 public MtpObjectInfo sendObjectInfo(MtpObjectInfo info) {
325 return native_send_object_info(info);
326 }
327
Daichi Hirono0b494662015-09-10 20:38:15 +0900328 /**
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
Daichi Hirono60fa3612016-04-19 12:50:34 +0900334 * @throws IOException
Daichi Hirono0b494662015-09-10 20:38:15 +0900335 */
Daichi Hirono60fa3612016-04-19 12:50:34 +0900336 public @NonNull MtpEvent readEvent(@Nullable CancellationSignal signal) throws IOException {
Daichi Hirono0b494662015-09-10 20:38:15 +0900337 final int handle = native_submit_event_request();
Daichi Hirono60fa3612016-04-19 12:50:34 +0900338 Preconditions.checkState(handle >= 0, "Other thread is reading an event.");
Daichi Hirono0b494662015-09-10 20:38:15 +0900339
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 Hirono60fa3612016-04-19 12:50:34 +0900394 private native int native_submit_event_request() throws IOException;
395 private native MtpEvent native_reap_event_request(int handle) throws IOException;
Daichi Hirono0b494662015-09-10 20:38:15 +0900396 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}