1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.data; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19d43ea8bb1b1afcb27c1c6c673c8ed2707bc70ff0Owen Linimport android.annotation.TargetApi; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.app.PendingIntent; 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.BroadcastReceiver; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Intent; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.IntentFilter; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.hardware.usb.UsbConstants; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.hardware.usb.UsbDevice; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.hardware.usb.UsbDeviceConnection; 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.hardware.usb.UsbInterface; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.hardware.usb.UsbManager; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.mtp.MtpDevice; 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.mtp.MtpObjectInfo; 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.mtp.MtpStorageInfo; 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.util.Log; 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 35d43ea8bb1b1afcb27c1c6c673c8ed2707bc70ff0Owen Linimport com.android.gallery3d.common.ApiHelper; 36d43ea8bb1b1afcb27c1c6c673c8ed2707bc70ff0Owen Lin 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList; 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.HashMap; 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.List; 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/** 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * This class helps an application manage a list of connected MTP or PTP devices. 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * It listens for MTP devices being attached and removed from the USB host bus 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * and notifies the application when the MTP device list changes. 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 46d43ea8bb1b1afcb27c1c6c673c8ed2707bc70ff0Owen Lin@TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB_MR1) 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class MtpClient { 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "MtpClient"; 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String ACTION_USB_PERMISSION = 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin "android.mtp.MtpClient.action.USB_PERMISSION"; 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final Context mContext; 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final UsbManager mUsbManager; 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ArrayList<Listener> mListeners = new ArrayList<Listener>(); 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // mDevices contains all MtpDevices that have been seen by our client, 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // so we can inform when the device has been detached. 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // mDevices is also used for synchronization in this class. 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>(); 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // List of MTP devices we should not try to open for which we are currently 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // asking for permission to open. 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ArrayList<String> mRequestPermissionDevices = new ArrayList<String>(); 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // List of MTP devices we should not try to open. 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We add devices to this list if the user canceled a permission request or we were 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // unable to open the device. 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ArrayList<String> mIgnoredDevices = new ArrayList<String>(); 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final PendingIntent mPermissionIntent; 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onReceive(Context context, Intent intent) { 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String action = intent.getAction(); 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String deviceName = usbDevice.getDeviceName(); 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mDevices) { 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpDevice mtpDevice = mDevices.get(deviceName); 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mtpDevice == null) { 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mtpDevice = openDeviceLocked(usbDevice); 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mtpDevice != null) { 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (Listener listener : mListeners) { 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin listener.deviceAdded(mtpDevice); 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mtpDevice != null) { 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDevices.remove(deviceName); 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRequestPermissionDevices.remove(deviceName); 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIgnoredDevices.remove(deviceName); 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (Listener listener : mListeners) { 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin listener.deviceRemoved(mtpDevice); 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (ACTION_USB_PERMISSION.equals(action)) { 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRequestPermissionDevices.remove(deviceName); 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean permission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin false); 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Log.d(TAG, "ACTION_USB_PERMISSION: " + permission); 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (permission) { 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mtpDevice == null) { 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mtpDevice = openDeviceLocked(usbDevice); 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mtpDevice != null) { 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (Listener listener : mListeners) { 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin listener.deviceAdded(mtpDevice); 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // so we don't ask for permission again 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIgnoredDevices.add(deviceName); 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin }; 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * An interface for being notified when MTP or PTP devices are attached 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * or removed. In the current implementation, only PTP devices are supported. 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public interface Listener { 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Called when a new device has been added 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param device the new device that was added 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void deviceAdded(MtpDevice device); 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Called when a new device has been removed 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param device the device that was removed 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void deviceRemoved(MtpDevice device); 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Tests to see if a {@link android.hardware.usb.UsbDevice} 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * supports the PTP protocol (typically used by digital cameras) 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param device the device to test 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return true if the device is a PTP device. 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin static public boolean isCamera(UsbDevice device) { 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int count = device.getInterfaceCount(); 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < count; i++) { 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UsbInterface intf = device.getInterface(i); 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (intf.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE && 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin intf.getInterfaceSubclass() == 1 && 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin intf.getInterfaceProtocol() == 1) { 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * MtpClient constructor 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param context the {@link android.content.Context} to use for the MtpClient 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MtpClient(Context context) { 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContext = context; 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE); 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0); 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin IntentFilter filter = new IntentFilter(); 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin filter.addAction(ACTION_USB_PERMISSION); 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.registerReceiver(mUsbReceiver, filter); 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Opens the {@link android.hardware.usb.UsbDevice} for an MTP or PTP 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * device and return an {@link android.mtp.MtpDevice} for it. 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 1827817979db0c52ffeacb951625b1e821eba303285Ahbong Chang * @param usbDevice the device to open 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return an MtpDevice for the device. 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private MtpDevice openDeviceLocked(UsbDevice usbDevice) { 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String deviceName = usbDevice.getDeviceName(); 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // don't try to open devices that we have decided to ignore 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // or are currently asking permission for 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (isCamera(usbDevice) && !mIgnoredDevices.contains(deviceName) 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && !mRequestPermissionDevices.contains(deviceName)) { 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!mUsbManager.hasPermission(usbDevice)) { 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUsbManager.requestPermission(usbDevice, mPermissionIntent); 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRequestPermissionDevices.add(deviceName); 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice); 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (connection != null) { 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpDevice mtpDevice = new MtpDevice(usbDevice); 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mtpDevice.open(connection)) { 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDevices.put(usbDevice.getDeviceName(), mtpDevice); 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mtpDevice; 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // so we don't try to open it again 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIgnoredDevices.add(deviceName); 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // so we don't try to open it again 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIgnoredDevices.add(deviceName); 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Closes all resources related to the MtpClient object 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void close() { 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContext.unregisterReceiver(mUsbReceiver); 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 2237817979db0c52ffeacb951625b1e821eba303285Ahbong Chang * Registers a {@link com.android.gallery3d.data.MtpClient.Listener} interface to receive 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * notifications when MTP or PTP devices are added or removed. 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param listener the listener to register 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void addListener(Listener listener) { 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mDevices) { 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!mListeners.contains(listener)) { 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListeners.add(listener); 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 2377817979db0c52ffeacb951625b1e821eba303285Ahbong Chang * Unregisters a {@link com.android.gallery3d.data.MtpClient.Listener} interface. 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param listener the listener to unregister 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void removeListener(Listener listener) { 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mDevices) { 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListeners.remove(listener); 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Retrieves an {@link android.mtp.MtpDevice} object for the USB device 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * with the given name. 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param deviceName the name of the USB device 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return the MtpDevice, or null if it does not exist 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MtpDevice getDevice(String deviceName) { 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mDevices) { 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mDevices.get(deviceName); 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Retrieves an {@link android.mtp.MtpDevice} object for the USB device 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * with the given ID. 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param id the ID of the USB device 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return the MtpDevice, or null if it does not exist 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MtpDevice getDevice(int id) { 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mDevices) { 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mDevices.get(UsbDevice.getDeviceName(id)); 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Retrieves a list of all currently connected {@link android.mtp.MtpDevice}. 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return the list of MtpDevices 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public List<MtpDevice> getDeviceList() { 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mDevices) { 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Query the USB manager since devices might have attached 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // before we added our listener. 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) { 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mDevices.get(usbDevice.getDeviceName()) == null) { 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin openDeviceLocked(usbDevice); 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return new ArrayList<MtpDevice>(mDevices.values()); 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Retrieves a list of all {@link android.mtp.MtpStorageInfo} 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * for the MTP or PTP device with the given USB device name 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param deviceName the name of the USB device 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return the list of MtpStorageInfo 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public List<MtpStorageInfo> getStorageList(String deviceName) { 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpDevice device = getDevice(deviceName); 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (device == null) { 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int[] storageIds = device.getStorageIds(); 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (storageIds == null) { 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int length = storageIds.length; 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ArrayList<MtpStorageInfo> storageList = new ArrayList<MtpStorageInfo>(length); 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < length; i++) { 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpStorageInfo info = device.getStorageInfo(storageIds[i]); 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (info == null) { 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Log.w(TAG, "getStorageInfo failed"); 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin storageList.add(info); 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return storageList; 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Retrieves the {@link android.mtp.MtpObjectInfo} for an object on 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * the MTP or PTP device with the given USB device name with the given 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * object handle 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param deviceName the name of the USB device 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param objectHandle handle of the object to query 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return the MtpObjectInfo 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MtpObjectInfo getObjectInfo(String deviceName, int objectHandle) { 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpDevice device = getDevice(deviceName); 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (device == null) { 334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return device.getObjectInfo(objectHandle); 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Deletes an object on the MTP or PTP device with the given USB device name. 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param deviceName the name of the USB device 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param objectHandle handle of the object to delete 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return true if the deletion succeeds 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean deleteObject(String deviceName, int objectHandle) { 347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpDevice device = getDevice(deviceName); 348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (device == null) { 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return device.deleteObject(objectHandle); 352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Retrieves a list of {@link android.mtp.MtpObjectInfo} for all objects 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * on the MTP or PTP device with the given USB device name and given storage ID 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * and/or object handle. 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * If the object handle is zero, then all objects in the root of the storage unit 359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * will be returned. Otherwise, all immediate children of the object will be returned. 360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * If the storage ID is also zero, then all objects on all storage units will be returned. 361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param deviceName the name of the USB device 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param storageId the ID of the storage unit to query, or zero for all 364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param objectHandle the handle of the parent object to query, or zero for the storage root 365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return the list of MtpObjectInfo 366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public List<MtpObjectInfo> getObjectList(String deviceName, int storageId, int objectHandle) { 368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpDevice device = getDevice(deviceName); 369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (device == null) { 370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (objectHandle == 0) { 373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // all objects in root of storage 374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin objectHandle = 0xFFFFFFFF; 375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int[] handles = device.getObjectHandles(storageId, 0, objectHandle); 377f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (handles == null) { 378f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 379f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 380f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 381f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int length = handles.length; 382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ArrayList<MtpObjectInfo> objectList = new ArrayList<MtpObjectInfo>(length); 383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < length; i++) { 384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpObjectInfo info = device.getObjectInfo(handles[i]); 385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (info == null) { 386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Log.w(TAG, "getObjectInfo failed"); 387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin objectList.add(info); 389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return objectList; 392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Returns the data for an object as a byte array. 396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param deviceName the name of the USB device containing the object 398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param objectHandle handle of the object to read 399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param objectSize the size of the object (this should match 400f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * {@link android.mtp.MtpObjectInfo#getCompressedSize} 401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return the object's data, or null if reading fails 402f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 403f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public byte[] getObject(String deviceName, int objectHandle, int objectSize) { 404f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpDevice device = getDevice(deviceName); 405f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (device == null) { 406f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 407f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 408f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return device.getObject(objectHandle, objectSize); 409f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 410f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 411f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 412f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Returns the thumbnail data for an object as a byte array. 413f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 414f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param deviceName the name of the USB device containing the object 415f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param objectHandle handle of the object to read 416f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return the object's thumbnail, or null if reading fails 417f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 418f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public byte[] getThumbnail(String deviceName, int objectHandle) { 419f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpDevice device = getDevice(deviceName); 420f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (device == null) { 421f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 422f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 423f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return device.getThumbnail(objectHandle); 424f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 425f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 426f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /** 427f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copies the data for an object to a file in external storage. 428f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 429f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param deviceName the name of the USB device containing the object 430f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param objectHandle handle of the object to read 431f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @param destPath path to destination for the file transfer. 432f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * This path should be in the external storage as defined by 433f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * {@link android.os.Environment#getExternalStorageDirectory} 434f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * @return true if the file transfer succeeds 435f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 436f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean importFile(String deviceName, int objectHandle, String destPath) { 437f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MtpDevice device = getDevice(deviceName); 438f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (device == null) { 439f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 440f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 441f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return device.importFile(objectHandle, destPath); 442f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 443f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 444