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 17 package com.android.documentsui.files; 18 19 import android.content.Context; 20 import android.content.res.Resources; 21 import android.net.Uri; 22 import android.view.KeyEvent; 23 import android.view.KeyboardShortcutGroup; 24 import android.view.KeyboardShortcutInfo; 25 import android.view.Menu; 26 import android.view.MenuInflater; 27 import android.view.MenuItem; 28 import android.view.View; 29 30 import androidx.fragment.app.Fragment; 31 import androidx.recyclerview.selection.SelectionTracker; 32 33 import com.android.documentsui.R; 34 import com.android.documentsui.base.DocumentInfo; 35 import com.android.documentsui.base.Features; 36 import com.android.documentsui.base.Lookup; 37 import com.android.documentsui.base.LookupApplicationName; 38 import com.android.documentsui.base.Menus; 39 import com.android.documentsui.base.RootInfo; 40 import com.android.documentsui.base.Shared; 41 import com.android.documentsui.base.State; 42 import com.android.documentsui.base.UserId; 43 import com.android.documentsui.queries.SearchViewManager; 44 45 import java.util.List; 46 import java.util.function.IntFunction; 47 import java.util.function.IntSupplier; 48 49 public final class MenuManager extends com.android.documentsui.MenuManager { 50 51 private final Features mFeatures; 52 private final Context mContext; 53 private final SelectionTracker<String> mSelectionManager; 54 private final Lookup<String, Uri> mUriLookup; 55 private final LookupApplicationName mAppNameLookup; 56 MenuManager( Features features, SearchViewManager searchManager, State displayState, DirectoryDetails dirDetails, Context context, SelectionTracker<String> selectionManager, LookupApplicationName appNameLookup, Lookup<String, Uri> uriLookup, IntSupplier filesCountSupplier)57 public MenuManager( 58 Features features, 59 SearchViewManager searchManager, 60 State displayState, 61 DirectoryDetails dirDetails, 62 Context context, 63 SelectionTracker<String> selectionManager, 64 LookupApplicationName appNameLookup, 65 Lookup<String, Uri> uriLookup, 66 IntSupplier filesCountSupplier) { 67 68 super(searchManager, displayState, dirDetails, filesCountSupplier); 69 70 mFeatures = features; 71 mContext = context; 72 mSelectionManager = selectionManager; 73 mAppNameLookup = appNameLookup; 74 mUriLookup = uriLookup; 75 } 76 77 @Override updateKeyboardShortcutsMenu( List<KeyboardShortcutGroup> data, IntFunction<String> stringSupplier)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 showContextMenu(Fragment f, View v, float x, float y)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 inflateContextMenuForContainer( Menu menu, MenuInflater inflater, SelectionDetails selectionDetails)112 public void inflateContextMenuForContainer( 113 Menu menu, MenuInflater inflater, SelectionDetails selectionDetails) { 114 inflater.inflate(R.menu.container_context_menu, menu); 115 updateContextMenuForContainer(menu, selectionDetails); 116 } 117 118 @Override inflateContextMenuForDocs( Menu menu, MenuInflater inflater, SelectionDetails selectionDetails)119 public void inflateContextMenuForDocs( 120 Menu menu, MenuInflater inflater, SelectionDetails selectionDetails) { 121 final boolean hasDir = selectionDetails.containsDirectories(); 122 final boolean hasFile = selectionDetails.containsFiles(); 123 124 assert(hasDir || hasFile); 125 if (!hasDir) { 126 inflater.inflate(R.menu.file_context_menu, menu); 127 updateContextMenuForFiles(menu, selectionDetails); 128 return; 129 } 130 131 if (!hasFile) { 132 inflater.inflate(R.menu.dir_context_menu, menu); 133 updateContextMenuForDirs(menu, selectionDetails); 134 return; 135 } 136 137 inflater.inflate(R.menu.mixed_context_menu, menu); 138 updateContextMenu(menu, selectionDetails); 139 } 140 141 @Override updateSettings(MenuItem settings, RootInfo root)142 protected void updateSettings(MenuItem settings, RootInfo root) { 143 Menus.setEnabledAndVisible(settings, root.hasSettings()); 144 } 145 146 @Override updateEject(MenuItem eject, RootInfo root)147 protected void updateEject(MenuItem eject, RootInfo root) { 148 Menus.setEnabledAndVisible(eject, root.supportsEject() && !root.ejecting); 149 } 150 151 @Override updateSettings(MenuItem settings)152 protected void updateSettings(MenuItem settings) { 153 boolean enabled = mDirDetails.hasRootSettings(); 154 Menus.setEnabledAndVisible(settings, enabled); 155 } 156 157 @Override updateNewWindow(MenuItem newWindow)158 protected void updateNewWindow(MenuItem newWindow) { 159 Menus.setEnabledAndVisible(newWindow, true); 160 } 161 162 @Override updateOpenWith(MenuItem openWith, SelectionDetails selectionDetails)163 protected void updateOpenWith(MenuItem openWith, SelectionDetails selectionDetails) { 164 Menus.setEnabledAndVisible(openWith, selectionDetails.canOpenWith()); 165 } 166 167 @Override updateOpenInNewWindow( MenuItem openInNewWindow, SelectionDetails selectionDetails)168 protected void updateOpenInNewWindow( 169 MenuItem openInNewWindow, SelectionDetails selectionDetails) { 170 Menus.setEnabledAndVisible(openInNewWindow, selectionDetails.size() == 1 171 && !selectionDetails.containsPartialFiles()); 172 } 173 174 @Override updateOpenInNewWindow(MenuItem openInNewWindow, RootInfo root)175 protected void updateOpenInNewWindow(MenuItem openInNewWindow, RootInfo root) { 176 assert(openInNewWindow.isVisible() && openInNewWindow.isEnabled()); 177 } 178 179 @Override updateMoveTo(MenuItem moveTo, SelectionDetails selectionDetails)180 protected void updateMoveTo(MenuItem moveTo, SelectionDetails selectionDetails) { 181 Menus.setEnabledAndVisible(moveTo, 182 !selectionDetails.containsPartialFiles() && selectionDetails.canDelete()); 183 } 184 185 @Override updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails)186 protected void updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails) { 187 Menus.setEnabledAndVisible(copyTo, !selectionDetails.containsPartialFiles() 188 && !selectionDetails.canExtract()); 189 } 190 191 @Override updateCompress(MenuItem compress, SelectionDetails selectionDetails)192 protected void updateCompress(MenuItem compress, SelectionDetails selectionDetails) { 193 final boolean readOnly = !mDirDetails.canCreateDoc(); 194 Menus.setEnabledAndVisible(compress, mFeatures.isArchiveCreationEnabled() 195 && !readOnly 196 && !selectionDetails.containsPartialFiles() 197 && !selectionDetails.canExtract()); 198 } 199 200 @Override updateExtractTo(MenuItem extractTo, SelectionDetails selectionDetails)201 protected void updateExtractTo(MenuItem extractTo, SelectionDetails selectionDetails) { 202 boolean enabled = selectionDetails.canExtract(); 203 Menus.setEnabledAndVisible(extractTo, enabled); 204 } 205 206 @Override updatePasteInto(MenuItem pasteInto, SelectionDetails selectionDetails)207 protected void updatePasteInto(MenuItem pasteInto, SelectionDetails selectionDetails) { 208 Menus.setEnabledAndVisible(pasteInto, 209 selectionDetails.canPasteInto() && mDirDetails.hasItemsToPaste()); 210 } 211 212 @Override updatePasteInto(MenuItem pasteInto, RootInfo root, DocumentInfo docInfo)213 protected void updatePasteInto(MenuItem pasteInto, RootInfo root, DocumentInfo docInfo) { 214 Menus.setEnabledAndVisible(pasteInto, root.supportsCreate() 215 && docInfo != null 216 && docInfo.isCreateSupported() 217 && mDirDetails.hasItemsToPaste()); 218 } 219 220 @Override updateSelectAll(MenuItem selectAll)221 protected void updateSelectAll(MenuItem selectAll) { 222 Menus.setEnabledAndVisible(selectAll, true); 223 } 224 225 @Override updateSelectAll(MenuItem selectAll, SelectionDetails selectionDetails)226 protected void updateSelectAll(MenuItem selectAll, SelectionDetails selectionDetails) { 227 final boolean visible = selectionDetails.size() < mFilesCountSupplier.getAsInt(); 228 Menus.setEnabledAndVisible(selectAll, visible); 229 } 230 231 @Override 232 protected void updateDeselectAll(MenuItem deselectAll, SelectionDetails selectionDetails) { 233 final boolean visible = selectionDetails.size() == mFilesCountSupplier.getAsInt(); 234 Menus.setEnabledAndVisible(deselectAll, visible); 235 } 236 237 @Override 238 protected void updateCreateDir(MenuItem createDir) { 239 Menus.setEnabledAndVisible(createDir, mDirDetails.canCreateDirectory()); 240 } 241 242 @Override 243 protected void updateShare(MenuItem share, SelectionDetails selectionDetails) { 244 boolean enabled = !selectionDetails.containsDirectories() 245 && !selectionDetails.containsPartialFiles() 246 && !selectionDetails.canExtract(); 247 Menus.setEnabledAndVisible(share, enabled); 248 } 249 250 @Override 251 protected void updateDelete(MenuItem delete, SelectionDetails selectionDetails) { 252 boolean enabled = selectionDetails.canDelete(); 253 Menus.setEnabledAndVisible(delete, enabled); 254 } 255 256 @Override 257 protected void updateRename(MenuItem rename, SelectionDetails selectionDetails) { 258 Menus.setEnabledAndVisible(rename, 259 !selectionDetails.containsPartialFiles() && selectionDetails.canRename()); 260 } 261 262 @Override 263 protected void updateInspect(MenuItem inspect) { 264 boolean visible = mFeatures.isInspectorEnabled(); 265 Menus.setEnabledAndVisible(inspect, visible && mDirDetails.canInspectDirectory()); 266 } 267 268 @Override 269 protected void updateInspect(MenuItem inspect, SelectionDetails selectionDetails) { 270 boolean visible = mFeatures.isInspectorEnabled() && selectionDetails.size() <= 1; 271 Menus.setEnabledAndVisible(inspect, visible); 272 } 273 274 @Override 275 protected void updateViewInOwner(MenuItem view, SelectionDetails selectionDetails) { 276 if (selectionDetails.canViewInOwner() && 277 mSelectionManager.getSelection().iterator().hasNext()) { 278 Menus.setEnabledAndVisible(view, true); 279 Resources res = mContext.getResources(); 280 String selectedModelId = mSelectionManager.getSelection().iterator().next(); 281 Uri selectedUri = mUriLookup.lookup(selectedModelId); 282 String appName = mAppNameLookup.getApplicationName(UserId.DEFAULT_USER, 283 selectedUri.getAuthority()); 284 String title = res.getString(R.string.menu_view_in_owner, appName); 285 view.setTitle(title); 286 } 287 else { 288 Menus.setEnabledAndVisible(view, false); 289 } 290 } 291 292 @Override 293 protected void updateLauncher(MenuItem launcher) { 294 Menus.setEnabledAndVisible(launcher, mState.debugMode); 295 launcher.setTitle(Shared.isLauncherEnabled(mContext) 296 ? "Hide launcher icon" : "Show launcher icon"); 297 } 298 } 299