18182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood/* 28182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * Copyright (C) 2010 The Android Open Source Project 38182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * 48182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License"); 58182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * you may not use this file except in compliance with the License. 68182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * You may obtain a copy of the License at 78182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * 88182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * http://www.apache.org/licenses/LICENSE-2.0 98182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * 108182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * Unless required by applicable law or agreed to in writing, software 118182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS, 128182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * See the License for the specific language governing permissions and 148182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * limitations under the License. 158182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood */ 168182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 17c72eb9113a2f3f7886afcecf5c29507e0a3a8266Mike Lockwoodpackage com.android.camerabrowser; 188182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 193a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwoodimport android.app.PendingIntent; 208182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwoodimport android.content.BroadcastReceiver; 218182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwoodimport android.content.Context; 228182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwoodimport android.content.Intent; 238182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwoodimport android.content.IntentFilter; 24c4308f01c965571dc2354107c3574df113e397eeMike Lockwoodimport android.hardware.usb.UsbConstants; 25c4308f01c965571dc2354107c3574df113e397eeMike Lockwoodimport android.hardware.usb.UsbDevice; 26acc29cc91be634070c92a807df412ced97b9b375Mike Lockwoodimport android.hardware.usb.UsbDeviceConnection; 27c4308f01c965571dc2354107c3574df113e397eeMike Lockwoodimport android.hardware.usb.UsbInterface; 28c4308f01c965571dc2354107c3574df113e397eeMike Lockwoodimport android.hardware.usb.UsbManager; 29c72eb9113a2f3f7886afcecf5c29507e0a3a8266Mike Lockwoodimport android.mtp.MtpDevice; 30c72eb9113a2f3f7886afcecf5c29507e0a3a8266Mike Lockwoodimport android.mtp.MtpDeviceInfo; 31c72eb9113a2f3f7886afcecf5c29507e0a3a8266Mike Lockwoodimport android.mtp.MtpObjectInfo; 32c72eb9113a2f3f7886afcecf5c29507e0a3a8266Mike Lockwoodimport android.mtp.MtpStorageInfo; 338182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwoodimport android.os.ParcelFileDescriptor; 348182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwoodimport android.util.Log; 358182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 368182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwoodimport java.io.IOException; 378182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwoodimport java.util.ArrayList; 382b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwoodimport java.util.HashMap; 398182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwoodimport java.util.List; 408182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 418182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood/** 42540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * This class helps an application manage a list of connected MTP or PTP devices. 438182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * It listens for MTP devices being attached and removed from the USB host bus 448182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood * and notifies the application when the MTP device list changes. 458182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood */ 468182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwoodpublic class MtpClient { 478182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 488182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood private static final String TAG = "MtpClient"; 498182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 503a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood private static final String ACTION_USB_PERMISSION = 513a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood "android.mtp.MtpClient.action.USB_PERMISSION"; 523a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood 538182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood private final Context mContext; 548182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood private final UsbManager mUsbManager; 558182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood private final ArrayList<Listener> mListeners = new ArrayList<Listener>(); 562b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood // mDevices contains all MtpDevices that have been seen by our client, 572b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood // so we can inform when the device has been detached. 582b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood // mDevices is also used for synchronization in this class. 592b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>(); 608182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 613a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood private final PendingIntent mPermissionIntent; 623a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood 638182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { 648182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood @Override 658182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public void onReceive(Context context, Intent intent) { 663a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood String action = intent.getAction(); 67188d00b07ef0b8968868b3489e80dd9f53d3bafaMike Lockwood UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 68188d00b07ef0b8968868b3489e80dd9f53d3bafaMike Lockwood String deviceName = usbDevice.getDeviceName(); 698182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 702b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood synchronized (mDevices) { 712b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood MtpDevice mtpDevice = mDevices.get(deviceName); 728182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 733a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { 748182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (mtpDevice == null) { 752b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood mtpDevice = openDeviceLocked(usbDevice); 768182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 778182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (mtpDevice != null) { 788182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood for (Listener listener : mListeners) { 798182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood listener.deviceAdded(mtpDevice); 808182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 818182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 823a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { 833a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood if (mtpDevice != null) { 843a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood mDevices.remove(deviceName); 853a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood for (Listener listener : mListeners) { 863a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood listener.deviceRemoved(mtpDevice); 873a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood } 883a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood } 893a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood } else if (ACTION_USB_PERMISSION.equals(action)) { 903a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood boolean permission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, 913a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood false); 923a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood Log.d(TAG, "ACTION_USB_PERMISSION: " + permission); 933a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood if (permission) { 943a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood if (mtpDevice == null) { 953a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood mtpDevice = openDeviceLocked(usbDevice); 963a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood } 973a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood if (mtpDevice != null) { 983a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood for (Listener listener : mListeners) { 993a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood listener.deviceAdded(mtpDevice); 1003a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood } 1013a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood } 1028182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 1038182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 1048182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 1058182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 1068182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood }; 1078182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 108540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 109540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * An interface for being notified when MTP or PTP devices are attached 110540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * or removed. In the current implementation, only PTP devices are supported. 111540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 1128182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public interface Listener { 113540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 114540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Called when a new device has been added 115540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 116540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param device the new device that was added 117540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 1188182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public void deviceAdded(MtpDevice device); 119540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood 120540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 121540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Called when a new device has been removed 122540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 123540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param device the device that was removed 124540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 1258182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public void deviceRemoved(MtpDevice device); 1268182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 1278182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 128540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 129c4308f01c965571dc2354107c3574df113e397eeMike Lockwood * Tests to see if a {@link android.hardware.usb.UsbDevice} 130540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * supports the PTP protocol (typically used by digital cameras) 131540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 132540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param device the device to test 133540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return true if the device is a PTP device. 134540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 135540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood static public boolean isCamera(UsbDevice device) { 1368182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood int count = device.getInterfaceCount(); 1378182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood for (int i = 0; i < count; i++) { 1388182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood UsbInterface intf = device.getInterface(i); 1398182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (intf.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE && 1408182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood intf.getInterfaceSubclass() == 1 && 1418182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood intf.getInterfaceProtocol() == 1) { 1428182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return true; 1438182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 1448182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 1458182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return false; 1468182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 1478182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 148540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 149540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * MtpClient constructor 150540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 151540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param context the {@link android.content.Context} to use for the MtpClient 152540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 1538182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public MtpClient(Context context) { 1548182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood mContext = context; 1558182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE); 1563a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0); 1578182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood IntentFilter filter = new IntentFilter(); 1588182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); 1598182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); 1603a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood filter.addAction(ACTION_USB_PERMISSION); 1618182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood context.registerReceiver(mUsbReceiver, filter); 1628182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 1638182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 164540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 165c4308f01c965571dc2354107c3574df113e397eeMike Lockwood * Opens the {@link android.hardware.usb.UsbDevice} for an MTP or PTP 166540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * device and return an {@link android.mtp.MtpDevice} for it. 167540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 168540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param device the device to open 169540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return an MtpDevice for the device. 170540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 1712b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood private MtpDevice openDeviceLocked(UsbDevice usbDevice) { 172540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood if (isCamera(usbDevice)) { 1733a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood if (!mUsbManager.hasPermission(usbDevice)) { 1743a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood mUsbManager.requestPermission(usbDevice, mPermissionIntent); 1753a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood } else { 176acc29cc91be634070c92a807df412ced97b9b375Mike Lockwood UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice); 177acc29cc91be634070c92a807df412ced97b9b375Mike Lockwood if (connection != null) { 178acc29cc91be634070c92a807df412ced97b9b375Mike Lockwood MtpDevice mtpDevice = new MtpDevice(usbDevice); 179acc29cc91be634070c92a807df412ced97b9b375Mike Lockwood if (mtpDevice.open(connection)) { 180acc29cc91be634070c92a807df412ced97b9b375Mike Lockwood mDevices.put(usbDevice.getDeviceName(), mtpDevice); 181acc29cc91be634070c92a807df412ced97b9b375Mike Lockwood return mtpDevice; 182acc29cc91be634070c92a807df412ced97b9b375Mike Lockwood } 1833a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood } 184540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood } 185540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood } 186540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood return null; 187540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood } 188540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood 189540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 190540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Closes all resources related to the MtpClient object 191540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 1928182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public void close() { 1938182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood mContext.unregisterReceiver(mUsbReceiver); 1948182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 1958182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 196540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 197540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Registers a {@link android.mtp.MtpClient.Listener} interface to receive 198540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * notifications when MTP or PTP devices are added or removed. 199540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 200540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param listener the listener to register 201540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 2028182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public void addListener(Listener listener) { 2032b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood synchronized (mDevices) { 2048182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (!mListeners.contains(listener)) { 2058182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood mListeners.add(listener); 2068182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2078182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2088182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2098182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 210540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 211540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Unregisters a {@link android.mtp.MtpClient.Listener} interface. 212540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 213540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param listener the listener to unregister 214540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 2158182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public void removeListener(Listener listener) { 2162b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood synchronized (mDevices) { 2178182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood mListeners.remove(listener); 2188182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2198182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2208182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 221540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 222540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Retrieves an {@link android.mtp.MtpDevice} object for the USB device 223540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * with the given name. 224540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 225540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param deviceName the name of the USB device 226540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return the MtpDevice, or null if it does not exist 227540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 2288182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public MtpDevice getDevice(String deviceName) { 2292b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood synchronized (mDevices) { 2302b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood return mDevices.get(deviceName); 2318182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2328182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2338182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 234540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 235540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Retrieves an {@link android.mtp.MtpDevice} object for the USB device 236540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * with the given ID. 237540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 238540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param id the ID of the USB device 239540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return the MtpDevice, or null if it does not exist 240540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 2418182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public MtpDevice getDevice(int id) { 2422b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood synchronized (mDevices) { 2432b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood return mDevices.get(UsbDevice.getDeviceName(id)); 2448182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2458182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2468182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 247540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 248540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Retrieves a list of all currently connected {@link android.mtp.MtpDevice}. 249540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 250540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return the list of MtpDevices 251540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 2528182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public List<MtpDevice> getDeviceList() { 2532b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood synchronized (mDevices) { 2542b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood // Query the USB manager since devices might have attached 2552b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood // before we added our listener. 2562b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) { 2573a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood if (mDevices.get(usbDevice.getDeviceName()) == null) { 2583a68b8338b431eb15d28e92f06452efbbda9493eMike Lockwood openDeviceLocked(usbDevice); 2592b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood } 2602b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood } 2612b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood 2622b8a1ee0578e81b6600d5b2b03db9446d63e4616Mike Lockwood return new ArrayList<MtpDevice>(mDevices.values()); 2638182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2648182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2658182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 266540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 267540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Retrieves a list of all {@link android.mtp.MtpStorageInfo} 268540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * for the MTP or PTP device with the given USB device name 269540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 270540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param deviceName the name of the USB device 271540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return the list of MtpStorageInfo 272540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 2738182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public List<MtpStorageInfo> getStorageList(String deviceName) { 2748182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood MtpDevice device = getDevice(deviceName); 2758182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (device == null) { 2768182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return null; 2778182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2788182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood int[] storageIds = device.getStorageIds(); 2798182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (storageIds == null) { 2808182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return null; 2818182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2828182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 2838182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood int length = storageIds.length; 2848182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood ArrayList<MtpStorageInfo> storageList = new ArrayList<MtpStorageInfo>(length); 2858182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood for (int i = 0; i < length; i++) { 2868182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood MtpStorageInfo info = device.getStorageInfo(storageIds[i]); 2878182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (info == null) { 2888182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood Log.w(TAG, "getStorageInfo failed"); 2898182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } else { 2908182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood storageList.add(info); 2918182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2928182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2938182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return storageList; 2948182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 2958182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 296540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 297540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Retrieves the {@link android.mtp.MtpObjectInfo} for an object on 298540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * the MTP or PTP device with the given USB device name with the given 299540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * object handle 300540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 301540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param deviceName the name of the USB device 302540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param objectHandle handle of the object to query 303540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return the MtpObjectInfo 304540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 3058182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public MtpObjectInfo getObjectInfo(String deviceName, int objectHandle) { 3068182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood MtpDevice device = getDevice(deviceName); 3078182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (device == null) { 3088182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return null; 3098182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3108182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return device.getObjectInfo(objectHandle); 3118182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3128182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 313540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 314540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Deletes an object on the MTP or PTP device with the given USB device name. 315540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 316540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param deviceName the name of the USB device 317540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param objectHandle handle of the object to delete 318540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return true if the deletion succeeds 319540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 3208182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public boolean deleteObject(String deviceName, int objectHandle) { 3218182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood MtpDevice device = getDevice(deviceName); 3228182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (device == null) { 3238182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return false; 3248182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3258182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return device.deleteObject(objectHandle); 3268182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3278182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 328540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 329540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Retrieves a list of {@link android.mtp.MtpObjectInfo} for all objects 330540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * on the MTP or PTP device with the given USB device name and given storage ID 331540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * and/or object handle. 332540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * If the object handle is zero, then all objects in the root of the storage unit 333540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * will be returned. Otherwise, all immediate children of the object will be returned. 334540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * If the storage ID is also zero, then all objects on all storage units will be returned. 335540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 336540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param deviceName the name of the USB device 337540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param storageId the ID of the storage unit to query, or zero for all 338540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param objectHandle the handle of the parent object to query, or zero for the storage root 339540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return the list of MtpObjectInfo 340540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 3418182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public List<MtpObjectInfo> getObjectList(String deviceName, int storageId, int objectHandle) { 3428182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood MtpDevice device = getDevice(deviceName); 3438182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (device == null) { 3448182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return null; 3458182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3468182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (objectHandle == 0) { 3478182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood // all objects in root of storage 3488182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood objectHandle = 0xFFFFFFFF; 3498182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3508182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood int[] handles = device.getObjectHandles(storageId, 0, objectHandle); 3518182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (handles == null) { 3528182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return null; 3538182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3548182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 3558182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood int length = handles.length; 3568182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood ArrayList<MtpObjectInfo> objectList = new ArrayList<MtpObjectInfo>(length); 3578182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood for (int i = 0; i < length; i++) { 3588182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood MtpObjectInfo info = device.getObjectInfo(handles[i]); 3598182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (info == null) { 3608182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood Log.w(TAG, "getObjectInfo failed"); 3618182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } else { 3628182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood objectList.add(info); 3638182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3648182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3658182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return objectList; 3668182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3678182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 368540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 369540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Returns the data for an object as a byte array. 370540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 371540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param deviceName the name of the USB device containing the object 372540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param objectHandle handle of the object to read 373540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param objectSize the size of the object (this should match 374540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * {@link android.mtp.MtpObjectInfo#getCompressedSize} 375540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return the object's data, or null if reading fails 376540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 3778182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public byte[] getObject(String deviceName, int objectHandle, int objectSize) { 3788182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood MtpDevice device = getDevice(deviceName); 3798182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (device == null) { 3808182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return null; 3818182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3828182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return device.getObject(objectHandle, objectSize); 3838182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3848182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 385540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 386540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Returns the thumbnail data for an object as a byte array. 387540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 388540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param deviceName the name of the USB device containing the object 389540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param objectHandle handle of the object to read 390540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return the object's thumbnail, or null if reading fails 391540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 3928182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public byte[] getThumbnail(String deviceName, int objectHandle) { 3938182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood MtpDevice device = getDevice(deviceName); 3948182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (device == null) { 3958182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return null; 3968182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3978182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return device.getThumbnail(objectHandle); 3988182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 3998182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood 400540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood /** 401540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * Copies the data for an object to a file in external storage. 402540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * 403540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param deviceName the name of the USB device containing the object 404540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param objectHandle handle of the object to read 405540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @param destPath path to destination for the file transfer. 406540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * This path should be in the external storage as defined by 407540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * {@link android.os.Environment#getExternalStorageDirectory} 408540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood * @return true if the file transfer succeeds 409540380fb0a45b12af3970f9ea1ed041607451f46Mike Lockwood */ 4108182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood public boolean importFile(String deviceName, int objectHandle, String destPath) { 4118182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood MtpDevice device = getDevice(deviceName); 4128182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood if (device == null) { 4138182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return false; 4148182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 4158182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood return device.importFile(objectHandle, destPath); 4168182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood } 4178182e72479a8b0d832df9c392890b25bfa6f97b5Mike Lockwood} 418