Loading src/com/android/documentsui/Metrics.java +35 −14 Original line number Diff line number Diff line Loading @@ -392,7 +392,9 @@ public final class Metrics { @OpType int operationType, List<DocumentInfo> srcs, @Nullable DocumentInfo dst) { ProviderCounts counts = countProviders(srcs, dst); ProviderCounts counts = new ProviderCounts(); countProviders(counts, srcs, dst); if (counts.intraProvider > 0) { logIntraProviderFileOps(context, dst.authority, operationType); Loading Loading @@ -438,8 +440,13 @@ public final class Metrics { * @param failedFiles */ public static void logFileOperationErrors(Context context, @OpType int operationType, List<DocumentInfo> failedFiles) { ProviderCounts counts = countProviders(failedFiles, null); List<DocumentInfo> failedFiles, List<Uri> failedUris) { ProviderCounts counts = new ProviderCounts(); countProviders(counts, failedFiles, null); // TODO: Report URI errors separate from file operation errors. countProviders(counts, failedUris); @FileOp int opCode = FILEOP_OTHER_ERROR; switch (operationType) { Loading Loading @@ -826,20 +833,34 @@ public final class Metrics { * the dst document (if a dst is provided), how many come from system providers, and how many * come from external 3rd-party providers. */ private static ProviderCounts countProviders( List<DocumentInfo> srcs, @Nullable DocumentInfo dst) { ProviderCounts counts = new ProviderCounts(); private static void countProviders( ProviderCounts counts, List<DocumentInfo> srcs, @Nullable DocumentInfo dst) { for (DocumentInfo doc: srcs) { if (dst != null && doc.authority.equals(dst.authority)) { countForAuthority(counts, doc.authority, dst); } } /** * Count the given uris and provide a tally of how many come from the same provider as * the dst document (if a dst is provided), how many come from system providers, and how many * come from external 3rd-party providers. */ private static void countProviders(ProviderCounts counts, List<Uri> uris) { for (Uri uri: uris) { countForAuthority(counts, uri.getAuthority(), null); } } private static void countForAuthority( ProviderCounts counts, String authority, @Nullable DocumentInfo dst) { if (dst != null && authority.equals(dst.authority)) { counts.intraProvider++; } else if (isSystemProvider(doc.authority)){ } else if (isSystemProvider(authority)){ counts.systemProvider++; } else { counts.externalProvider++; } } return counts; } private static class ProviderCounts { int intraProvider; Loading src/com/android/documentsui/OperationDialogFragment.java +20 −9 Original line number Diff line number Diff line Loading @@ -17,13 +17,14 @@ package com.android.documentsui; import android.annotation.IntDef; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.DialogInterface; import android.net.Uri; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.text.Html; import com.android.documentsui.base.DocumentInfo; Loading @@ -34,7 +35,6 @@ import com.android.documentsui.services.FileOperationService.OpType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; /** * Alert dialog for operation dialogs. */ Loading @@ -55,13 +55,18 @@ public class OperationDialogFragment extends DialogFragment { private static final String TAG = "OperationDialogFragment"; public static void show(FragmentManager fm, @DialogType int dialogType, ArrayList<DocumentInfo> failedSrcList, DocumentStack dstStack, public static void show( FragmentManager fm, @DialogType int dialogType, ArrayList<DocumentInfo> failedSrcList, ArrayList<DocumentInfo> uriList, DocumentStack dstStack, @OpType int operationType) { final Bundle args = new Bundle(); args.putInt(FileOperationService.EXTRA_DIALOG_TYPE, dialogType); args.putInt(FileOperationService.EXTRA_OPERATION_TYPE, operationType); args.putParcelableArrayList(FileOperationService.EXTRA_SRC_LIST, failedSrcList); args.putParcelableArrayList(FileOperationService.EXTRA_FAILED_DOCS, failedSrcList); final FragmentTransaction ft = fm.beginTransaction(); final OperationDialogFragment fragment = new OperationDialogFragment(); Loading @@ -79,8 +84,10 @@ public class OperationDialogFragment extends DialogFragment { getArguments().getInt(FileOperationService.EXTRA_DIALOG_TYPE); final @OpType int operationType = getArguments().getInt(FileOperationService.EXTRA_OPERATION_TYPE); final ArrayList<DocumentInfo> srcList = getArguments().getParcelableArrayList( FileOperationService.EXTRA_SRC_LIST); final ArrayList<Uri> uriList = getArguments().getParcelableArrayList( FileOperationService.EXTRA_FAILED_URIS); final ArrayList<DocumentInfo> docList = getArguments().getParcelableArrayList( FileOperationService.EXTRA_FAILED_DOCS); final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); String messageFormat; Loading Loading @@ -111,10 +118,14 @@ public class OperationDialogFragment extends DialogFragment { } final StringBuilder list = new StringBuilder("<p>"); for (DocumentInfo documentInfo : srcList) { list.append(String.format("• %s<br>", Html.escapeHtml(documentInfo.displayName))); for (DocumentInfo documentInfo : docList) { list.append("• " + Html.escapeHtml(documentInfo.displayName) + "<br>"); } for (Uri uri : uriList) { list.append("• " + uri.toSafeString() + "<br>"); } list.append("</p>"); builder.setMessage(Html.fromHtml(String.format(messageFormat, list.toString()))); builder.setPositiveButton( R.string.close, Loading src/com/android/documentsui/files/FilesActivity.java +6 −3 Original line number Diff line number Diff line Loading @@ -154,12 +154,15 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons final int opType = intent.getIntExtra( FileOperationService.EXTRA_OPERATION_TYPE, FileOperationService.OPERATION_COPY); final ArrayList<DocumentInfo> srcList = intent.getParcelableArrayListExtra(FileOperationService.EXTRA_SRC_LIST); final ArrayList<DocumentInfo> docList = intent.getParcelableArrayListExtra(FileOperationService.EXTRA_FAILED_DOCS); final ArrayList<DocumentInfo> uriList = intent.getParcelableArrayListExtra(FileOperationService.EXTRA_FAILED_URIS); OperationDialogFragment.show( getFragmentManager(), dialogType, srcList, docList, uriList, mState.stack, opType); } Loading src/com/android/documentsui/services/CopyJob.java +25 −61 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import android.app.Notification; import android.app.Notification.Builder; import android.app.PendingIntent; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.res.AssetFileDescriptor; Loading Loading @@ -67,18 +66,16 @@ import java.io.IOException; import java.io.InputStream; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; class CopyJob extends Job { class CopyJob extends ResolvedResourcesJob { private static final String TAG = "CopyJob"; final List<DocumentInfo> mSrcs; final ArrayList<DocumentInfo> convertedFiles = new ArrayList<>(); private long mStartTime = -1; private long mBatchSize; private long mBytesRequired; private volatile long mBytesCopied; // Speed estimation private long mBytesCopiedSample; Loading @@ -99,9 +96,6 @@ class CopyJob extends Job { super(service, listener, id, opType, destination, srcs); assert(srcs.getItemCount() > 0); // delay the initialization of it to setUp() because it may be IO extensive. mSrcs = new ArrayList<>(srcs.getItemCount()); } @Override Loading @@ -121,8 +115,8 @@ class CopyJob extends Job { Notification getProgressNotification(@StringRes int msgId) { updateRemainingTimeEstimate(); if (mBatchSize >= 0) { double completed = (double) this.mBytesCopied / mBatchSize; if (mBytesRequired >= 0) { double completed = (double) this.mBytesCopied / mBytesRequired; mProgressBuilder.setProgress(100, (int) (completed * 100), false); mProgressBuilder.setSubText( NumberFormat.getPercentInstance().format(completed)); Loading Loading @@ -171,7 +165,7 @@ class CopyJob extends Job { } if (mSampleTime > 0 && mSpeed > 0) { mRemainingTime = ((mBatchSize - bytesCopied) * 1000) / mSpeed; mRemainingTime = ((mBytesRequired - bytesCopied) * 1000) / mSpeed; } else { mRemainingTime = 0; } Loading Loading @@ -211,10 +205,7 @@ class CopyJob extends Job { @Override boolean setUp() { try { buildDocumentList(); } catch (ResourceException e) { Log.e(TAG, "Failed to get the list of docs.", e); if (!super.setUp()) { return false; } Loading @@ -224,10 +215,10 @@ class CopyJob extends Job { } try { mBatchSize = calculateSize(mSrcs); mBytesRequired = calculateBytesRequired(); } catch (ResourceException e) { Log.w(TAG, "Failed to calculate total size. Copying without progress.", e); mBatchSize = -1; mBytesRequired = -1; } // Check if user has canceled this task. We should check it again here as user cancels Loading @@ -246,8 +237,8 @@ class CopyJob extends Job { mStartTime = elapsedRealtime(); DocumentInfo srcInfo; DocumentInfo dstInfo = stack.peek(); for (int i = 0; i < mSrcs.size() && !isCanceled(); ++i) { srcInfo = mSrcs.get(i); for (int i = 0; i < mResolvedDocs.size() && !isCanceled(); ++i) { srcInfo = mResolvedDocs.get(i); if (DEBUG) Log.d(TAG, "Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")" Loading @@ -265,39 +256,12 @@ class CopyJob extends Job { onFileFailed(srcInfo); } } Metrics.logFileOperation(service, operationType, mSrcs, dstInfo); } private void buildDocumentList() throws ResourceException { try { final ContentResolver resolver = appContext.getContentResolver(); final Iterable<Uri> uris = srcs.getUris(appContext); int docProcessed = 0; for (Uri uri : uris) { DocumentInfo doc = DocumentInfo.fromUri(resolver, uri); if (canCopy(doc, stack.getRoot())) { mSrcs.add(doc); } else { onFileFailed(doc); Metrics.logFileOperation(service, operationType, mResolvedDocs, dstInfo); } ++docProcessed; if (isCanceled()) { return; } } // If docProcessed is different than the count claimed by UrisSupplier, add the number // to failedFileCount. failedFileCount += (srcs.getItemCount() - docProcessed); } catch(IOException e) { failedFileCount += srcs.getItemCount(); throw new ResourceException("Failed to open the list of docs to copy.", e); } } private static boolean canCopy(DocumentInfo doc, RootInfo root) { @Override boolean isEligibleDoc(DocumentInfo doc, RootInfo root) { // Can't copy folders to downloads, because we don't show folders there. return !root.isDownloads() || !doc.isDirectory(); } Loading @@ -307,7 +271,7 @@ class CopyJob extends Job { * @return true if the root has enough space or doesn't provide free space info; otherwise false */ boolean checkSpace() { return checkSpace(mBatchSize); return verifySpaceAvailable(mBytesRequired); } /** Loading @@ -315,10 +279,10 @@ class CopyJob extends Job { * @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) { final boolean verifySpaceAvailable(long batchSize) { // Default to be true because if batchSize or available space is invalid, we still let the // copy start anyway. boolean result = true; boolean available = true; if (batchSize >= 0) { RootsCache cache = DocumentsApplication.getRootsCache(appContext); Loading @@ -327,18 +291,18 @@ class CopyJob extends Job { // stale. root = cache.getRootOneshot(root.authority, root.rootId, true); if (root.availableBytes >= 0) { result = (batchSize <= root.availableBytes); available = (batchSize <= root.availableBytes); } else { Log.w(TAG, root.toString() + " doesn't provide available bytes."); } } if (!result) { failedFileCount += mSrcs.size(); failedFiles.addAll(mSrcs); if (!available) { failureCount = mResolvedDocs.size(); failedDocs.addAll(mResolvedDocs); } return result; return available; } @Override Loading Loading @@ -626,14 +590,13 @@ class CopyJob extends Job { * Calculates the cumulative size of all the documents in the list. Directories are recursed * into and totaled up. * * @param srcs * @return Size in bytes. * @throws ResourceException */ private long calculateSize(List<DocumentInfo> srcs) throws ResourceException { private long calculateBytesRequired() throws ResourceException { long result = 0; for (DocumentInfo src : srcs) { for (DocumentInfo src : mResolvedDocs) { if (src.isDirectory()) { // Directories need to be recursed into. try { Loading Loading @@ -719,7 +682,8 @@ class CopyJob extends Job { .append("CopyJob") .append("{") .append("id=" + id) .append(", docs=" + srcs) .append(", uris=" + mResourceUris) .append(", docs=" + mResolvedDocs) .append(", destination=" + stack) .append("}") .toString(); Loading src/com/android/documentsui/services/DeleteJob.java +37 −45 Original line number Diff line number Diff line Loading @@ -26,22 +26,21 @@ import android.content.Context; import android.net.Uri; import android.util.Log; import com.android.documentsui.clipping.UrisSupplier; import com.android.documentsui.Metrics; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.clipping.UrisSupplier; import java.io.FileNotFoundException; import javax.annotation.Nullable; import java.io.IOException; import java.util.ArrayList; import java.util.List; final class DeleteJob extends Job { final class DeleteJob extends ResolvedResourcesJob { private static final String TAG = "DeleteJob"; private final Uri mSrcParent; private final Uri mParentUri; private volatile int mDocsProcessed = 0; /** Loading @@ -54,7 +53,7 @@ final class DeleteJob extends Job { DeleteJob(Context service, Listener listener, String id, DocumentStack stack, UrisSupplier srcs, @Nullable Uri srcParent) { super(service, listener, id, OPERATION_DELETE, stack, srcs); mSrcParent = srcParent; mParentUri = srcParent; } @Override Loading @@ -73,9 +72,10 @@ final class DeleteJob extends Job { @Override public Notification getProgressNotification() { mProgressBuilder.setProgress(srcs.getItemCount(), mDocsProcessed, false); mProgressBuilder.setProgress(mResourceUris.getItemCount(), mDocsProcessed, false); String format = service.getString(R.string.delete_progress); mProgressBuilder.setSubText(String.format(format, mDocsProcessed, srcs.getItemCount())); mProgressBuilder.setSubText( String.format(format, mDocsProcessed, mResourceUris.getItemCount())); mProgressBuilder.setContentText(null); Loading @@ -95,44 +95,35 @@ final class DeleteJob extends Job { @Override void start() { try { final List<DocumentInfo> srcs = new ArrayList<>(this.srcs.getItemCount()); ContentResolver resolver = appContext.getContentResolver(); final Iterable<Uri> uris = this.srcs.getUris(appContext); final ContentResolver resolver = appContext.getContentResolver(); final DocumentInfo srcParent = mSrcParent != null ? DocumentInfo.fromUri(resolver, mSrcParent) DocumentInfo parentDoc; try { parentDoc = mParentUri != null ? DocumentInfo.fromUri(resolver, mParentUri) : null; for (Uri uri : uris) { DocumentInfo doc = DocumentInfo.fromUri(resolver, uri); srcs.add(doc); } catch (FileNotFoundException e) { Log.e(TAG, "Failed to resolve parent from Uri: " + mParentUri + ". Cannot continue.", e); failureCount += this.mResourceUris.getItemCount(); return; } for (DocumentInfo doc : mResolvedDocs) { if (DEBUG) Log.d(TAG, "Deleting document @ " + doc.derivedUri); try { deleteDocument(doc, srcParent); if (isCanceled()) { // Canceled, dump the rest of the work. Deleted docs are not recoverable. return; } deleteDocument(doc, parentDoc); } catch (ResourceException e) { Log.e(TAG, "Failed to delete document @ " + doc.derivedUri, e); onFileFailed(doc); } ++mDocsProcessed; mDocsProcessed++; if (isCanceled()) { return; } // If mDocProcessed is different than the count claimed by UrisSupplier, add the number // to failedFileCount. failedFileCount += (this.srcs.getItemCount() - mDocsProcessed); Metrics.logFileOperation(service, operationType, srcs, null); } catch(IOException e) { Log.e(TAG, "Failed to get list of docs or parent source.", e); failedFileCount += srcs.getItemCount(); } Metrics.logFileOperation(service, operationType, mResolvedDocs, null); } @Override Loading @@ -141,8 +132,9 @@ final class DeleteJob extends Job { .append("DeleteJob") .append("{") .append("id=" + id) .append(", docs=" + srcs) .append(", srcParent=" + mSrcParent) .append(", uris=" + mResourceUris) .append(", docs=" + mResolvedDocs) .append(", srcParent=" + mParentUri) .append(", location=" + stack) .append("}") .toString(); Loading Loading
src/com/android/documentsui/Metrics.java +35 −14 Original line number Diff line number Diff line Loading @@ -392,7 +392,9 @@ public final class Metrics { @OpType int operationType, List<DocumentInfo> srcs, @Nullable DocumentInfo dst) { ProviderCounts counts = countProviders(srcs, dst); ProviderCounts counts = new ProviderCounts(); countProviders(counts, srcs, dst); if (counts.intraProvider > 0) { logIntraProviderFileOps(context, dst.authority, operationType); Loading Loading @@ -438,8 +440,13 @@ public final class Metrics { * @param failedFiles */ public static void logFileOperationErrors(Context context, @OpType int operationType, List<DocumentInfo> failedFiles) { ProviderCounts counts = countProviders(failedFiles, null); List<DocumentInfo> failedFiles, List<Uri> failedUris) { ProviderCounts counts = new ProviderCounts(); countProviders(counts, failedFiles, null); // TODO: Report URI errors separate from file operation errors. countProviders(counts, failedUris); @FileOp int opCode = FILEOP_OTHER_ERROR; switch (operationType) { Loading Loading @@ -826,20 +833,34 @@ public final class Metrics { * the dst document (if a dst is provided), how many come from system providers, and how many * come from external 3rd-party providers. */ private static ProviderCounts countProviders( List<DocumentInfo> srcs, @Nullable DocumentInfo dst) { ProviderCounts counts = new ProviderCounts(); private static void countProviders( ProviderCounts counts, List<DocumentInfo> srcs, @Nullable DocumentInfo dst) { for (DocumentInfo doc: srcs) { if (dst != null && doc.authority.equals(dst.authority)) { countForAuthority(counts, doc.authority, dst); } } /** * Count the given uris and provide a tally of how many come from the same provider as * the dst document (if a dst is provided), how many come from system providers, and how many * come from external 3rd-party providers. */ private static void countProviders(ProviderCounts counts, List<Uri> uris) { for (Uri uri: uris) { countForAuthority(counts, uri.getAuthority(), null); } } private static void countForAuthority( ProviderCounts counts, String authority, @Nullable DocumentInfo dst) { if (dst != null && authority.equals(dst.authority)) { counts.intraProvider++; } else if (isSystemProvider(doc.authority)){ } else if (isSystemProvider(authority)){ counts.systemProvider++; } else { counts.externalProvider++; } } return counts; } private static class ProviderCounts { int intraProvider; Loading
src/com/android/documentsui/OperationDialogFragment.java +20 −9 Original line number Diff line number Diff line Loading @@ -17,13 +17,14 @@ package com.android.documentsui; import android.annotation.IntDef; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.DialogInterface; import android.net.Uri; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.text.Html; import com.android.documentsui.base.DocumentInfo; Loading @@ -34,7 +35,6 @@ import com.android.documentsui.services.FileOperationService.OpType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; /** * Alert dialog for operation dialogs. */ Loading @@ -55,13 +55,18 @@ public class OperationDialogFragment extends DialogFragment { private static final String TAG = "OperationDialogFragment"; public static void show(FragmentManager fm, @DialogType int dialogType, ArrayList<DocumentInfo> failedSrcList, DocumentStack dstStack, public static void show( FragmentManager fm, @DialogType int dialogType, ArrayList<DocumentInfo> failedSrcList, ArrayList<DocumentInfo> uriList, DocumentStack dstStack, @OpType int operationType) { final Bundle args = new Bundle(); args.putInt(FileOperationService.EXTRA_DIALOG_TYPE, dialogType); args.putInt(FileOperationService.EXTRA_OPERATION_TYPE, operationType); args.putParcelableArrayList(FileOperationService.EXTRA_SRC_LIST, failedSrcList); args.putParcelableArrayList(FileOperationService.EXTRA_FAILED_DOCS, failedSrcList); final FragmentTransaction ft = fm.beginTransaction(); final OperationDialogFragment fragment = new OperationDialogFragment(); Loading @@ -79,8 +84,10 @@ public class OperationDialogFragment extends DialogFragment { getArguments().getInt(FileOperationService.EXTRA_DIALOG_TYPE); final @OpType int operationType = getArguments().getInt(FileOperationService.EXTRA_OPERATION_TYPE); final ArrayList<DocumentInfo> srcList = getArguments().getParcelableArrayList( FileOperationService.EXTRA_SRC_LIST); final ArrayList<Uri> uriList = getArguments().getParcelableArrayList( FileOperationService.EXTRA_FAILED_URIS); final ArrayList<DocumentInfo> docList = getArguments().getParcelableArrayList( FileOperationService.EXTRA_FAILED_DOCS); final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); String messageFormat; Loading Loading @@ -111,10 +118,14 @@ public class OperationDialogFragment extends DialogFragment { } final StringBuilder list = new StringBuilder("<p>"); for (DocumentInfo documentInfo : srcList) { list.append(String.format("• %s<br>", Html.escapeHtml(documentInfo.displayName))); for (DocumentInfo documentInfo : docList) { list.append("• " + Html.escapeHtml(documentInfo.displayName) + "<br>"); } for (Uri uri : uriList) { list.append("• " + uri.toSafeString() + "<br>"); } list.append("</p>"); builder.setMessage(Html.fromHtml(String.format(messageFormat, list.toString()))); builder.setPositiveButton( R.string.close, Loading
src/com/android/documentsui/files/FilesActivity.java +6 −3 Original line number Diff line number Diff line Loading @@ -154,12 +154,15 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons final int opType = intent.getIntExtra( FileOperationService.EXTRA_OPERATION_TYPE, FileOperationService.OPERATION_COPY); final ArrayList<DocumentInfo> srcList = intent.getParcelableArrayListExtra(FileOperationService.EXTRA_SRC_LIST); final ArrayList<DocumentInfo> docList = intent.getParcelableArrayListExtra(FileOperationService.EXTRA_FAILED_DOCS); final ArrayList<DocumentInfo> uriList = intent.getParcelableArrayListExtra(FileOperationService.EXTRA_FAILED_URIS); OperationDialogFragment.show( getFragmentManager(), dialogType, srcList, docList, uriList, mState.stack, opType); } Loading
src/com/android/documentsui/services/CopyJob.java +25 −61 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import android.app.Notification; import android.app.Notification.Builder; import android.app.PendingIntent; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.res.AssetFileDescriptor; Loading Loading @@ -67,18 +66,16 @@ import java.io.IOException; import java.io.InputStream; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; class CopyJob extends Job { class CopyJob extends ResolvedResourcesJob { private static final String TAG = "CopyJob"; final List<DocumentInfo> mSrcs; final ArrayList<DocumentInfo> convertedFiles = new ArrayList<>(); private long mStartTime = -1; private long mBatchSize; private long mBytesRequired; private volatile long mBytesCopied; // Speed estimation private long mBytesCopiedSample; Loading @@ -99,9 +96,6 @@ class CopyJob extends Job { super(service, listener, id, opType, destination, srcs); assert(srcs.getItemCount() > 0); // delay the initialization of it to setUp() because it may be IO extensive. mSrcs = new ArrayList<>(srcs.getItemCount()); } @Override Loading @@ -121,8 +115,8 @@ class CopyJob extends Job { Notification getProgressNotification(@StringRes int msgId) { updateRemainingTimeEstimate(); if (mBatchSize >= 0) { double completed = (double) this.mBytesCopied / mBatchSize; if (mBytesRequired >= 0) { double completed = (double) this.mBytesCopied / mBytesRequired; mProgressBuilder.setProgress(100, (int) (completed * 100), false); mProgressBuilder.setSubText( NumberFormat.getPercentInstance().format(completed)); Loading Loading @@ -171,7 +165,7 @@ class CopyJob extends Job { } if (mSampleTime > 0 && mSpeed > 0) { mRemainingTime = ((mBatchSize - bytesCopied) * 1000) / mSpeed; mRemainingTime = ((mBytesRequired - bytesCopied) * 1000) / mSpeed; } else { mRemainingTime = 0; } Loading Loading @@ -211,10 +205,7 @@ class CopyJob extends Job { @Override boolean setUp() { try { buildDocumentList(); } catch (ResourceException e) { Log.e(TAG, "Failed to get the list of docs.", e); if (!super.setUp()) { return false; } Loading @@ -224,10 +215,10 @@ class CopyJob extends Job { } try { mBatchSize = calculateSize(mSrcs); mBytesRequired = calculateBytesRequired(); } catch (ResourceException e) { Log.w(TAG, "Failed to calculate total size. Copying without progress.", e); mBatchSize = -1; mBytesRequired = -1; } // Check if user has canceled this task. We should check it again here as user cancels Loading @@ -246,8 +237,8 @@ class CopyJob extends Job { mStartTime = elapsedRealtime(); DocumentInfo srcInfo; DocumentInfo dstInfo = stack.peek(); for (int i = 0; i < mSrcs.size() && !isCanceled(); ++i) { srcInfo = mSrcs.get(i); for (int i = 0; i < mResolvedDocs.size() && !isCanceled(); ++i) { srcInfo = mResolvedDocs.get(i); if (DEBUG) Log.d(TAG, "Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")" Loading @@ -265,39 +256,12 @@ class CopyJob extends Job { onFileFailed(srcInfo); } } Metrics.logFileOperation(service, operationType, mSrcs, dstInfo); } private void buildDocumentList() throws ResourceException { try { final ContentResolver resolver = appContext.getContentResolver(); final Iterable<Uri> uris = srcs.getUris(appContext); int docProcessed = 0; for (Uri uri : uris) { DocumentInfo doc = DocumentInfo.fromUri(resolver, uri); if (canCopy(doc, stack.getRoot())) { mSrcs.add(doc); } else { onFileFailed(doc); Metrics.logFileOperation(service, operationType, mResolvedDocs, dstInfo); } ++docProcessed; if (isCanceled()) { return; } } // If docProcessed is different than the count claimed by UrisSupplier, add the number // to failedFileCount. failedFileCount += (srcs.getItemCount() - docProcessed); } catch(IOException e) { failedFileCount += srcs.getItemCount(); throw new ResourceException("Failed to open the list of docs to copy.", e); } } private static boolean canCopy(DocumentInfo doc, RootInfo root) { @Override boolean isEligibleDoc(DocumentInfo doc, RootInfo root) { // Can't copy folders to downloads, because we don't show folders there. return !root.isDownloads() || !doc.isDirectory(); } Loading @@ -307,7 +271,7 @@ class CopyJob extends Job { * @return true if the root has enough space or doesn't provide free space info; otherwise false */ boolean checkSpace() { return checkSpace(mBatchSize); return verifySpaceAvailable(mBytesRequired); } /** Loading @@ -315,10 +279,10 @@ class CopyJob extends Job { * @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) { final boolean verifySpaceAvailable(long batchSize) { // Default to be true because if batchSize or available space is invalid, we still let the // copy start anyway. boolean result = true; boolean available = true; if (batchSize >= 0) { RootsCache cache = DocumentsApplication.getRootsCache(appContext); Loading @@ -327,18 +291,18 @@ class CopyJob extends Job { // stale. root = cache.getRootOneshot(root.authority, root.rootId, true); if (root.availableBytes >= 0) { result = (batchSize <= root.availableBytes); available = (batchSize <= root.availableBytes); } else { Log.w(TAG, root.toString() + " doesn't provide available bytes."); } } if (!result) { failedFileCount += mSrcs.size(); failedFiles.addAll(mSrcs); if (!available) { failureCount = mResolvedDocs.size(); failedDocs.addAll(mResolvedDocs); } return result; return available; } @Override Loading Loading @@ -626,14 +590,13 @@ class CopyJob extends Job { * Calculates the cumulative size of all the documents in the list. Directories are recursed * into and totaled up. * * @param srcs * @return Size in bytes. * @throws ResourceException */ private long calculateSize(List<DocumentInfo> srcs) throws ResourceException { private long calculateBytesRequired() throws ResourceException { long result = 0; for (DocumentInfo src : srcs) { for (DocumentInfo src : mResolvedDocs) { if (src.isDirectory()) { // Directories need to be recursed into. try { Loading Loading @@ -719,7 +682,8 @@ class CopyJob extends Job { .append("CopyJob") .append("{") .append("id=" + id) .append(", docs=" + srcs) .append(", uris=" + mResourceUris) .append(", docs=" + mResolvedDocs) .append(", destination=" + stack) .append("}") .toString(); Loading
src/com/android/documentsui/services/DeleteJob.java +37 −45 Original line number Diff line number Diff line Loading @@ -26,22 +26,21 @@ import android.content.Context; import android.net.Uri; import android.util.Log; import com.android.documentsui.clipping.UrisSupplier; import com.android.documentsui.Metrics; import com.android.documentsui.R; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentStack; import com.android.documentsui.clipping.UrisSupplier; import java.io.FileNotFoundException; import javax.annotation.Nullable; import java.io.IOException; import java.util.ArrayList; import java.util.List; final class DeleteJob extends Job { final class DeleteJob extends ResolvedResourcesJob { private static final String TAG = "DeleteJob"; private final Uri mSrcParent; private final Uri mParentUri; private volatile int mDocsProcessed = 0; /** Loading @@ -54,7 +53,7 @@ final class DeleteJob extends Job { DeleteJob(Context service, Listener listener, String id, DocumentStack stack, UrisSupplier srcs, @Nullable Uri srcParent) { super(service, listener, id, OPERATION_DELETE, stack, srcs); mSrcParent = srcParent; mParentUri = srcParent; } @Override Loading @@ -73,9 +72,10 @@ final class DeleteJob extends Job { @Override public Notification getProgressNotification() { mProgressBuilder.setProgress(srcs.getItemCount(), mDocsProcessed, false); mProgressBuilder.setProgress(mResourceUris.getItemCount(), mDocsProcessed, false); String format = service.getString(R.string.delete_progress); mProgressBuilder.setSubText(String.format(format, mDocsProcessed, srcs.getItemCount())); mProgressBuilder.setSubText( String.format(format, mDocsProcessed, mResourceUris.getItemCount())); mProgressBuilder.setContentText(null); Loading @@ -95,44 +95,35 @@ final class DeleteJob extends Job { @Override void start() { try { final List<DocumentInfo> srcs = new ArrayList<>(this.srcs.getItemCount()); ContentResolver resolver = appContext.getContentResolver(); final Iterable<Uri> uris = this.srcs.getUris(appContext); final ContentResolver resolver = appContext.getContentResolver(); final DocumentInfo srcParent = mSrcParent != null ? DocumentInfo.fromUri(resolver, mSrcParent) DocumentInfo parentDoc; try { parentDoc = mParentUri != null ? DocumentInfo.fromUri(resolver, mParentUri) : null; for (Uri uri : uris) { DocumentInfo doc = DocumentInfo.fromUri(resolver, uri); srcs.add(doc); } catch (FileNotFoundException e) { Log.e(TAG, "Failed to resolve parent from Uri: " + mParentUri + ". Cannot continue.", e); failureCount += this.mResourceUris.getItemCount(); return; } for (DocumentInfo doc : mResolvedDocs) { if (DEBUG) Log.d(TAG, "Deleting document @ " + doc.derivedUri); try { deleteDocument(doc, srcParent); if (isCanceled()) { // Canceled, dump the rest of the work. Deleted docs are not recoverable. return; } deleteDocument(doc, parentDoc); } catch (ResourceException e) { Log.e(TAG, "Failed to delete document @ " + doc.derivedUri, e); onFileFailed(doc); } ++mDocsProcessed; mDocsProcessed++; if (isCanceled()) { return; } // If mDocProcessed is different than the count claimed by UrisSupplier, add the number // to failedFileCount. failedFileCount += (this.srcs.getItemCount() - mDocsProcessed); Metrics.logFileOperation(service, operationType, srcs, null); } catch(IOException e) { Log.e(TAG, "Failed to get list of docs or parent source.", e); failedFileCount += srcs.getItemCount(); } Metrics.logFileOperation(service, operationType, mResolvedDocs, null); } @Override Loading @@ -141,8 +132,9 @@ final class DeleteJob extends Job { .append("DeleteJob") .append("{") .append("id=" + id) .append(", docs=" + srcs) .append(", srcParent=" + mSrcParent) .append(", uris=" + mResourceUris) .append(", docs=" + mResolvedDocs) .append(", srcParent=" + mParentUri) .append(", location=" + stack) .append("}") .toString(); Loading