14b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani/* 24b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Copyright (C) 2010 The Android Open Source Project 34b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * 44b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Licensed under the Apache License, Version 2.0 (the "License"); 54b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * you may not use this file except in compliance with the License. 64b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * You may obtain a copy of the License at 74b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * 84b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * http://www.apache.org/licenses/LICENSE-2.0 94b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * 104b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Unless required by applicable law or agreed to in writing, software 114b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * distributed under the License is distributed on an "AS IS" BASIS, 124b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * See the License for the specific language governing permissions and 144b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * limitations under the License. 154b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani */ 164b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 174b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasanipackage com.android.camerabrowser; 184b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 19ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkeyimport android.app.PendingIntent; 204b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport android.content.BroadcastReceiver; 21db6a14cc85cede0769735fdac4da70766989a3ceAmith Yamasaniimport android.content.Context; 222a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasaniimport android.content.Intent; 2380a4af2bbc6af42ae605e454bf89558e564f5244Dianne Hackbornimport android.content.IntentFilter; 2480a4af2bbc6af42ae605e454bf89558e564f5244Dianne Hackbornimport android.hardware.usb.UsbConstants; 25db6a14cc85cede0769735fdac4da70766989a3ceAmith Yamasaniimport android.hardware.usb.UsbDevice; 26258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport android.hardware.usb.UsbDeviceConnection; 27258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport android.hardware.usb.UsbInterface; 280b285499db739ba50f2f839d633e763c70e67f96Amith Yamasaniimport android.hardware.usb.UsbManager; 294b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport android.mtp.MtpDevice; 30e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasaniimport android.mtp.MtpDeviceInfo; 31e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasaniimport android.mtp.MtpObjectInfo; 32258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport android.mtp.MtpStorageInfo; 334b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport android.os.ParcelFileDescriptor; 344b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasaniimport android.util.Log; 35ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey 36258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport java.io.IOException; 37258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport java.util.ArrayList; 3880a4af2bbc6af42ae605e454bf89558e564f5244Dianne Hackbornimport java.util.HashMap; 39f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport java.util.List; 4027bd34d9d9fe99f11b80aa0bbdb402fb47ef4158Jeff Sharkey 412a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani/** 424b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * This class helps an application manage a list of connected MTP or PTP devices. 434b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * It listens for MTP devices being attached and removed from the USB host bus 44ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey * and notifies the application when the MTP device list changes. 45920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani */ 464b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasanipublic class MtpClient { 474b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 48ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey private static final String TAG = "MtpClient"; 49ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey 50ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey private static final String ACTION_USB_PERMISSION = 51ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey "android.mtp.MtpClient.action.USB_PERMISSION"; 52ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey 53ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey private final Context mContext; 54ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey private final UsbManager mUsbManager; 554b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private final ArrayList<Listener> mListeners = new ArrayList<Listener>(); 564b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani // mDevices contains all MtpDevices that have been seen by our client, 57920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani // so we can inform when the device has been detached. 584b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani // mDevices is also used for synchronization in this class. 59b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>(); 604b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 614b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private final PendingIntent mPermissionIntent; 62920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani 634b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { 644b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani @Override 654b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani public void onReceive(Context context, Intent intent) { 66258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani String action = intent.getAction(); 67b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 682a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani String deviceName = usbDevice.getDeviceName(); 69b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani 701638931166b7b5571886a8fe6d413ea90d4194b5Amith Yamasani synchronized (mDevices) { 711638931166b7b5571886a8fe6d413ea90d4194b5Amith Yamasani MtpDevice mtpDevice = mDevices.get(deviceName); 724b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 734b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { 74b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani if (mtpDevice == null) { 754b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani mtpDevice = openDeviceLocked(usbDevice); 76920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani } 77920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani if (mtpDevice != null) { 782a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani for (Listener listener : mListeners) { 792a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani listener.deviceAdded(mtpDevice); 80d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 816f34b411144a8202c96d05ff79e8040d3885643aAmith Yamasani } 824b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { 834b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (mtpDevice != null) { 844b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani mDevices.remove(deviceName); 850b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani for (Listener listener : mListeners) { 864b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani listener.deviceRemoved(mtpDevice); 87b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani } 884b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 89634cf31345ae843392215237e741d76271a5cfedAmith Yamasani } else if (ACTION_USB_PERMISSION.equals(action)) { 90634cf31345ae843392215237e741d76271a5cfedAmith Yamasani boolean permission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, 91bc9625059bccc8f0d70540d0affd73320620c3c0Amith Yamasani false); 926f34b411144a8202c96d05ff79e8040d3885643aAmith Yamasani Log.d(TAG, "ACTION_USB_PERMISSION: " + permission); 93920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani if (permission) { 94920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani if (mtpDevice == null) { 954428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn mtpDevice = openDeviceLocked(usbDevice); 964428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 974428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn if (mtpDevice != null) { 984428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn for (Listener listener : mListeners) { 994b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani listener.deviceAdded(mtpDevice); 100ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey } 101ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey } 1024b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1034b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani } 1044428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 1054428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 106ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey }; 107ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey 108ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey /** 109ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey * An interface for being notified when MTP or PTP devices are attached 110ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey * or removed. In the current implementation, only PTP devices are supported. 111ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey */ 112ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey public interface Listener { 113ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey /** 1144428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * Called when a new device has been added 1150b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * 116258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * @param device the new device that was added 1172a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani */ 1186f34b411144a8202c96d05ff79e8040d3885643aAmith Yamasani public void deviceAdded(MtpDevice device); 1190b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 120258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani /** 121258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * Called when a new device has been removed 1224428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * 1234428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * @param device the device that was removed 1244428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn */ 125258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani public void deviceRemoved(MtpDevice device); 126258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 1274b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani 1284b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani /** 1294b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Tests to see if a {@link android.hardware.usb.UsbDevice} 1304b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * supports the PTP protocol (typically used by digital cameras) 131258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * 1324428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * @param device the device to test 1334b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * @return true if the device is a PTP device. 1344b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani */ 1354428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn static public boolean isCamera(UsbDevice device) { 1364428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn int count = device.getInterfaceCount(); 1374428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn for (int i = 0; i < count; i++) { 1384428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn UsbInterface intf = device.getInterface(i); 1394428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn if (intf.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE && 1404428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn intf.getInterfaceSubclass() == 1 && 1414428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn intf.getInterfaceProtocol() == 1) { 1424428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn return true; 1434428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 1444428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 145258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani return false; 146258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 1474428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn 1484428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn /** 1494428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * MtpClient constructor 1504428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * 1514428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * @param context the {@link android.content.Context} to use for the MtpClient 1524428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn */ 153d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn public MtpClient(Context context) { 154d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn mContext = context; 155d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE); 156d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0); 157ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey IntentFilter filter = new IntentFilter(); 158d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); 159d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); 160d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn filter.addAction(ACTION_USB_PERMISSION); 161d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn context.registerReceiver(mUsbReceiver, filter); 162d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 163d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn 164d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn /** 165d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * Opens the {@link android.hardware.usb.UsbDevice} for an MTP or PTP 166d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * device and return an {@link android.mtp.MtpDevice} for it. 167d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * 168d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * @param device the device to open 169d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * @return an MtpDevice for the device. 170d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn */ 171d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn private MtpDevice openDeviceLocked(UsbDevice usbDevice) { 172756901d82b41f50610a63b7cf4c7747a70f1f724Amith Yamasani if (isCamera(usbDevice)) { 173d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn if (!mUsbManager.hasPermission(usbDevice)) { 174d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn mUsbManager.requestPermission(usbDevice, mPermissionIntent); 175d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } else { 176d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice); 177d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn if (connection != null) { 178d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn MtpDevice mtpDevice = new MtpDevice(usbDevice); 179d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn if (mtpDevice.open(connection)) { 180d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn mDevices.put(usbDevice.getDeviceName(), mtpDevice); 181d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn return mtpDevice; 182d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 183d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 184d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 185d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 186d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn return null; 187d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 1884428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn 1894b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani /** 1904b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani * Closes all resources related to the MtpClient object 191258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani */ 192920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani public void close() { 1932a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani mContext.unregisterReceiver(mUsbReceiver); 1944428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 195135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani 196135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani /** 197d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * Registers a {@link android.mtp.MtpClient.Listener} interface to receive 198d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * notifications when MTP or PTP devices are added or removed. 199d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * 200d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * @param listener the listener to register 201ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey */ 202d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn public void addListener(Listener listener) { 203920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani synchronized (mDevices) { 204135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani if (!mListeners.contains(listener)) { 205135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani mListeners.add(listener); 206135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 207135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 208135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 209258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani 210258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani /** 2112a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani * Unregisters a {@link android.mtp.MtpClient.Listener} interface. 2124428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * 2131952637425eece18aa1ce3d80d4b49086ef3bcf7Amith Yamasani * @param listener the listener to unregister 214135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani */ 215135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani public void removeListener(Listener listener) { 216135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani synchronized (mDevices) { 2171952637425eece18aa1ce3d80d4b49086ef3bcf7Amith Yamasani mListeners.remove(listener); 2181952637425eece18aa1ce3d80d4b49086ef3bcf7Amith Yamasani } 2191952637425eece18aa1ce3d80d4b49086ef3bcf7Amith Yamasani } 2201952637425eece18aa1ce3d80d4b49086ef3bcf7Amith Yamasani 221d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn /** 2221638931166b7b5571886a8fe6d413ea90d4194b5Amith Yamasani * Retrieves an {@link android.mtp.MtpDevice} object for the USB device 223ffe0cb49d14d9c21b5609de009f7e7434e5b0753Jeff Sharkey * with the given name. 224d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * 225d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * @param deviceName the name of the USB device 226d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * @return the MtpDevice, or null if it does not exist 227d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn */ 2281952637425eece18aa1ce3d80d4b49086ef3bcf7Amith Yamasani public MtpDevice getDevice(String deviceName) { 2291952637425eece18aa1ce3d80d4b49086ef3bcf7Amith Yamasani synchronized (mDevices) { 230135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani return mDevices.get(deviceName); 2314428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 232135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 233135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani 234135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani /** 235135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani * Retrieves an {@link android.mtp.MtpDevice} object for the USB device 236258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * with the given ID. 237b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani * 2382a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani * @param id the ID of the USB device 239d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * @return the MtpDevice, or null if it does not exist 2404428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn */ 241135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani public MtpDevice getDevice(int id) { 242d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn synchronized (mDevices) { 243d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn return mDevices.get(UsbDevice.getDeviceName(id)); 244d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 245d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 246135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani 247135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani /** 248135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani * Retrieves a list of all currently connected {@link android.mtp.MtpDevice}. 249d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * 250135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani * @return the list of MtpDevices 2514b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani */ 252d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn public List<MtpDevice> getDeviceList() { 253d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn synchronized (mDevices) { 254d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn // Query the USB manager since devices might have attached 2554b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani // before we added our listener. 2564b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) { 257258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani if (mDevices.get(usbDevice.getDeviceName()) == null) { 258e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani openDeviceLocked(usbDevice); 2592a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani } 2604428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn } 261b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani 262d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn return new ArrayList<MtpDevice>(mDevices.values()); 263d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 264d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } 265d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn 266e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani /** 267e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani * Retrieves a list of all {@link android.mtp.MtpStorageInfo} 268b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani * for the MTP or PTP device with the given USB device name 269e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani * 270e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani * @param deviceName the name of the USB device 271e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani * @return the list of MtpStorageInfo 272e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani */ 273e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani public List<MtpStorageInfo> getStorageList(String deviceName) { 274e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani MtpDevice device = getDevice(deviceName); 275e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani if (device == null) { 276e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani return null; 277b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani } 278b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani int[] storageIds = device.getStorageIds(); 279258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani if (storageIds == null) { 280e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani return null; 2813b49f07a452e0a77c1d22db2065255689a461d31Amith Yamasani } 2823b49f07a452e0a77c1d22db2065255689a461d31Amith Yamasani 2833b49f07a452e0a77c1d22db2065255689a461d31Amith Yamasani int length = storageIds.length; 284d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn ArrayList<MtpStorageInfo> storageList = new ArrayList<MtpStorageInfo>(length); 285d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn for (int i = 0; i < length; i++) { 286d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn MtpStorageInfo info = device.getStorageInfo(storageIds[i]); 287d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn if (info == null) { 288d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn Log.w(TAG, "getStorageInfo failed"); 289d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn } else { 290d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn storageList.add(info); 291e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani } 2923b49f07a452e0a77c1d22db2065255689a461d31Amith Yamasani } 2933b49f07a452e0a77c1d22db2065255689a461d31Amith Yamasani return storageList; 2943b49f07a452e0a77c1d22db2065255689a461d31Amith Yamasani } 2953b49f07a452e0a77c1d22db2065255689a461d31Amith Yamasani 296258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani /** 2972a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani * Retrieves the {@link android.mtp.MtpObjectInfo} for an object on 2984428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * the MTP or PTP device with the given USB device name with the given 299258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * object handle 300258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * 301258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * @param deviceName the name of the USB device 302258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * @param objectHandle handle of the object to query 303258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * @return the MtpObjectInfo 304d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn */ 305258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani public MtpObjectInfo getObjectInfo(String deviceName, int objectHandle) { 306258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani MtpDevice device = getDevice(deviceName); 307258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani if (device == null) { 308258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani return null; 309258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 310258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani return device.getObjectInfo(objectHandle); 311258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 312258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani 313258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani /** 314258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * Deletes an object on the MTP or PTP device with the given USB device name. 315258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * 316258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * @param deviceName the name of the USB device 317258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * @param objectHandle handle of the object to delete 318258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * @return true if the deletion succeeds 319258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani */ 320258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani public boolean deleteObject(String deviceName, int objectHandle) { 3214428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn MtpDevice device = getDevice(deviceName); 322258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani if (device == null) { 323258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani return false; 324258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 325258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani return device.deleteObject(objectHandle); 326258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 327258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani 3282a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani /** 329258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * Retrieves a list of {@link android.mtp.MtpObjectInfo} for all objects 330258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * on the MTP or PTP device with the given USB device name and given storage ID 331258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * and/or object handle. 3325dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn * If the object handle is zero, then all objects in the root of the storage unit 3335dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn * will be returned. Otherwise, all immediate children of the object will be returned. 3345dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn * If the storage ID is also zero, then all objects on all storage units will be returned. 3355dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn * 336d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * @param deviceName the name of the USB device 337d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * @param storageId the ID of the storage unit to query, or zero for all 338d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * @param objectHandle the handle of the parent object to query, or zero for the storage root 339d4ac8d7b3de27a9f0e4c6af2496ca71d794e42d1Dianne Hackborn * @return the list of MtpObjectInfo 3405dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn */ 3415dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn public List<MtpObjectInfo> getObjectList(String deviceName, int storageId, int objectHandle) { 3425dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn MtpDevice device = getDevice(deviceName); 3435dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn if (device == null) { 3445dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn return null; 3455dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn } 346258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani if (objectHandle == 0) { 347faea76ff8bc9a350765873af81334afe4d14afbdAmith Yamasani // all objects in root of storage 348faea76ff8bc9a350765873af81334afe4d14afbdAmith Yamasani objectHandle = 0xFFFFFFFF; 3495dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn } 3505dc5a00e7ebadc085ded7e29feacd17e53698486Dianne Hackborn int[] handles = device.getObjectHandles(storageId, 0, objectHandle); 35127bd34d9d9fe99f11b80aa0bbdb402fb47ef4158Jeff Sharkey if (handles == null) { 352faea76ff8bc9a350765873af81334afe4d14afbdAmith Yamasani return null; 353faea76ff8bc9a350765873af81334afe4d14afbdAmith Yamasani } 354faea76ff8bc9a350765873af81334afe4d14afbdAmith Yamasani 3551952637425eece18aa1ce3d80d4b49086ef3bcf7Amith Yamasani int length = handles.length; 3561952637425eece18aa1ce3d80d4b49086ef3bcf7Amith Yamasani ArrayList<MtpObjectInfo> objectList = new ArrayList<MtpObjectInfo>(length); 3571952637425eece18aa1ce3d80d4b49086ef3bcf7Amith Yamasani for (int i = 0; i < length; i++) { 358258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani MtpObjectInfo info = device.getObjectInfo(handles[i]); 359258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani if (info == null) { 360258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani Log.w(TAG, "getObjectInfo failed"); 361258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } else { 3622a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani objectList.add(info); 363258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 3642a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani } 3652a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani return objectList; 3662a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani } 3672a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani 3682a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani /** 369258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * Returns the data for an object as a byte array. 370258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * 371258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * @param deviceName the name of the USB device containing the object 372e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani * @param objectHandle handle of the object to read 373b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani * @param objectSize the size of the object (this should match 374b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani * {@link android.mtp.MtpObjectInfo#getCompressedSize} 375b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani * @return the object's data, or null if reading fails 376b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani */ 377b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani public byte[] getObject(String deviceName, int objectHandle, int objectSize) { 378b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani MtpDevice device = getDevice(deviceName); 379b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani if (device == null) { 380b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani return null; 381b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani } 382b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani return device.getObject(objectHandle, objectSize); 383e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani } 384e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani 3853b49f07a452e0a77c1d22db2065255689a461d31Amith Yamasani /** 3863b49f07a452e0a77c1d22db2065255689a461d31Amith Yamasani * Returns the thumbnail data for an object as a byte array. 387e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani * 388e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani * @param deviceName the name of the USB device containing the object 389e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani * @param objectHandle handle of the object to read 390e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani * @return the object's thumbnail, or null if reading fails 391e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani */ 392b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani public byte[] getThumbnail(String deviceName, int objectHandle) { 3932a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani MtpDevice device = getDevice(deviceName); 394b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani if (device == null) { 395b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani return null; 396b8151ecd6ef4faa5c16d0a4c3abb45ec84d1f97aAmith Yamasani } 3970b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani return device.getThumbnail(objectHandle); 3980b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani } 3990b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani 4000b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani /** 4010b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * Copies the data for an object to a file in external storage. 4021676c856d61b97c871dc2be0cb1f1fb1e12e24e9Dianne Hackborn * 4034428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * @param deviceName the name of the USB device containing the object 4047767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * @param objectHandle handle of the object to read 4057767eac3232ba2fb9828766813cdb481d6a97584Dianne Hackborn * @param destPath path to destination for the file transfer. 4060b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * This path should be in the external storage as defined by 4070b285499db739ba50f2f839d633e763c70e67f96Amith Yamasani * {@link android.os.Environment#getExternalStorageDirectory} 4084428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn * @return true if the file transfer succeeds 4094428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn */ 4104428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn public boolean importFile(String deviceName, int objectHandle, String destPath) { 4114428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn MtpDevice device = getDevice(deviceName); 4124b2e934928a2eb65927bd39197198c28c49efb94Amith Yamasani if (device == null) { 4134428e17c5e05c0dad76da8f1c28ccba62a66cd91Dianne Hackborn return false; 414135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 415135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani return device.importFile(objectHandle, destPath); 416135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani } 417135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani} 418135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani