Skip to content
Snippets Groups Projects
Commit b25c0d97 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add free space precondition check for copy job."

parents 0238f640 71ac8a00
No related branches found
No related tags found
No related merge requests found
......@@ -36,6 +36,7 @@ import android.os.Handler;
import android.os.SystemClock;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
......@@ -350,11 +351,20 @@ public class RootsCache {
* waiting for all the other roots to come back.
*/
public RootInfo getRootOneshot(String authority, String rootId) {
return getRootOneshot(authority, rootId, false);
}
/**
* Return the requested {@link RootInfo}, but only loading the roots of the requested authority.
* It always fetches from {@link DocumentsProvider} if forceRefresh is true, which is used to
* get the most up-to-date free space before starting copy operations.
*/
public RootInfo getRootOneshot(String authority, String rootId, boolean forceRefresh) {
synchronized (mLock) {
RootInfo root = getRootLocked(authority, rootId);
RootInfo root = forceRefresh ? null : getRootLocked(authority, rootId);
if (root == null) {
mRoots.putAll(authority,
loadRootsForAuthority(mContext.getContentResolver(), authority, false));
mRoots.putAll(authority, loadRootsForAuthority(
mContext.getContentResolver(), authority, forceRefresh));
root = getRootLocked(authority, rootId);
}
return root;
......
......@@ -51,9 +51,11 @@ import android.text.format.DateUtils;
import android.util.Log;
import android.webkit.MimeTypeMap;
import com.android.documentsui.UrisSupplier;
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.Metrics;
import com.android.documentsui.R;
import com.android.documentsui.RootsCache;
import com.android.documentsui.UrisSupplier;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
......@@ -210,7 +212,6 @@ class CopyJob extends Job {
@Override
boolean setUp() {
try {
buildDocumentList();
} catch (ResourceException e) {
......@@ -218,6 +219,7 @@ class CopyJob extends Job {
return false;
}
// Check if user has canceled this task.
if (isCanceled()) {
return false;
}
......@@ -229,7 +231,15 @@ class CopyJob extends Job {
mBatchSize = -1;
}
return true;
// Check if user has canceled this task. We should check it again here as user cancels
// tasks in main thread, but this is running in a worker thread. calculateSize() may
// take a long time during which user can cancel this task, and we don't want to waste
// resources doing useless large chunk of work.
if (isCanceled()) {
return false;
}
return checkSpace();
}
@Override
......@@ -286,6 +296,44 @@ class CopyJob extends Job {
return !root.isDownloads() || !doc.isDirectory();
}
/**
* Checks whether the destination folder has enough space to take all source files.
* @return true if the root has enough space or doesn't provide free space info; otherwise false
*/
boolean checkSpace() {
return checkSpace(mBatchSize);
}
/**
* Checks whether the destination folder has enough space to take files of batchSize
* @param batchSize the total size of files
* @return true if the root has enough space or doesn't provide free space info; otherwise false
*/
final boolean checkSpace(long batchSize) {
// Default to be true because if batchSize or available space is invalid, we still let the
// copy start anyway.
boolean result = true;
if (batchSize >= 0) {
RootsCache cache = DocumentsApplication.getRootsCache(appContext);
// Query root info here instead of using stack.root because the number there may be
// stale.
RootInfo root = cache.getRootOneshot(stack.root.authority, stack.root.rootId, true);
if (root.availableBytes >= 0) {
result = (batchSize <= root.availableBytes);
} else {
Log.w(TAG, root.toString() + " doesn't provide available bytes.");
}
}
if (!result) {
failedFileCount += mSrcs.size();
failedFiles.addAll(mSrcs);
}
return result;
}
@Override
boolean hasWarnings() {
return !convertedFiles.isEmpty();
......@@ -585,7 +633,7 @@ class CopyJob extends Job {
result += calculateFileSizesRecursively(getClient(src), src.derivedUri);
} catch (RemoteException e) {
throw new ResourceException("Failed to obtain the client for %s.",
src.derivedUri);
src.derivedUri, e);
}
} else {
result += src.size;
......@@ -603,7 +651,7 @@ class CopyJob extends Job {
*
* @throws ResourceException
*/
private long calculateFileSizesRecursively(
long calculateFileSizesRecursively(
ContentProviderClient client, Uri uri) throws ResourceException {
final String authority = uri.getAuthority();
final Uri queryUri = buildChildDocumentsUri(authority, getDocumentId(uri));
......
......@@ -29,8 +29,8 @@ import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.util.Log;
import com.android.documentsui.UrisSupplier;
import com.android.documentsui.R;
import com.android.documentsui.UrisSupplier;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
......@@ -96,9 +96,35 @@ final class MoveJob extends CopyJob {
return super.setUp();
}
/**
* {@inheritDoc}
*
* Only check space for moves across authorities. For now we don't know if the doc in
* {@link #mSrcs} is in the same root of destination, and if it's optimized move in the same
* root it should succeed regardless of free space, but it's for sure a failure if there is no
* enough free space if docs are moved from another authority.
*/
@Override
public void start() {
super.start();
boolean checkSpace() {
long size = 0;
for (DocumentInfo src : mSrcs) {
if (!src.authority.equals(stack.root.authority)) {
if (src.isDirectory()) {
try {
size += calculateFileSizesRecursively(getClient(src), src.derivedUri);
} catch (RemoteException|ResourceException e) {
Log.w(TAG, "Failed to obtain client for %s" + src.derivedUri + ".", e);
// Failed to calculate size, but move may still succeed.
return true;
}
} else {
size += src.size;
}
}
}
return checkSpace(size);
}
void processDocument(DocumentInfo src, DocumentInfo srcParent, DocumentInfo dest)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment