Loading packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java +5 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.documentsui; package com.android.documentsui; import android.annotation.Nullable; import android.annotation.Nullable; import android.provider.DocumentsContract.Document; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentInfo; import com.android.internal.util.Predicate; import com.android.internal.util.Predicate; Loading Loading @@ -99,4 +100,8 @@ public class MimePredicate implements Predicate<DocumentInfo> { public static boolean isApkType(@Nullable String mimeType) { public static boolean isApkType(@Nullable String mimeType) { return APK_TYPE.equals(mimeType); return APK_TYPE.equals(mimeType); } } public static boolean isDirectoryType(@Nullable String mimeType) { return Document.MIME_TYPE_DIR.equals(mimeType); } } } packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java +39 −20 Original line number Original line Diff line number Diff line Loading @@ -63,7 +63,6 @@ import android.support.v7.widget.RecyclerView.ViewHolder; import android.text.TextUtils; import android.text.TextUtils; import android.util.Log; import android.util.Log; import android.util.SparseArray; import android.util.SparseArray; import android.util.TypedValue; import android.view.ActionMode; import android.view.ActionMode; import android.view.DragEvent; import android.view.DragEvent; import android.view.GestureDetector; import android.view.GestureDetector; Loading Loading @@ -91,6 +90,7 @@ import com.android.documentsui.Events.MotionInputEvent; import com.android.documentsui.Menus; import com.android.documentsui.Menus; import com.android.documentsui.MessageBar; import com.android.documentsui.MessageBar; import com.android.documentsui.Metrics; import com.android.documentsui.Metrics; import com.android.documentsui.MimePredicate; import com.android.documentsui.R; import com.android.documentsui.R; import com.android.documentsui.RecentsLoader; import com.android.documentsui.RecentsLoader; import com.android.documentsui.RootsCache; import com.android.documentsui.RootsCache; Loading @@ -105,6 +105,7 @@ import com.android.documentsui.model.RootInfo; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperationService.OpType; import com.android.documentsui.services.FileOperationService.OpType; import com.android.documentsui.services.FileOperations; import com.android.documentsui.services.FileOperations; import com.google.common.collect.Lists; import com.google.common.collect.Lists; import java.lang.annotation.Retention; import java.lang.annotation.Retention; Loading @@ -112,7 +113,6 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.ArrayList; import java.util.Collections; import java.util.Collections; import java.util.HashSet; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.List; import java.util.Objects; import java.util.Objects; import java.util.Set; import java.util.Set; Loading Loading @@ -460,13 +460,17 @@ public class DirectoryFragment extends Fragment * ActionMode when there is a selection, canceling it when there is no selection, * 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. * and clearing selection when action mode is explicitly exited by the user. */ */ private final class SelectionModeListener private final class SelectionModeListener implements MultiSelectManager.Callback, implements MultiSelectManager.Callback, ActionMode.Callback { ActionMode.Callback, FragmentTuner.SelectionDetails { private Selection mSelected = new Selection(); 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 mNoDeleteCount = 0; private int mNoRenameCount = -1; private int mNoRenameCount = 0; private Menu mMenu; private Menu mMenu; @Override @Override Loading Loading @@ -508,14 +512,19 @@ public class DirectoryFragment extends Fragment // TODO: Should this be happening in onSelectionChanged? Technically this callback is // TODO: Should this be happening in onSelectionChanged? Technically this callback is // triggered on "silent" selection updates (i.e. we might be reacting to unfinalized // triggered on "silent" selection updates (i.e. we might be reacting to unfinalized // selection changes here) // 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); final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS); if ((docFlags & Document.FLAG_PARTIAL) != 0) { if ((docFlags & Document.FLAG_PARTIAL) != 0) { mNoCopyCount += selected ? 1 : -1; mPartialCount += selected ? 1 : -1; } } if ((docFlags & Document.FLAG_SUPPORTS_DELETE) == 0) { if ((docFlags & Document.FLAG_SUPPORTS_DELETE) == 0) { mNoDeleteCount += selected ? 1 : -1; mNoDeleteCount += selected ? 1 : -1; } } if ((docFlags & Document.FLAG_SUPPORTS_RENAME) != 0) { if ((docFlags & Document.FLAG_SUPPORTS_RENAME) == 0) { mNoRenameCount += selected ? 1 : -1; mNoRenameCount += selected ? 1 : -1; } } } } Loading Loading @@ -554,8 +563,11 @@ public class DirectoryFragment extends Fragment // clear selection // clear selection mSelectionManager.clearSelection(); mSelectionManager.clearSelection(); mSelected.clear(); mSelected.clear(); mDirectoryCount = 0; mPartialCount = 0; mNoDeleteCount = 0; mNoDeleteCount = 0; mNoRenameCount = -1; mNoRenameCount = 0; // Re-enable TalkBack for the toolbars, as they are no longer covered by action mode. // Re-enable TalkBack for the toolbars, as they are no longer covered by action mode. final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar); final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar); Loading Loading @@ -603,24 +615,29 @@ public class DirectoryFragment extends Fragment return true; return true; } } boolean canCopySelection() { @Override return mNoCopyCount == 0; public boolean containsDirectories() { return mDirectoryCount > 0; } @Override public boolean containsPartialFiles() { return mPartialCount > 0; } } boolean canDeleteSelection() { @Override public boolean canDelete() { return mNoDeleteCount == 0; return mNoDeleteCount == 0; } } boolean canRenameSelection() { @Override public boolean canRename() { return mNoRenameCount == 0 && mSelectionManager.getSelection().size() == 1; return mNoRenameCount == 0 && mSelectionManager.getSelection().size() == 1; } } private void updateActionMenu() { private void updateActionMenu() { assert(mMenu != null); assert(mMenu != null); mTuner.updateActionMenu(mMenu, this); // Delegate update logic to our owning action, since specialized logic is desired. mTuner.updateActionMenu( mMenu, mType, canCopySelection(), canDeleteSelection(), canRenameSelection()); Menus.disableHiddenItems(mMenu); Menus.disableHiddenItems(mMenu); } } Loading Loading @@ -1224,9 +1241,11 @@ public class DirectoryFragment extends Fragment view.setOnDragListener(mOnDragListener); view.setOnDragListener(mOnDragListener); } } if (mTuner.dragAndDropEnabled()) { // Make all items draggable. // Make all items draggable. view.setOnLongClickListener(onLongClickListener); view.setOnLongClickListener(onLongClickListener); } } } private View.OnDragListener mOnDragListener = new View.OnDragListener() { private View.OnDragListener mOnDragListener = new View.OnDragListener() { @Override @Override Loading Loading @@ -1817,7 +1836,7 @@ public class DirectoryFragment extends Fragment mRoot.authority, mRoot.rootId, mQuery) mRoot.authority, mRoot.rootId, mQuery) : DocumentsContract.buildChildDocumentsUri( : DocumentsContract.buildChildDocumentsUri( mDocument.authority, mDocument.documentId); mDocument.authority, mDocument.documentId); if (mTuner.enableManagedMode()) { if (mTuner.managedModeEnabled()) { contentsUri = DocumentsContract.setManageMode(contentsUri); contentsUri = DocumentsContract.setManageMode(contentsUri); } } return new DirectoryLoader( return new DirectoryLoader( Loading packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java +58 −34 Original line number Original line Diff line number Diff line Loading @@ -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. // 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 // A folder is enabled such that it may be double clicked, even in settings Loading @@ -73,13 +70,23 @@ public abstract class FragmentTuner { return true; 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. * When managed mode is enabled, active downloads will be visible in the UI. * Presumably this should only be true when in the downloads directory. * 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 */ 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. * Provides support for Platform specific specializations of DirectoryFragment. Loading @@ -100,7 +107,7 @@ public abstract class FragmentTuner { return false; return false; } } if (isDirectory(docMimeType)) { if (MimePredicate.isDirectoryType(docMimeType)) { return false; return false; } } Loading @@ -116,9 +123,9 @@ public abstract class FragmentTuner { } } @Override @Override public boolean isDocumentEnabled(String docMimeType, int docFlags) { public boolean isDocumentEnabled(String mimeType, int docFlags) { // Directories are always enabled. // Directories are always enabled. if (isDirectory(docMimeType)) { if (MimePredicate.isDirectoryType(mimeType)) { return true; return true; } } Loading @@ -136,13 +143,11 @@ public abstract class FragmentTuner { } } } } return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType); return MimePredicate.mimeMatches(mState.acceptMimes, mimeType); } } @Override @Override public void updateActionMenu( public void updateActionMenu(Menu menu, SelectionDetails selection) { Menu menu, @ResultType int dirType, boolean canCopy, boolean canDelete, boolean canRename) { MenuItem open = menu.findItem(R.id.menu_open); MenuItem open = menu.findItem(R.id.menu_open); MenuItem share = menu.findItem(R.id.menu_share); MenuItem share = menu.findItem(R.id.menu_share); Loading @@ -150,8 +155,8 @@ public abstract class FragmentTuner { MenuItem rename = menu.findItem(R.id.menu_rename); MenuItem rename = menu.findItem(R.id.menu_rename); MenuItem selectAll = menu.findItem(R.id.menu_select_all); MenuItem selectAll = menu.findItem(R.id.menu_select_all); open.setVisible(mState.action == ACTION_GET_CONTENT || open.setVisible(mState.action == ACTION_GET_CONTENT mState.action == ACTION_OPEN); || mState.action == ACTION_OPEN); share.setVisible(false); share.setVisible(false); delete.setVisible(false); delete.setVisible(false); rename.setVisible(false); rename.setVisible(false); Loading Loading @@ -186,11 +191,6 @@ public abstract class FragmentTuner { } } mModelPreviousLoaded = true; mModelPreviousLoaded = true; } } @Override public boolean enableManagedMode() { return false; } } } /** /** Loading @@ -207,29 +207,39 @@ public abstract class FragmentTuner { } } @Override @Override public void updateActionMenu( public void updateActionMenu(Menu menu, SelectionDetails selection) { Menu menu, @ResultType int dirType, boolean canCopy, boolean canDelete, boolean canRename) { 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 copy = menu.findItem(R.id.menu_copy_to_clipboard); MenuItem paste = menu.findItem(R.id.menu_paste_from_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 rename = menu.findItem(R.id.menu_rename); MenuItem moveTo = menu.findItem(R.id.menu_move_to); MenuItem moveTo = menu.findItem(R.id.menu_move_to); MenuItem copyTo = menu.findItem(R.id.menu_copy_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); copyTo.setVisible(true); moveTo.setVisible(true); moveTo.setVisible(true); rename.setVisible(true); rename.setVisible(true); copyTo.setEnabled(canCopy); copyTo.setEnabled(!selection.containsPartialFiles()); moveTo.setEnabled(canCopy && canDelete); moveTo.setEnabled(!selection.containsPartialFiles() && selection.canDelete()); rename.setEnabled(canRename); rename.setEnabled(!selection.containsPartialFiles() && selection.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); Menus.disableHiddenItems(menu, copy, paste); Menus.disableHiddenItems(menu, copy, paste); } } Loading @@ -246,7 +256,7 @@ public abstract class FragmentTuner { } } @Override @Override public boolean enableManagedMode() { public boolean managedModeEnabled() { // When in downloads top level directory, we also show active downloads. // 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 // 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. // downloads that themselves can be opened and viewed like directories. Loading @@ -255,9 +265,23 @@ public abstract class FragmentTuner { && mState.stack.root.isDownloads() && mState.stack.root.isDownloads() && mState.stack.size() == 1; && mState.stack.size() == 1; } } @Override 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(); } } } } Loading
packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java +5 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.documentsui; package com.android.documentsui; import android.annotation.Nullable; import android.annotation.Nullable; import android.provider.DocumentsContract.Document; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentInfo; import com.android.internal.util.Predicate; import com.android.internal.util.Predicate; Loading Loading @@ -99,4 +100,8 @@ public class MimePredicate implements Predicate<DocumentInfo> { public static boolean isApkType(@Nullable String mimeType) { public static boolean isApkType(@Nullable String mimeType) { return APK_TYPE.equals(mimeType); return APK_TYPE.equals(mimeType); } } public static boolean isDirectoryType(@Nullable String mimeType) { return Document.MIME_TYPE_DIR.equals(mimeType); } } }
packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java +39 −20 Original line number Original line Diff line number Diff line Loading @@ -63,7 +63,6 @@ import android.support.v7.widget.RecyclerView.ViewHolder; import android.text.TextUtils; import android.text.TextUtils; import android.util.Log; import android.util.Log; import android.util.SparseArray; import android.util.SparseArray; import android.util.TypedValue; import android.view.ActionMode; import android.view.ActionMode; import android.view.DragEvent; import android.view.DragEvent; import android.view.GestureDetector; import android.view.GestureDetector; Loading Loading @@ -91,6 +90,7 @@ import com.android.documentsui.Events.MotionInputEvent; import com.android.documentsui.Menus; import com.android.documentsui.Menus; import com.android.documentsui.MessageBar; import com.android.documentsui.MessageBar; import com.android.documentsui.Metrics; import com.android.documentsui.Metrics; import com.android.documentsui.MimePredicate; import com.android.documentsui.R; import com.android.documentsui.R; import com.android.documentsui.RecentsLoader; import com.android.documentsui.RecentsLoader; import com.android.documentsui.RootsCache; import com.android.documentsui.RootsCache; Loading @@ -105,6 +105,7 @@ import com.android.documentsui.model.RootInfo; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperationService; import com.android.documentsui.services.FileOperationService.OpType; import com.android.documentsui.services.FileOperationService.OpType; import com.android.documentsui.services.FileOperations; import com.android.documentsui.services.FileOperations; import com.google.common.collect.Lists; import com.google.common.collect.Lists; import java.lang.annotation.Retention; import java.lang.annotation.Retention; Loading @@ -112,7 +113,6 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.ArrayList; import java.util.Collections; import java.util.Collections; import java.util.HashSet; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.List; import java.util.Objects; import java.util.Objects; import java.util.Set; import java.util.Set; Loading Loading @@ -460,13 +460,17 @@ public class DirectoryFragment extends Fragment * ActionMode when there is a selection, canceling it when there is no selection, * 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. * and clearing selection when action mode is explicitly exited by the user. */ */ private final class SelectionModeListener private final class SelectionModeListener implements MultiSelectManager.Callback, implements MultiSelectManager.Callback, ActionMode.Callback { ActionMode.Callback, FragmentTuner.SelectionDetails { private Selection mSelected = new Selection(); 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 mNoDeleteCount = 0; private int mNoRenameCount = -1; private int mNoRenameCount = 0; private Menu mMenu; private Menu mMenu; @Override @Override Loading Loading @@ -508,14 +512,19 @@ public class DirectoryFragment extends Fragment // TODO: Should this be happening in onSelectionChanged? Technically this callback is // TODO: Should this be happening in onSelectionChanged? Technically this callback is // triggered on "silent" selection updates (i.e. we might be reacting to unfinalized // triggered on "silent" selection updates (i.e. we might be reacting to unfinalized // selection changes here) // 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); final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS); if ((docFlags & Document.FLAG_PARTIAL) != 0) { if ((docFlags & Document.FLAG_PARTIAL) != 0) { mNoCopyCount += selected ? 1 : -1; mPartialCount += selected ? 1 : -1; } } if ((docFlags & Document.FLAG_SUPPORTS_DELETE) == 0) { if ((docFlags & Document.FLAG_SUPPORTS_DELETE) == 0) { mNoDeleteCount += selected ? 1 : -1; mNoDeleteCount += selected ? 1 : -1; } } if ((docFlags & Document.FLAG_SUPPORTS_RENAME) != 0) { if ((docFlags & Document.FLAG_SUPPORTS_RENAME) == 0) { mNoRenameCount += selected ? 1 : -1; mNoRenameCount += selected ? 1 : -1; } } } } Loading Loading @@ -554,8 +563,11 @@ public class DirectoryFragment extends Fragment // clear selection // clear selection mSelectionManager.clearSelection(); mSelectionManager.clearSelection(); mSelected.clear(); mSelected.clear(); mDirectoryCount = 0; mPartialCount = 0; mNoDeleteCount = 0; mNoDeleteCount = 0; mNoRenameCount = -1; mNoRenameCount = 0; // Re-enable TalkBack for the toolbars, as they are no longer covered by action mode. // Re-enable TalkBack for the toolbars, as they are no longer covered by action mode. final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar); final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar); Loading Loading @@ -603,24 +615,29 @@ public class DirectoryFragment extends Fragment return true; return true; } } boolean canCopySelection() { @Override return mNoCopyCount == 0; public boolean containsDirectories() { return mDirectoryCount > 0; } @Override public boolean containsPartialFiles() { return mPartialCount > 0; } } boolean canDeleteSelection() { @Override public boolean canDelete() { return mNoDeleteCount == 0; return mNoDeleteCount == 0; } } boolean canRenameSelection() { @Override public boolean canRename() { return mNoRenameCount == 0 && mSelectionManager.getSelection().size() == 1; return mNoRenameCount == 0 && mSelectionManager.getSelection().size() == 1; } } private void updateActionMenu() { private void updateActionMenu() { assert(mMenu != null); assert(mMenu != null); mTuner.updateActionMenu(mMenu, this); // Delegate update logic to our owning action, since specialized logic is desired. mTuner.updateActionMenu( mMenu, mType, canCopySelection(), canDeleteSelection(), canRenameSelection()); Menus.disableHiddenItems(mMenu); Menus.disableHiddenItems(mMenu); } } Loading Loading @@ -1224,9 +1241,11 @@ public class DirectoryFragment extends Fragment view.setOnDragListener(mOnDragListener); view.setOnDragListener(mOnDragListener); } } if (mTuner.dragAndDropEnabled()) { // Make all items draggable. // Make all items draggable. view.setOnLongClickListener(onLongClickListener); view.setOnLongClickListener(onLongClickListener); } } } private View.OnDragListener mOnDragListener = new View.OnDragListener() { private View.OnDragListener mOnDragListener = new View.OnDragListener() { @Override @Override Loading Loading @@ -1817,7 +1836,7 @@ public class DirectoryFragment extends Fragment mRoot.authority, mRoot.rootId, mQuery) mRoot.authority, mRoot.rootId, mQuery) : DocumentsContract.buildChildDocumentsUri( : DocumentsContract.buildChildDocumentsUri( mDocument.authority, mDocument.documentId); mDocument.authority, mDocument.documentId); if (mTuner.enableManagedMode()) { if (mTuner.managedModeEnabled()) { contentsUri = DocumentsContract.setManageMode(contentsUri); contentsUri = DocumentsContract.setManageMode(contentsUri); } } return new DirectoryLoader( return new DirectoryLoader( Loading
packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java +58 −34 Original line number Original line Diff line number Diff line Loading @@ -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. // 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 // A folder is enabled such that it may be double clicked, even in settings Loading @@ -73,13 +70,23 @@ public abstract class FragmentTuner { return true; 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. * When managed mode is enabled, active downloads will be visible in the UI. * Presumably this should only be true when in the downloads directory. * 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 */ 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. * Provides support for Platform specific specializations of DirectoryFragment. Loading @@ -100,7 +107,7 @@ public abstract class FragmentTuner { return false; return false; } } if (isDirectory(docMimeType)) { if (MimePredicate.isDirectoryType(docMimeType)) { return false; return false; } } Loading @@ -116,9 +123,9 @@ public abstract class FragmentTuner { } } @Override @Override public boolean isDocumentEnabled(String docMimeType, int docFlags) { public boolean isDocumentEnabled(String mimeType, int docFlags) { // Directories are always enabled. // Directories are always enabled. if (isDirectory(docMimeType)) { if (MimePredicate.isDirectoryType(mimeType)) { return true; return true; } } Loading @@ -136,13 +143,11 @@ public abstract class FragmentTuner { } } } } return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType); return MimePredicate.mimeMatches(mState.acceptMimes, mimeType); } } @Override @Override public void updateActionMenu( public void updateActionMenu(Menu menu, SelectionDetails selection) { Menu menu, @ResultType int dirType, boolean canCopy, boolean canDelete, boolean canRename) { MenuItem open = menu.findItem(R.id.menu_open); MenuItem open = menu.findItem(R.id.menu_open); MenuItem share = menu.findItem(R.id.menu_share); MenuItem share = menu.findItem(R.id.menu_share); Loading @@ -150,8 +155,8 @@ public abstract class FragmentTuner { MenuItem rename = menu.findItem(R.id.menu_rename); MenuItem rename = menu.findItem(R.id.menu_rename); MenuItem selectAll = menu.findItem(R.id.menu_select_all); MenuItem selectAll = menu.findItem(R.id.menu_select_all); open.setVisible(mState.action == ACTION_GET_CONTENT || open.setVisible(mState.action == ACTION_GET_CONTENT mState.action == ACTION_OPEN); || mState.action == ACTION_OPEN); share.setVisible(false); share.setVisible(false); delete.setVisible(false); delete.setVisible(false); rename.setVisible(false); rename.setVisible(false); Loading Loading @@ -186,11 +191,6 @@ public abstract class FragmentTuner { } } mModelPreviousLoaded = true; mModelPreviousLoaded = true; } } @Override public boolean enableManagedMode() { return false; } } } /** /** Loading @@ -207,29 +207,39 @@ public abstract class FragmentTuner { } } @Override @Override public void updateActionMenu( public void updateActionMenu(Menu menu, SelectionDetails selection) { Menu menu, @ResultType int dirType, boolean canCopy, boolean canDelete, boolean canRename) { 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 copy = menu.findItem(R.id.menu_copy_to_clipboard); MenuItem paste = menu.findItem(R.id.menu_paste_from_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 rename = menu.findItem(R.id.menu_rename); MenuItem moveTo = menu.findItem(R.id.menu_move_to); MenuItem moveTo = menu.findItem(R.id.menu_move_to); MenuItem copyTo = menu.findItem(R.id.menu_copy_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); copyTo.setVisible(true); moveTo.setVisible(true); moveTo.setVisible(true); rename.setVisible(true); rename.setVisible(true); copyTo.setEnabled(canCopy); copyTo.setEnabled(!selection.containsPartialFiles()); moveTo.setEnabled(canCopy && canDelete); moveTo.setEnabled(!selection.containsPartialFiles() && selection.canDelete()); rename.setEnabled(canRename); rename.setEnabled(!selection.containsPartialFiles() && selection.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); Menus.disableHiddenItems(menu, copy, paste); Menus.disableHiddenItems(menu, copy, paste); } } Loading @@ -246,7 +256,7 @@ public abstract class FragmentTuner { } } @Override @Override public boolean enableManagedMode() { public boolean managedModeEnabled() { // When in downloads top level directory, we also show active downloads. // 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 // 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. // downloads that themselves can be opened and viewed like directories. Loading @@ -255,9 +265,23 @@ public abstract class FragmentTuner { && mState.stack.root.isDownloads() && mState.stack.root.isDownloads() && mState.stack.size() == 1; && mState.stack.size() == 1; } } @Override 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(); } } } }