Merge "Add suffix number when copying a file." into nyc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
1360868de8
@@ -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) {
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user