我只能从MTP设备下载一次吗?

时间:2019-08-06 16:23:39

标签: c# android xamarin mtp

有人有使用Xamarin的Android MTPDevice的经验吗? 我支持Xamarin中的一个应用程序,该应用程序可在Android上运行,并且需要使用MTP协议通过USB电缆从Nikon DSLR下载图像。

尽管我可以获得访问设备,读取设备属性,获取存储信息和下载的权限,但是只能在单个功能内进行。

下面有很多代码,因此我删除了大约90%的代码,其中包括try / catch,记录调试信息,创建我自己的类的对象并插入SQLite数据库。

问题是,如果我从Recurse函数中退出对DownloadFileAsync的调用,而只是返回一个ObjectHandles列表,然后从调用GetFilesAsync的同一后台服务中调用DownloadFileAsync,则读取设备信息的调用将失败,并且存储设备为空。

即使该代码有效,也只能运行一次。如果我然后断开相机的连接并重新连接它,甚至退出应用程序然后重新启动,我也会遇到同样的问题。

private UsbDevice GetAttachedDevice()
{
    // find devices
    UsbDevice usbDevice = null;
    if (UsbManager.DeviceList != null && UsbManager.DeviceList.Count > 0)
    {
        foreach (var usbAccessory in UsbManager.DeviceList)
        {
            return usbAccessory.Value;  // yeah, i know
        }
    }
    return null;
}

public async Task<bool> OpenAttachedDevice()
{
    var connectedDevice = await GetAttachedDevice();
    if (connectedDevice == null)
        return false;

    usbDeviceConnection = UsbManager.OpenDevice(connectedDevice);
    mtpDevice = new MtpDevice(connectedDevice);
    mtpDevice.Open(usbDeviceConnection);

    MtpDeviceInfo info = mtpDevice.DeviceInfo;
    if (info != null)
        Log.Information($"Device Info: {info.Manufacturer} {info.Model} {info.SerialNumber}");
    else
        Log.Information($"Device Info is null");

    return true;
}

// finds each storage unit and calls the recursive function to find and download files
public async Task<List<string>> GetFilesAsync()
{
    var results = new List<string>();
    if (await OpenAttachedDevice())
    {
        storageUnits = mtpDevice.GetStorageIds();
        if (storageUnits == null || storageUnits.Length == 0)
        {
            Log.Information("GetFileListAsync: StorageUnits is empty");
            return results;
        }

        foreach (var storageUnitId in storageUnits)
        {
            var storageUnit = mtpDevice.GetStorageInfo(storageUnitId);
            if (storageUnit != null)
            {
                var objectHandles = mtpDevice.GetObjectHandles(storageUnitId, 0, 0);

                // this works, I get all the object handles

                foreach (var objectHandle in objectHandles)
                {
                    // do stuff here
                }
                await RecurseMTPDirectories(results, storageUnitId);
            }
        }
    }
    return results;
}

// look through all objects in the given folder - download files, recurse back in for folders
private async Task RecurseMTPDirectories(List<string> exhibits, int storageUnitId, string parentFolder = "\\", int parentHandle = -1)
{
    // find all the objects in the folder - download the files, add the folders to a list and then recurse into each
    var directories = new List<MtpObjectInfo>();
    var objectHandles = mtpDevice.GetObjectHandles(storageUnitId, 0, parentHandle);

    if (objectHandles != null && objectHandles.Length > 0)
    {
        foreach (var objectHandle in objectHandles)
        {
            MtpObjectInfo objectInfo = mtpDevice.GetObjectInfo(objectHandle);
            if (objectInfo != null)
            {
                if (objectInfo.Format == MtpFormat.Association)
                {
                    // add to list of directories
                    directories.Add(objectInfo);
                }
                else
                {
                    var imagePath = await GetImagePathForFile();

                    await DownloadFileAsync(objectHandle, objectInfo.Name, imagePath, thumbPath, objectInfo.CompressedSize);
                    exhibits.Add(objectInfo.Name);
                }
            }
        }
    }

    foreach (var objectInfo in directories)
    {
        string fullname = parentFolder + objectInfo.Name;
        await RecurseMTPDirectories(exhibits, storageUnitId, $"{fullname}\\", objectInfo.ObjectHandle);
    }
}

// download the actual file, and thumbnail
public async Task DownloadFileAsync(int objectHandle, string nameOnCamera, string destination, string thumbdestination, int size)
{
    int receivedBytes = 0;

    if (await OpenAttachedDevice())
    {
        var rootFolder = await FileSystem.Current.GetFolderFromPathAsync(destination);
        var thumbFolder = await FileSystem.Current.GetFolderFromPathAsync(thumbdestination);

        var fileService = DependencyService.Get<IFileStorageService>();

        // download the image data here
        byte[] imageData = await mtpDevice.GetObjectAsync(objectHandle, size);

        var fileWriter = await rootFolder.CreateFileAsync(nameOnCamera + ".part", CreationCollisionOption.ReplaceExisting);
        using (var fileStream = await fileWriter.OpenAsync(PCLStorage.FileAccess.ReadAndWrite))
        {
            await fileStream.WriteAsync(imageData, 0, size);
        }
        await fileWriter.RenameAsync(nameOnCamera, NameCollisionOption.ReplaceExisting);
    }
}

因此,问题(似乎很疯狂)是,尽管我可以访问MTP设备,但是如果我离开调用该函数的函数来创建MTPdevice,即使MTPdevice对象是全局的,它也只会起作用一次。

我还尝试过关闭连接,MTP设备甚至处置它们,都没有关系。

0 个答案:

没有答案