summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author shawnlin <shawnlin@google.com> 2018-10-16 16:20:42 +0800
committer shawnlin <shawnlin@google.com> 2018-10-16 20:26:55 +0800
commit48200cdc95f31c65feb856260ac532e6a42510f5 (patch)
treec146eeb51d423fb9969d472ebfdbb2ce8175a03d
parentd6a692ffc40fa4259e05ebfa906a21011fd804bf (diff)
Roll back delete/undo feature to dialog style
Bug: 111863032 Test: atest DocumentsUITests Change-Id: I03af16932548c10a9d69208ad7c25e9044863f28
-rw-r--r--res/layout/dialog_delete_confirmation.xml3
-rw-r--r--src/com/android/documentsui/ActionModeAddons.java2
-rw-r--r--src/com/android/documentsui/ActionModeController.java9
-rw-r--r--src/com/android/documentsui/Metrics.java4
-rw-r--r--src/com/android/documentsui/Model.java104
-rw-r--r--src/com/android/documentsui/files/ActionHandler.java122
-rw-r--r--src/com/android/documentsui/files/FilesActivity.java6
-rw-r--r--src/com/android/documentsui/services/DeleteJob.java57
-rw-r--r--src/com/android/documentsui/services/FileOperation.java2
-rw-r--r--src/com/android/documentsui/ui/DialogController.java42
-rw-r--r--src/com/android/documentsui/ui/Snackbars.java12
-rw-r--r--tests/common/com/android/documentsui/TestActionModeAddons.java8
-rw-r--r--tests/common/com/android/documentsui/ui/TestDialogController.java19
-rw-r--r--tests/functional/com/android/documentsui/FileDeleteUiTest.java18
-rw-r--r--tests/functional/com/android/documentsui/FileManagementUiTest.java10
-rw-r--r--tests/functional/com/android/documentsui/FileUndoDeletionUiTest.java116
-rw-r--r--tests/unit/com/android/documentsui/ModelTest.java46
-rw-r--r--tests/unit/com/android/documentsui/files/ActionHandlerTest.java42
-rw-r--r--tests/unit/com/android/documentsui/picker/ActionHandlerTest.java2
-rw-r--r--tests/unit/com/android/documentsui/services/DeleteJobTest.java90
20 files changed, 150 insertions, 564 deletions
diff --git a/res/layout/dialog_delete_confirmation.xml b/res/layout/dialog_delete_confirmation.xml
index cd4d537ce..501736cec 100644
--- a/res/layout/dialog_delete_confirmation.xml
+++ b/res/layout/dialog_delete_confirmation.xml
@@ -21,6 +21,5 @@
android:paddingTop="24dp"
android:paddingStart="24dp"
android:paddingEnd="24dp"
- android:textAppearance="@android:style/TextAppearance.Material.Subhead"
- android:textColor="@color/dialog_title">
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead">
</TextView>
diff --git a/src/com/android/documentsui/ActionModeAddons.java b/src/com/android/documentsui/ActionModeAddons.java
index ef8ae1999..83eba78bb 100644
--- a/src/com/android/documentsui/ActionModeAddons.java
+++ b/src/com/android/documentsui/ActionModeAddons.java
@@ -21,4 +21,6 @@ package com.android.documentsui;
public interface ActionModeAddons {
void finishActionMode();
+
+ void finishOnConfirmed(int code);
}
diff --git a/src/com/android/documentsui/ActionModeController.java b/src/com/android/documentsui/ActionModeController.java
index 8b74dbf5a..8ef20c4fb 100644
--- a/src/com/android/documentsui/ActionModeController.java
+++ b/src/com/android/documentsui/ActionModeController.java
@@ -29,6 +29,8 @@ import android.view.MenuItem;
import android.view.View;
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.Menus;
import com.android.documentsui.ui.MessageBuilder;
@@ -184,6 +186,13 @@ public class ActionModeController extends SelectionObserver<String>
}
}
+ @Override
+ public void finishOnConfirmed(@Result int code) {
+ if (code == ConfirmationCallback.CONFIRM) {
+ finishActionMode();
+ }
+ }
+
public ActionModeController reset(
SelectionDetails selectionDetails, EventHandler<MenuItem> menuItemClicker) {
assert(mActionMode == null);
diff --git a/src/com/android/documentsui/Metrics.java b/src/com/android/documentsui/Metrics.java
index 12df0bf1d..838ebf8b7 100644
--- a/src/com/android/documentsui/Metrics.java
+++ b/src/com/android/documentsui/Metrics.java
@@ -318,7 +318,6 @@ public final class Metrics {
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_INSPECTOR = 30;
- public static final int USER_ACTION_UNDO_DELETE = 31;
@IntDef(flag = false, value = {
USER_ACTION_OTHER,
@@ -350,8 +349,7 @@ public final class Metrics {
USER_ACTION_COMPRESS,
USER_ACTION_EXTRACT_TO,
USER_ACTION_VIEW_IN_APPLICATION,
- USER_ACTION_INSPECTOR,
- USER_ACTION_UNDO_DELETE
+ USER_ACTION_INSPECTOR
})
@Retention(RetentionPolicy.SOURCE)
public @interface UserAction {}
diff --git a/src/com/android/documentsui/Model.java b/src/com/android/documentsui/Model.java
index f2de80228..afc85467b 100644
--- a/src/com/android/documentsui/Model.java
+++ b/src/com/android/documentsui/Model.java
@@ -43,7 +43,6 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -72,8 +71,6 @@ public class Model {
private @Nullable Cursor mCursor;
private int mCursorCount;
private String mIds[] = new String[0];
- private Set<Selection<String>> mDocumentsToBeDeleted = new HashSet<>();
- private HashMap<Integer, ArrayList<String>> mDeletionFailedDocIds = new HashMap<>();
public Model(Features features) {
mFeatures = features;
@@ -110,8 +107,6 @@ public class Model {
doc = null;
mIsLoading = false;
mFileNames.clear();
- mDocumentsToBeDeleted.clear();
- mDeletionFailedDocIds.clear();
notifyUpdateListeners();
}
@@ -143,89 +138,9 @@ public class Model {
notifyUpdateListeners();
}
- public void markDocumentsToBeDeleted(Selection<String> selection) {
- if (mDocumentsToBeDeleted.contains(selection)) {
- return;
- }
- mDocumentsToBeDeleted.add(selection);
- updateModelData();
- notifyUpdateListeners();
- }
-
- public void clearDocumentsToBeDeleted(Selection<String> selection) {
- if (!mDocumentsToBeDeleted.contains(selection)) {
- return;
- }
- mDocumentsToBeDeleted.remove(selection);
- updateModelData();
- notifyUpdateListeners();
- }
-
- public void setDeletionFailedUris(Selection<String> selection,
- ArrayList<Uri> deletionFailedUris) {
- if (!mDocumentsToBeDeleted.contains(selection)) {
- return;
- }
-
- mDeletionFailedDocIds.put(selection.hashCode(), ModelId.build(deletionFailedUris));
- updateModelData();
- notifyUpdateListeners();
- }
-
- private void updateDocumentsToBeDeleted() {
- for (Iterator<Selection<String>> i = mDocumentsToBeDeleted.iterator(); i.hasNext();) {
- Selection<String> selection = i.next();
- int size = selection.size();
- ArrayList<String> failedDocIds = mDeletionFailedDocIds.get(selection.hashCode());
- for (String id : selection) {
- // Check whether the id is in the current cursor or in the deletion failed list.
- // If all ids are either not in the current cursor or in the deletion failed list,
- // it means the deletion of this selection is done, and we can clear this selection.
- if (!mPositions.containsKey(id) ||
- (failedDocIds != null && failedDocIds.contains(id))) {
- size--;
- }
- if (size == 0) {
- i.remove();
- mDeletionFailedDocIds.remove(selection.hashCode());
- break;
- }
- }
- }
- }
-
- private int getVisibleCount() {
- int count = mPositions.size();
- for (Selection<String> selection : mDocumentsToBeDeleted) {
- for (String id : selection) {
- if (mPositions.containsKey(id)) {
- count--;
- }
- }
- }
- return count;
- }
-
- private boolean isDocumentToBeDeleted(String id) {
- for (Selection<String> s : mDocumentsToBeDeleted) {
- if (s.contains(id)) {
- return true;
- }
- }
- return false;
- }
-
- private int getDocumentsToBeDeletedCount() {
- int count = 0;
- for (Selection<String> s : mDocumentsToBeDeleted) {
- count += s.size();
- }
- return count;
- }
-
@VisibleForTesting
public int getItemCount() {
- return mCursorCount - getDocumentsToBeDeletedCount();
+ return mCursorCount;
}
/**
@@ -233,10 +148,9 @@ public class Model {
* according to the current sort order.
*/
private void updateModelData() {
+ mIds = new String[mCursorCount];
mFileNames.clear();
mCursor.moveToPosition(-1);
- mPositions.clear();
- String[] tmpIds = new String[mCursorCount];
for (int pos = 0; pos < mCursorCount; ++pos) {
if (!mCursor.moveToNext()) {
Log.e(TAG, "Fail to move cursor to next pos: " + pos);
@@ -245,20 +159,14 @@ public class Model {
// Generates a Model ID for a cursor entry that refers to a document. The Model ID is a
// unique string that can be used to identify the document referred to by the cursor.
// Prefix the ids with the authority to avoid collisions.
- tmpIds[pos] = ModelId.build(mCursor);
- mPositions.put(tmpIds[pos], pos);
+ mIds[pos] = ModelId.build(mCursor);
mFileNames.add(getCursorString(mCursor, Document.COLUMN_DISPLAY_NAME));
}
- updateDocumentsToBeDeleted();
-
- mIds = new String[getVisibleCount()];
- int index = 0;
+ // Populate the positions.
+ mPositions.clear();
for (int i = 0; i < mCursorCount; ++i) {
- if (!isDocumentToBeDeleted(tmpIds[i])) {
- mIds[index] = tmpIds[i];
- index++;
- }
+ mPositions.put(mIds[i], i);
}
}
diff --git a/src/com/android/documentsui/files/ActionHandler.java b/src/com/android/documentsui/files/ActionHandler.java
index b8b35a08e..69319d325 100644
--- a/src/com/android/documentsui/files/ActionHandler.java
+++ b/src/com/android/documentsui/files/ActionHandler.java
@@ -25,13 +25,10 @@ import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
import android.provider.DocumentsContract;
import android.text.TextUtils;
import android.util.Log;
import android.view.DragEvent;
-import android.view.View;
import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
import androidx.recyclerview.selection.MutableSelection;
@@ -48,6 +45,7 @@ import com.android.documentsui.Metrics;
import com.android.documentsui.Model;
import com.android.documentsui.R;
import com.android.documentsui.TimeoutTask;
+import com.android.documentsui.base.ConfirmationCallback;
import com.android.documentsui.base.DebugFlags;
import com.android.documentsui.base.DocumentFilters;
import com.android.documentsui.base.DocumentInfo;
@@ -66,21 +64,16 @@ import com.android.documentsui.files.ActionHandler.Addons;
import com.android.documentsui.inspector.InspectorActivity;
import com.android.documentsui.queries.SearchViewManager;
import com.android.documentsui.roots.ProvidersAccess;
-import com.android.documentsui.services.DeleteJob;
import com.android.documentsui.services.FileOperation;
import com.android.documentsui.services.FileOperationService;
import com.android.documentsui.services.FileOperations;
import com.android.documentsui.ui.DialogController;
-import com.android.documentsui.ui.Snackbars;
-
-import com.google.android.material.snackbar.Snackbar;
import androidx.annotation.VisibleForTesting;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
-import java.util.function.Consumer;
import javax.annotation.Nullable;
@@ -100,8 +93,6 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
private final DragAndDropManager mDragAndDropManager;
private final Model mModel;
- private Snackbar mDeletionSnackbar;
-
ActionHandler(
T activity,
State state,
@@ -302,7 +293,7 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
@Override
public void deleteSelectedDocuments() {
Metrics.logUserAction(mActivity, Metrics.USER_ACTION_DELETE);
- final Selection<String> selection = getSelectedOrFocused();
+ Selection selection = getSelectedOrFocused();
if (selection.isEmpty()) {
return;
@@ -310,82 +301,44 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
final @Nullable DocumentInfo srcParent = mState.stack.peek();
- UrisSupplier srcs;
- try {
- srcs = UrisSupplier.create(
- selection,
- mModel::getItemUri,
- mClipStore);
- } catch (Exception e) {
- Log.e(TAG, "Failed to delete a file because we were unable to get item URIs.", e);
- mDialogs.showFileOperationStatus(
- FileOperations.Callback.STATUS_FAILED,
- FileOperationService.OPERATION_DELETE,
- selection.size());
- return;
- }
- mModel.markDocumentsToBeDeleted(selection);
- Consumer<View> action = v -> {
- Metrics.logUserAction(mActivity, Metrics.USER_ACTION_UNDO_DELETE);
- mModel.clearDocumentsToBeDeleted(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()
- .withOpType(FileOperationService.OPERATION_DELETE)
- .withDestination(mState.stack)
- .withSrcs(srcs)
- .withSrcParent(srcParent == null ? null : srcParent.derivedUri)
- .build();
- operation.addMessageListener(new Handler.Callback() {
- @Override
- public boolean handleMessage(Message message) {
- if (message.what == FileOperationService.MESSAGE_FINISH) {
- operation.removeMessageListener(this);
-
- // If failure count equals selection size,
- // it means all deletions failed. Just clear the selection.
- final int failureCount = message.arg1;
- if (failureCount == selection.size()) {
- mModel.clearDocumentsToBeDeleted(selection);
- return true;
- }
-
- ArrayList<Uri> failureUris = message.getData()
- .getParcelableArrayList(DeleteJob.KEY_FAILED_URIS);
- if (failureUris != null) {
- mModel.setDeletionFailedUris(selection, failureUris);
- }
- return true;
- }
- return false;
- }
- });
- FileOperations.start(mActivity, operation, null, FileOperations.createJobId());
- }
- if (mDeletionSnackbar == snackbar) {
- mDeletionSnackbar = null;
- }
- if (snackbar != null) {
- snackbar.removeCallback(this);
- }
+ // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
+ List<DocumentInfo> docs = mModel.getDocuments(selection);
+
+ ConfirmationCallback result = (@ConfirmationCallback.Result int code) -> {
+ // share the news with our caller, be it good or bad.
+ mActionModeAddons.finishOnConfirmed(code);
+
+ if (code != ConfirmationCallback.CONFIRM) {
+ return;
}
- };
- 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);
- }
+ UrisSupplier srcs;
+ try {
+ srcs = UrisSupplier.create(
+ selection,
+ mModel::getItemUri,
+ mClipStore);
+ } catch (Exception e) {
+ Log.e(TAG,"Failed to delete a file because we were unable to get item URIs.", e);
+ mDialogs.showFileOperationStatus(
+ FileOperations.Callback.STATUS_FAILED,
+ FileOperationService.OPERATION_DELETE,
+ selection.size());
+ return;
+ }
- public void dismissDeletionSnackBar() {
- if (mDeletionSnackbar != null) {
- mDeletionSnackbar.dismiss();
- }
+ FileOperation operation = new FileOperation.Builder()
+ .withOpType(FileOperationService.OPERATION_DELETE)
+ .withDestination(mState.stack)
+ .withSrcs(srcs)
+ .withSrcParent(srcParent == null ? null : srcParent.derivedUri)
+ .build();
+
+ FileOperations.start(mActivity, operation, mDialogs::showFileOperationStatus,
+ FileOperations.createJobId());
+ };
+
+ mDialogs.confirmDelete(docs, result);
}
@Override
@@ -442,7 +395,6 @@ public class ActionHandler<T extends Activity & Addons> extends AbstractActionHa
@Override
public void loadDocumentsForCurrentStack() {
- dismissDeletionSnackBar();
super.loadDocumentsForCurrentStack();
}
diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java
index c07deb6ed..5db68344c 100644
--- a/src/com/android/documentsui/files/FilesActivity.java
+++ b/src/com/android/documentsui/files/FilesActivity.java
@@ -262,12 +262,6 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons
}
@Override
- protected void onPause() {
- super.onPause();
- mInjector.actions.dismissDeletionSnackBar();
- }
-
- @Override
public String getDrawerTitle() {
Intent intent = getIntent();
return (intent != null && intent.hasExtra(Intent.EXTRA_TITLE))
diff --git a/src/com/android/documentsui/services/DeleteJob.java b/src/com/android/documentsui/services/DeleteJob.java
index c8b302b75..82c6e1301 100644
--- a/src/com/android/documentsui/services/DeleteJob.java
+++ b/src/com/android/documentsui/services/DeleteJob.java
@@ -17,7 +17,6 @@
package com.android.documentsui.services;
import static com.android.documentsui.base.SharedMinimal.DEBUG;
-import static com.android.documentsui.services.FileOperationService.MESSAGE_FINISH;
import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
import android.app.Notification;
@@ -25,10 +24,6 @@ import android.app.Notification.Builder;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
-import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
import android.util.Log;
import com.android.documentsui.Metrics;
@@ -39,25 +34,17 @@ import com.android.documentsui.base.Features;
import com.android.documentsui.clipping.UrisSupplier;
import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
import javax.annotation.Nullable;
-public final class DeleteJob extends ResolvedResourcesJob {
+final class DeleteJob extends ResolvedResourcesJob {
private static final String TAG = "DeleteJob";
- public final static String KEY_FAILED_URIS = "deletion_failed_uris";
-
private final Uri mParentUri;
private volatile int mDocsProcessed = 0;
- private final Messenger mMessenger;
-
- private final ArrayList<Uri> mDeletionFailedUris = new ArrayList<>();
-
/**
* Moves files to a destination identified by {@code destination}.
* Performs most work by delegating to CopyJob, then deleting
@@ -66,25 +53,9 @@ public final class DeleteJob extends ResolvedResourcesJob {
* @see @link {@link Job} constructor for most param descriptions.
*/
DeleteJob(Context service, Listener listener, String id, DocumentStack stack,
- UrisSupplier srcs, Messenger messenger, @Nullable Uri srcParent, Features features) {
+ UrisSupplier srcs, @Nullable Uri srcParent, Features features) {
super(service, listener, id, OPERATION_DELETE, stack, srcs, features);
mParentUri = srcParent;
- mMessenger = messenger;
- initDeletionFailedUrisList();
- }
-
- private void initDeletionFailedUrisList() {
- Iterable<Uri> uris;
- try {
- uris = mResourceUris.getUris(appContext);
- } catch (IOException e) {
- Log.e(TAG, "Failed to read list of target resource Uris.", e);
- failureCount = this.mResourceUris.getItemCount();
- return;
- }
- for (Uri uri : uris) {
- mDeletionFailedUris.add(uri);
- }
}
@Override
@@ -143,7 +114,6 @@ public final class DeleteJob extends ResolvedResourcesJob {
if (DEBUG) Log.d(TAG, "Deleting document @ " + doc.derivedUri);
try {
deleteDocument(doc, parentDoc);
- mDeletionFailedUris.remove(doc.derivedUri);
} catch (ResourceException e) {
Metrics.logFileOperationFailure(
appContext, Metrics.SUBFILEOP_DELETE_DOCUMENT, doc.derivedUri);
@@ -161,29 +131,6 @@ public final class DeleteJob extends ResolvedResourcesJob {
}
@Override
- void finish() {
- super.finish();
- try {
- Message message = Message.obtain();
- message.what = MESSAGE_FINISH;
- // If the size of mDeletionFailedUris is 0, it means either 1). all deletions succeeded
- // or 2). reading all uris from mResourceUris failed. For case 2). We also need to check
- // the failureCount to get the correct count.
- message.arg1 = mDeletionFailedUris.size() == 0
- ? (failureCount == mResourceUris.getItemCount() ? failureCount : 0)
- : mDeletionFailedUris.size();
- if (message.arg1 > 0 && message.arg1 < mResourceUris.getItemCount()) {
- Bundle b = new Bundle();
- b.putParcelableArrayList(KEY_FAILED_URIS, mDeletionFailedUris);
- message.setData(b);
- }
- mMessenger.send(message);
- } catch (RemoteException e) {
- // Ignore. Most likely the frontend was killed.
- }
- }
-
- @Override
public String toString() {
return new StringBuilder()
.append("DeleteJob")
diff --git a/src/com/android/documentsui/services/FileOperation.java b/src/com/android/documentsui/services/FileOperation.java
index 9ff16543d..29393a81e 100644
--- a/src/com/android/documentsui/services/FileOperation.java
+++ b/src/com/android/documentsui/services/FileOperation.java
@@ -261,7 +261,7 @@ public abstract class FileOperation implements Parcelable {
getMessenger(), features);
case OPERATION_DELETE:
return new DeleteJob(service, listener, id, getDestination(), getSrc(),
- getMessenger(), mSrcParent, features);
+ mSrcParent, features);
default:
throw new UnsupportedOperationException("Unsupported op type: " + getOpType());
}
diff --git a/src/com/android/documentsui/ui/DialogController.java b/src/com/android/documentsui/ui/DialogController.java
index c831052e2..6b46ea41e 100644
--- a/src/com/android/documentsui/ui/DialogController.java
+++ b/src/com/android/documentsui/ui/DialogController.java
@@ -25,6 +25,7 @@ import android.widget.TextView;
import com.google.android.material.snackbar.Snackbar;
import com.android.documentsui.R;
+import com.android.documentsui.base.ConfirmationCallback;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.base.Features;
import com.android.documentsui.picker.OverwriteConfirmFragment;
@@ -38,6 +39,8 @@ import java.util.List;
public interface DialogController {
+ // Dialogs used in FilesActivity
+ void confirmDelete(List<DocumentInfo> docs, ConfirmationCallback callback);
void showFileOperationStatus(int status, int opType, int docCount);
/**
@@ -69,6 +72,42 @@ public interface DialogController {
}
@Override
+ public void confirmDelete(List<DocumentInfo> docs, ConfirmationCallback callback) {
+ assert(!docs.isEmpty());
+
+ TextView message =
+ (TextView) mActivity.getLayoutInflater().inflate(
+ R.layout.dialog_delete_confirmation, null);
+ message.setText(mMessages.generateDeleteMessage(docs));
+
+ // For now, we implement this dialog NOT
+ // as a fragment (which can survive rotation and have its own state),
+ // but as a simple runtime dialog. So rotating a device with an
+ // active delete dialog...results in that dialog disappearing.
+ // We can do better, but don't have cycles for it now.
+ final AlertDialog alertDialog = new AlertDialog.Builder(mActivity)
+ .setView(message)
+ .setPositiveButton(
+ android.R.string.ok,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ callback.accept(ConfirmationCallback.CONFIRM);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+
+ alertDialog.setOnShowListener(
+ (DialogInterface) -> {
+ Button positive = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
+ positive.setFocusable(true);
+ positive.requestFocus();
+ });
+ alertDialog.show();
+ }
+
+ @Override
public void showFileOperationStatus(@Status int status, @OpType int opType, int docCount) {
if (status == FileOperations.Callback.STATUS_REJECTED) {
showOperationUnsupported();
@@ -103,6 +142,9 @@ public interface DialogController {
case FileOperationService.OPERATION_EXTRACT:
Snackbars.showExtract(mActivity, docCount);
break;
+ case FileOperationService.OPERATION_DELETE:
+ Snackbars.showDelete(mActivity, docCount);
+ break;
default:
throw new UnsupportedOperationException("Unsupported Operation: " + opType);
}
diff --git a/src/com/android/documentsui/ui/Snackbars.java b/src/com/android/documentsui/ui/Snackbars.java
index eb6547da7..26b4307c8 100644
--- a/src/com/android/documentsui/ui/Snackbars.java
+++ b/src/com/android/documentsui/ui/Snackbars.java
@@ -18,8 +18,6 @@ package com.android.documentsui.ui;
import androidx.annotation.StringRes;
import android.app.Activity;
-import android.content.res.TypedArray;
-import android.graphics.Color;
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;
@@ -32,7 +30,6 @@ import com.android.documentsui.base.Shared;
import java.util.function.Consumer;
public final class Snackbars {
- public static final int DELETION_TIMEOUT = 10000;
private Snackbars() {}
@@ -62,14 +59,9 @@ public final class Snackbars {
makeSnackbar(activity, message, Snackbar.LENGTH_SHORT).show();
}
- public static final Snackbar showDelete(Activity activity, int docCount, Consumer<View> action,
- Snackbar.Callback callback) {
+ public static final void showDelete(Activity activity, int docCount) {
CharSequence message = Shared.getQuantityString(activity, R.plurals.deleting, docCount);
- CharSequence actionText = activity.getResources().getText(R.string.undo);
- Snackbar snackbar = makeSnackbarWithAction(activity, docCount, message, DELETION_TIMEOUT,
- actionText, action, callback);
- snackbar.show();
- return snackbar;
+ makeSnackbar(activity, message, Snackbar.LENGTH_SHORT).show();
}
public static final void showOperationRejected(Activity activity) {
diff --git a/tests/common/com/android/documentsui/TestActionModeAddons.java b/tests/common/com/android/documentsui/TestActionModeAddons.java
index c928d6f23..5379bbb4c 100644
--- a/tests/common/com/android/documentsui/TestActionModeAddons.java
+++ b/tests/common/com/android/documentsui/TestActionModeAddons.java
@@ -15,12 +15,20 @@
*/
package com.android.documentsui;
+import com.android.documentsui.testing.TestConfirmationCallback;
+
public class TestActionModeAddons implements ActionModeAddons {
public boolean finishActionModeCalled;
+ public final TestConfirmationCallback finishOnConfirmed = new TestConfirmationCallback();
@Override
public void finishActionMode() {
finishActionModeCalled = true;
}
+
+ @Override
+ public void finishOnConfirmed(int code) {
+ finishOnConfirmed.accept(code);
+ }
}
diff --git a/tests/common/com/android/documentsui/ui/TestDialogController.java b/tests/common/com/android/documentsui/ui/TestDialogController.java
index d87cd0c80..3bd6db6fb 100644
--- a/tests/common/com/android/documentsui/ui/TestDialogController.java
+++ b/tests/common/com/android/documentsui/ui/TestDialogController.java
@@ -17,15 +17,19 @@ package com.android.documentsui.ui;
import android.app.FragmentManager;
+import com.android.documentsui.base.ConfirmationCallback;
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.services.FileOperation;
import com.android.documentsui.services.FileOperations;
import junit.framework.Assert;
+import java.util.List;
+
public class TestDialogController implements DialogController {
+ public int mNextConfirmationCode;
private int mFileOpStatus;
private boolean mNoApplicationFound;
private boolean mDocumentsClipped;
@@ -34,6 +38,13 @@ public class TestDialogController implements DialogController {
private DocumentInfo mOverwriteTarget;
public TestDialogController() {
+ // by default, always confirm
+ mNextConfirmationCode = ConfirmationCallback.CONFIRM;
+ }
+
+ @Override
+ public void confirmDelete(List<DocumentInfo> docs, ConfirmationCallback callback) {
+ callback.accept(mNextConfirmationCode);
}
@Override
@@ -97,4 +108,12 @@ public class TestDialogController implements DialogController {
public void assertOverwriteConfirmed(DocumentInfo expected) {
Assert.assertEquals(expected, mOverwriteTarget);
}
+
+ public void confirmNext() {
+ mNextConfirmationCode = ConfirmationCallback.CONFIRM;
+ }
+
+ public void rejectNext() {
+ mNextConfirmationCode = ConfirmationCallback.REJECT;
+ }
}
diff --git a/tests/functional/com/android/documentsui/FileDeleteUiTest.java b/tests/functional/com/android/documentsui/FileDeleteUiTest.java
index b86e417ac..fbeaf3463 100644
--- a/tests/functional/com/android/documentsui/FileDeleteUiTest.java
+++ b/tests/functional/com/android/documentsui/FileDeleteUiTest.java
@@ -155,16 +155,16 @@ public class FileDeleteUiTest extends ActivityTest<FilesActivity> {
exec.shutdown();
}
- public void testDeleteAllDocument_AfterSnackbarDismissed() throws Exception {
+ public void testDeleteAllDocument() throws Exception {
bots.roots.openRoot(ROOT_0_ID);
bots.main.clickToolbarOverflowItem(
context.getResources().getString(R.string.menu_select_all));
device.waitForIdle();
bots.main.clickToolbarItem(R.id.action_menu_delete);
+ bots.main.clickDialogOkButton();
device.waitForIdle();
- bots.directory.waitForDeleteSnackbarGone();
try {
mCountDownLatch.await(WAIT_TIME_SECONDS, TimeUnit.SECONDS);
} catch (Exception e) {
@@ -179,18 +179,4 @@ public class FileDeleteUiTest extends ActivityTest<FilesActivity> {
List<DocumentInfo> root1 = mDocsHelper.listChildren(rootDir0.documentId, 1000);
assertTrue("Delete operation was not completed", root1.size() == 0);
}
-
- public void testDeleteAllDocument_BeforeSnackbarDismissed() throws Exception {
- bots.roots.openRoot(ROOT_0_ID);
- bots.main.clickToolbarOverflowItem(
- context.getResources().getString(R.string.menu_select_all));
- device.waitForIdle();
-
- bots.main.clickToolbarItem(R.id.action_menu_delete);
- device.waitForIdle();
-
- bots.directory.waitForDeleteSnackbar();
- List<DocumentInfo> root1 = mDocsHelper.listChildren(rootDir0.documentId, 1000);
- assertTrue("Documents are deleted", root1.size() == 1000);
- }
}
diff --git a/tests/functional/com/android/documentsui/FileManagementUiTest.java b/tests/functional/com/android/documentsui/FileManagementUiTest.java
index 0cdab9d80..5157ec331 100644
--- a/tests/functional/com/android/documentsui/FileManagementUiTest.java
+++ b/tests/functional/com/android/documentsui/FileManagementUiTest.java
@@ -81,7 +81,7 @@ public class FileManagementUiTest extends ActivityTest<FilesActivity> {
device.waitForIdle();
bots.main.clickToolbarItem(R.id.action_menu_delete);
- bots.directory.waitForDeleteSnackbarGone();
+ bots.main.clickDialogOkButton();
device.waitForIdle();
bots.directory.assertDocumentsAbsent("file1.png");
@@ -120,16 +120,12 @@ public class FileManagementUiTest extends ActivityTest<FilesActivity> {
bots.directory.waitForDocument("file1.png");
}
- public void testDeleteDocument_Undo() throws Exception {
+ public void testDeleteDocument_Cancel() throws Exception {
bots.directory.selectDocument("file1.png");
device.waitForIdle();
bots.main.clickToolbarItem(R.id.action_menu_delete);
- bots.directory.waitForDeleteSnackbar();
- device.waitForIdle();
-
- bots.directory.clickSnackbarAction();
- device.waitForIdle();
+ bots.main.clickDialogCancelButton();
bots.directory.waitForDocument("file1.png");
}
diff --git a/tests/functional/com/android/documentsui/FileUndoDeletionUiTest.java b/tests/functional/com/android/documentsui/FileUndoDeletionUiTest.java
deleted file mode 100644
index 49b8110dc..000000000
--- a/tests/functional/com/android/documentsui/FileUndoDeletionUiTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.documentsui;
-
-import static com.android.documentsui.StubProvider.ROOT_0_ID;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.provider.DocumentsContract;
-import android.support.test.filters.LargeTest;
-import android.support.test.uiautomator.UiObject;
-import android.util.Log;
-
-import com.android.documentsui.base.DocumentInfo;
-import com.android.documentsui.files.FilesActivity;
-import com.android.documentsui.services.TestNotificationService;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
-* This class test the below points
-* - Undo the deleted files
-*/
-@LargeTest
-public class FileUndoDeletionUiTest extends ActivityTest<FilesActivity> {
- private static final String TAG = "FileUndoDeletionUiTest";
-
- private static final int DUMMY_FILE_COUNT = 3;
-
- private String[] filenames = new String[DUMMY_FILE_COUNT];
-
- public FileUndoDeletionUiTest() {
- super(FilesActivity.class);
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- // Set a flag to prevent many refreshes.
- Bundle bundle = new Bundle();
- bundle.putBoolean(StubProvider.EXTRA_ENABLE_ROOT_NOTIFICATION, false);
- mDocsHelper.configure(null, bundle);
-
- initTestFiles();
- }
-
- @Override
- public void initTestFiles() {
- for (int i = 0; i < DUMMY_FILE_COUNT; i++) {
- filenames[i] = "file" + i + ".log";
- mDocsHelper.createDocument(rootDir0, "text/plain", filenames[i]);
- }
- }
-
- public void testDeleteUndoDocumentsUI() throws Exception {
- bots.roots.openRoot(ROOT_0_ID);
- bots.main.clickToolbarOverflowItem(
- context.getResources().getString(R.string.menu_select_all));
- device.waitForIdle();
-
- bots.main.clickToolbarItem(R.id.action_menu_delete);
- device.waitForIdle();
-
- bots.directory.waitForDeleteSnackbar();
- for (String filename : filenames) {
- assertFalse("files are not deleted", bots.directory.hasDocuments(filename));
- }
-
- bots.directory.clickSnackbarAction();
- device.waitForIdle();
-
- assertTrue("deleted files are not restored", bots.directory.hasDocuments(filenames));
- }
-
- public void testSelectionStateAfterDeleteUndo() throws Exception {
- bots.roots.openRoot(ROOT_0_ID);
- bots.directory.selectDocument("file1.log");
- device.waitForIdle();
-
- bots.main.clickToolbarItem(R.id.action_menu_delete);
- device.waitForIdle();
-
- bots.directory.waitForDeleteSnackbar();
-
- bots.directory.clickSnackbarAction();
- device.waitForIdle();
-
- assertFalse("the file after deleting/undo is still selected",
- bots.directory.isDocumentSelected("file1.log"));
- }
-}
diff --git a/tests/unit/com/android/documentsui/ModelTest.java b/tests/unit/com/android/documentsui/ModelTest.java
index 7d46f189d..8d3a33ba2 100644
--- a/tests/unit/com/android/documentsui/ModelTest.java
+++ b/tests/unit/com/android/documentsui/ModelTest.java
@@ -22,13 +22,10 @@ import static junit.framework.Assert.fail;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.MergeCursor;
-import android.net.Uri;
import android.provider.DocumentsContract.Document;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import androidx.recyclerview.selection.MutableSelection;
-
import com.android.documentsui.base.DocumentInfo;
import com.android.documentsui.roots.RootCursorWrapper;
import com.android.documentsui.testing.TestEventListener;
@@ -38,10 +35,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.BitSet;
-import java.util.List;
import java.util.Random;
@RunWith(AndroidJUnit4.class)
@@ -186,44 +180,4 @@ public class ModelTest {
assertEquals(0, model.getItemCount());
}
-
- @Test
- public void testDeletion_showFailedItem() {
- // set all items to be deleted.
- List<String> idsTobeDeleted = Arrays.asList(model.getModelIds());
- MutableSelection<String> selection = new MutableSelection<>();
- for (String id : idsTobeDeleted) {
- selection.add(id);
- }
-
- // set the first item as the deletion failed one.
- String failedId = idsTobeDeleted.get(0);
- ArrayList<Uri> failedUris = new ArrayList<>();
- failedUris.add(model.getItemUri(failedId));
-
- // mark items to be deleted
- model.markDocumentsToBeDeleted(selection);
- String[] ids = model.getModelIds();
- assertEquals(0, ids.length);
-
- // simulate deletion but keep the failed item.
- cursor.moveToFirst();
- MatrixCursor c = new MatrixCursor(COLUMNS);
- MatrixCursor.RowBuilder row = c.newRow();
- row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
- row.add(Document.COLUMN_DOCUMENT_ID, 0);
- row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE);
- row.add(Document.COLUMN_DISPLAY_NAME, NAMES[0]);
- row.add(Document.COLUMN_SIZE, cursor.getColumnIndex(Document.COLUMN_SIZE));
- DirectoryResult r = new DirectoryResult();
- r.cursor = c;
- model.update(r);
-
- // simulate receiving failed uris
- model.setDeletionFailedUris(selection, failedUris);
- ids = model.getModelIds();
-
- assertEquals(1, ids.length);
- assertEquals(failedId, ids[0]);
- }
}
diff --git a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
index 805fade2c..24f8d7d85 100644
--- a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
@@ -29,10 +29,6 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyObject;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.spy;
import android.app.Activity;
import android.app.PendingIntent;
@@ -47,9 +43,6 @@ import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.Pair;
import android.view.DragEvent;
-import android.view.View;
-
-import com.google.android.material.snackbar.Snackbar;
import com.android.documentsui.AbstractActionHandler;
import com.android.documentsui.ModelId;
@@ -76,11 +69,8 @@ import androidx.core.util.Preconditions;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
import java.util.Arrays;
-import java.util.function.Consumer;
@RunWith(AndroidJUnit4.class)
@MediumTest
@@ -110,8 +100,9 @@ public class ActionHandlerTest {
((TestActivityConfig) mEnv.injector.config).nextDocumentEnabled = true;
mEnv.injector.dialogs = mDialogs;
- ActionHandler<TestActivity> handler = createHandler();
- mHandler = spy(handler);
+ mHandler = createHandler();
+
+ mDialogs.confirmNext();
mEnv.selectDocument(TestEnv.FILE_GIF);
}
@@ -171,38 +162,31 @@ public class ActionHandlerTest {
mEnv.selectionMgr.clearSelection();
mHandler.deleteSelectedDocuments();
+ mDialogs.assertNoFileFailures();
mActivity.startService.assertNotCalled();
+ mActionModeAddons.finishOnConfirmed.assertNeverCalled();
}
@Test
- public void testDeleteSelectedDocuments_Undo() {
+ public void testDeleteSelectedDocuments_Cancelable() {
mEnv.populateStack();
- doAnswer(new Answer() {
- @Override
- public Object answer(InvocationOnMock invocation) throws Throwable {
- Consumer<View> callback = invocation.getArgument(2);
- callback.accept(null);
- return null;
- }
- }).when(mHandler).showDeletionSnackbar(anyObject(), anyInt(), anyObject(), anyObject());
+
+ mDialogs.rejectNext();
mHandler.deleteSelectedDocuments();
+ mDialogs.assertNoFileFailures();
mActivity.startService.assertNotCalled();
+ mActionModeAddons.finishOnConfirmed.assertRejected();
}
// Recents root means when deleting the srcParent will be null.
@Test
public void testDeleteSelectedDocuments_RecentsRoot() {
mEnv.state.stack.changeRoot(TestProvidersAccess.RECENTS);
- doAnswer(new Answer() {
- @Override
- public Object answer(InvocationOnMock invocation) throws Throwable {
- Snackbar.Callback callback = invocation.getArgument(3);
- callback.onDismissed(null, Snackbar.Callback.DISMISS_EVENT_MANUAL);
- return null;
- }
- }).when(mHandler).showDeletionSnackbar(anyObject(), anyInt(), anyObject(), anyObject());
+
mHandler.deleteSelectedDocuments();
+ mDialogs.assertNoFileFailures();
mActivity.startService.assertCalled();
+ mActionModeAddons.finishOnConfirmed.assertCalled();
}
@Test
diff --git a/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java b/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
index 99947e886..5d4156558 100644
--- a/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/picker/ActionHandlerTest.java
@@ -78,6 +78,8 @@ public class ActionHandlerTest {
mLastAccessed
);
+ mEnv.dialogs.confirmNext();
+
mEnv.selectionMgr.select("1");
AsyncTask.setDefaultExecutor(mEnv.mExecutor);
diff --git a/tests/unit/com/android/documentsui/services/DeleteJobTest.java b/tests/unit/com/android/documentsui/services/DeleteJobTest.java
index 50b3dad7a..0d8d39be8 100644
--- a/tests/unit/com/android/documentsui/services/DeleteJobTest.java
+++ b/tests/unit/com/android/documentsui/services/DeleteJobTest.java
@@ -21,16 +21,10 @@ import static com.android.documentsui.services.FileOperationService.OPERATION_DE
import static com.google.common.collect.Lists.newArrayList;
import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
import android.provider.DocumentsContract;
import android.support.test.filters.MediumTest;
-import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
@MediumTest
public class DeleteJobTest extends AbstractJobTest<DeleteJob> {
@@ -62,90 +56,6 @@ public class DeleteJobTest extends AbstractJobTest<DeleteJob> {
mDocs.assertChildCount(mSrcRoot, 0);
}
- public void testDeleteFile_SendDeletionFailedUris() throws Exception {
- Uri invalidUri1 = Uri.parse("content://poodles/chuckleberry/ham");
- Uri validUri = mDocs.createDocument(mSrcRoot, "text/plain", "test2.txt");
- Uri invalidUri2 = Uri.parse("content://poodles/chuckleberry/ham2");
- mDocs.writeDocument(validUri, FRUITY_BYTES);
-
- Uri stack = DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId);
- FileOperation operation = createOperation(OPERATION_DELETE,
- newArrayList(invalidUri1, validUri, invalidUri2),
- DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId), stack);
-
- CountDownLatch latch = new CountDownLatch(1);
- final ArrayList<Uri> deletionFailedUris = new ArrayList<>();
- operation.addMessageListener(
- new Handler.Callback() {
- @Override
- public boolean handleMessage(Message message) {
- if (message.what == FileOperationService.MESSAGE_FINISH) {
- operation.removeMessageListener(this);
- deletionFailedUris.addAll(message.getData()
- .getParcelableArrayList(DeleteJob.KEY_FAILED_URIS));
- latch.countDown();
- return true;
- }
- return false;
- }
- }
- );
-
- createJob(operation).run();
- latch.await(10, TimeUnit.SECONDS);
-
- assertTrue("Not received failed uri:" + invalidUri1,
- deletionFailedUris.contains(invalidUri1));
- assertTrue("Not received failed uri:" + invalidUri2,
- deletionFailedUris.contains(invalidUri2));
- assertFalse("Received valid uri:" + validUri,
- deletionFailedUris.contains(validUri));
- }
-
- public void testDeleteFile_SendDeletionCanceledUris() throws Exception {
- Uri testUri1 = mDocs.createDocument(mSrcRoot, "text/plain", "test1.txt");
- Uri testUri2 = mDocs.createDocument(mSrcRoot, "text/plain", "test2.txt");
- Uri testUri3 = mDocs.createDocument(mSrcRoot, "text/plain", "test3.txt");
- mDocs.writeDocument(testUri1, FRUITY_BYTES);
- mDocs.writeDocument(testUri2, FRUITY_BYTES);
- mDocs.writeDocument(testUri3, FRUITY_BYTES);
-
- Uri stack = DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId);
- FileOperation operation = createOperation(OPERATION_DELETE,
- newArrayList(testUri1, testUri2, testUri3),
- DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId), stack);
-
- CountDownLatch latch = new CountDownLatch(1);
- final AtomicInteger cancelCount = new AtomicInteger();
- operation.addMessageListener(
- new Handler.Callback() {
- @Override
- public boolean handleMessage(Message message) {
- if (message.what == FileOperationService.MESSAGE_FINISH) {
- operation.removeMessageListener(this);
- cancelCount.set(message.arg1);
- latch.countDown();
- return true;
- }
- return false;
- }
- }
- );
-
- // Cancel the deletion job at onStart to ensure that none of the files will be deleted
- TestJobListener listener = new TestJobListener() {
- @Override
- public void onStart(Job job) {
- super.onStart(job);
- job.cancel();
- }
- };
- createJob(operation, listener).run();
- latch.await(10, TimeUnit.SECONDS);
-
- assertEquals(3, cancelCount.get());
- }
-
/**
* Creates a job with a stack consisting to the default src directory.
*/