Loading src/com/android/documentsui/ActionModeAddons.java +0 −2 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,4 @@ package com.android.documentsui; public interface ActionModeAddons { public interface ActionModeAddons { void finishActionMode(); void finishActionMode(); void finishOnConfirmed(int code); } } src/com/android/documentsui/ActionModeController.java +0 −9 Original line number Original line Diff line number Diff line Loading @@ -29,8 +29,6 @@ import android.view.MenuItem; import android.view.View; import android.view.View; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.base.ConfirmationCallback; import com.android.documentsui.base.ConfirmationCallback.Result; import com.android.documentsui.base.EventHandler; import com.android.documentsui.base.EventHandler; import com.android.documentsui.base.Menus; import com.android.documentsui.base.Menus; import com.android.documentsui.selection.Selection; import com.android.documentsui.selection.Selection; Loading Loading @@ -185,13 +183,6 @@ public class ActionModeController extends SelectionObserver } } } } @Override public void finishOnConfirmed(@Result int code) { if (code == ConfirmationCallback.CONFIRM) { finishActionMode(); } } public ActionModeController reset( public ActionModeController reset( SelectionDetails selectionDetails, EventHandler<MenuItem> menuItemClicker) { SelectionDetails selectionDetails, EventHandler<MenuItem> menuItemClicker) { assert(mActionMode == null); assert(mActionMode == null); Loading src/com/android/documentsui/Metrics.java +3 −1 Original line number Original line Diff line number Diff line Loading @@ -318,6 +318,7 @@ public final class Metrics { public static final int USER_ACTION_EXTRACT_TO = 28; public static final int USER_ACTION_EXTRACT_TO = 28; public static final int USER_ACTION_VIEW_IN_APPLICATION = 29; public static final int USER_ACTION_VIEW_IN_APPLICATION = 29; public static final int USER_ACTION_INSPECTOR = 30; public static final int USER_ACTION_INSPECTOR = 30; public static final int USER_ACTION_UNDO_DELETE = 31; @IntDef(flag = false, value = { @IntDef(flag = false, value = { USER_ACTION_OTHER, USER_ACTION_OTHER, Loading Loading @@ -349,7 +350,8 @@ public final class Metrics { USER_ACTION_COMPRESS, USER_ACTION_COMPRESS, USER_ACTION_EXTRACT_TO, USER_ACTION_EXTRACT_TO, USER_ACTION_VIEW_IN_APPLICATION, USER_ACTION_VIEW_IN_APPLICATION, USER_ACTION_INSPECTOR USER_ACTION_INSPECTOR, USER_ACTION_UNDO_DELETE }) }) @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) public @interface UserAction {} public @interface UserAction {} Loading src/com/android/documentsui/Model.java +64 −9 Original line number Original line Diff line number Diff line Loading @@ -32,7 +32,6 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting; import android.util.Log; import android.util.Log; import com.android.documentsui.DirectoryResult; import com.android.documentsui.base.DocumentFilters; import com.android.documentsui.base.DocumentFilters; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.EventListener; import com.android.documentsui.base.EventListener; Loading @@ -45,6 +44,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashMap; import java.util.HashMap; import java.util.HashSet; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.List; import java.util.Map; import java.util.Map; import java.util.Set; import java.util.Set; Loading Loading @@ -73,6 +73,7 @@ public class Model { private @Nullable Cursor mCursor; private @Nullable Cursor mCursor; private int mCursorCount; private int mCursorCount; private String mIds[] = new String[0]; private String mIds[] = new String[0]; private Set<Selection> mDocumentsToBeDeleted = new HashSet<>(); public Model(Features features) { public Model(Features features) { mFeatures = features; mFeatures = features; Loading Loading @@ -109,13 +110,13 @@ public class Model { doc = null; doc = null; mIsLoading = false; mIsLoading = false; mFileNames.clear(); mFileNames.clear(); mDocumentsToBeDeleted.clear(); notifyUpdateListeners(); notifyUpdateListeners(); } } @VisibleForTesting @VisibleForTesting protected void update(DirectoryResult result) { protected void update(DirectoryResult result) { assert(result != null); assert(result != null); if (DEBUG) Log.i(TAG, "Updating model with new result set."); if (DEBUG) Log.i(TAG, "Updating model with new result set."); if (result.exception != null) { if (result.exception != null) { Loading @@ -141,9 +142,56 @@ public class Model { notifyUpdateListeners(); notifyUpdateListeners(); } } public void markDocumentsToBeDeleted(Selection selection) { if (mDocumentsToBeDeleted.contains(selection)) { return; } mDocumentsToBeDeleted.add(selection); updateModelData(); notifyUpdateListeners(); } public void restoreDocumentsToBeDeleted(Selection selection) { if (!mDocumentsToBeDeleted.contains(selection)) { return; } mDocumentsToBeDeleted.remove(selection); updateModelData(); notifyUpdateListeners(); } private boolean isDocumentToBeDeleted(String id) { for (Selection s : mDocumentsToBeDeleted) { if (s.contains(id)) { return true; } } return false; } private void updateDocumentsToBeDeleted() { for (Iterator<Selection> i = mDocumentsToBeDeleted.iterator(); i.hasNext();) { Selection selection = i.next(); for (String id : selection) { if (!mPositions.containsKey(id)) { i.remove(); break; } } } } private int getDocumentsToBeDeletedCount() { int count = 0; for (Selection s : mDocumentsToBeDeleted) { count += s.size(); } return count; } @VisibleForTesting @VisibleForTesting public int getItemCount() { public int getItemCount() { return mCursorCount; return mCursorCount - getDocumentsToBeDeletedCount(); } } /** /** Loading @@ -151,9 +199,10 @@ public class Model { * according to the current sort order. * according to the current sort order. */ */ private void updateModelData() { private void updateModelData() { mIds = new String[mCursorCount]; mFileNames.clear(); mFileNames.clear(); mCursor.moveToPosition(-1); mCursor.moveToPosition(-1); mPositions.clear(); String[] tmpIds = new String[mCursorCount]; for (int pos = 0; pos < mCursorCount; ++pos) { for (int pos = 0; pos < mCursorCount; ++pos) { if (!mCursor.moveToNext()) { if (!mCursor.moveToNext()) { Log.e(TAG, "Fail to move cursor to next pos: " + pos); Log.e(TAG, "Fail to move cursor to next pos: " + pos); Loading @@ -164,18 +213,24 @@ public class Model { // If the cursor is a merged cursor over multiple authorities, then prefix the ids // If the cursor is a merged cursor over multiple authorities, then prefix the ids // with the authority to avoid collisions. // with the authority to avoid collisions. if (mCursor instanceof MergeCursor) { if (mCursor instanceof MergeCursor) { mIds[pos] = getCursorString(mCursor, RootCursorWrapper.COLUMN_AUTHORITY) tmpIds[pos] = getCursorString(mCursor, RootCursorWrapper.COLUMN_AUTHORITY) + "|" + getCursorString(mCursor, Document.COLUMN_DOCUMENT_ID); + "|" + getCursorString(mCursor, Document.COLUMN_DOCUMENT_ID); } else { } else { mIds[pos] = getCursorString(mCursor, Document.COLUMN_DOCUMENT_ID); tmpIds[pos] = getCursorString(mCursor, Document.COLUMN_DOCUMENT_ID); } } mPositions.put(tmpIds[pos], pos); mFileNames.add(getCursorString(mCursor, Document.COLUMN_DISPLAY_NAME)); mFileNames.add(getCursorString(mCursor, Document.COLUMN_DISPLAY_NAME)); } } // Populate the positions. updateDocumentsToBeDeleted(); mPositions.clear(); mIds = new String[mCursorCount - getDocumentsToBeDeletedCount()]; int index = 0; for (int i = 0; i < mCursorCount; ++i) { for (int i = 0; i < mCursorCount; ++i) { mPositions.put(mIds[i], i); if (!isDocumentToBeDeleted(tmpIds[i])) { mIds[index] = tmpIds[i]; index++; } } } } } Loading src/com/android/documentsui/files/ActionHandler.java +61 −38 Original line number Original line Diff line number Diff line Loading @@ -25,11 +25,11 @@ import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentResolver; import android.content.Intent; import android.content.Intent; import android.net.Uri; import android.net.Uri; import android.os.Build; import android.provider.DocumentsContract; import android.provider.DocumentsContract; import android.text.TextUtils; import android.text.TextUtils; import android.util.Log; import android.util.Log; import android.view.DragEvent; import android.view.DragEvent; import android.view.View; import com.android.documentsui.AbstractActionHandler; import com.android.documentsui.AbstractActionHandler; import com.android.documentsui.ActionModeAddons; import com.android.documentsui.ActionModeAddons; Loading @@ -42,8 +42,6 @@ import com.android.documentsui.Metrics; import com.android.documentsui.Model; import com.android.documentsui.Model; import com.android.documentsui.R; import com.android.documentsui.R; import com.android.documentsui.TimeoutTask; import com.android.documentsui.TimeoutTask; import com.android.documentsui.base.ConfirmationCallback; import com.android.documentsui.base.ConfirmationCallback.Result; import com.android.documentsui.base.DebugFlags; import com.android.documentsui.base.DebugFlags; import com.android.documentsui.base.DocumentFilters; import com.android.documentsui.base.DocumentFilters; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentInfo; Loading @@ -69,11 +67,15 @@ import com.android.documentsui.services.FileOperation; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperations; import com.android.documentsui.services.FileOperations; import com.android.documentsui.ui.DialogController; import com.android.documentsui.ui.DialogController; import com.android.documentsui.ui.Snackbars; import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting; import android.support.design.widget.Snackbar; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executor; import java.util.function.Consumer; import javax.annotation.Nullable; import javax.annotation.Nullable; Loading @@ -93,6 +95,8 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa private final DragAndDropManager mDragAndDropManager; private final DragAndDropManager mDragAndDropManager; private final Model mModel; private final Model mModel; private Snackbar mDeletionSnackbar; ActionHandler( ActionHandler( T activity, T activity, State state, State state, Loading Loading @@ -301,17 +305,6 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa final @Nullable DocumentInfo srcParent = mState.stack.peek(); final @Nullable DocumentInfo srcParent = mState.stack.peek(); // Model must be accessed in UI thread, since underlying cursor is not threadsafe. List<DocumentInfo> docs = mModel.getDocuments(selection); ConfirmationCallback result = (@Result int code) -> { // share the news with our caller, be it good or bad. mActionModeAddons.finishOnConfirmed(code); if (code != ConfirmationCallback.CONFIRM) { return; } UrisSupplier srcs; UrisSupplier srcs; try { try { srcs = UrisSupplier.create( srcs = UrisSupplier.create( Loading @@ -326,7 +319,16 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa selection.size()); selection.size()); return; return; } } mModel.markDocumentsToBeDeleted(selection); Consumer<View> action = v -> { Metrics.logUserAction(mActivity, Metrics.USER_ACTION_UNDO_DELETE); mModel.restoreDocumentsToBeDeleted(selection); }; Snackbar.Callback callback = new Snackbar.Callback() { @Override public void onDismissed(Snackbar snackbar, int event) { super.onDismissed(snackbar, event); if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) { FileOperation operation = new FileOperation.Builder() FileOperation operation = new FileOperation.Builder() .withOpType(FileOperationService.OPERATION_DELETE) .withOpType(FileOperationService.OPERATION_DELETE) .withDestination(mState.stack) .withDestination(mState.stack) Loading @@ -334,11 +336,26 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa .withSrcParent(srcParent == null ? null : srcParent.derivedUri) .withSrcParent(srcParent == null ? null : srcParent.derivedUri) .build(); .build(); FileOperations.start(mActivity, operation, mDialogs::showFileOperationStatus, FileOperations.start(mActivity, operation, null, FileOperations.createJobId()); FileOperations.createJobId()); } if (mDeletionSnackbar == snackbar) { mDeletionSnackbar = null; } } }; }; mDeletionSnackbar = showDeletionSnackbar(mActivity, selection.size(), action, callback); } public Snackbar showDeletionSnackbar(Activity activity, int docCount, Consumer<View> action, Snackbar.Callback callback) { return Snackbars.showDelete(mActivity, docCount, action, callback); } mDialogs.confirmDelete(docs, result); public void dismissDeletionSnackBar() { if (mDeletionSnackbar != null) { mDeletionSnackbar.dismiss(); } } } @Override @Override Loading Loading @@ -393,6 +410,12 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa mActivity.startActivity(chooserIntent); mActivity.startActivity(chooserIntent); } } @Override public void loadDocumentsForCurrentStack() { dismissDeletionSnackBar(); super.loadDocumentsForCurrentStack(); } @Override @Override public void initLocation(Intent intent) { public void initLocation(Intent intent) { assert(intent != null); assert(intent != null); Loading Loading
src/com/android/documentsui/ActionModeAddons.java +0 −2 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,4 @@ package com.android.documentsui; public interface ActionModeAddons { public interface ActionModeAddons { void finishActionMode(); void finishActionMode(); void finishOnConfirmed(int code); } }
src/com/android/documentsui/ActionModeController.java +0 −9 Original line number Original line Diff line number Diff line Loading @@ -29,8 +29,6 @@ import android.view.MenuItem; import android.view.View; import android.view.View; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.MenuManager.SelectionDetails; import com.android.documentsui.base.ConfirmationCallback; import com.android.documentsui.base.ConfirmationCallback.Result; import com.android.documentsui.base.EventHandler; import com.android.documentsui.base.EventHandler; import com.android.documentsui.base.Menus; import com.android.documentsui.base.Menus; import com.android.documentsui.selection.Selection; import com.android.documentsui.selection.Selection; Loading Loading @@ -185,13 +183,6 @@ public class ActionModeController extends SelectionObserver } } } } @Override public void finishOnConfirmed(@Result int code) { if (code == ConfirmationCallback.CONFIRM) { finishActionMode(); } } public ActionModeController reset( public ActionModeController reset( SelectionDetails selectionDetails, EventHandler<MenuItem> menuItemClicker) { SelectionDetails selectionDetails, EventHandler<MenuItem> menuItemClicker) { assert(mActionMode == null); assert(mActionMode == null); Loading
src/com/android/documentsui/Metrics.java +3 −1 Original line number Original line Diff line number Diff line Loading @@ -318,6 +318,7 @@ public final class Metrics { public static final int USER_ACTION_EXTRACT_TO = 28; public static final int USER_ACTION_EXTRACT_TO = 28; public static final int USER_ACTION_VIEW_IN_APPLICATION = 29; public static final int USER_ACTION_VIEW_IN_APPLICATION = 29; public static final int USER_ACTION_INSPECTOR = 30; public static final int USER_ACTION_INSPECTOR = 30; public static final int USER_ACTION_UNDO_DELETE = 31; @IntDef(flag = false, value = { @IntDef(flag = false, value = { USER_ACTION_OTHER, USER_ACTION_OTHER, Loading Loading @@ -349,7 +350,8 @@ public final class Metrics { USER_ACTION_COMPRESS, USER_ACTION_COMPRESS, USER_ACTION_EXTRACT_TO, USER_ACTION_EXTRACT_TO, USER_ACTION_VIEW_IN_APPLICATION, USER_ACTION_VIEW_IN_APPLICATION, USER_ACTION_INSPECTOR USER_ACTION_INSPECTOR, USER_ACTION_UNDO_DELETE }) }) @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) public @interface UserAction {} public @interface UserAction {} Loading
src/com/android/documentsui/Model.java +64 −9 Original line number Original line Diff line number Diff line Loading @@ -32,7 +32,6 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting; import android.util.Log; import android.util.Log; import com.android.documentsui.DirectoryResult; import com.android.documentsui.base.DocumentFilters; import com.android.documentsui.base.DocumentFilters; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.EventListener; import com.android.documentsui.base.EventListener; Loading @@ -45,6 +44,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashMap; import java.util.HashMap; import java.util.HashSet; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.List; import java.util.Map; import java.util.Map; import java.util.Set; import java.util.Set; Loading Loading @@ -73,6 +73,7 @@ public class Model { private @Nullable Cursor mCursor; private @Nullable Cursor mCursor; private int mCursorCount; private int mCursorCount; private String mIds[] = new String[0]; private String mIds[] = new String[0]; private Set<Selection> mDocumentsToBeDeleted = new HashSet<>(); public Model(Features features) { public Model(Features features) { mFeatures = features; mFeatures = features; Loading Loading @@ -109,13 +110,13 @@ public class Model { doc = null; doc = null; mIsLoading = false; mIsLoading = false; mFileNames.clear(); mFileNames.clear(); mDocumentsToBeDeleted.clear(); notifyUpdateListeners(); notifyUpdateListeners(); } } @VisibleForTesting @VisibleForTesting protected void update(DirectoryResult result) { protected void update(DirectoryResult result) { assert(result != null); assert(result != null); if (DEBUG) Log.i(TAG, "Updating model with new result set."); if (DEBUG) Log.i(TAG, "Updating model with new result set."); if (result.exception != null) { if (result.exception != null) { Loading @@ -141,9 +142,56 @@ public class Model { notifyUpdateListeners(); notifyUpdateListeners(); } } public void markDocumentsToBeDeleted(Selection selection) { if (mDocumentsToBeDeleted.contains(selection)) { return; } mDocumentsToBeDeleted.add(selection); updateModelData(); notifyUpdateListeners(); } public void restoreDocumentsToBeDeleted(Selection selection) { if (!mDocumentsToBeDeleted.contains(selection)) { return; } mDocumentsToBeDeleted.remove(selection); updateModelData(); notifyUpdateListeners(); } private boolean isDocumentToBeDeleted(String id) { for (Selection s : mDocumentsToBeDeleted) { if (s.contains(id)) { return true; } } return false; } private void updateDocumentsToBeDeleted() { for (Iterator<Selection> i = mDocumentsToBeDeleted.iterator(); i.hasNext();) { Selection selection = i.next(); for (String id : selection) { if (!mPositions.containsKey(id)) { i.remove(); break; } } } } private int getDocumentsToBeDeletedCount() { int count = 0; for (Selection s : mDocumentsToBeDeleted) { count += s.size(); } return count; } @VisibleForTesting @VisibleForTesting public int getItemCount() { public int getItemCount() { return mCursorCount; return mCursorCount - getDocumentsToBeDeletedCount(); } } /** /** Loading @@ -151,9 +199,10 @@ public class Model { * according to the current sort order. * according to the current sort order. */ */ private void updateModelData() { private void updateModelData() { mIds = new String[mCursorCount]; mFileNames.clear(); mFileNames.clear(); mCursor.moveToPosition(-1); mCursor.moveToPosition(-1); mPositions.clear(); String[] tmpIds = new String[mCursorCount]; for (int pos = 0; pos < mCursorCount; ++pos) { for (int pos = 0; pos < mCursorCount; ++pos) { if (!mCursor.moveToNext()) { if (!mCursor.moveToNext()) { Log.e(TAG, "Fail to move cursor to next pos: " + pos); Log.e(TAG, "Fail to move cursor to next pos: " + pos); Loading @@ -164,18 +213,24 @@ public class Model { // If the cursor is a merged cursor over multiple authorities, then prefix the ids // If the cursor is a merged cursor over multiple authorities, then prefix the ids // with the authority to avoid collisions. // with the authority to avoid collisions. if (mCursor instanceof MergeCursor) { if (mCursor instanceof MergeCursor) { mIds[pos] = getCursorString(mCursor, RootCursorWrapper.COLUMN_AUTHORITY) tmpIds[pos] = getCursorString(mCursor, RootCursorWrapper.COLUMN_AUTHORITY) + "|" + getCursorString(mCursor, Document.COLUMN_DOCUMENT_ID); + "|" + getCursorString(mCursor, Document.COLUMN_DOCUMENT_ID); } else { } else { mIds[pos] = getCursorString(mCursor, Document.COLUMN_DOCUMENT_ID); tmpIds[pos] = getCursorString(mCursor, Document.COLUMN_DOCUMENT_ID); } } mPositions.put(tmpIds[pos], pos); mFileNames.add(getCursorString(mCursor, Document.COLUMN_DISPLAY_NAME)); mFileNames.add(getCursorString(mCursor, Document.COLUMN_DISPLAY_NAME)); } } // Populate the positions. updateDocumentsToBeDeleted(); mPositions.clear(); mIds = new String[mCursorCount - getDocumentsToBeDeletedCount()]; int index = 0; for (int i = 0; i < mCursorCount; ++i) { for (int i = 0; i < mCursorCount; ++i) { mPositions.put(mIds[i], i); if (!isDocumentToBeDeleted(tmpIds[i])) { mIds[index] = tmpIds[i]; index++; } } } } } Loading
src/com/android/documentsui/files/ActionHandler.java +61 −38 Original line number Original line Diff line number Diff line Loading @@ -25,11 +25,11 @@ import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentResolver; import android.content.Intent; import android.content.Intent; import android.net.Uri; import android.net.Uri; import android.os.Build; import android.provider.DocumentsContract; import android.provider.DocumentsContract; import android.text.TextUtils; import android.text.TextUtils; import android.util.Log; import android.util.Log; import android.view.DragEvent; import android.view.DragEvent; import android.view.View; import com.android.documentsui.AbstractActionHandler; import com.android.documentsui.AbstractActionHandler; import com.android.documentsui.ActionModeAddons; import com.android.documentsui.ActionModeAddons; Loading @@ -42,8 +42,6 @@ import com.android.documentsui.Metrics; import com.android.documentsui.Model; import com.android.documentsui.Model; import com.android.documentsui.R; import com.android.documentsui.R; import com.android.documentsui.TimeoutTask; import com.android.documentsui.TimeoutTask; import com.android.documentsui.base.ConfirmationCallback; import com.android.documentsui.base.ConfirmationCallback.Result; import com.android.documentsui.base.DebugFlags; import com.android.documentsui.base.DebugFlags; import com.android.documentsui.base.DocumentFilters; import com.android.documentsui.base.DocumentFilters; import com.android.documentsui.base.DocumentInfo; import com.android.documentsui.base.DocumentInfo; Loading @@ -69,11 +67,15 @@ import com.android.documentsui.services.FileOperation; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperations; import com.android.documentsui.services.FileOperations; import com.android.documentsui.ui.DialogController; import com.android.documentsui.ui.DialogController; import com.android.documentsui.ui.Snackbars; import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting; import android.support.design.widget.Snackbar; import java.util.ArrayList; import java.util.ArrayList; import java.util.List; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executor; import java.util.function.Consumer; import javax.annotation.Nullable; import javax.annotation.Nullable; Loading @@ -93,6 +95,8 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa private final DragAndDropManager mDragAndDropManager; private final DragAndDropManager mDragAndDropManager; private final Model mModel; private final Model mModel; private Snackbar mDeletionSnackbar; ActionHandler( ActionHandler( T activity, T activity, State state, State state, Loading Loading @@ -301,17 +305,6 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa final @Nullable DocumentInfo srcParent = mState.stack.peek(); final @Nullable DocumentInfo srcParent = mState.stack.peek(); // Model must be accessed in UI thread, since underlying cursor is not threadsafe. List<DocumentInfo> docs = mModel.getDocuments(selection); ConfirmationCallback result = (@Result int code) -> { // share the news with our caller, be it good or bad. mActionModeAddons.finishOnConfirmed(code); if (code != ConfirmationCallback.CONFIRM) { return; } UrisSupplier srcs; UrisSupplier srcs; try { try { srcs = UrisSupplier.create( srcs = UrisSupplier.create( Loading @@ -326,7 +319,16 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa selection.size()); selection.size()); return; return; } } mModel.markDocumentsToBeDeleted(selection); Consumer<View> action = v -> { Metrics.logUserAction(mActivity, Metrics.USER_ACTION_UNDO_DELETE); mModel.restoreDocumentsToBeDeleted(selection); }; Snackbar.Callback callback = new Snackbar.Callback() { @Override public void onDismissed(Snackbar snackbar, int event) { super.onDismissed(snackbar, event); if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) { FileOperation operation = new FileOperation.Builder() FileOperation operation = new FileOperation.Builder() .withOpType(FileOperationService.OPERATION_DELETE) .withOpType(FileOperationService.OPERATION_DELETE) .withDestination(mState.stack) .withDestination(mState.stack) Loading @@ -334,11 +336,26 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa .withSrcParent(srcParent == null ? null : srcParent.derivedUri) .withSrcParent(srcParent == null ? null : srcParent.derivedUri) .build(); .build(); FileOperations.start(mActivity, operation, mDialogs::showFileOperationStatus, FileOperations.start(mActivity, operation, null, FileOperations.createJobId()); FileOperations.createJobId()); } if (mDeletionSnackbar == snackbar) { mDeletionSnackbar = null; } } }; }; mDeletionSnackbar = showDeletionSnackbar(mActivity, selection.size(), action, callback); } public Snackbar showDeletionSnackbar(Activity activity, int docCount, Consumer<View> action, Snackbar.Callback callback) { return Snackbars.showDelete(mActivity, docCount, action, callback); } mDialogs.confirmDelete(docs, result); public void dismissDeletionSnackBar() { if (mDeletionSnackbar != null) { mDeletionSnackbar.dismiss(); } } } @Override @Override Loading Loading @@ -393,6 +410,12 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa mActivity.startActivity(chooserIntent); mActivity.startActivity(chooserIntent); } } @Override public void loadDocumentsForCurrentStack() { dismissDeletionSnackBar(); super.loadDocumentsForCurrentStack(); } @Override @Override public void initLocation(Intent intent) { public void initLocation(Intent intent) { assert(intent != null); assert(intent != null); Loading