blob: c965c3211c9213a25aac0999709468a5664d7eec [file] [log] [blame]
Ben Lin7c35b032016-05-31 13:24:01 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.documentsui;
18
Garfield Tan239ab972016-09-16 13:33:48 -070019import android.app.Fragment;
Steve McKay92ae43d2016-11-08 12:06:58 -080020import android.view.KeyboardShortcutGroup;
Ben Lin7c35b032016-05-31 13:24:01 -070021import android.view.Menu;
Garfield Tan239ab972016-09-16 13:33:48 -070022import android.view.MenuInflater;
Ben Linebf2a172016-06-03 13:46:52 -070023import android.view.MenuItem;
Garfield Tan239ab972016-09-16 13:33:48 -070024import android.view.View;
Ben Lin7c35b032016-05-31 13:24:01 -070025
Ben Lin8e912582016-09-23 14:25:14 -070026import com.android.documentsui.base.DocumentInfo;
Steve McKayd9caa6a2016-09-15 16:36:45 -070027import com.android.documentsui.base.Menus;
Steve McKayd0805062016-09-15 14:30:38 -070028import com.android.documentsui.base.RootInfo;
Steve McKayd9caa6a2016-09-15 16:36:45 -070029import com.android.documentsui.base.State;
Garfield Tan06c4b112016-09-14 11:05:58 -070030import com.android.documentsui.dirlist.DirectoryFragment;
Steve McKay92ae43d2016-11-08 12:06:58 -080031import com.android.documentsui.files.FilesActivity;
Steve McKay3a268232016-10-19 11:15:47 -070032import com.android.documentsui.queries.SearchViewManager;
Garfield Tanb285b402016-09-21 17:12:18 -070033import com.android.documentsui.sidebar.RootsFragment;
Garfield Tan239ab972016-09-16 13:33:48 -070034import com.android.internal.annotations.VisibleForTesting;
Ben Lin5668b862016-06-28 17:12:52 -070035
Steve McKay92ae43d2016-11-08 12:06:58 -080036import java.util.List;
37import java.util.function.IntFunction;
38
Ben Linebf2a172016-06-03 13:46:52 -070039public abstract class MenuManager {
Ben Lin7c35b032016-05-31 13:24:01 -070040
Garfield Tan25676032016-09-19 13:52:35 -070041 final protected SearchViewManager mSearchManager;
Steve McKaye5d6ca22016-09-19 20:27:24 -070042 final protected State mState;
43 final protected DirectoryDetails mDirDetails;
Ben Lin25679912016-06-17 11:48:57 -070044
Steve McKaye5d6ca22016-09-19 20:27:24 -070045 public MenuManager(
46 SearchViewManager searchManager,
47 State displayState,
48 DirectoryDetails dirDetails) {
Ben Lin25679912016-06-17 11:48:57 -070049 mSearchManager = searchManager;
50 mState = displayState;
Steve McKaye5d6ca22016-09-19 20:27:24 -070051 mDirDetails = dirDetails;
Ben Lin25679912016-06-17 11:48:57 -070052 }
53
Garfield Tan06c4b112016-09-14 11:05:58 -070054 /** @see ActionModeController */
Ben Linebf2a172016-06-03 13:46:52 -070055 public void updateActionMenu(Menu menu, SelectionDetails selection) {
Garfield Tan06c4b112016-09-14 11:05:58 -070056 updateOpenInActionMode(menu.findItem(R.id.menu_open), selection);
Tomasz Mikolajewskiac3e63e2017-02-13 10:08:58 +090057 updateOpenWith(menu.findItem(R.id.menu_open_with), selection);
Ben Linebf2a172016-06-03 13:46:52 -070058 updateDelete(menu.findItem(R.id.menu_delete), selection);
59 updateShare(menu.findItem(R.id.menu_share), selection);
60 updateRename(menu.findItem(R.id.menu_rename), selection);
Garfield Tan06c4b112016-09-14 11:05:58 -070061 updateSelectAll(menu.findItem(R.id.menu_select_all));
Ben Linebf2a172016-06-03 13:46:52 -070062 updateMoveTo(menu.findItem(R.id.menu_move_to), selection);
63 updateCopyTo(menu.findItem(R.id.menu_copy_to), selection);
Tomasz Mikolajewski26640ab2017-02-06 10:37:59 +090064 updateCompress(menu.findItem(R.id.menu_compress), selection);
Tomasz Mikolajewski5a8e3782017-01-24 12:40:55 +090065 updateExtractTo(menu.findItem(R.id.menu_extract_to), selection);
Jon Mann253a9922017-03-21 18:53:27 -070066 updateViewInOwner(menu.findItem(R.id.menu_view_in_owner), selection);
Ben Lin7c35b032016-05-31 13:24:01 -070067
Ben Linebf2a172016-06-03 13:46:52 -070068 Menus.disableHiddenItems(menu);
69 }
Ben Lin7c35b032016-05-31 13:24:01 -070070
Garfield Tan06c4b112016-09-14 11:05:58 -070071 /** @see BaseActivity#onPrepareOptionsMenu */
Steve McKaye5d6ca22016-09-19 20:27:24 -070072 public void updateOptionMenu(Menu menu) {
73 updateCreateDir(menu.findItem(R.id.menu_create_dir));
74 updateSettings(menu.findItem(R.id.menu_settings));
Jon Mann49be24c2017-02-13 17:29:20 -080075 updateSelectAll(menu.findItem(R.id.menu_select_all));
Steve McKaye5d6ca22016-09-19 20:27:24 -070076 updateNewWindow(menu.findItem(R.id.menu_new_window));
77 updateModePicker(menu.findItem(R.id.menu_grid), menu.findItem(R.id.menu_list));
Steve McKaye5d6ca22016-09-19 20:27:24 -070078 updateAdvanced(menu.findItem(R.id.menu_advanced));
Jon Manneb1d11b2017-04-01 15:36:59 -070079 updateDebug(menu.findItem(R.id.menu_debug));
Ben Lin7c35b032016-05-31 13:24:01 -070080
Ben Linebf2a172016-06-03 13:46:52 -070081 Menus.disableHiddenItems(menu);
82 }
Ben Lin7c35b032016-05-31 13:24:01 -070083
Garfield Tan06c4b112016-09-14 11:05:58 -070084 /**
Garfield Tan239ab972016-09-16 13:33:48 -070085 * Called when we needs {@link MenuManager} to ask Android to show context menu for us.
86 * {@link MenuManager} can choose to defeat this request.
87 *
88 * {@link #inflateContextMenuForDocs} and {@link #inflateContextMenuForContainer} are called
89 * afterwards when Android asks us to provide the content of context menus, so they're not
90 * correct locations to suppress context menus.
91 */
92 public void showContextMenu(Fragment f, View v, float x, float y) {
93 // Pickers don't have any context menu at this moment.
94 }
95
Steve McKaye5d6ca22016-09-19 20:27:24 -070096 public void inflateContextMenuForContainer(Menu menu, MenuInflater inflater) {
Garfield Tan239ab972016-09-16 13:33:48 -070097 throw new UnsupportedOperationException("Pickers don't allow context menu.");
98 }
99
100 public void inflateContextMenuForDocs(
101 Menu menu, MenuInflater inflater, SelectionDetails selectionDetails) {
102 throw new UnsupportedOperationException("Pickers don't allow context menu.");
103 }
104
105 /**
Garfield Tan06c4b112016-09-14 11:05:58 -0700106 * @see DirectoryFragment#onCreateContextMenu
Ben Linb2dfa122016-08-11 17:42:57 -0700107 *
Garfield Tan06c4b112016-09-14 11:05:58 -0700108 * Called when user tries to generate a context menu anchored to a file when the selection
109 * doesn't contain any folder.
110 *
111 * @param selectionDetails
112 * containsFiles may return false because this may be called when user right clicks on an
113 * unselectable item in pickers
114 */
Garfield Tan239ab972016-09-16 13:33:48 -0700115 @VisibleForTesting
Garfield Tan25676032016-09-19 13:52:35 -0700116 public void updateContextMenuForFiles(Menu menu, SelectionDetails selectionDetails) {
Garfield Tan06c4b112016-09-14 11:05:58 -0700117 assert(selectionDetails != null);
118
119 MenuItem share = menu.findItem(R.id.menu_share);
120 MenuItem open = menu.findItem(R.id.menu_open);
121 MenuItem openWith = menu.findItem(R.id.menu_open_with);
122 MenuItem rename = menu.findItem(R.id.menu_rename);
Jon Mann253a9922017-03-21 18:53:27 -0700123 MenuItem viewInOwner = menu.findItem(R.id.menu_view_in_owner);
Garfield Tan06c4b112016-09-14 11:05:58 -0700124
125 updateShare(share, selectionDetails);
126 updateOpenInContextMenu(open, selectionDetails);
127 updateOpenWith(openWith, selectionDetails);
128 updateRename(rename, selectionDetails);
Jon Mann253a9922017-03-21 18:53:27 -0700129 updateViewInOwner(viewInOwner, selectionDetails);
Garfield Tan06c4b112016-09-14 11:05:58 -0700130
131 updateContextMenu(menu, selectionDetails);
132 }
133
134 /**
135 * @see DirectoryFragment#onCreateContextMenu
136 *
137 * Called when user tries to generate a context menu anchored to a folder when the selection
138 * doesn't contain any file.
139 *
140 * @param selectionDetails
141 * containDirectories may return false because this may be called when user right clicks on
142 * an unselectable item in pickers
143 */
Garfield Tan239ab972016-09-16 13:33:48 -0700144 @VisibleForTesting
Garfield Tan25676032016-09-19 13:52:35 -0700145 public void updateContextMenuForDirs(Menu menu, SelectionDetails selectionDetails) {
Garfield Tan06c4b112016-09-14 11:05:58 -0700146 assert(selectionDetails != null);
147
148 MenuItem openInNewWindow = menu.findItem(R.id.menu_open_in_new_window);
149 MenuItem rename = menu.findItem(R.id.menu_rename);
150 MenuItem pasteInto = menu.findItem(R.id.menu_paste_into_folder);
151
152 updateOpenInNewWindow(openInNewWindow, selectionDetails);
153 updateRename(rename, selectionDetails);
154 updatePasteInto(pasteInto, selectionDetails);
155
156 updateContextMenu(menu, selectionDetails);
157 }
158
159 /**
160 * @see DirectoryFragment#onCreateContextMenu
161 *
162 * Update shared context menu items of both files and folders context menus.
163 */
Garfield Tan239ab972016-09-16 13:33:48 -0700164 @VisibleForTesting
Garfield Tan25676032016-09-19 13:52:35 -0700165 public void updateContextMenu(Menu menu, SelectionDetails selectionDetails) {
Ben Linb2dfa122016-08-11 17:42:57 -0700166 assert(selectionDetails != null);
167
168 MenuItem cut = menu.findItem(R.id.menu_cut_to_clipboard);
169 MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
Ben Linb2dfa122016-08-11 17:42:57 -0700170 MenuItem delete = menu.findItem(R.id.menu_delete);
Ben Linb2dfa122016-08-11 17:42:57 -0700171
Garfield Tan06c4b112016-09-14 11:05:58 -0700172 final boolean canCopy =
173 selectionDetails.size() > 0 && !selectionDetails.containsPartialFiles();
174 final boolean canDelete = selectionDetails.canDelete();
175 cut.setEnabled(canCopy && canDelete);
176 copy.setEnabled(canCopy);
177 delete.setEnabled(canDelete);
Ben Linb2dfa122016-08-11 17:42:57 -0700178 }
179
Garfield Tan06c4b112016-09-14 11:05:58 -0700180 /**
181 * @see DirectoryFragment#onCreateContextMenu
Ben Linb2dfa122016-08-11 17:42:57 -0700182 *
183 * Called when user tries to generate a context menu anchored to an empty pane.
Garfield Tan06c4b112016-09-14 11:05:58 -0700184 */
Garfield Tan239ab972016-09-16 13:33:48 -0700185 @VisibleForTesting
Steve McKaye5d6ca22016-09-19 20:27:24 -0700186 public void updateContextMenuForContainer(Menu menu) {
Ben Linebf2a172016-06-03 13:46:52 -0700187 MenuItem paste = menu.findItem(R.id.menu_paste_from_clipboard);
Garfield Tan06c4b112016-09-14 11:05:58 -0700188 MenuItem selectAll = menu.findItem(R.id.menu_select_all);
Garfield Tand3307272016-10-10 13:33:25 -0700189 MenuItem createDir = menu.findItem(R.id.menu_create_dir);
Ben Lin7c35b032016-05-31 13:24:01 -0700190
Steve McKaye5d6ca22016-09-19 20:27:24 -0700191 paste.setEnabled(mDirDetails.hasItemsToPaste() && mDirDetails.canCreateDoc());
Garfield Tan06c4b112016-09-14 11:05:58 -0700192 updateSelectAll(selectAll);
Garfield Tand3307272016-10-10 13:33:25 -0700193 updateCreateDir(createDir);
Ben Linebf2a172016-06-03 13:46:52 -0700194 }
Ben Lin7c35b032016-05-31 13:24:01 -0700195
Garfield Tan06c4b112016-09-14 11:05:58 -0700196 /**
197 * @see RootsFragment#onCreateContextMenu
198 */
Ben Lin8e912582016-09-23 14:25:14 -0700199 public void updateRootContextMenu(Menu menu, RootInfo root, DocumentInfo docInfo) {
Ben Lin5668b862016-06-28 17:12:52 -0700200 MenuItem eject = menu.findItem(R.id.menu_eject_root);
Garfield Tanb285b402016-09-21 17:12:18 -0700201 MenuItem pasteInto = menu.findItem(R.id.menu_paste_into_folder);
202 MenuItem openInNewWindow = menu.findItem(R.id.menu_open_in_new_window);
203 MenuItem settings = menu.findItem(R.id.menu_settings);
Ben Lin5668b862016-06-28 17:12:52 -0700204
Ben Lin5668b862016-06-28 17:12:52 -0700205 updateEject(eject, root);
Ben Lin8e912582016-09-23 14:25:14 -0700206 updatePasteInto(pasteInto, root, docInfo);
Garfield Tanb285b402016-09-21 17:12:18 -0700207 updateOpenInNewWindow(openInNewWindow, root);
208 updateSettings(settings, root);
Ben Lin5668b862016-06-28 17:12:52 -0700209 }
210
Steve McKay92ae43d2016-11-08 12:06:58 -0800211 public abstract void updateKeyboardShortcutsMenu(
212 List<KeyboardShortcutGroup> data, IntFunction<String> stringSupplier);
213
Steve McKaye5d6ca22016-09-19 20:27:24 -0700214 protected void updateModePicker(MenuItem grid, MenuItem list) {
Ben Lin25679912016-06-17 11:48:57 -0700215 grid.setVisible(mState.derivedMode != State.MODE_GRID);
216 list.setVisible(mState.derivedMode != State.MODE_LIST);
217 }
218
Steve McKaye5d6ca22016-09-19 20:27:24 -0700219 protected void updateAdvanced(MenuItem advanced) {
Steve McKay01996bc2016-10-21 13:38:49 -0700220 advanced.setVisible(mState.showDeviceStorageOption);
221 advanced.setTitle(mState.showDeviceStorageOption && mState.showAdvanced
Ben Lin25679912016-06-17 11:48:57 -0700222 ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
223 }
224
Jon Manneb1d11b2017-04-01 15:36:59 -0700225 protected void updateDebug(MenuItem debug) {
226 debug.setVisible(mState.debugMode);
227 }
228
Steve McKaye5d6ca22016-09-19 20:27:24 -0700229 protected void updateSettings(MenuItem settings) {
Ben Lin25679912016-06-17 11:48:57 -0700230 settings.setVisible(false);
231 }
232
Garfield Tan25676032016-09-19 13:52:35 -0700233 protected void updateSettings(MenuItem settings, RootInfo root) {
Ben Lin5668b862016-06-28 17:12:52 -0700234 settings.setVisible(false);
235 }
236
Garfield Tan25676032016-09-19 13:52:35 -0700237 protected void updateEject(MenuItem eject, RootInfo root) {
Ben Lin5668b862016-06-28 17:12:52 -0700238 eject.setVisible(false);
239 }
240
Steve McKaye5d6ca22016-09-19 20:27:24 -0700241 protected void updateNewWindow(MenuItem newWindow) {
Ben Lin25679912016-06-17 11:48:57 -0700242 newWindow.setVisible(false);
243 }
244
Garfield Tan25676032016-09-19 13:52:35 -0700245 protected void updateOpenInActionMode(MenuItem open, SelectionDetails selectionDetails) {
Ben Lin25679912016-06-17 11:48:57 -0700246 open.setVisible(false);
247 }
248
Garfield Tan25676032016-09-19 13:52:35 -0700249 protected void updateOpenWith(MenuItem openWith, SelectionDetails selectionDetails) {
Garfield Tan06c4b112016-09-14 11:05:58 -0700250 openWith.setVisible(false);
251 }
252
Garfield Tan25676032016-09-19 13:52:35 -0700253 protected void updateOpenInNewWindow(
254 MenuItem openInNewWindow, SelectionDetails selectionDetails) {
Garfield Tan06c4b112016-09-14 11:05:58 -0700255 openInNewWindow.setVisible(false);
256 }
257
Garfield Tanb285b402016-09-21 17:12:18 -0700258 protected void updateOpenInNewWindow(
259 MenuItem openInNewWindow, RootInfo root) {
260 openInNewWindow.setVisible(false);
261 }
262
Garfield Tan25676032016-09-19 13:52:35 -0700263 protected void updateShare(MenuItem share, SelectionDetails selectionDetails) {
Ben Lin25679912016-06-17 11:48:57 -0700264 share.setVisible(false);
265 }
266
Garfield Tan25676032016-09-19 13:52:35 -0700267 protected void updateDelete(MenuItem delete, SelectionDetails selectionDetails) {
Ben Lin25679912016-06-17 11:48:57 -0700268 delete.setVisible(false);
269 }
270
Garfield Tan25676032016-09-19 13:52:35 -0700271 protected void updateRename(MenuItem rename, SelectionDetails selectionDetails) {
Ben Lin25679912016-06-17 11:48:57 -0700272 rename.setVisible(false);
273 }
274
Jon Mann253a9922017-03-21 18:53:27 -0700275 protected void updateViewInOwner(MenuItem view, SelectionDetails selectionDetails) {
276 view.setVisible(false);
277 }
278
Garfield Tan25676032016-09-19 13:52:35 -0700279 protected void updateMoveTo(MenuItem moveTo, SelectionDetails selectionDetails) {
Ben Lin25679912016-06-17 11:48:57 -0700280 moveTo.setVisible(false);
281 }
282
Garfield Tan25676032016-09-19 13:52:35 -0700283 protected void updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails) {
Ben Lin25679912016-06-17 11:48:57 -0700284 copyTo.setVisible(false);
285 }
286
Tomasz Mikolajewski26640ab2017-02-06 10:37:59 +0900287 protected void updateCompress(MenuItem compress, SelectionDetails selectionDetails) {
288 compress.setVisible(false);
289 }
290
Tomasz Mikolajewski5a8e3782017-01-24 12:40:55 +0900291 protected void updateExtractTo(MenuItem extractTo, SelectionDetails selectionDetails) {
292 extractTo.setVisible(false);
293 }
294
Garfield Tan25676032016-09-19 13:52:35 -0700295 protected void updatePasteInto(MenuItem pasteInto, SelectionDetails selectionDetails) {
Garfield Tan06c4b112016-09-14 11:05:58 -0700296 pasteInto.setVisible(false);
Ben Linb2dfa122016-08-11 17:42:57 -0700297 }
298
Ben Lin8e912582016-09-23 14:25:14 -0700299 protected void updatePasteInto(MenuItem pasteInto, RootInfo root, DocumentInfo docInfo) {
Garfield Tanb285b402016-09-21 17:12:18 -0700300 pasteInto.setVisible(false);
301 }
302
Garfield Tan25676032016-09-19 13:52:35 -0700303 protected abstract void updateOpenInContextMenu(
304 MenuItem open, SelectionDetails selectionDetails);
305 protected abstract void updateSelectAll(MenuItem selectAll);
Steve McKaye5d6ca22016-09-19 20:27:24 -0700306 protected abstract void updateCreateDir(MenuItem createDir);
Ben Lin7c35b032016-05-31 13:24:01 -0700307
Ben Linebf2a172016-06-03 13:46:52 -0700308 /**
309 * Access to meta data about the selection.
310 */
311 public interface SelectionDetails {
312 boolean containsDirectories();
313
Garfield Tan06c4b112016-09-14 11:05:58 -0700314 boolean containsFiles();
315
316 int size();
317
Ben Linebf2a172016-06-03 13:46:52 -0700318 boolean containsPartialFiles();
319
320 // TODO: Update these to express characteristics instead of answering concrete questions,
321 // since the answer to those questions is (or can be) activity specific.
322 boolean canDelete();
323
324 boolean canRename();
Ben Linb2dfa122016-08-11 17:42:57 -0700325
326 boolean canPasteInto();
Tomasz Mikolajewski5a8e3782017-01-24 12:40:55 +0900327
328 boolean canExtract();
Tomasz Mikolajewskiac3e63e2017-02-13 10:08:58 +0900329
330 boolean canOpenWith();
Jon Mann253a9922017-03-21 18:53:27 -0700331
332 boolean canViewInOwner();
Ben Linebf2a172016-06-03 13:46:52 -0700333 }
334
335 public static class DirectoryDetails {
Steve McKay92ae43d2016-11-08 12:06:58 -0800336 private final BaseActivity mActivity;
Ben Linebf2a172016-06-03 13:46:52 -0700337
Steve McKay92ae43d2016-11-08 12:06:58 -0800338 public DirectoryDetails(BaseActivity activity) {
Ben Linebf2a172016-06-03 13:46:52 -0700339 mActivity = activity;
340 }
341
Ben Linebf2a172016-06-03 13:46:52 -0700342 public boolean hasRootSettings() {
343 return mActivity.getCurrentRoot().hasSettings();
344 }
345
346 public boolean hasItemsToPaste() {
347 return false;
348 }
349
Garfield Tan06c4b112016-09-14 11:05:58 -0700350 public boolean canCreateDoc() {
351 return isInRecents() ? false : mActivity.getCurrentDirectory().isCreateSupported();
352 }
353
Ben Linebf2a172016-06-03 13:46:52 -0700354 public boolean isInRecents() {
355 return mActivity.getCurrentDirectory() == null;
356 }
357
358 public boolean canCreateDirectory() {
359 return mActivity.canCreateDirectory();
360 }
361 }
362}