Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ab7865cd authored by Steve McKay's avatar Steve McKay
Browse files

Do more work off main thread.

Create List<DocumentInfo> in asynctask to avoid UI jank.

Change-Id: I0a1274b4903c48332c2593714a2e7972b7b2686c
parent f3bd63ce
Loading
Loading
Loading
Loading
+138 −104
Original line number Diff line number Diff line
@@ -516,37 +516,39 @@ public class DirectoryFragment extends Fragment {
        @Override
        public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {

            // TODO: Call `getSelectedDocuments` in an AsyncTask to avoid UI jank.
            List<DocumentInfo> docs = getSelectedDocuments();
            // ListView returns a reference to its internal selection container,
            // which will get cleared when we cancel action mode. So we
            // make a defensive clone here.
            final SparseBooleanArray selected = mCurrentView.getCheckedItemPositions().clone();

            final int id = item.getItemId();
            if (id == R.id.menu_open) {
                BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
                openDocuments(selected);
                mode.finish();
                return true;

            } else if (id == R.id.menu_share) {
                onShareDocuments(docs);
                shareDocuments(selected);
                mode.finish();
                return true;

            } else if (id == R.id.menu_delete) {
                onDeleteDocuments(docs);
                deleteDocuments(selected);
                mode.finish();
                return true;

            } else if (id == R.id.menu_copy_to) {
                onTransferDocuments(docs, CopyService.TRANSFER_MODE_COPY);
                transferDocuments(selected, CopyService.TRANSFER_MODE_COPY);
                mode.finish();
                return true;

            } else if (id == R.id.menu_move_to) {
                onTransferDocuments(docs, CopyService.TRANSFER_MODE_MOVE);
                transferDocuments(selected, CopyService.TRANSFER_MODE_MOVE);
                mode.finish();
                return true;

            } else if (id == R.id.menu_copy_to_clipboard) {
                copySelectedToClipboard();
                copySelectionToClipboard(selected);
                mode.finish();
                return true;

@@ -602,7 +604,20 @@ public class DirectoryFragment extends Fragment {
        }
    };

    private void onShareDocuments(List<DocumentInfo> docs) {
    private void openDocuments(final SparseBooleanArray selected) {
        new GetDocumentsTask() {
            @Override
            void onDocumentsReady(List<DocumentInfo> docs) {
                // TODO: Implement support in standalone for opening multiple docs.
                BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
            }
        }.execute(selected);
    }

    private void shareDocuments(final SparseBooleanArray selected) {
        new GetDocumentsTask() {
            @Override
            void onDocumentsReady(List<DocumentInfo> docs) {
                Intent intent;

                // Filter out directories - those can't be shared.
@@ -644,11 +659,16 @@ public class DirectoryFragment extends Fragment {
                intent = Intent.createChooser(intent, getActivity().getText(R.string.share_via));
                startActivity(intent);
            }
        }.execute(selected);
    }

    private void onDeleteDocuments(List<DocumentInfo> docs) {
    private void deleteDocuments(final SparseBooleanArray selected) {
        final Context context = getActivity();
        final ContentResolver resolver = context.getContentResolver();

        new GetDocumentsTask() {
            @Override
            void onDocumentsReady(List<DocumentInfo> docs) {
                boolean hadTrouble = false;
                for (DocumentInfo doc : docs) {
                    if (!doc.isDeleteSupported()) {
@@ -671,13 +691,16 @@ public class DirectoryFragment extends Fragment {
                }

                if (hadTrouble) {
            Toast.makeText(context, R.string.toast_failed_delete, Toast.LENGTH_SHORT).show();
                    Toast.makeText(
                            context,
                            R.string.toast_failed_delete,
                            Toast.LENGTH_SHORT).show();
                }
            }
        }.execute(selected);
    }

    private void onTransferDocuments(List<DocumentInfo> docs, int mode) {
        getDisplayState(this).selectedDocumentsForCopy = docs;

    private void transferDocuments(final SparseBooleanArray selected, final int mode) {
        // Pop up a dialog to pick a destination.  This is inadequate but works for now.
        // TODO: Implement a picker that is to spec.
        final Intent intent = new Intent(
@@ -685,6 +708,12 @@ public class DirectoryFragment extends Fragment {
                Uri.EMPTY,
                getActivity(),
                DocumentsActivity.class);

        new GetDocumentsTask() {
            @Override
            void onDocumentsReady(List<DocumentInfo> docs) {
                getDisplayState(DirectoryFragment.this).selectedDocumentsForCopy = docs;

                boolean directoryCopy = false;
                for (DocumentInfo info : docs) {
                    if (Document.MIME_TYPE_DIR.equals(info.mimeType)) {
@@ -696,6 +725,8 @@ public class DirectoryFragment extends Fragment {
                intent.putExtra(CopyService.EXTRA_TRANSFER_MODE, mode);
                startActivityForResult(intent, REQUEST_COPY_DESTINATION);
            }
        }.execute(selected);
    }

    private static State getDisplayState(Fragment fragment) {
        return ((BaseActivity) fragment.getActivity()).getDisplayState();
@@ -1309,34 +1340,21 @@ public class DirectoryFragment extends Fragment {
    }

    void copySelectedToClipboard() {
        // ListView returns a reference to its internal selection container,
        // which will get cleared when we cancel action mode. So we
        // make a defensive clone here.
        //
        // Furthermore, we don't want to call this from within the async task for
        // basically the same reason...when mode is cancelled, selection is cleared.
        final SparseBooleanArray selection = mCurrentView.getCheckedItemPositions().clone();
        copySelectionToClipboard(mCurrentView.getCheckedItemPositions().clone());
    }

        new AsyncTask<Void, Void, List<DocumentInfo>>() {
            protected List<DocumentInfo> doInBackground(Void... params) {
                List<DocumentInfo> docs = getItemsAsDocuments(selection);
                if (!docs.isEmpty()) {
    void copySelectionToClipboard(SparseBooleanArray selected) {
        new GetDocumentsTask() {
            @Override
            void onDocumentsReady(List<DocumentInfo> docs) {
                mClipper.clipDocuments(docs);
                }
                return docs;
            };
            protected void onPostExecute(List<DocumentInfo> docs) {
                if (docs.isEmpty()) {
                    Log.i(TAG, "Skipped populating clipboard with empty selection.");
                    return;
                }
                Activity activity = getActivity();
                Toast.makeText(activity,
                        activity.getResources().getQuantityString(
                                R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
                                Toast.LENGTH_SHORT).show();
            };
        }.execute();
            }
        }.execute(selected);
    }

    void pasteFromClipboard() {
@@ -1344,10 +1362,6 @@ public class DirectoryFragment extends Fragment {
        getActivity().invalidateOptionsMenu();
    }

    private ClipboardManager getClipboardManager() {
        return (ClipboardManager)getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
    }

    /**
     * Returns true if the list of files can be copied to destination. Note that this
     * is a policy check only. Currently the method does not attempt to verify
@@ -1526,6 +1540,26 @@ public class DirectoryFragment extends Fragment {
        void updateActionMenu(Menu menu, int dirType);
    }

    /**
     * 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<SparseBooleanArray, Void, List<DocumentInfo>> {
        @Override
        protected final List<DocumentInfo> doInBackground(SparseBooleanArray... selected) {
            return getItemsAsDocuments(selected[0]);
        }

        @Override
        protected final void onPostExecute(List<DocumentInfo> docs) {
            onDocumentsReady(docs);
        }

        abstract void onDocumentsReady(List<DocumentInfo> docs);
    }

    /**
     * Provides support for Platform specific specializations of DirectoryFragment.
     */