Merge "Disable share when dirs selected." into nyc-dev
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package com.android.documentsui;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.provider.DocumentsContract.Document;
|
||||
|
||||
import com.android.documentsui.model.DocumentInfo;
|
||||
import com.android.internal.util.Predicate;
|
||||
@@ -99,4 +100,8 @@ public class MimePredicate implements Predicate<DocumentInfo> {
|
||||
public static boolean isApkType(@Nullable String mimeType) {
|
||||
return APK_TYPE.equals(mimeType);
|
||||
}
|
||||
|
||||
public static boolean isDirectoryType(@Nullable String mimeType) {
|
||||
return Document.MIME_TYPE_DIR.equals(mimeType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ActionMode;
|
||||
import android.view.DragEvent;
|
||||
import android.view.GestureDetector;
|
||||
@@ -89,6 +88,7 @@ import com.android.documentsui.Events.MotionInputEvent;
|
||||
import com.android.documentsui.Menus;
|
||||
import com.android.documentsui.MessageBar;
|
||||
import com.android.documentsui.Metrics;
|
||||
import com.android.documentsui.MimePredicate;
|
||||
import com.android.documentsui.R;
|
||||
import com.android.documentsui.RecentsLoader;
|
||||
import com.android.documentsui.RootsCache;
|
||||
@@ -103,6 +103,7 @@ import com.android.documentsui.model.RootInfo;
|
||||
import com.android.documentsui.services.FileOperationService;
|
||||
import com.android.documentsui.services.FileOperationService.OpType;
|
||||
import com.android.documentsui.services.FileOperations;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -110,7 +111,6 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@@ -458,13 +458,17 @@ public class DirectoryFragment extends Fragment
|
||||
* ActionMode when there is a selection, canceling it when there is no selection,
|
||||
* and clearing selection when action mode is explicitly exited by the user.
|
||||
*/
|
||||
private final class SelectionModeListener
|
||||
implements MultiSelectManager.Callback, ActionMode.Callback {
|
||||
private final class SelectionModeListener implements MultiSelectManager.Callback,
|
||||
ActionMode.Callback, FragmentTuner.SelectionDetails {
|
||||
|
||||
private Selection mSelected = new Selection();
|
||||
private int mNoCopyCount = 0;
|
||||
|
||||
// Partial files are files that haven't been fully downloaded.
|
||||
private int mPartialCount = 0;
|
||||
private int mDirectoryCount = 0;
|
||||
private int mNoDeleteCount = 0;
|
||||
private int mNoRenameCount = -1;
|
||||
private int mNoRenameCount = 0;
|
||||
|
||||
private Menu mMenu;
|
||||
|
||||
@Override
|
||||
@@ -506,14 +510,19 @@ public class DirectoryFragment extends Fragment
|
||||
// TODO: Should this be happening in onSelectionChanged? Technically this callback is
|
||||
// triggered on "silent" selection updates (i.e. we might be reacting to unfinalized
|
||||
// selection changes here)
|
||||
final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
|
||||
if (MimePredicate.isDirectoryType(mimeType)) {
|
||||
mDirectoryCount += selected ? 1 : -1;
|
||||
}
|
||||
|
||||
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
|
||||
if ((docFlags & Document.FLAG_PARTIAL) != 0) {
|
||||
mNoCopyCount += selected ? 1 : -1;
|
||||
mPartialCount += selected ? 1 : -1;
|
||||
}
|
||||
if ((docFlags & Document.FLAG_SUPPORTS_DELETE) == 0) {
|
||||
mNoDeleteCount += selected ? 1 : -1;
|
||||
}
|
||||
if ((docFlags & Document.FLAG_SUPPORTS_RENAME) != 0) {
|
||||
if ((docFlags & Document.FLAG_SUPPORTS_RENAME) == 0) {
|
||||
mNoRenameCount += selected ? 1 : -1;
|
||||
}
|
||||
}
|
||||
@@ -552,8 +561,11 @@ public class DirectoryFragment extends Fragment
|
||||
// clear selection
|
||||
mSelectionManager.clearSelection();
|
||||
mSelected.clear();
|
||||
|
||||
mDirectoryCount = 0;
|
||||
mPartialCount = 0;
|
||||
mNoDeleteCount = 0;
|
||||
mNoRenameCount = -1;
|
||||
mNoRenameCount = 0;
|
||||
|
||||
// Re-enable TalkBack for the toolbars, as they are no longer covered by action mode.
|
||||
final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
|
||||
@@ -601,24 +613,29 @@ public class DirectoryFragment extends Fragment
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean canCopySelection() {
|
||||
return mNoCopyCount == 0;
|
||||
@Override
|
||||
public boolean containsDirectories() {
|
||||
return mDirectoryCount > 0;
|
||||
}
|
||||
|
||||
boolean canDeleteSelection() {
|
||||
@Override
|
||||
public boolean containsPartialFiles() {
|
||||
return mPartialCount > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDelete() {
|
||||
return mNoDeleteCount == 0;
|
||||
}
|
||||
|
||||
boolean canRenameSelection() {
|
||||
@Override
|
||||
public boolean canRename() {
|
||||
return mNoRenameCount == 0 && mSelectionManager.getSelection().size() == 1;
|
||||
}
|
||||
|
||||
private void updateActionMenu() {
|
||||
assert(mMenu != null);
|
||||
|
||||
// Delegate update logic to our owning action, since specialized logic is desired.
|
||||
mTuner.updateActionMenu(
|
||||
mMenu, mType, canCopySelection(), canDeleteSelection(), canRenameSelection());
|
||||
mTuner.updateActionMenu(mMenu, this);
|
||||
Menus.disableHiddenItems(mMenu);
|
||||
}
|
||||
|
||||
@@ -1174,7 +1191,7 @@ public class DirectoryFragment extends Fragment
|
||||
view.setOnDragListener(mOnDragListener);
|
||||
}
|
||||
|
||||
if (mTuner.allowDragNDrop()) {
|
||||
if (mTuner.dragAndDropEnabled()) {
|
||||
// Make all items draggable.
|
||||
view.setOnLongClickListener(onLongClickListener);
|
||||
}
|
||||
@@ -1761,7 +1778,7 @@ public class DirectoryFragment extends Fragment
|
||||
mRoot.authority, mRoot.rootId, mQuery)
|
||||
: DocumentsContract.buildChildDocumentsUri(
|
||||
mDocument.authority, mDocument.documentId);
|
||||
if (mTuner.enableManagedMode()) {
|
||||
if (mTuner.managedModeEnabled()) {
|
||||
contentsUri = DocumentsContract.setManageMode(contentsUri);
|
||||
}
|
||||
return new DirectoryLoader(
|
||||
|
||||
@@ -58,9 +58,6 @@ public abstract class FragmentTuner {
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void updateActionMenu(
|
||||
Menu menu, @ResultType int dirType,
|
||||
boolean canCopy, boolean canDelete, boolean canRename);
|
||||
|
||||
// Subtly different from isDocumentEnabled. The reason may be illuminated as follows.
|
||||
// A folder is enabled such that it may be double clicked, even in settings
|
||||
@@ -73,18 +70,23 @@ public abstract class FragmentTuner {
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
|
||||
|
||||
/**
|
||||
* When managed mode is enabled, active downloads will be visible in the UI.
|
||||
* Presumably this should only be true when in the downloads directory.
|
||||
*/
|
||||
abstract boolean enableManagedMode();
|
||||
boolean managedModeEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether drag n' drop is allowed in this context
|
||||
*/
|
||||
abstract boolean allowDragNDrop();
|
||||
boolean dragAndDropEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract void updateActionMenu(Menu menu, SelectionDetails selection);
|
||||
abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
|
||||
|
||||
/**
|
||||
* Provides support for Platform specific specializations of DirectoryFragment.
|
||||
@@ -105,7 +107,7 @@ public abstract class FragmentTuner {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDirectory(docMimeType)) {
|
||||
if (MimePredicate.isDirectoryType(docMimeType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -121,9 +123,9 @@ public abstract class FragmentTuner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDocumentEnabled(String docMimeType, int docFlags) {
|
||||
public boolean isDocumentEnabled(String mimeType, int docFlags) {
|
||||
// Directories are always enabled.
|
||||
if (isDirectory(docMimeType)) {
|
||||
if (MimePredicate.isDirectoryType(mimeType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -141,13 +143,11 @@ public abstract class FragmentTuner {
|
||||
}
|
||||
}
|
||||
|
||||
return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
|
||||
return MimePredicate.mimeMatches(mState.acceptMimes, mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateActionMenu(
|
||||
Menu menu, @ResultType int dirType,
|
||||
boolean canCopy, boolean canDelete, boolean canRename) {
|
||||
public void updateActionMenu(Menu menu, SelectionDetails selection) {
|
||||
|
||||
MenuItem open = menu.findItem(R.id.menu_open);
|
||||
MenuItem share = menu.findItem(R.id.menu_share);
|
||||
@@ -155,8 +155,8 @@ public abstract class FragmentTuner {
|
||||
MenuItem rename = menu.findItem(R.id.menu_rename);
|
||||
MenuItem selectAll = menu.findItem(R.id.menu_select_all);
|
||||
|
||||
open.setVisible(mState.action == ACTION_GET_CONTENT ||
|
||||
mState.action == ACTION_OPEN);
|
||||
open.setVisible(mState.action == ACTION_GET_CONTENT
|
||||
|| mState.action == ACTION_OPEN);
|
||||
share.setVisible(false);
|
||||
delete.setVisible(false);
|
||||
rename.setVisible(false);
|
||||
@@ -191,16 +191,6 @@ public abstract class FragmentTuner {
|
||||
}
|
||||
mModelPreviousLoaded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enableManagedMode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDragNDrop() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,29 +207,39 @@ public abstract class FragmentTuner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateActionMenu(
|
||||
Menu menu, @ResultType int dirType,
|
||||
boolean canCopy, boolean canDelete, boolean canRename) {
|
||||
public void updateActionMenu(Menu menu, SelectionDetails selection) {
|
||||
|
||||
menu.findItem(R.id.menu_open).setVisible(false); // "open" is never used in Files.
|
||||
|
||||
// Commands accessible only via keyboard...
|
||||
MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
|
||||
MenuItem paste = menu.findItem(R.id.menu_paste_from_clipboard);
|
||||
copy.setEnabled(canCopy);
|
||||
|
||||
// Commands visible in the UI...
|
||||
MenuItem rename = menu.findItem(R.id.menu_rename);
|
||||
MenuItem moveTo = menu.findItem(R.id.menu_move_to);
|
||||
MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
|
||||
MenuItem share = menu.findItem(R.id.menu_share);
|
||||
MenuItem delete = menu.findItem(R.id.menu_delete);
|
||||
|
||||
// copy is not visible, keyboard only
|
||||
copy.setEnabled(!selection.containsPartialFiles());
|
||||
|
||||
// Commands usually on action-bar, so we always manage visibility.
|
||||
share.setVisible(!selection.containsDirectories() && !selection.containsPartialFiles());
|
||||
delete.setVisible(selection.canDelete());
|
||||
|
||||
share.setEnabled(!selection.containsDirectories() && !selection.containsPartialFiles());
|
||||
delete.setEnabled(selection.canDelete());
|
||||
|
||||
// Commands always in overflow, so we don't bother showing/hiding...
|
||||
copyTo.setVisible(true);
|
||||
moveTo.setVisible(true);
|
||||
rename.setVisible(true);
|
||||
|
||||
copyTo.setEnabled(canCopy);
|
||||
moveTo.setEnabled(canCopy && canDelete);
|
||||
rename.setEnabled(canRename);
|
||||
|
||||
menu.findItem(R.id.menu_share).setVisible(true);
|
||||
menu.findItem(R.id.menu_delete).setVisible(canDelete);
|
||||
menu.findItem(R.id.menu_open).setVisible(false);
|
||||
copyTo.setEnabled(!selection.containsPartialFiles());
|
||||
moveTo.setEnabled(!selection.containsPartialFiles() && selection.canDelete());
|
||||
rename.setEnabled(!selection.containsPartialFiles() && selection.canRename());
|
||||
|
||||
Menus.disableHiddenItems(menu, copy, paste);
|
||||
}
|
||||
@@ -256,7 +256,7 @@ public abstract class FragmentTuner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enableManagedMode() {
|
||||
public boolean managedModeEnabled() {
|
||||
// When in downloads top level directory, we also show active downloads.
|
||||
// And while we don't allow folders in Downloads, we do allow Zip files in
|
||||
// downloads that themselves can be opened and viewed like directories.
|
||||
@@ -267,12 +267,21 @@ public abstract class FragmentTuner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowDragNDrop() {
|
||||
public boolean dragAndDropEnabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDirectory(String mimeType) {
|
||||
return Document.MIME_TYPE_DIR.equals(mimeType);
|
||||
/**
|
||||
* Access to meta data about the selection.
|
||||
*/
|
||||
interface SelectionDetails {
|
||||
boolean containsDirectories();
|
||||
boolean containsPartialFiles();
|
||||
|
||||
// TODO: Update these to express characteristics instead of answering concrete questions,
|
||||
// since the answer to those questions is (or can be) activity specific.
|
||||
boolean canDelete();
|
||||
boolean canRename();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user