DO NOT MERGE: Don't create DocumentInfo instances in background.
Cursor access is not threadsafe resulting in operations on incorrect files. Bug: 30082168 Change-Id: Ib36d5b7acdee9463b6ebd2553172e5ecb4d70857
This commit is contained in:
@@ -753,21 +753,17 @@ 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.
|
||||||
@@ -809,8 +805,6 @@ public class DirectoryFragment extends Fragment
|
|||||||
intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
|
intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
}.execute(selected);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String generateDeleteMessage(final List<DocumentInfo> docs) {
|
private String generateDeleteMessage(final List<DocumentInfo> docs) {
|
||||||
String message;
|
String message;
|
||||||
@@ -855,9 +849,9 @@ 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
|
// Model must be accessed in UI thread, since underlying cursor is not threadsafe.
|
||||||
void onDocumentsReady(final List<DocumentInfo> docs) {
|
List<DocumentInfo> docs = mModel.getDocuments(selected);
|
||||||
|
|
||||||
TextView message =
|
TextView message =
|
||||||
(TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
|
(TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
|
||||||
@@ -878,6 +872,7 @@ public class DirectoryFragment extends Fragment
|
|||||||
.setPositiveButton(
|
.setPositiveButton(
|
||||||
android.R.string.yes,
|
android.R.string.yes,
|
||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
// Finish selection mode first which clears selection so we
|
// Finish selection mode first which clears selection so we
|
||||||
// don't end up trying to deselect deleted documents.
|
// don't end up trying to deselect deleted documents.
|
||||||
@@ -900,8 +895,6 @@ public class DirectoryFragment extends Fragment
|
|||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
}.execute(selected);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void transferDocuments(final Selection selected, final @OpType int mode) {
|
private void transferDocuments(final Selection selected, final @OpType int mode) {
|
||||||
if(mode == FileOperationService.OPERATION_COPY) {
|
if(mode == FileOperationService.OPERATION_COPY) {
|
||||||
@@ -934,9 +927,8 @@ 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;
|
||||||
|
|
||||||
@@ -952,9 +944,6 @@ public class DirectoryFragment extends Fragment
|
|||||||
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) {
|
||||||
for (DocumentInfo info : docs) {
|
for (DocumentInfo info : docs) {
|
||||||
if (Document.MIME_TYPE_DIR.equals(info.mimeType)) {
|
if (Document.MIME_TYPE_DIR.equals(info.mimeType)) {
|
||||||
@@ -971,13 +960,10 @@ 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
|
||||||
public void initDocumentHolder(DocumentHolder holder) {
|
public void initDocumentHolder(DocumentHolder holder) {
|
||||||
@@ -1135,11 +1121,11 @@ 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,
|
||||||
@@ -1147,8 +1133,6 @@ public class DirectoryFragment extends Fragment
|
|||||||
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() {
|
||||||
Metrics.logUserAction(getContext(), Metrics.USER_ACTION_PASTE_CLIPBOARD);
|
Metrics.logUserAction(getContext(), Metrics.USER_ACTION_PASTE_CLIPBOARD);
|
||||||
@@ -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