Merge "Add suffix number when copying a file." into nyc-dev

This commit is contained in:
Daichi Hirono
2016-03-17 04:53:34 +00:00
committed by Android (Google) Code Review
6 changed files with 118 additions and 33 deletions

View File

@@ -605,6 +605,30 @@ public class FileUtils {
*/
public static File buildUniqueFile(File parent, String mimeType, String displayName)
throws FileNotFoundException {
final String[] parts = splitFileName(mimeType, displayName);
final String name = parts[0];
final String ext = parts[1];
File file = buildFile(parent, name, ext);
// If conflicting file, try adding counter suffix
int n = 0;
while (file.exists()) {
if (n++ >= 32) {
throw new FileNotFoundException("Failed to create unique file");
}
file = buildFile(parent, name + " (" + n + ")", ext);
}
return file;
}
/**
* Splits file name into base name and extension.
* If the display name doesn't have an extension that matches the requested MIME type, the
* extension is regarded as a part of filename and default extension for that MIME type is
* appended.
*/
public static String[] splitFileName(String mimeType, String displayName) {
String name;
String ext;
@@ -642,18 +666,11 @@ public class FileUtils {
}
}
File file = buildFile(parent, name, ext);
// If conflicting file, try adding counter suffix
int n = 0;
while (file.exists()) {
if (n++ >= 32) {
throw new FileNotFoundException("Failed to create unique file");
}
file = buildFile(parent, name + " (" + n + ")", ext);
if (ext == null) {
ext = "";
}
return file;
return new String[] { name, ext };
}
private static File buildFile(File parent, String name, String ext) {

View File

@@ -14,12 +14,15 @@
* limitations under the License.
*/
package com.android.mtp.exceptions;
package com.android.mtp;
import java.io.IOException;
/**
* Exception thrown when the device is busy and the requested operation cannon be completed.
*/
public class BusyDeviceException extends IOException {
class BusyDeviceException extends IOException {
BusyDeviceException() {
super("The MTP device is busy.");
}
}

View File

@@ -30,6 +30,8 @@ import android.mtp.MtpObjectInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.FileUriExposedException;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.storage.StorageManager;
import android.provider.DocumentsContract.Document;
@@ -41,7 +43,6 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.mtp.exceptions.BusyDeviceException;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -324,25 +325,61 @@ public class MtpDocumentsProvider extends DocumentsProvider {
if (DEBUG) {
Log.d(TAG, "createDocument: " + displayName);
}
final Identifier parentId;
final MtpDeviceRecord record;
final ParcelFileDescriptor[] pipe;
try {
final Identifier parentId = mDatabase.createIdentifier(parentDocumentId);
parentId = mDatabase.createIdentifier(parentDocumentId);
openDevice(parentId.mDeviceId);
final MtpDeviceRecord record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord;
record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord;
if (!MtpDeviceRecord.isWritingSupported(record.operationsSupported)) {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException(
"Writing operation is not supported by the device.");
}
pipe = ParcelFileDescriptor.createReliablePipe();
int objectHandle = -1;
MtpObjectInfo info = null;
try {
pipe[0].close(); // 0 bytes for a new document.
final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ?
MtpConstants.FORMAT_ASSOCIATION :
MediaFile.getFormatCode(displayName, mimeType);
info = new MtpObjectInfo.Builder()
.setStorageId(parentId.mStorageId)
.setParent(parentId.mObjectHandle)
.setFormat(formatCode)
.setName(displayName)
.build();
final String[] parts = FileUtils.splitFileName(mimeType, displayName);
final String baseName = parts[0];
final String extension = parts[1];
for (int i = 0; i <= 32; i++) {
final MtpObjectInfo infoUniqueName;
if (i == 0) {
infoUniqueName = info;
} else {
infoUniqueName = new MtpObjectInfo.Builder(info).setName(
baseName + " (" + i + ")." + extension).build();
}
try {
objectHandle = mMtpManager.createDocument(
parentId.mDeviceId, infoUniqueName, pipe[1]);
break;
} catch (SendObjectInfoFailure exp) {
// This can be caused when we have an existing file with the same name.
continue;
}
}
} finally {
pipe[1].close();
}
if (objectHandle == -1) {
throw new IllegalArgumentException(
"The file name \"" + displayName + "\" is conflicted with existing files " +
"and the provider failed to find unique name.");
}
final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe();
pipe[0].close(); // 0 bytes for a new document.
final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ?
MtpConstants.FORMAT_ASSOCIATION :
MediaFile.getFormatCode(displayName, mimeType);
final MtpObjectInfo info = new MtpObjectInfo.Builder()
.setStorageId(parentId.mStorageId)
.setParent(parentId.mObjectHandle)
.setFormat(formatCode)
.setName(displayName)
.build();
final int objectHandle = mMtpManager.createDocument(parentId.mDeviceId, info, pipe[1]);
final MtpObjectInfo infoWithHandle =
new MtpObjectInfo.Builder(info).setObjectHandle(objectHandle).build();
final String documentId = mDatabase.putNewDocument(
@@ -351,9 +388,12 @@ public class MtpDocumentsProvider extends DocumentsProvider {
getDocumentLoader(parentId).clearTask(parentId);
notifyChildDocumentsChange(parentDocumentId);
return documentId;
} catch (FileNotFoundException | RuntimeException error) {
Log.e(TAG, "createDocument", error);
throw error;
} catch (IOException error) {
Log.e(TAG, "createDocument", error);
throw new FileNotFoundException(error.getMessage());
throw new IllegalStateException(error);
}
}

View File

@@ -33,7 +33,6 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.mtp.exceptions.BusyDeviceException;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -190,7 +189,7 @@ class MtpManager {
synchronized (device) {
final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
if (sendObjectInfoResult == null) {
throw new IOException("Failed to create a document");
throw new SendObjectInfoFailure();
}
if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),

View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.mtp;
import java.io.IOException;
/**
* Exception thrown when sendObjectInfo failed.
*/
class SendObjectInfoFailure extends IOException {
SendObjectInfoFailure() {
super("Failed to MtpDevice#sendObjectInfo.");
}
}

View File

@@ -30,8 +30,6 @@ import android.provider.DocumentsContract;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import com.android.mtp.exceptions.BusyDeviceException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;