DO NOT MERGE: Don't create DocumentInfo instances in background.

am: b818058f4e

Change-Id: Ib43fd7c9cba300821a908f7036415b8b1635bb4a
This commit is contained in:
Steve McKay
2016-08-24 19:55:22 +00:00
committed by android-build-merger

View File

@@ -753,63 +753,57 @@ public class DirectoryFragment extends Fragment
private void openDocuments(final Selection selected) { private void openDocuments(final Selection selected) {
Metrics.logUserAction(getContext(), Metrics.USER_ACTION_OPEN); Metrics.logUserAction(getContext(), Metrics.USER_ACTION_OPEN);
new GetDocumentsTask() { // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
@Override List<DocumentInfo> docs = mModel.getDocuments(selected);
void onDocumentsReady(List<DocumentInfo> docs) { // TODO: Implement support in Files activity for opening multiple docs.
// TODO: Implement support in Files activity for opening multiple docs. BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
}
}.execute(selected);
} }
private void shareDocuments(final Selection selected) { private void shareDocuments(final Selection selected) {
Metrics.logUserAction(getContext(), Metrics.USER_ACTION_SHARE); Metrics.logUserAction(getContext(), Metrics.USER_ACTION_SHARE);
new GetDocumentsTask() { // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
@Override List<DocumentInfo> docs = mModel.getDocuments(selected);
void onDocumentsReady(List<DocumentInfo> docs) { Intent intent;
Intent intent;
// Filter out directories and virtual files - those can't be shared. // Filter out directories and virtual files - those can't be shared.
List<DocumentInfo> docsForSend = new ArrayList<>(); List<DocumentInfo> docsForSend = new ArrayList<>();
for (DocumentInfo doc: docs) { for (DocumentInfo doc: docs) {
if (!doc.isDirectory() && !doc.isVirtualDocument()) { if (!doc.isDirectory() && !doc.isVirtualDocument()) {
docsForSend.add(doc); docsForSend.add(doc);
}
}
if (docsForSend.size() == 1) {
final DocumentInfo doc = docsForSend.get(0);
intent = new Intent(Intent.ACTION_SEND);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setType(doc.mimeType);
intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
} else if (docsForSend.size() > 1) {
intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addCategory(Intent.CATEGORY_DEFAULT);
final ArrayList<String> mimeTypes = new ArrayList<>();
final ArrayList<Uri> uris = new ArrayList<>();
for (DocumentInfo doc : docsForSend) {
mimeTypes.add(doc.mimeType);
uris.add(doc.derivedUri);
}
intent.setType(findCommonMimeType(mimeTypes));
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
} else {
return;
}
intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
startActivity(intent);
} }
}.execute(selected); }
if (docsForSend.size() == 1) {
final DocumentInfo doc = docsForSend.get(0);
intent = new Intent(Intent.ACTION_SEND);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setType(doc.mimeType);
intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
} else if (docsForSend.size() > 1) {
intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addCategory(Intent.CATEGORY_DEFAULT);
final ArrayList<String> mimeTypes = new ArrayList<>();
final ArrayList<Uri> uris = new ArrayList<>();
for (DocumentInfo doc : docsForSend) {
mimeTypes.add(doc.mimeType);
uris.add(doc.derivedUri);
}
intent.setType(findCommonMimeType(mimeTypes));
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
} else {
return;
}
intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
startActivity(intent);
} }
private String generateDeleteMessage(final List<DocumentInfo> docs) { private String generateDeleteMessage(final List<DocumentInfo> docs) {
@@ -855,52 +849,51 @@ public class DirectoryFragment extends Fragment
assert(!selected.isEmpty()); assert(!selected.isEmpty());
final DocumentInfo srcParent = getDisplayState().stack.peek(); final DocumentInfo srcParent = getDisplayState().stack.peek();
new GetDocumentsTask() {
@Override
void onDocumentsReady(final List<DocumentInfo> docs) {
TextView message = // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
(TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null); List<DocumentInfo> docs = mModel.getDocuments(selected);
message.setText(generateDeleteMessage(docs));
// This "insta-hides" files that are being deleted, because TextView message =
// the delete operation may be not execute immediately (it (TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
// may be queued up on the FileOperationService.) message.setText(generateDeleteMessage(docs));
// To hide the files locally, we call the hide method on the adapter
// ...which a live object...cannot be parceled. // This "insta-hides" files that are being deleted, because
// For that reason, for now, we implement this dialog NOT // the delete operation may be not execute immediately (it
// as a fragment (which can survive rotation and have its own state), // may be queued up on the FileOperationService.)
// but as a simple runtime dialog. So rotating a device with an // To hide the files locally, we call the hide method on the adapter
// active delete dialog...results in that dialog disappearing. // ...which a live object...cannot be parceled.
// We can do better, but don't have cycles for it now. // For that reason, for now, we implement this dialog NOT
new AlertDialog.Builder(getActivity()) // as a fragment (which can survive rotation and have its own state),
.setView(message) // but as a simple runtime dialog. So rotating a device with an
.setPositiveButton( // active delete dialog...results in that dialog disappearing.
android.R.string.yes, // We can do better, but don't have cycles for it now.
new DialogInterface.OnClickListener() { new AlertDialog.Builder(getActivity())
public void onClick(DialogInterface dialog, int id) { .setView(message)
// Finish selection mode first which clears selection so we .setPositiveButton(
// don't end up trying to deselect deleted documents. android.R.string.yes,
// This is done here, rather in the onActionItemClicked new DialogInterface.OnClickListener() {
// so we can avoid de-selecting items in the case where @Override
// the user cancels the delete. public void onClick(DialogInterface dialog, int id) {
if (mActionMode != null) { // Finish selection mode first which clears selection so we
mActionMode.finish(); // don't end up trying to deselect deleted documents.
} else { // This is done here, rather in the onActionItemClicked
Log.w(TAG, "Action mode is null before deleting documents."); // so we can avoid de-selecting items in the case where
} // the user cancels the delete.
// Hide the files in the UI...since the operation if (mActionMode != null) {
// might be queued up on FileOperationService. mActionMode.finish();
// We're walking a line here. } else {
mAdapter.hide(selected.getAll()); Log.w(TAG, "Action mode is null before deleting documents.");
FileOperations.delete( }
getActivity(), docs, srcParent, getDisplayState().stack); // Hide the files in the UI...since the operation
} // might be queued up on FileOperationService.
}) // We're walking a line here.
.setNegativeButton(android.R.string.no, null) mAdapter.hide(selected.getAll());
.show(); FileOperations.delete(
} getActivity(), docs, srcParent, getDisplayState().stack);
}.execute(selected); }
})
.setNegativeButton(android.R.string.no, null)
.show();
} }
private void transferDocuments(final Selection selected, final @OpType int mode) { private void transferDocuments(final Selection selected, final @OpType int mode) {
@@ -934,25 +927,21 @@ public class DirectoryFragment extends Fragment
? R.string.menu_move : R.string.menu_copy; ? R.string.menu_move : R.string.menu_copy;
intent.putExtra(DocumentsContract.EXTRA_PROMPT, getResources().getString(drawerTitleId)); intent.putExtra(DocumentsContract.EXTRA_PROMPT, getResources().getString(drawerTitleId));
new GetDocumentsTask() { // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
@Override List<DocumentInfo> docs = mModel.getDocuments(selected);
void onDocumentsReady(List<DocumentInfo> docs) { // TODO: Can this move to Fragment bundle state?
// TODO: Can this move to Fragment bundle state? getDisplayState().selectedDocumentsForCopy = docs;
getDisplayState().selectedDocumentsForCopy = docs;
// Determine if there is a directory in the set of documents // Determine if there is a directory in the set of documents
// to be copied? Why? Directory creation isn't supported by some roots // to be copied? Why? Directory creation isn't supported by some roots
// (like Downloads). This informs DocumentsActivity (the "picker") // (like Downloads). This informs DocumentsActivity (the "picker")
// to restrict available roots to just those with support. // to restrict available roots to just those with support.
intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, hasDirectory(docs)); intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, hasDirectory(docs));
intent.putExtra(FileOperationService.EXTRA_OPERATION, mode); intent.putExtra(FileOperationService.EXTRA_OPERATION, mode);
// This just identifies the type of request...we'll check it // This just identifies the type of request...we'll check it
// when we reveive a response. // when we reveive a response.
startActivityForResult(intent, REQUEST_COPY_DESTINATION); startActivityForResult(intent, REQUEST_COPY_DESTINATION);
}
}.execute(selected);
} }
private static boolean hasDirectory(List<DocumentInfo> docs) { private static boolean hasDirectory(List<DocumentInfo> docs) {
@@ -971,12 +960,9 @@ public class DirectoryFragment extends Fragment
// Rename option is only available in menu when 1 document selected // Rename option is only available in menu when 1 document selected
assert(selected.size() == 1); assert(selected.size() == 1);
new GetDocumentsTask() { // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
@Override List<DocumentInfo> docs = mModel.getDocuments(selected);
void onDocumentsReady(List<DocumentInfo> docs) { RenameDocumentFragment.show(getFragmentManager(), docs.get(0));
RenameDocumentFragment.show(getFragmentManager(), docs.get(0));
}
}.execute(selected);
} }
@Override @Override
@@ -1135,19 +1121,17 @@ public class DirectoryFragment extends Fragment
} }
} }
void copySelectionToClipboard(Selection selection) { void copySelectionToClipboard(Selection selected) {
assert(!selection.isEmpty()); assert(!selected.isEmpty());
new GetDocumentsTask() {
@Override // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
void onDocumentsReady(List<DocumentInfo> docs) { List<DocumentInfo> docs = mModel.getDocuments(selected);
mClipper.clipDocuments(docs); mClipper.clipDocuments(docs);
Activity activity = getActivity(); Activity activity = getActivity();
Snackbars.makeSnackbar(activity, Snackbars.makeSnackbar(activity,
activity.getResources().getQuantityString( activity.getResources().getQuantityString(
R.plurals.clipboard_files_clipped, docs.size(), docs.size()), R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
Snackbar.LENGTH_SHORT).show(); Snackbar.LENGTH_SHORT).show();
}
}.execute(selection);
} }
public void pasteFromClipboard() { public void pasteFromClipboard() {
@@ -1456,25 +1440,6 @@ public class DirectoryFragment extends Fragment
mShadowView.draw(canvas); mShadowView.draw(canvas);
} }
} }
/**
* Abstract task providing support for loading documents *off*
* the main thread. And if it isn't obvious, creating a list
* of documents (especially large lists) can be pretty expensive.
*/
private abstract class GetDocumentsTask
extends AsyncTask<Selection, Void, List<DocumentInfo>> {
@Override
protected final List<DocumentInfo> doInBackground(Selection... selected) {
return mModel.getDocuments(selected[0]);
}
@Override
protected final void onPostExecute(List<DocumentInfo> docs) {
onDocumentsReady(docs);
}
abstract void onDocumentsReady(List<DocumentInfo> docs);
}
@Override @Override
public boolean isSelected(String modelId) { public boolean isSelected(String modelId) {