DO NOT MERGE: Don't create DocumentInfo instances in background.
am: b818058f4e
Change-Id: Ib43fd7c9cba300821a908f7036415b8b1635bb4a
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user