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.picker; 18 19 import static com.android.documentsui.base.State.ACTION_CREATE; 20 import static com.android.documentsui.base.State.ACTION_GET_CONTENT; 21 import static com.android.documentsui.base.State.ACTION_OPEN; 22 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertTrue; 25 26 import android.database.MatrixCursor; 27 import android.provider.DocumentsContract.Document; 28 import android.provider.DocumentsContract.Root; 29 30 import androidx.test.filters.SmallTest; 31 import androidx.test.runner.AndroidJUnit4; 32 33 import com.android.documentsui.DirectoryResult; 34 import com.android.documentsui.Model; 35 import com.android.documentsui.R; 36 import com.android.documentsui.base.DocumentInfo; 37 import com.android.documentsui.base.RootInfo; 38 import com.android.documentsui.base.State; 39 import com.android.documentsui.roots.RootCursorWrapper; 40 import com.android.documentsui.testing.TestDirectoryDetails; 41 import com.android.documentsui.testing.TestFeatures; 42 import com.android.documentsui.testing.TestMenu; 43 import com.android.documentsui.testing.TestMenuItem; 44 import com.android.documentsui.testing.TestSearchViewManager; 45 import com.android.documentsui.testing.TestSelectionDetails; 46 47 import org.junit.Before; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 51 @RunWith(AndroidJUnit4.class) 52 @SmallTest 53 public final class MenuManagerTest { 54 55 private TestMenu testMenu; 56 57 /* Directory Context Menu items */ 58 private TestMenuItem dirShare; 59 private TestMenuItem dirOpen; 60 private TestMenuItem dirOpenWith; 61 private TestMenuItem dirCutToClipboard; 62 private TestMenuItem dirCopyToClipboard; 63 private TestMenuItem dirPasteFromClipboard; 64 private TestMenuItem dirCreateDir; 65 private TestMenuItem dirSelectAll; 66 private TestMenuItem mDirDeselectAll; 67 private TestMenuItem dirRename; 68 private TestMenuItem dirDelete; 69 private TestMenuItem dirViewInOwner; 70 private TestMenuItem dirOpenInNewWindow; 71 private TestMenuItem dirPasteIntoFolder; 72 73 /* Root List Context Menu items */ 74 private TestMenuItem rootEjectRoot; 75 private TestMenuItem rootOpenInNewWindow; 76 private TestMenuItem rootPasteIntoFolder; 77 private TestMenuItem rootSettings; 78 79 /* Action Mode menu items */ 80 private TestMenuItem actionModeOpen; 81 private TestMenuItem actionModeOpenWith; 82 private TestMenuItem actionModeSelect; 83 private TestMenuItem actionModeShare; 84 private TestMenuItem actionModeDelete; 85 private TestMenuItem actionModeSelectAll; 86 private TestMenuItem mActionModeDeselectAll; 87 private TestMenuItem actionModeCopyTo; 88 private TestMenuItem actionModeExtractTo; 89 private TestMenuItem actionModeMoveTo; 90 private TestMenuItem actionModeCompress; 91 private TestMenuItem actionModeRename; 92 private TestMenuItem actionModeViewInOwner; 93 private TestMenuItem actionModeSort; 94 95 /* Option Menu items */ 96 private TestMenuItem optionSearch; 97 private TestMenuItem optionDebug; 98 private TestMenuItem optionNewWindow; 99 private TestMenuItem optionCreateDir; 100 private TestMenuItem optionSelectAll; 101 private TestMenuItem optionSettings; 102 private TestMenuItem optionSort; 103 private TestMenuItem mOptionLauncher; 104 private TestMenuItem mOptionShowHiddenFiles; 105 106 private TestMenuItem subOptionGrid; 107 private TestMenuItem subOptionList; 108 109 private TestSelectionDetails selectionDetails; 110 private TestDirectoryDetails dirDetails; 111 private TestSearchViewManager testSearchManager; 112 private State state = new State(); 113 private RootInfo testRootInfo; 114 private DocumentInfo testDocInfo; 115 private MenuManager mgr; 116 117 private int mFilesCount; 118 119 @Before setUp()120 public void setUp() { 121 testMenu = TestMenu.create(); 122 dirShare = testMenu.findItem(R.id.dir_menu_share); 123 dirOpen = testMenu.findItem(R.id.dir_menu_open); 124 dirOpenWith = testMenu.findItem(R.id.dir_menu_open_with); 125 dirCutToClipboard = testMenu.findItem(R.id.dir_menu_cut_to_clipboard); 126 dirCopyToClipboard = testMenu.findItem(R.id.dir_menu_copy_to_clipboard); 127 dirPasteFromClipboard = testMenu.findItem(R.id.dir_menu_paste_from_clipboard); 128 dirCreateDir = testMenu.findItem(R.id.dir_menu_create_dir); 129 dirSelectAll = testMenu.findItem(R.id.dir_menu_select_all); 130 mDirDeselectAll = testMenu.findItem(R.id.dir_menu_deselect_all); 131 dirRename = testMenu.findItem(R.id.dir_menu_rename); 132 dirDelete = testMenu.findItem(R.id.dir_menu_delete); 133 dirViewInOwner = testMenu.findItem(R.id.dir_menu_view_in_owner); 134 dirOpenInNewWindow = testMenu.findItem(R.id.dir_menu_open_in_new_window); 135 dirPasteIntoFolder = testMenu.findItem(R.id.dir_menu_paste_into_folder); 136 137 rootEjectRoot = testMenu.findItem(R.id.root_menu_eject_root); 138 rootOpenInNewWindow = testMenu.findItem(R.id.root_menu_open_in_new_window); 139 rootPasteIntoFolder = testMenu.findItem(R.id.root_menu_paste_into_folder); 140 rootSettings = testMenu.findItem(R.id.root_menu_settings); 141 142 actionModeOpenWith = testMenu.findItem(R.id.action_menu_open_with); 143 actionModeSelect = testMenu.findItem(R.id.action_menu_select); 144 actionModeShare = testMenu.findItem(R.id.action_menu_share); 145 actionModeDelete = testMenu.findItem(R.id.action_menu_delete); 146 actionModeSelectAll = testMenu.findItem(R.id.action_menu_select_all); 147 mActionModeDeselectAll = testMenu.findItem(R.id.action_menu_deselect_all); 148 actionModeCopyTo = testMenu.findItem(R.id.action_menu_copy_to); 149 actionModeExtractTo = testMenu.findItem(R.id.action_menu_extract_to); 150 actionModeMoveTo = testMenu.findItem(R.id.action_menu_move_to); 151 actionModeCompress = testMenu.findItem(R.id.action_menu_compress); 152 actionModeRename = testMenu.findItem(R.id.action_menu_rename); 153 actionModeViewInOwner = testMenu.findItem(R.id.action_menu_view_in_owner); 154 actionModeSort = testMenu.findItem(R.id.action_menu_sort); 155 156 optionSearch = testMenu.findItem(R.id.option_menu_search); 157 optionDebug = testMenu.findItem(R.id.option_menu_debug); 158 optionNewWindow = testMenu.findItem(R.id.option_menu_new_window); 159 optionCreateDir = testMenu.findItem(R.id.option_menu_create_dir); 160 optionSelectAll = testMenu.findItem(R.id.option_menu_select_all); 161 optionSettings = testMenu.findItem(R.id.option_menu_settings); 162 optionSort = testMenu.findItem(R.id.option_menu_sort); 163 mOptionLauncher = testMenu.findItem(R.id.option_menu_launcher); 164 mOptionShowHiddenFiles = testMenu.findItem(R.id.option_menu_show_hidden_files); 165 166 // Menu actions on root title row. 167 subOptionGrid = testMenu.findItem(R.id.sub_menu_grid); 168 subOptionList = testMenu.findItem(R.id.sub_menu_list); 169 170 selectionDetails = new TestSelectionDetails(); 171 dirDetails = new TestDirectoryDetails(); 172 testSearchManager = new TestSearchViewManager(); 173 mgr = new MenuManager(testSearchManager, state, dirDetails, this::getFilesCount); 174 selectionDetails.size = 1; 175 mFilesCount = 10; 176 177 testRootInfo = new RootInfo(); 178 testDocInfo = new DocumentInfo(); 179 state.action = ACTION_CREATE; 180 state.allowMultiple = true; 181 } 182 getFilesCount()183 private int getFilesCount() { 184 return mFilesCount; 185 } 186 187 @Test testActionMenu()188 public void testActionMenu() { 189 mgr.updateActionMenu(testMenu, selectionDetails); 190 actionModeSelect.assertDisabledAndInvisible(); 191 actionModeDelete.assertDisabledAndInvisible(); 192 actionModeShare.assertDisabledAndInvisible(); 193 actionModeRename.assertDisabledAndInvisible(); 194 actionModeSelectAll.assertEnabledAndVisible(); 195 mActionModeDeselectAll.assertDisabledAndInvisible(); 196 actionModeViewInOwner.assertDisabledAndInvisible(); 197 actionModeSort.assertEnabledAndVisible(); 198 } 199 200 @Test testActionMenu_selectAction()201 public void testActionMenu_selectAction() { 202 state.action = ACTION_OPEN; 203 mgr.updateActionMenu(testMenu, selectionDetails); 204 205 actionModeSelect.assertEnabledAndVisible(); 206 } 207 208 @Test testActionMenu_selectActionTitle()209 public void testActionMenu_selectActionTitle() { 210 state.action = ACTION_OPEN; 211 mgr.updateActionMenu(testMenu, selectionDetails); 212 213 actionModeSelect.assertTitle(R.string.menu_select); 214 } 215 216 @Test testActionMenu_getContentAction()217 public void testActionMenu_getContentAction() { 218 state.action = ACTION_GET_CONTENT; 219 mgr.updateActionMenu(testMenu, selectionDetails); 220 221 actionModeSelect.assertEnabledAndVisible(); 222 } 223 224 @Test testActionMenu_getContentActionTitle()225 public void testActionMenu_getContentActionTitle() { 226 state.action = ACTION_GET_CONTENT; 227 mgr.updateActionMenu(testMenu, selectionDetails); 228 229 actionModeSelect.assertTitle(R.string.menu_select); 230 } 231 232 @Test testActionMenu_notAllowMultiple()233 public void testActionMenu_notAllowMultiple() { 234 state.allowMultiple = false; 235 mgr.updateActionMenu(testMenu, selectionDetails); 236 237 actionModeSelectAll.assertDisabledAndInvisible(); 238 mActionModeDeselectAll.assertDisabledAndInvisible(); 239 } 240 241 @Test testActionMenu_AllowMultiple()242 public void testActionMenu_AllowMultiple() { 243 state.allowMultiple = true; 244 mgr.updateActionMenu(testMenu, selectionDetails); 245 246 actionModeSelectAll.assertEnabledAndVisible(); 247 mActionModeDeselectAll.assertDisabledAndInvisible(); 248 } 249 250 @Test testActionMenu_CanDeselectAll()251 public void testActionMenu_CanDeselectAll() { 252 state.allowMultiple = true; 253 selectionDetails.size = 1; 254 mFilesCount = 1; 255 256 mgr.updateActionMenu(testMenu, selectionDetails); 257 258 actionModeSelectAll.assertDisabledAndInvisible(); 259 mActionModeDeselectAll.assertEnabledAndVisible(); 260 } 261 262 @Test testOptionMenu()263 public void testOptionMenu() { 264 mgr.updateOptionMenu(testMenu); 265 266 optionCreateDir.assertDisabledAndInvisible(); 267 optionDebug.assertDisabledAndInvisible(); 268 optionSort.assertEnabledAndVisible(); 269 mOptionLauncher.assertDisabledAndInvisible(); 270 mOptionShowHiddenFiles.assertEnabledAndVisible(); 271 assertTrue(testSearchManager.showMenuCalled()); 272 } 273 274 @Test testOptionMenu_notPicking()275 public void testOptionMenu_notPicking() { 276 state.action = ACTION_OPEN; 277 state.derivedMode = State.MODE_LIST; 278 mgr.updateOptionMenu(testMenu); 279 mgr.updateSubMenu(testMenu); 280 281 optionCreateDir.assertDisabledAndInvisible(); 282 subOptionGrid.assertEnabledAndVisible(); 283 subOptionList.assertDisabledAndInvisible(); 284 assertFalse(testSearchManager.showMenuCalled()); 285 } 286 287 @Test testOptionMenu_canCreateDirectory()288 public void testOptionMenu_canCreateDirectory() { 289 dirDetails.canCreateDirectory = true; 290 mgr.updateOptionMenu(testMenu); 291 292 optionCreateDir.assertEnabledAndVisible(); 293 } 294 295 @Test testOptionMenu_inRecents()296 public void testOptionMenu_inRecents() { 297 dirDetails.isInRecents = true; 298 mgr.updateOptionMenu(testMenu); 299 mgr.updateSubMenu(testMenu); 300 301 subOptionGrid.assertDisabledAndInvisible(); 302 subOptionList.assertDisabledAndInvisible(); 303 } 304 305 306 @Test testOptionMenu_onlyContainer()307 public void testOptionMenu_onlyContainer() { 308 state.allowMultiple = true; 309 mgr.updateModel(getTestModel(true)); 310 mgr.updateOptionMenu(testMenu); 311 312 optionSelectAll.assertDisabledAndInvisible(); 313 } 314 315 @Test testOptionMenu_containerAndFile()316 public void testOptionMenu_containerAndFile() { 317 state.allowMultiple = true; 318 mgr.updateModel(getTestModel(false)); 319 mgr.updateOptionMenu(testMenu); 320 321 optionSelectAll.assertEnabledAndVisible(); 322 } 323 324 @Test testContextMenu_EmptyArea()325 public void testContextMenu_EmptyArea() { 326 dirDetails.hasItemsToPaste = false; 327 dirDetails.canCreateDoc = false; 328 dirDetails.canCreateDirectory = false; 329 330 mgr.updateContextMenuForContainer(testMenu, selectionDetails); 331 332 dirSelectAll.assertEnabledAndVisible(); 333 mDirDeselectAll.assertDisabledAndInvisible(); 334 dirPasteFromClipboard.assertDisabledAndInvisible(); 335 dirCreateDir.assertDisabledAndInvisible(); 336 } 337 338 @Test testContextMenu_EmptyArea_NoItemToPaste()339 public void testContextMenu_EmptyArea_NoItemToPaste() { 340 dirDetails.hasItemsToPaste = false; 341 dirDetails.canCreateDoc = true; 342 343 mgr.updateContextMenuForContainer(testMenu, selectionDetails); 344 345 dirSelectAll.assertEnabledAndVisible(); 346 dirPasteFromClipboard.assertDisabledAndInvisible(); 347 dirCreateDir.assertDisabledAndInvisible(); 348 } 349 350 @Test testContextMenu_EmptyArea_CantCreateDoc()351 public void testContextMenu_EmptyArea_CantCreateDoc() { 352 dirDetails.hasItemsToPaste = true; 353 dirDetails.canCreateDoc = false; 354 355 mgr.updateContextMenuForContainer(testMenu, selectionDetails); 356 357 dirSelectAll.assertEnabledAndVisible(); 358 dirPasteFromClipboard.assertDisabledAndInvisible(); 359 dirCreateDir.assertDisabledAndInvisible(); 360 } 361 362 @Test testContextMenu_EmptyArea_canPaste()363 public void testContextMenu_EmptyArea_canPaste() { 364 dirDetails.hasItemsToPaste = true; 365 dirDetails.canCreateDoc = true; 366 367 mgr.updateContextMenuForContainer(testMenu, selectionDetails); 368 369 dirSelectAll.assertEnabledAndVisible(); 370 dirPasteFromClipboard.assertEnabledAndVisible(); 371 dirCreateDir.assertDisabledAndInvisible(); 372 } 373 374 @Test testContextMenu_EmptyArea_CanCreateDirectory()375 public void testContextMenu_EmptyArea_CanCreateDirectory() { 376 dirDetails.canCreateDirectory = true; 377 378 mgr.updateContextMenuForContainer(testMenu, selectionDetails); 379 380 dirSelectAll.assertEnabledAndVisible(); 381 dirPasteFromClipboard.assertDisabledAndInvisible(); 382 dirCreateDir.assertEnabledAndVisible(); 383 } 384 385 @Test testContextMenu_EmptyArea_CanDeselectAll()386 public void testContextMenu_EmptyArea_CanDeselectAll() { 387 selectionDetails.size = 1; 388 mFilesCount = 1; 389 390 mgr.updateContextMenuForContainer(testMenu, selectionDetails); 391 392 dirSelectAll.assertDisabledAndInvisible(); 393 mDirDeselectAll.assertEnabledAndVisible(); 394 } 395 396 @Test testContextMenu_OnFile()397 public void testContextMenu_OnFile() { 398 mgr.updateContextMenuForFiles(testMenu, selectionDetails); 399 // We don't want share in pickers. 400 dirShare.assertDisabledAndInvisible(); 401 // We don't want openWith in pickers. 402 dirOpenWith.assertDisabledAndInvisible(); 403 dirCutToClipboard.assertDisabledAndInvisible(); 404 dirCopyToClipboard.assertEnabledAndVisible(); 405 dirRename.assertDisabledAndInvisible(); 406 dirDelete.assertDisabledAndInvisible(); 407 } 408 409 @Test testContextMenu_OnDirectory()410 public void testContextMenu_OnDirectory() { 411 selectionDetails.canPasteInto = true; 412 mgr.updateContextMenuForDirs(testMenu, selectionDetails); 413 // We don't want openInNewWindow in pickers 414 dirOpenInNewWindow.assertDisabledAndInvisible(); 415 dirCutToClipboard.assertDisabledAndInvisible(); 416 dirCopyToClipboard.assertEnabledAndVisible(); 417 // Doesn't matter if directory is selected, we don't want pasteInto for PickerActivity 418 dirPasteIntoFolder.assertDisabledAndInvisible(); 419 dirRename.assertDisabledAndInvisible(); 420 dirDelete.assertDisabledAndInvisible(); 421 } 422 423 @Test testContextMenu_OnMixedDocs()424 public void testContextMenu_OnMixedDocs() { 425 selectionDetails.containDirectories = true; 426 selectionDetails.containFiles = true; 427 selectionDetails.size = 2; 428 selectionDetails.canDelete = true; 429 mgr.updateContextMenu(testMenu, selectionDetails); 430 dirCutToClipboard.assertEnabledAndVisible(); 431 dirCopyToClipboard.assertEnabledAndVisible(); 432 dirDelete.assertEnabledAndVisible(); 433 } 434 435 @Test testContextMenu_OnMixedDocs_hasPartialFile()436 public void testContextMenu_OnMixedDocs_hasPartialFile() { 437 selectionDetails.containDirectories = true; 438 selectionDetails.containFiles = true; 439 selectionDetails.size = 2; 440 selectionDetails.containPartial = true; 441 selectionDetails.canDelete = true; 442 mgr.updateContextMenu(testMenu, selectionDetails); 443 dirCutToClipboard.assertDisabledAndInvisible(); 444 dirCopyToClipboard.assertDisabledAndInvisible(); 445 dirDelete.assertEnabledAndVisible(); 446 } 447 448 @Test testContextMenu_OnMixedDocs_hasUndeletableFile()449 public void testContextMenu_OnMixedDocs_hasUndeletableFile() { 450 selectionDetails.containDirectories = true; 451 selectionDetails.containFiles = true; 452 selectionDetails.size = 2; 453 selectionDetails.canDelete = false; 454 mgr.updateContextMenu(testMenu, selectionDetails); 455 dirCutToClipboard.assertDisabledAndInvisible(); 456 dirCopyToClipboard.assertEnabledAndVisible(); 457 dirDelete.assertDisabledAndInvisible(); 458 } 459 460 @Test testRootContextMenu()461 public void testRootContextMenu() { 462 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 463 464 rootEjectRoot.assertDisabledAndInvisible(); 465 rootOpenInNewWindow.assertDisabledAndInvisible(); 466 rootPasteIntoFolder.assertDisabledAndInvisible(); 467 rootSettings.assertDisabledAndInvisible(); 468 } 469 470 @Test testRootContextMenu_hasRootSettings()471 public void testRootContextMenu_hasRootSettings() { 472 testRootInfo.flags = Root.FLAG_HAS_SETTINGS; 473 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 474 475 rootSettings.assertDisabledAndInvisible(); 476 } 477 478 @Test testRootContextMenu_nonWritableRoot()479 public void testRootContextMenu_nonWritableRoot() { 480 dirDetails.hasItemsToPaste = true; 481 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 482 483 rootPasteIntoFolder.assertDisabledAndInvisible(); 484 } 485 486 @Test testRootContextMenu_nothingToPaste()487 public void testRootContextMenu_nothingToPaste() { 488 testRootInfo.flags = Root.FLAG_SUPPORTS_CREATE; 489 dirDetails.hasItemsToPaste = false; 490 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 491 492 rootPasteIntoFolder.assertDisabledAndInvisible(); 493 } 494 495 @Test testRootContextMenu_canEject()496 public void testRootContextMenu_canEject() { 497 testRootInfo.flags = Root.FLAG_SUPPORTS_EJECT; 498 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 499 500 rootEjectRoot.assertDisabledAndInvisible(); 501 } 502 getTestModel(boolean onlyDirectory)503 private Model getTestModel(boolean onlyDirectory) { 504 String[] COLUMNS = new String[]{ 505 RootCursorWrapper.COLUMN_AUTHORITY, 506 Document.COLUMN_DOCUMENT_ID, 507 Document.COLUMN_FLAGS, 508 Document.COLUMN_DISPLAY_NAME, 509 Document.COLUMN_SIZE, 510 Document.COLUMN_LAST_MODIFIED, 511 Document.COLUMN_MIME_TYPE 512 }; 513 MatrixCursor c = new MatrixCursor(COLUMNS); 514 for (int i = 0; i < 3; ++i) { 515 MatrixCursor.RowBuilder row = c.newRow(); 516 row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i)); 517 row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); 518 } 519 520 if (!onlyDirectory) { 521 MatrixCursor.RowBuilder row = c.newRow(); 522 row.add(Document.COLUMN_DOCUMENT_ID, "4"); 523 row.add(Document.COLUMN_MIME_TYPE, "image/jpg"); 524 } 525 526 DirectoryResult r = new DirectoryResult(); 527 r.setCursor(c); 528 Model model = new Model(new TestFeatures()); 529 model.update(r); 530 531 return model; 532 } 533 } 534