1/* 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.files; 18 19import android.app.Fragment; 20import android.content.Context; 21import android.content.res.Resources; 22import android.net.Uri; 23import android.view.KeyEvent; 24import android.view.KeyboardShortcutGroup; 25import android.view.KeyboardShortcutInfo; 26import android.view.Menu; 27import android.view.MenuInflater; 28import android.view.MenuItem; 29import android.view.View; 30 31import com.android.documentsui.R; 32import com.android.documentsui.base.DocumentInfo; 33import com.android.documentsui.base.Features; 34import com.android.documentsui.base.Lookup; 35import com.android.documentsui.base.RootInfo; 36import com.android.documentsui.base.State; 37import com.android.documentsui.queries.SearchViewManager; 38import com.android.documentsui.selection.SelectionManager; 39 40import java.util.List; 41import java.util.function.Function; 42import java.util.function.IntFunction; 43 44public final class MenuManager extends com.android.documentsui.MenuManager { 45 46 private final Features mFeatures; 47 private final Context mContext; 48 private final SelectionManager mSelectionManager; 49 private final Lookup<String, Uri> mUriLookup; 50 private final Lookup<String, String> mAppNameLookup; 51 52 public MenuManager( 53 Features features, 54 SearchViewManager searchManager, 55 State displayState, 56 DirectoryDetails dirDetails, 57 Context context, 58 SelectionManager selectionManager, 59 Lookup<String, String> appNameLookup, 60 Lookup<String, Uri> uriLookup) { 61 super(searchManager, displayState, dirDetails); 62 mFeatures = features; 63 mContext = context; 64 mSelectionManager = selectionManager; 65 mAppNameLookup = appNameLookup; 66 mUriLookup = uriLookup; 67 } 68 69 @Override 70 public void updateOptionMenu(Menu menu) { 71 super.updateOptionMenu(menu); 72 73 // It hides icon if searching in progress 74 mSearchManager.updateMenu(); 75 } 76 77 @Override 78 public void updateKeyboardShortcutsMenu( 79 List<KeyboardShortcutGroup> data, IntFunction<String> stringSupplier) { 80 KeyboardShortcutGroup group = new KeyboardShortcutGroup( 81 stringSupplier.apply(R.string.app_label)); 82 group.addItem(new KeyboardShortcutInfo( 83 stringSupplier.apply(R.string.menu_cut_to_clipboard), KeyEvent.KEYCODE_X, 84 KeyEvent.META_CTRL_ON)); 85 group.addItem(new KeyboardShortcutInfo( 86 stringSupplier.apply(R.string.menu_copy_to_clipboard), KeyEvent.KEYCODE_C, 87 KeyEvent.META_CTRL_ON)); 88 group.addItem(new KeyboardShortcutInfo( 89 stringSupplier.apply(R.string.menu_paste_from_clipboard), KeyEvent.KEYCODE_V, 90 KeyEvent.META_CTRL_ON)); 91 group.addItem(new KeyboardShortcutInfo( 92 stringSupplier.apply(R.string.menu_create_dir), KeyEvent.KEYCODE_E, 93 KeyEvent.META_CTRL_ON)); 94 group.addItem(new KeyboardShortcutInfo( 95 stringSupplier.apply(R.string.menu_select_all), KeyEvent.KEYCODE_A, 96 KeyEvent.META_CTRL_ON)); 97 group.addItem(new KeyboardShortcutInfo( 98 stringSupplier.apply(R.string.menu_new_window), KeyEvent.KEYCODE_N, 99 KeyEvent.META_CTRL_ON)); 100 data.add(group); 101 } 102 103 @Override 104 public void showContextMenu(Fragment f, View v, float x, float y) { 105 // Register context menu here so long-press doesn't trigger this context floating menu. 106 f.registerForContextMenu(v); 107 v.showContextMenu(x, y); 108 f.unregisterForContextMenu(v); 109 } 110 111 @Override 112 public void inflateContextMenuForContainer(Menu menu, MenuInflater inflater) { 113 inflater.inflate(R.menu.container_context_menu, menu); 114 updateContextMenuForContainer(menu); 115 } 116 117 @Override 118 public void inflateContextMenuForDocs( 119 Menu menu, MenuInflater inflater, SelectionDetails selectionDetails) { 120 final boolean hasDir = selectionDetails.containsDirectories(); 121 final boolean hasFile = selectionDetails.containsFiles(); 122 123 assert(hasDir || hasFile); 124 if (!hasDir) { 125 inflater.inflate(R.menu.file_context_menu, menu); 126 updateContextMenuForFiles(menu, selectionDetails); 127 return; 128 } 129 130 if (!hasFile) { 131 inflater.inflate(R.menu.dir_context_menu, menu); 132 updateContextMenuForDirs(menu, selectionDetails); 133 return; 134 } 135 136 inflater.inflate(R.menu.mixed_context_menu, menu); 137 updateContextMenu(menu, selectionDetails); 138 } 139 140 @Override 141 protected void updateSettings(MenuItem settings, RootInfo root) { 142 settings.setVisible(true); 143 settings.setEnabled(root.hasSettings()); 144 } 145 146 @Override 147 protected void updateEject(MenuItem eject, RootInfo root) { 148 eject.setVisible(root.supportsEject()); 149 eject.setEnabled(!root.ejecting); 150 } 151 152 @Override 153 protected void updateSettings(MenuItem settings) { 154 boolean enabled = mDirDetails.hasRootSettings(); 155 settings.setVisible(enabled); 156 settings.setEnabled(enabled); 157 } 158 159 @Override 160 protected void updateNewWindow(MenuItem newWindow) { 161 newWindow.setVisible(true); 162 } 163 164 @Override 165 protected void updateOpenInContextMenu(MenuItem open, SelectionDetails selectionDetails) { 166 open.setVisible(true); 167 open.setEnabled(selectionDetails.size() == 1 168 && !selectionDetails.containsPartialFiles()); 169 } 170 171 @Override 172 protected void updateOpenWith(MenuItem openWith, SelectionDetails selectionDetails) { 173 openWith.setVisible(true); 174 openWith.setEnabled(selectionDetails.canOpenWith()); 175 } 176 177 @Override 178 protected void updateOpenInNewWindow( 179 MenuItem openInNewWindow, SelectionDetails selectionDetails) { 180 openInNewWindow.setVisible(true); 181 openInNewWindow.setEnabled(selectionDetails.size() == 1 182 && !selectionDetails.containsPartialFiles()); 183 } 184 185 @Override 186 protected void updateOpenInNewWindow(MenuItem openInNewWindow, RootInfo root) { 187 assert(openInNewWindow.isVisible() && openInNewWindow.isEnabled()); 188 } 189 190 @Override 191 protected void updateMoveTo(MenuItem moveTo, SelectionDetails selectionDetails) { 192 moveTo.setVisible(true); 193 moveTo.setEnabled(!selectionDetails.containsPartialFiles() && selectionDetails.canDelete()); 194 } 195 196 @Override 197 protected void updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails) { 198 copyTo.setVisible(true); 199 copyTo.setEnabled(!selectionDetails.containsPartialFiles() && 200 !selectionDetails.canExtract()); 201 } 202 203 @Override 204 protected void updateCompress(MenuItem compress, SelectionDetails selectionDetails) { 205 final boolean readOnly = !mDirDetails.canCreateDoc(); 206 compress.setVisible(mFeatures.isArchiveCreationEnabled()); 207 compress.setEnabled(!readOnly && !selectionDetails.containsPartialFiles() && 208 !selectionDetails.canExtract()); 209 } 210 211 @Override 212 protected void updateExtractTo(MenuItem extractTo, SelectionDetails selectionDetails) { 213 boolean enabled = selectionDetails.canExtract(); 214 extractTo.setVisible(enabled); 215 extractTo.setEnabled(enabled); 216 } 217 218 @Override 219 protected void updatePasteInto(MenuItem pasteInto, SelectionDetails selectionDetails) { 220 pasteInto.setVisible(true); 221 pasteInto.setEnabled(selectionDetails.canPasteInto() && mDirDetails.hasItemsToPaste()); 222 } 223 224 @Override 225 protected void updatePasteInto(MenuItem pasteInto, RootInfo root, DocumentInfo docInfo) { 226 pasteInto.setVisible(true); 227 pasteInto.setEnabled(root.supportsCreate() 228 && docInfo != null 229 && docInfo.isCreateSupported() 230 && mDirDetails.hasItemsToPaste()); 231 } 232 233 @Override 234 protected void updateSelectAll(MenuItem selectAll) { 235 selectAll.setVisible(true); 236 selectAll.setEnabled(true); 237 } 238 239 @Override 240 protected void updateCreateDir(MenuItem createDir) { 241 createDir.setVisible(true); 242 createDir.setEnabled(mDirDetails.canCreateDirectory()); 243 } 244 245 @Override 246 protected void updateShare(MenuItem share, SelectionDetails selectionDetails) { 247 boolean enabled = !selectionDetails.containsDirectories() 248 && !selectionDetails.containsPartialFiles() 249 && !selectionDetails.canExtract(); 250 share.setVisible(enabled); 251 share.setEnabled(enabled); 252 } 253 254 @Override 255 protected void updateDelete(MenuItem delete, SelectionDetails selectionDetails) { 256 boolean enabled = selectionDetails.canDelete(); 257 delete.setVisible(enabled); 258 delete.setEnabled(enabled); 259 } 260 261 @Override 262 protected void updateRename(MenuItem rename, SelectionDetails selectionDetails) { 263 rename.setVisible(true); 264 rename.setEnabled(!selectionDetails.containsPartialFiles() && selectionDetails.canRename()); 265 } 266 267 @Override 268 protected void updateInspector(MenuItem properties, SelectionDetails selectionDetails) { 269 boolean visible = mFeatures.isInspectorEnabled(); 270 properties.setVisible(visible); 271 properties.setEnabled(visible && selectionDetails.size() == 1); 272 } 273 274 @Override 275 protected void updateViewInOwner(MenuItem view, SelectionDetails selectionDetails) { 276 if (selectionDetails.canViewInOwner()) { 277 view.setVisible(true); 278 view.setEnabled(true); 279 Resources res = mContext.getResources(); 280 String selectedModelId = mSelectionManager.getSelection().iterator().next(); 281 Uri selectedUri = mUriLookup.lookup(selectedModelId); 282 String appName = mAppNameLookup.lookup(selectedUri.getAuthority()); 283 String title = res.getString(R.string.menu_view_in_owner, appName); 284 view.setTitle(title); 285 } 286 else { 287 view.setVisible(false); 288 } 289 } 290} 291