Merge "Poll jobs' status to update notifications."
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 85e7a7a..ed47bbc 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -58,13 +58,6 @@
android:showAsAction="never"
android:visible="false" />
<item
- android:id="@+id/menu_paste_from_clipboard"
- android:title="@string/menu_paste_from_clipboard"
- android:alphabeticShortcut="v"
- android:showAsAction="never"
- android:visible="false" />
- <!-- Copy action is defined in mode_directory.xml -->
- <item
android:id="@+id/menu_sort"
android:title="@string/menu_sort"
android:icon="@drawable/ic_menu_sortby"
diff --git a/packages/DocumentsUI/res/menu/context_menu.xml b/packages/DocumentsUI/res/menu/context_menu.xml
new file mode 100644
index 0000000..7474859
--- /dev/null
+++ b/packages/DocumentsUI/res/menu/context_menu.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/menu_cut_to_clipboard"
+ android:title="@string/menu_cut_to_clipboard" />
+ <item
+ android:id="@+id/menu_copy_to_clipboard"
+ android:title="@string/menu_copy_to_clipboard" />
+ <item
+ android:id="@+id/menu_paste_from_clipboard"
+ android:title="@string/menu_paste_from_clipboard" />
+</menu>
diff --git a/packages/DocumentsUI/res/menu/mode_directory.xml b/packages/DocumentsUI/res/menu/mode_directory.xml
index 6f9bfb5..e2125ad 100644
--- a/packages/DocumentsUI/res/menu/mode_directory.xml
+++ b/packages/DocumentsUI/res/menu/mode_directory.xml
@@ -30,11 +30,6 @@
android:title="@string/menu_delete"
android:showAsAction="always" />
<item
- android:id="@+id/menu_copy_to_clipboard"
- android:title="@string/menu_copy_to_clipboard"
- android:showAsAction="never"
- android:visible="false" />
- <item
android:id="@+id/menu_select_all"
android:title="@string/menu_select_all"
android:showAsAction="never" />
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index f7124e6..bf34461 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -56,6 +56,8 @@
<!-- Menu item title that creates a new window in the activity [CHAR LIMIT=24] -->
<string name="menu_new_window">New window</string>
+ <!-- Menu item title that cuts the selected documents to clipboard [CHAR LIMIT=24] -->
+ <string name="menu_cut_to_clipboard">Cut</string>
<!-- Menu item title that copies the selected documents to clipboard [CHAR LIMIT=24] -->
<string name="menu_copy_to_clipboard">Copy</string>
<!-- Menu item title that pastes files from the clipboard [CHAR LIMIT=24] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index e13e982..6f17b54 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -50,6 +50,7 @@
import android.view.MenuItem;
import android.widget.Spinner;
+import com.android.documentsui.MenuManager.DirectoryDetails;
import com.android.documentsui.SearchViewManager.SearchManagerListener;
import com.android.documentsui.State.ViewMode;
import com.android.documentsui.dirlist.AnimationView;
@@ -98,6 +99,7 @@
public abstract void onDocumentsPicked(List<DocumentInfo> docs);
public abstract FragmentTuner createFragmentTuner();
public abstract MenuManager getMenuManager();
+ public abstract DirectoryDetails getDirectoryDetails();
abstract void onTaskFinished(Uri... uris);
abstract void refreshDirectory(int anim);
@@ -302,13 +304,6 @@
setViewMode(State.MODE_LIST);
return true;
- case R.id.menu_paste_from_clipboard:
- DirectoryFragment dir = getDirectoryFragment();
- if (dir != null) {
- dir.pasteFromClipboard();
- }
- return true;
-
case R.id.menu_advanced:
setDisplayAdvancedDevices(!mState.showAdvanced);
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 830b118..b8559bc1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -414,6 +414,11 @@
return mMenuManager;
}
+ @Override
+ public DirectoryDetails getDirectoryDetails() {
+ return mDetails;
+ }
+
/**
* Loads the last used path (stack) from Recents (history).
* The path selected is based on the calling package name. So the last
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsMenuManager.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsMenuManager.java
index e7f0e74..0b86894 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsMenuManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsMenuManager.java
@@ -25,63 +25,94 @@
import android.view.Menu;
import android.view.MenuItem;
-final class DocumentsMenuManager implements MenuManager {
+final class DocumentsMenuManager extends MenuManager {
- private final State mState;
- private final SearchViewManager mSearchManager;
+ private final State mState;
+ private final SearchViewManager mSearchManager;
+ private boolean mPicking;
- public DocumentsMenuManager(SearchViewManager searchManager, State displayState) {
- mSearchManager = searchManager;
- mState = displayState;
- }
+ public DocumentsMenuManager(SearchViewManager searchManager, State displayState) {
+ mSearchManager = searchManager;
+ mState = displayState;
- @Override
- public void updateActionMenu(Menu menu, MenuManager.SelectionDetails selection) {
- MenuItem open = menu.findItem(R.id.menu_open);
- MenuItem share = menu.findItem(R.id.menu_share);
- MenuItem delete = menu.findItem(R.id.menu_delete);
- 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);
- share.setVisible(false);
- delete.setVisible(false);
- rename.setVisible(false);
- selectAll.setVisible(mState.allowMultiple);
-
- Menus.disableHiddenItems(menu);
- }
+ mPicking = mState.action == ACTION_CREATE
+ || mState.action == ACTION_OPEN_TREE
+ || mState.action == ACTION_PICK_COPY_DESTINATION;
+ }
@Override
public void updateOptionMenu(Menu menu, DirectoryDetails details) {
-
- boolean picking = mState.action == ACTION_CREATE
- || mState.action == ACTION_OPEN_TREE
- || mState.action == ACTION_PICK_COPY_DESTINATION;
-
- if (picking) {
+ super.updateOptionMenu(menu, details);
+ if (mPicking) {
// May already be hidden because the root
// doesn't support search.
mSearchManager.showMenu(false);
}
+ }
- final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
- final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
-
- createDir.setVisible(picking);
- createDir.setEnabled(details.canCreateDirectory());
-
- // No display options in recent directories
- if (picking && details.isInRecents()) {
- final MenuItem grid = menu.findItem(R.id.menu_grid);
- final MenuItem list = menu.findItem(R.id.menu_list);
+ @Override
+ void updateModePicker(MenuItem grid, MenuItem list, DirectoryDetails directoryDetails) {
+ // No display options in recent directories
+ if (mPicking && directoryDetails.isInRecents()) {
grid.setVisible(false);
list.setVisible(false);
}
+ }
- fileSize.setVisible(fileSize.isVisible() && !picking);
+ @Override
+ void updateFileSize(MenuItem fileSize, DirectoryDetails directoryDetails) {
+ fileSize.setVisible(fileSize.isVisible() && !mPicking);
+ }
- Menus.disableHiddenItems(menu);
+ @Override
+ void updateSettings(MenuItem settings, DirectoryDetails directoryDetails) {
+ assert(!settings.isVisible());
+ }
+
+ @Override
+ void updateNewWindow(MenuItem newWindow, DirectoryDetails directoryDetails) {
+ assert(!newWindow.isVisible());
+ }
+
+ @Override
+ void updateSelectAll(MenuItem selectAll, SelectionDetails selectionDetails) {
+ selectAll.setVisible(mState.allowMultiple);
+ }
+
+ @Override
+ void updateCreateDir(MenuItem createDir, DirectoryDetails directoryDetails) {
+ createDir.setVisible(mPicking);
+ createDir.setEnabled(mPicking && directoryDetails.canCreateDirectory());
+ }
+
+ @Override
+ void updateOpen(MenuItem open, SelectionDetails selectionDetails) {
+ open.setVisible(mState.action == ACTION_GET_CONTENT
+ || mState.action == ACTION_OPEN);
+ }
+
+ @Override
+ void updateShare(MenuItem share, SelectionDetails selectionDetails) {
+ share.setVisible(false);
+ }
+
+ @Override
+ void updateDelete(MenuItem delete, SelectionDetails selectionDetails) {
+ delete.setVisible(false);
+ }
+
+ @Override
+ void updateRename(MenuItem rename, SelectionDetails selectionDetails) {
+ rename.setVisible(false);
+ }
+
+ @Override
+ void updateMoveTo(MenuItem moveTo, SelectionDetails selectionDetails) {
+ assert(!moveTo.isVisible());
+ }
+
+ @Override
+ void updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails) {
+ assert(!copyTo.isVisible());
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java
index d131f2e..27293e1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Events.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java
@@ -128,6 +128,8 @@
boolean isActionUp();
Point getOrigin();
+ float getX();
+ float getY();
/** Returns true if the there is an item under the finger/cursor. */
boolean isOverItem();
@@ -216,6 +218,16 @@
}
@Override
+ public float getX() {
+ return mEvent.getX();
+ }
+
+ @Override
+ public float getY() {
+ return mEvent.getY();
+ }
+
+ @Override
public boolean isOverItem() {
return getItemPosition() != RecyclerView.NO_POSITION;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 59b9e9b..be20c0e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -468,6 +468,11 @@
return mMenuManager;
}
+ @Override
+ public DirectoryDetails getDirectoryDetails() {
+ return mDetails;
+ }
+
/**
* Builds a stack for the specific Uris. Multi roots are not supported, as it's impossible
* to know which root to select. Also, the stack doesn't contain intermediate directories.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesMenuManager.java b/packages/DocumentsUI/src/com/android/documentsui/FilesMenuManager.java
index f7256ff..4b27a7e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesMenuManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesMenuManager.java
@@ -19,9 +19,7 @@
import android.view.Menu;
import android.view.MenuItem;
-import com.android.documentsui.R;
-
-final class FilesMenuManager implements MenuManager {
+final class FilesMenuManager extends MenuManager {
private final SearchViewManager mSearchManager;
@@ -30,58 +28,76 @@
}
@Override
- 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);
-
- // 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);
-
- // Commands usually on action-bar, so we always manage visibility.
- share.setVisible(!selection.containsDirectories() && !selection.containsPartialFiles());
- delete.setVisible(selection.canDelete());
-
- // Commands always in overflow, so we don't bother showing/hiding...
- copyTo.setVisible(true);
- moveTo.setVisible(true);
- rename.setVisible(true);
-
- // copy is not visible, keyboard only
- copy.setEnabled(!selection.containsPartialFiles());
-
- copyTo.setEnabled(!selection.containsPartialFiles());
- moveTo.setEnabled(!selection.containsPartialFiles() && selection.canDelete());
- rename.setEnabled(!selection.containsPartialFiles() && selection.canRename());
-
- Menus.disableHiddenItems(menu, copy, paste);
- }
-
- @Override
public void updateOptionMenu(Menu menu, DirectoryDetails details) {
-
- final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
- final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
- final MenuItem settings = menu.findItem(R.id.menu_settings);
- final MenuItem newWindow = menu.findItem(R.id.menu_new_window);
-
- createDir.setVisible(true);
- createDir.setEnabled(details.canCreateDirectory());
- pasteFromCb.setEnabled(details.hasItemsToPaste());
- settings.setVisible(details.hasRootSettings());
- newWindow.setVisible(details.shouldShowFancyFeatures());
-
- Menus.disableHiddenItems(menu, pasteFromCb);
+ super.updateOptionMenu(menu, details);
// It hides icon if searching in progress
mSearchManager.updateMenu();
}
-}
+ @Override
+ void updateModePicker(MenuItem grid, MenuItem list, DirectoryDetails directoryDetails) {
+ assert(!grid.isVisible());
+ assert(list.isVisible());
+ }
+
+ @Override
+ void updateFileSize(MenuItem fileSize, DirectoryDetails directoryDetails) {
+ assert(fileSize.isVisible());
+ }
+
+ @Override
+ void updateSettings(MenuItem settings, DirectoryDetails directoryDetails) {
+ settings.setVisible(directoryDetails.hasRootSettings());
+ }
+
+ @Override
+ void updateNewWindow(MenuItem newWindow, DirectoryDetails directoryDetails) {
+ newWindow.setVisible(directoryDetails.shouldShowFancyFeatures());
+ }
+
+ @Override
+ void updateMoveTo(MenuItem moveTo, SelectionDetails selectionDetails) {
+ moveTo.setVisible(true);
+ moveTo.setEnabled(!selectionDetails.containsPartialFiles() && selectionDetails.canDelete());
+ }
+
+ @Override
+ void updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails) {
+ copyTo.setVisible(true);
+ copyTo.setEnabled(!selectionDetails.containsPartialFiles());
+ }
+
+ @Override
+ void updateSelectAll(MenuItem selectAll, SelectionDetails selectionDetails) {
+ assert(selectAll.isVisible());
+ }
+
+ @Override
+ void updateCreateDir(MenuItem createDir, DirectoryDetails directoryDetails) {
+ createDir.setVisible(true);
+ createDir.setEnabled(directoryDetails.canCreateDirectory());
+ }
+
+ @Override
+ void updateOpen(MenuItem open, SelectionDetails selectionDetails) {
+ open.setVisible(false);
+ }
+
+ @Override
+ void updateShare(MenuItem share, SelectionDetails selectionDetails) {
+ share.setVisible(!selectionDetails.containsDirectories()
+ && !selectionDetails.containsPartialFiles());
+ }
+
+ @Override
+ void updateDelete(MenuItem delete, SelectionDetails selectionDetails) {
+ delete.setVisible(selectionDetails.canDelete());
+ }
+
+ @Override
+ void updateRename(MenuItem rename, SelectionDetails selectionDetails) {
+ rename.setVisible(true);
+ rename.setEnabled(!selectionDetails.containsPartialFiles() && selectionDetails.canRename());
+ }
+}
\ No newline at end of file
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MenuManager.java b/packages/DocumentsUI/src/com/android/documentsui/MenuManager.java
index b14fab3..24bc4f1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MenuManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MenuManager.java
@@ -16,53 +16,124 @@
package com.android.documentsui;
+import android.annotation.Nullable;
import android.view.Menu;
+import android.view.MenuItem;
-public interface MenuManager {
+public abstract class MenuManager {
- /** @See DirectoryFragment.SelectionModeListener#updateActionMenu */
- void updateActionMenu(Menu mMenu, MenuManager.SelectionDetails selectionDetails);
- /** @See Activity#onPrepareOptionsMenu */
- void updateOptionMenu(Menu menu, DirectoryDetails details);
+ /** @See DirectoryFragment.SelectionModeListener#updateActionMenu */
+ public void updateActionMenu(Menu menu, SelectionDetails selection) {
+ updateOpen(menu.findItem(R.id.menu_open), selection);
+ updateDelete(menu.findItem(R.id.menu_delete), selection);
+ updateShare(menu.findItem(R.id.menu_share), selection);
+ updateRename(menu.findItem(R.id.menu_rename), selection);
+ updateSelectAll(menu.findItem(R.id.menu_select_all), selection);
+ updateMoveTo(menu.findItem(R.id.menu_move_to), selection);
+ updateCopyTo(menu.findItem(R.id.menu_copy_to), selection);
- /**
- * Access to meta data about the selection.
- */
- interface SelectionDetails {
- boolean containsDirectories();
- boolean containsPartialFiles();
+ Menus.disableHiddenItems(menu);
+ }
- // 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();
- }
+ /** @See Activity#onPrepareOptionsMenu */
+ public void updateOptionMenu(Menu menu, DirectoryDetails details) {
+ updateCreateDir(menu.findItem(R.id.menu_create_dir), details);
+ updateSettings(menu.findItem(R.id.menu_settings), details);
+ updateNewWindow(menu.findItem(R.id.menu_new_window), details);
+ updateFileSize(menu.findItem(R.id.menu_file_size), details);
+ updateModePicker(menu.findItem(R.id.menu_grid), menu.findItem(R.id.menu_list), details);
- public static class DirectoryDetails {
- private final BaseActivity mActivity;
+ Menus.disableHiddenItems(menu);
+ }
- public DirectoryDetails(BaseActivity activity) {
- mActivity = activity;
- }
+ /** @See DirectoryFragment.onCreateContextMenu */
+ public void updateContextMenu(Menu menu,
+ @Nullable SelectionDetails selectionDetails,
+ DirectoryDetails directoryDetails) {
- public boolean shouldShowFancyFeatures() {
- return Shared.shouldShowFancyFeatures(mActivity);
- }
+ MenuItem cut = menu.findItem(R.id.menu_cut_to_clipboard);
+ MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
+ MenuItem paste = menu.findItem(R.id.menu_paste_from_clipboard);
+ MenuItem delete = menu.findItem(R.id.menu_delete);
+ MenuItem rename = menu.findItem(R.id.menu_rename);
+ MenuItem createDir = menu.findItem(R.id.menu_create_dir);
- public boolean hasRootSettings() {
- return mActivity.getCurrentRoot().hasSettings();
- }
+ if (selectionDetails == null) {
+ cut.setEnabled(false);
+ copy.setEnabled(false);
+ rename.setEnabled(false);
+ delete.setEnabled(false);
+ } else {
+ copy.setEnabled(!selectionDetails.containsPartialFiles());
+ cut.setEnabled(
+ !selectionDetails.containsPartialFiles() && selectionDetails.canDelete());
+ updateRename(rename, selectionDetails);
+ updateDelete(delete, selectionDetails);
+ }
+ menu.findItem(R.id.menu_paste_from_clipboard)
+ .setEnabled(directoryDetails.hasItemsToPaste());
+ updateCreateDir(createDir, directoryDetails);
- public boolean hasItemsToPaste() {
- return false;
- }
+ //Cut, Copy, Paste and Delete should always be visible
+ cut.setVisible(true);
+ copy.setVisible(true);
+ paste.setVisible(true);
+ delete.setVisible(true);
+ }
- public boolean isInRecents() {
- return mActivity.getCurrentDirectory() == null;
- }
+ abstract void updateModePicker(MenuItem grid, MenuItem list, DirectoryDetails directoryDetails);
+ abstract void updateFileSize(MenuItem fileSize, DirectoryDetails directoryDetails);
+ abstract void updateSettings(MenuItem settings, DirectoryDetails directoryDetails);
+ abstract void updateNewWindow(MenuItem newWindow, DirectoryDetails directoryDetails);
+ abstract void updateMoveTo(MenuItem moveTo, SelectionDetails selectionDetails);
+ abstract void updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails);
+ abstract void updateSelectAll(MenuItem selectAll, SelectionDetails selectionDetails);
+ abstract void updateCreateDir(MenuItem createDir, DirectoryDetails directoryDetails);
+ abstract void updateOpen(MenuItem open, SelectionDetails selectionDetails);
+ abstract void updateShare(MenuItem share, SelectionDetails selectionDetails);
+ abstract void updateRename(MenuItem rename, SelectionDetails selectionDetails);
+ abstract void updateDelete(MenuItem delete, SelectionDetails selectionDetails);
- public boolean canCreateDirectory() {
- return mActivity.canCreateDirectory();
- }
- }
-}
\ No newline at end of file
+ /**
+ * Access to meta data about the selection.
+ */
+ public 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();
+ }
+
+ public static class DirectoryDetails {
+ private final BaseActivity mActivity;
+
+ public DirectoryDetails(BaseActivity activity) {
+ mActivity = activity;
+ }
+
+ public boolean shouldShowFancyFeatures() {
+ return Shared.shouldShowFancyFeatures(mActivity);
+ }
+
+ public boolean hasRootSettings() {
+ return mActivity.getCurrentRoot().hasSettings();
+ }
+
+ public boolean hasItemsToPaste() {
+ return false;
+ }
+
+ public boolean isInRecents() {
+ return mActivity.getCurrentDirectory() == null;
+ }
+
+ public boolean canCreateDirectory() {
+ return mActivity.canCreateDirectory();
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 303db2e..7f35854 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -61,15 +61,18 @@
import android.util.Log;
import android.util.SparseArray;
import android.view.ActionMode;
+import android.view.ContextMenu;
import android.view.DragEvent;
import android.view.GestureDetector;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
+import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
@@ -147,6 +150,7 @@
private MultiSelectManager mSelectionManager;
private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
private ItemEventListener mItemEventListener = new ItemEventListener();
+ private SelectionModeListener mSelectionModeListener;
private FocusManager mFocusManager;
private IconHelper mIconHelper;
@@ -297,6 +301,7 @@
new ListeningGestureDetector(this.getContext(), mDragHelper, new GestureListener());
mRecView.addOnItemTouchListener(mGestureDetector);
+ mEmptyView.setOnTouchListener(mGestureDetector);
// TODO: instead of inserting the view into the constructor, extract listener-creation code
// and set the listener on the view after the fact. Then the view doesn't need to be passed
@@ -313,7 +318,8 @@
mBandController = new BandController(mRecView, mAdapter, mSelectionManager);
}
- mSelectionManager.addCallback(new SelectionModeListener());
+ mSelectionModeListener = new SelectionModeListener();
+ mSelectionManager.addCallback(mSelectionModeListener);
mModel = new Model();
mModel.addUpdateListener(mAdapter);
@@ -362,6 +368,31 @@
}
}
+ @Override
+ public void onCreateContextMenu(ContextMenu menu,
+ View v,
+ ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ MenuInflater inflater = getActivity().getMenuInflater();
+ inflater.inflate(R.menu.context_menu, menu);
+
+ menu.add(Menu.NONE, R.id.menu_create_dir, Menu.NONE, R.string.menu_create_dir);
+ menu.add(Menu.NONE, R.id.menu_delete, Menu.NONE, R.string.menu_delete);
+ menu.add(Menu.NONE, R.id.menu_rename, Menu.NONE, R.string.menu_rename);
+
+ if (v == mRecView || v == mEmptyView) {
+ mMenuManager.updateContextMenu(menu, null, getBaseActivity().getDirectoryDetails());
+ } else {
+ mMenuManager.updateContextMenu(menu, mSelectionModeListener,
+ getBaseActivity().getDirectoryDetails());
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ return handleMenuItemClick(item);
+ }
+
private void handleCopyResult(int resultCode, Intent data) {
if (resultCode == Activity.RESULT_CANCELED || data == null) {
// User pressed the back button or otherwise cancelled the destination pick. Don't
@@ -382,9 +413,9 @@
mFileOpCallback);
}
- protected boolean onDoubleTap(MotionEvent e) {
- if (Events.isMouseEvent(e)) {
- String id = getModelId(e);
+ protected boolean onDoubleTap(MotionInputEvent event) {
+ if (event.isMouseEvent()) {
+ String id = getModelId(event);
if (id != null) {
return handleViewItem(id);
}
@@ -392,6 +423,41 @@
return false;
}
+ protected boolean onRightClick(MotionInputEvent e) {
+ // First get target to see if it's a blank window or a file/doc
+ DocumentHolder holder = getTarget(e);
+ if (holder != null) {
+ String modelId = getModelId(holder.itemView);
+ if (!mSelectionManager.getSelection().contains(modelId)) {
+ mSelectionManager.clearSelection();
+ // Set selection on the one single item
+ List<String> ids = Collections.singletonList(modelId);
+ mSelectionManager.setItemsSelected(ids, true);
+ }
+
+ // We are registering for context menu here so long-press doesn't trigger this
+ // floating context menu, and then quickly unregister right afterwards
+ registerForContextMenu(holder.itemView);
+ mRecView.showContextMenuForChild(holder.itemView,
+ e.getX() - holder.itemView.getLeft(), e.getY() - holder.itemView.getTop());
+ unregisterForContextMenu(holder.itemView);
+ }
+ // If there was no holder item, that means user right-clicked on the blank pane
+ // We would want to show different options then, and not select any item
+ // The blank pane could be the recyclerView or the emptyView, so we need to register
+ // according to whichever one is visible
+ else if (mEmptyView.getVisibility() == View.VISIBLE) {
+ registerForContextMenu(mEmptyView);
+ mEmptyView.showContextMenu(e.getX(), e.getY());
+ unregisterForContextMenu(mEmptyView);
+ } else {
+ registerForContextMenu(mRecView);
+ mRecView.showContextMenu(e.getX(), e.getY());
+ unregisterForContextMenu(mRecView);
+ }
+ return true;
+ }
+
private boolean handleViewItem(String id) {
final Cursor cursor = mModel.getItem(id);
@@ -690,58 +756,74 @@
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- Selection selection = mSelectionManager.getSelection(new Selection());
+ return handleMenuItemClick(item);
+ }
+ }
- switch (item.getItemId()) {
- case R.id.menu_open:
- openDocuments(selection);
- mode.finish();
- return true;
+ private boolean handleMenuItemClick(MenuItem item) {
+ Selection selection = mSelectionManager.getSelection(new Selection());
- case R.id.menu_share:
- shareDocuments(selection);
- // TODO: Only finish selection if share action is completed.
- mode.finish();
- return true;
+ switch (item.getItemId()) {
+ case R.id.menu_open:
+ openDocuments(selection);
+ mActionMode.finish();
+ return true;
- case R.id.menu_delete:
- // deleteDocuments will end action mode if the documents are deleted.
- // It won't end action mode if user cancels the delete.
- deleteDocuments(selection);
- return true;
+ case R.id.menu_share:
+ shareDocuments(selection);
+ // TODO: Only finish selection if share action is completed.
+ mActionMode.finish();
+ return true;
- case R.id.menu_copy_to:
- transferDocuments(selection, FileOperationService.OPERATION_COPY);
- // TODO: Only finish selection mode if copy-to is not canceled.
- // Need to plum down into handling the way we do with deleteDocuments.
- mode.finish();
- return true;
+ case R.id.menu_delete:
+ // deleteDocuments will end action mode if the documents are deleted.
+ // It won't end action mode if user cancels the delete.
+ deleteDocuments(selection);
+ return true;
- case R.id.menu_move_to:
- // Exit selection mode first, so we avoid deselecting deleted documents.
- mode.finish();
- transferDocuments(selection, FileOperationService.OPERATION_MOVE);
- return true;
+ case R.id.menu_copy_to:
+ transferDocuments(selection, FileOperationService.OPERATION_COPY);
+ // TODO: Only finish selection mode if copy-to is not canceled.
+ // Need to plum down into handling the way we do with deleteDocuments.
+ mActionMode.finish();
+ return true;
- case R.id.menu_copy_to_clipboard:
- copySelectedToClipboard();
- return true;
+ case R.id.menu_move_to:
+ // Exit selection mode first, so we avoid deselecting deleted documents.
+ mActionMode.finish();
+ transferDocuments(selection, FileOperationService.OPERATION_MOVE);
+ return true;
- case R.id.menu_select_all:
- selectAllFiles();
- return true;
+ case R.id.menu_cut_to_clipboard:
+ cutSelectedToClipboard();
+ return true;
- case R.id.menu_rename:
- // Exit selection mode first, so we avoid deselecting deleted
- // (renamed) documents.
- mode.finish();
- renameDocuments(selection);
- return true;
+ case R.id.menu_copy_to_clipboard:
+ copySelectedToClipboard();
+ return true;
- default:
+ case R.id.menu_paste_from_clipboard:
+ pasteFromClipboard();
+ return true;
+
+ case R.id.menu_select_all:
+ selectAllFiles();
+ return true;
+
+ case R.id.menu_rename:
+ // Exit selection mode first, so we avoid deselecting deleted
+ // (renamed) documents.
+ mActionMode.finish();
+ renameDocuments(selection);
+ return true;
+
+ default:
+ // See if BaseActivity can handle this particular MenuItem
+ if (!getBaseActivity().onOptionsItemSelected(item)) {
if (DEBUG) Log.d(TAG, "Unhandled menu item selected: " + item);
return false;
- }
+ }
+ return true;
}
}
@@ -1258,12 +1340,8 @@
/**
* Gets the model ID for a given motion event (using the event position)
*/
- private String getModelId(MotionEvent e) {
- View view = mRecView.findChildViewUnder(e.getX(), e.getY());
- if (view == null) {
- return null;
- }
- RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view);
+ private String getModelId(MotionInputEvent e) {
+ RecyclerView.ViewHolder vh = getTarget(e);
if (vh instanceof DocumentHolder) {
return ((DocumentHolder) vh).modelId;
} else {
@@ -1271,13 +1349,22 @@
}
}
+ private @Nullable DocumentHolder getTarget(MotionInputEvent e) {
+ View childView = mRecView.findChildViewUnder(e.getX(), e.getY());
+ if (childView != null) {
+ return (DocumentHolder) mRecView.getChildViewHolder(childView);
+ } else {
+ return null;
+ }
+ }
+
/**
* Gets the model ID for a given RecyclerView item.
* @param view A View that is a document item view, or a child of a document item view.
* @return The Model ID for the given document, or null if the given view is not associated with
* a document item view.
*/
- protected String getModelId(View view) {
+ protected @Nullable String getModelId(View view) {
View itemView = mRecView.findContainingItemView(view);
if (itemView != null) {
RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(itemView);
@@ -1565,29 +1652,24 @@
// to GestureDetector. We're still doing that here, but with a single class
// that reduces overall complexity in our glue code.
private static final class ListeningGestureDetector extends GestureDetector
- implements OnItemTouchListener {
+ implements OnItemTouchListener, OnTouchListener {
- private int mLastTool = -1;
private DragStartHelper mDragHelper;
+ private GestureListener mGestureListener;
public ListeningGestureDetector(
Context context, DragStartHelper dragHelper, GestureListener listener) {
super(context, listener);
mDragHelper = dragHelper;
+ mGestureListener = listener;
setOnDoubleTapListener(listener);
}
- boolean mouseSpawnedLastEvent() {
- return Events.isMouseType(mLastTool);
- }
-
- boolean touchSpawnedLastEvent() {
- return Events.isTouchType(mLastTool);
- }
-
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
- mLastTool = e.getToolType(0);
+ if (e.getAction() == MotionEvent.ACTION_DOWN && Events.isMouseEvent(e)) {
+ mGestureListener.setLastButtonState(e.getButtonState());
+ }
// Detect drag events. When a drag is detected, intercept the rest of the gesture.
View itemView = rv.findChildViewUnder(e.getX(), e.getY());
@@ -1612,6 +1694,15 @@
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
+
+ // For mEmptyView right-click context menu
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
+ return mGestureListener.onSingleTapConfirmed(event);
+ }
+ return false;
+ }
}
/**
@@ -1619,11 +1710,32 @@
* events to the target DocumentHolder, whence they are routed to the appropriate listener.
*/
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
+ // From the RecyclerView, we get two events sent to
+ // ListeningGestureDetector#onInterceptTouchEvent on a mouse click; we first get an
+ // ACTION_DOWN Event for clicking on the mouse, and then an ACTION_UP event from releasing
+ // the mouse click. ACTION_UP event doesn't have information regarding the button (primary
+ // vs. secondary), so we have to save that somewhere first from ACTION_DOWN, and then reuse
+ // it later. The ACTION_DOWN event doesn't get forwarded to GestureListener, so we have open
+ // up a public set method to set it.
+ private int mLastButtonState = -1;
+
+ public void setLastButtonState(int state) {
+ mLastButtonState = state;
+ }
+
@Override
public boolean onSingleTapUp(MotionEvent e) {
// Single tap logic:
+ // We first see if it's a mouse event, and if it was right click by checking on
+ // @{code ListeningGestureDetector#mLastButtonState}
// If the selection manager is active, it gets first whack at handling tap
// events. Otherwise, tap events are routed to the target DocumentHolder.
+ if (Events.isMouseEvent(e) && mLastButtonState == MotionEvent.BUTTON_SECONDARY) {
+ mLastButtonState = -1;
+ final MotionInputEvent event = MotionInputEvent.obtain(e, mRecView);
+ return DirectoryFragment.this.onRightClick(event);
+ }
+
final MotionInputEvent event = MotionInputEvent.obtain(e, mRecView);
try {
boolean handled = mSelectionManager.onSingleTapUp(event);
@@ -1633,7 +1745,7 @@
}
// Give the DocumentHolder a crack at the event.
- DocumentHolder holder = getTarget(e);
+ DocumentHolder holder = DirectoryFragment.this.getTarget(event);
if (holder != null) {
handled = holder.onSingleTapUp(e);
}
@@ -1660,16 +1772,8 @@
public boolean onDoubleTap(MotionEvent e) {
// Double-tap events are handled directly by the DirectoryFragment. They can be changed
// to route through the DocumentHolder if necessary.
- return DirectoryFragment.this.onDoubleTap(e);
- }
-
- private @Nullable DocumentHolder getTarget(MotionEvent e) {
- View childView = mRecView.findChildViewUnder(e.getX(), e.getY());
- if (childView != null) {
- return (DocumentHolder) mRecView.getChildViewHolder(childView);
- } else {
- return null;
- }
+ final MotionInputEvent event = MotionInputEvent.obtain(e, mRecView);
+ return DirectoryFragment.this.onDoubleTap(event);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index 0922fb7..497887c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -249,7 +249,6 @@
handleAdapterEvent(input);
}
- @VisibleForTesting
boolean onSingleTapUp(InputEvent input) {
if (DEBUG) Log.d(TAG, "Processing tap event.");
if (!hasSelection()) {
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsMenuManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsMenuManagerTest.java
index e0c99d8..ce8bc03 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsMenuManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsMenuManagerTest.java
@@ -48,6 +48,9 @@
private TestMenuItem fileSize;
private TestMenuItem grid;
private TestMenuItem list;
+ private TestMenuItem cut;
+ private TestMenuItem copy;
+ private TestMenuItem paste;
private TestSelectionDetails selectionDetails;
private TestDirectoryDetails directoryDetails;
@@ -66,6 +69,9 @@
fileSize = testMenu.findItem(R.id.menu_file_size);
grid = testMenu.findItem(R.id.menu_grid);
list = testMenu.findItem(R.id.menu_list);
+ cut = testMenu.findItem(R.id.menu_cut_to_clipboard);
+ copy = testMenu.findItem(R.id.menu_copy_to_clipboard);
+ paste = testMenu.findItem(R.id.menu_paste_from_clipboard);
selectionDetails = new TestSelectionDetails();
directoryDetails = new TestDirectoryDetails();
@@ -145,4 +151,29 @@
grid.assertInvisible();
list.assertInvisible();
}
+
+ @Test
+ public void testContextMenu_NoSelection() {
+ FilesMenuManager mgr = new FilesMenuManager(testSearchManager);
+ mgr.updateContextMenu(testMenu, null, directoryDetails);
+ cut.assertVisible();
+ copy.assertVisible();
+ cut.assertDisabled();
+ copy.assertDisabled();
+ paste.assertVisible();
+ createDir.assertVisible();
+ delete.assertVisible();
+ }
+
+ @Test
+ public void testContextMenu_Selection() {
+ FilesMenuManager mgr = new FilesMenuManager(testSearchManager);
+ mgr.updateContextMenu(testMenu, selectionDetails, directoryDetails);
+ cut.assertVisible();
+ copy.assertVisible();
+ paste.assertVisible();
+ rename.assertVisible();
+ createDir.assertVisible();
+ delete.assertVisible();
+ }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesMenuManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesMenuManagerTest.java
index 244f7ec..8b2eeb5 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesMenuManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesMenuManagerTest.java
@@ -41,9 +41,11 @@
private TestMenuItem share;
private TestMenuItem delete;
private TestMenuItem createDir;
- private TestMenuItem pasteFromCb;
private TestMenuItem settings;
private TestMenuItem newWindow;
+ private TestMenuItem cut;
+ private TestMenuItem copy;
+ private TestMenuItem paste;
private TestSelectionDetails selectionDetails;
private TestDirectoryDetails directoryDetails;
private TestSearchViewManager testSearchManager;
@@ -57,9 +59,16 @@
share = testMenu.findItem(R.id.menu_share);
delete = testMenu.findItem(R.id.menu_delete);
createDir = testMenu.findItem(R.id.menu_create_dir);
- pasteFromCb = testMenu.findItem(R.id.menu_paste_from_clipboard);
settings = testMenu.findItem(R.id.menu_settings);
newWindow = testMenu.findItem(R.id.menu_new_window);
+ cut = testMenu.findItem(R.id.menu_cut_to_clipboard);
+ copy = testMenu.findItem(R.id.menu_copy_to_clipboard);
+ paste = testMenu.findItem(R.id.menu_paste_from_clipboard);
+
+ // These items by default are visible
+ testMenu.findItem(R.id.menu_select_all).setVisible(true);
+ testMenu.findItem(R.id.menu_list).setVisible(true);
+ testMenu.findItem(R.id.menu_file_size).setVisible(true);
selectionDetails = new TestSelectionDetails();
directoryDetails = new TestDirectoryDetails();
@@ -133,15 +142,6 @@
}
@Test
- public void testOptionMenu_hasItemsToPaste() {
- directoryDetails.hasItemsToPaste = true;
- FilesMenuManager mgr = new FilesMenuManager(testSearchManager);
- mgr.updateOptionMenu(testMenu, directoryDetails);
-
- pasteFromCb.assertEnabled();
- }
-
- @Test
public void testOptionMenu_hasRootSettings() {
directoryDetails.hasRootSettings = true;
FilesMenuManager mgr = new FilesMenuManager(testSearchManager);
@@ -158,4 +158,29 @@
newWindow.assertVisible();
}
+
+ @Test
+ public void testContextMenu_NoSelection() {
+ FilesMenuManager mgr = new FilesMenuManager(testSearchManager);
+ mgr.updateContextMenu(testMenu, null, directoryDetails);
+ cut.assertVisible();
+ copy.assertVisible();
+ cut.assertDisabled();
+ copy.assertDisabled();
+ paste.assertVisible();
+ createDir.assertVisible();
+ delete.assertVisible();
+ }
+
+ @Test
+ public void testContextMenu_Selection() {
+ FilesMenuManager mgr = new FilesMenuManager(testSearchManager);
+ mgr.updateContextMenu(testMenu, selectionDetails, directoryDetails);
+ cut.assertVisible();
+ copy.assertVisible();
+ paste.assertVisible();
+ rename.assertVisible();
+ createDir.assertVisible();
+ delete.assertVisible();
+ }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/TestInputEvent.java b/packages/DocumentsUI/tests/src/com/android/documentsui/TestInputEvent.java
index ec5321a..a215488 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/TestInputEvent.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/TestInputEvent.java
@@ -56,6 +56,16 @@
}
@Override
+ public float getX() {
+ return location.x;
+ }
+
+ @Override
+ public float getY() {
+ return location.y;
+ }
+
+ @Override
public boolean isOverItem() {
return position != Integer.MIN_VALUE && position != RecyclerView.NO_POSITION;
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/testing/TestMenu.java b/packages/DocumentsUI/tests/src/com/android/documentsui/testing/TestMenu.java
index 78f26df..88a56db 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/testing/TestMenu.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/testing/TestMenu.java
@@ -38,20 +38,21 @@
public static TestMenu create() {
return create(R.id.menu_open,
R.id.menu_rename,
- R.id.menu_copy_to_clipboard,
- R.id.menu_paste_from_clipboard,
R.id.menu_move_to,
R.id.menu_copy_to,
+ R.id.menu_cut_to_clipboard,
+ R.id.menu_copy_to_clipboard,
+ R.id.menu_paste_from_clipboard,
R.id.menu_share,
R.id.menu_delete,
R.id.menu_create_dir,
- R.id.menu_paste_from_clipboard,
R.id.menu_settings,
R.id.menu_new_window,
R.id.menu_select_all,
R.id.menu_file_size,
R.id.menu_grid,
- R.id.menu_list);
+ R.id.menu_list,
+ R.id.menu_sort);
}
public static TestMenu create(int... ids) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index a4742c1..6658c14 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -319,9 +319,6 @@
private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
@Override
protected List<DashboardCategory> doInBackground(Void... params) {
- if (sConfigTracker == null || sTileCache == null) {
- getDashboardCategories();
- }
if (sConfigTracker.applyNewConfig(getResources())) {
sTileCache.clear();
}