MenuManagerTest.java revision ac3e63e584a079c9efd84de66e65a8f6c05b773d
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2016 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 171d3165f10b12165f02b7015ac1a817c5f60e6399Neal Nguyenpackage com.android.documentsui.files; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 191d3165f10b12165f02b7015ac1a817c5f60e6399Neal Nguyenimport static junit.framework.Assert.assertEquals; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport static org.junit.Assert.assertTrue; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.DocumentsContract.Document; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.DocumentsContract.Root; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.support.test.filters.SmallTest; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.support.test.runner.AndroidJUnit4; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.documentsui.R; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.documentsui.base.DocumentInfo; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.documentsui.base.RootInfo; 311d3165f10b12165f02b7015ac1a817c5f60e6399Neal Nguyenimport com.android.documentsui.base.State; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.documentsui.testing.TestDirectoryDetails; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.documentsui.testing.TestMenu; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.documentsui.testing.TestMenuInflater; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.documentsui.testing.TestMenuItem; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.documentsui.testing.TestSearchViewManager; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.documentsui.testing.TestSelectionDetails; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.junit.Before; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.junit.Test; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.junit.runner.RunWith; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project@RunWith(AndroidJUnit4.class) 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project@SmallTest 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic final class MenuManagerTest { 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TestMenu testMenu; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TestMenuItem rename; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TestMenuItem selectAll; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TestMenuItem moveTo; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TestMenuItem copyTo; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TestMenuItem compress; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TestMenuItem extractTo; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TestMenuItem share; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TestMenuItem delete; 56 private TestMenuItem createDir; 57 private TestMenuItem settings; 58 private TestMenuItem newWindow; 59 private TestMenuItem open; 60 private TestMenuItem openWith; 61 private TestMenuItem openInNewWindow; 62 private TestMenuItem cut; 63 private TestMenuItem copy; 64 private TestMenuItem paste; 65 private TestMenuItem pasteInto; 66 private TestMenuItem advanced; 67 private TestMenuItem eject; 68 69 private TestActivity testActivity; 70 private TestSelectionDetails selectionDetails; 71 private TestDirectoryDetails dirDetails; 72 private TestSearchViewManager testSearchManager; 73 private RootInfo testRootInfo; 74 private DocumentInfo testDocInfo; 75 private State state = new State(); 76 private MenuManager mgr; 77 78 @Before 79 public void setUp() { 80 testMenu = TestMenu.create(); 81 rename = testMenu.findItem(R.id.menu_rename); 82 selectAll = testMenu.findItem(R.id.menu_select_all); 83 moveTo = testMenu.findItem(R.id.menu_move_to); 84 copyTo = testMenu.findItem(R.id.menu_copy_to); 85 compress = testMenu.findItem(R.id.menu_compress); 86 extractTo = testMenu.findItem(R.id.menu_extract_to); 87 share = testMenu.findItem(R.id.menu_share); 88 delete = testMenu.findItem(R.id.menu_delete); 89 createDir = testMenu.findItem(R.id.menu_create_dir); 90 settings = testMenu.findItem(R.id.menu_settings); 91 newWindow = testMenu.findItem(R.id.menu_new_window); 92 open = testMenu.findItem(R.id.menu_open); 93 openWith = testMenu.findItem(R.id.menu_open_with); 94 openInNewWindow = testMenu.findItem(R.id.menu_open_in_new_window); 95 cut = testMenu.findItem(R.id.menu_cut_to_clipboard); 96 copy = testMenu.findItem(R.id.menu_copy_to_clipboard); 97 paste = testMenu.findItem(R.id.menu_paste_from_clipboard); 98 pasteInto = testMenu.findItem(R.id.menu_paste_into_folder); 99 advanced = testMenu.findItem(R.id.menu_advanced); 100 eject = testMenu.findItem(R.id.menu_eject_root); 101 102 // These items by default are visible 103 testMenu.findItem(R.id.menu_select_all).setVisible(true); 104 testMenu.findItem(R.id.menu_list).setVisible(true); 105 106 selectionDetails = new TestSelectionDetails(); 107 dirDetails = new TestDirectoryDetails(); 108 testSearchManager = new TestSearchViewManager(); 109 mgr = new MenuManager(testSearchManager, state, dirDetails); 110 111 testRootInfo = new RootInfo(); 112 testDocInfo = new DocumentInfo(); 113 } 114 115 @Test 116 public void testActionMenu() { 117 selectionDetails.canDelete = true; 118 selectionDetails.canRename = true; 119 dirDetails.canCreateDoc = true; 120 121 mgr.updateActionMenu(testMenu, selectionDetails); 122 123 rename.assertEnabled(); 124 delete.assertVisible(); 125 share.assertVisible(); 126 copyTo.assertEnabled(); 127 compress.assertEnabled(); 128 extractTo.assertInvisible(); 129 moveTo.assertEnabled(); 130 } 131 132 @Test 133 public void testActionMenu_containsPartial() { 134 selectionDetails.containPartial = true; 135 dirDetails.canCreateDoc = true; 136 mgr.updateActionMenu(testMenu, selectionDetails); 137 138 rename.assertDisabled(); 139 share.assertInvisible(); 140 copyTo.assertDisabled(); 141 compress.assertDisabled(); 142 extractTo.assertDisabled(); 143 moveTo.assertDisabled(); 144 } 145 146 @Test 147 public void testActionMenu_compress() { 148 dirDetails.canCreateDoc = true; 149 mgr.updateActionMenu(testMenu, selectionDetails); 150 151 compress.assertEnabled(); 152 } 153 154 @Test 155 public void testActionMenu_cantCompress() { 156 dirDetails.canCreateDoc = false; 157 mgr.updateActionMenu(testMenu, selectionDetails); 158 159 compress.assertDisabled(); 160 } 161 162 @Test 163 public void testActionMenu_cantRename() { 164 selectionDetails.canRename = false; 165 mgr.updateActionMenu(testMenu, selectionDetails); 166 167 rename.assertDisabled(); 168 } 169 170 @Test 171 public void testActionMenu_cantDelete() { 172 selectionDetails.canDelete = false; 173 mgr.updateActionMenu(testMenu, selectionDetails); 174 175 delete.assertInvisible(); 176 // We shouldn't be able to move files if we can't delete them 177 moveTo.assertDisabled(); 178 } 179 180 @Test 181 public void testActionMenu_containsDirectory() { 182 selectionDetails.containDirectories = true; 183 mgr.updateActionMenu(testMenu, selectionDetails); 184 185 // We can't share directories 186 share.assertInvisible(); 187 } 188 189 @Test 190 public void testActionMenu_cantExtract() { 191 selectionDetails.canExtract = false; 192 mgr.updateActionMenu(testMenu, selectionDetails); 193 194 extractTo.assertInvisible(); 195 } 196 197 @Test 198 public void testActionMenu_canExtract_hidesCopyToAndCompressAndShare() { 199 selectionDetails.canExtract = true; 200 dirDetails.canCreateDoc = true; 201 mgr.updateActionMenu(testMenu, selectionDetails); 202 203 extractTo.assertEnabled(); 204 copyTo.assertDisabled(); 205 compress.assertDisabled(); 206 } 207 208 @Test 209 public void testActionMenu_canOpenWith() { 210 selectionDetails.canOpenWith = true; 211 mgr.updateActionMenu(testMenu, selectionDetails); 212 213 openWith.assertVisible(); 214 openWith.assertEnabled(); 215 } 216 217 @Test 218 public void testActionMenu_cantOpenWith() { 219 selectionDetails.canOpenWith = false; 220 mgr.updateActionMenu(testMenu, selectionDetails); 221 222 openWith.assertVisible(); 223 openWith.assertDisabled(); 224 } 225 226 @Test 227 public void testOptionMenu() { 228 mgr.updateOptionMenu(testMenu); 229 230 advanced.assertInvisible(); 231 advanced.assertTitle(R.string.menu_advanced_show); 232 createDir.assertDisabled(); 233 assertTrue(testSearchManager.updateMenuCalled()); 234 } 235 236 @Test 237 public void testOptionMenu_showAdvanced() { 238 state.showAdvanced = true; 239 state.showDeviceStorageOption = true; 240 mgr.updateOptionMenu(testMenu); 241 242 advanced.assertVisible(); 243 advanced.assertTitle(R.string.menu_advanced_hide); 244 } 245 246 @Test 247 public void testOptionMenu_canCreateDirectory() { 248 dirDetails.canCreateDirectory = true; 249 mgr.updateOptionMenu(testMenu); 250 251 createDir.assertEnabled(); 252 } 253 254 @Test 255 public void testOptionMenu_hasRootSettings() { 256 dirDetails.hasRootSettings = true; 257 mgr.updateOptionMenu(testMenu); 258 259 settings.assertVisible(); 260 } 261 262 @Test 263 public void testInflateContextMenu_Files() { 264 TestMenuInflater inflater = new TestMenuInflater(); 265 266 selectionDetails.containFiles = true; 267 selectionDetails.containDirectories = false; 268 mgr.inflateContextMenuForDocs(testMenu, inflater, selectionDetails); 269 270 assertEquals(R.menu.file_context_menu, inflater.lastInflatedMenuId); 271 } 272 273 @Test 274 public void testInflateContextMenu_Dirs() { 275 TestMenuInflater inflater = new TestMenuInflater(); 276 277 selectionDetails.containFiles = false; 278 selectionDetails.containDirectories = true; 279 mgr.inflateContextMenuForDocs(testMenu, inflater, selectionDetails); 280 281 assertEquals(R.menu.dir_context_menu, inflater.lastInflatedMenuId); 282 } 283 284 @Test 285 public void testInflateContextMenu_Mixed() { 286 TestMenuInflater inflater = new TestMenuInflater(); 287 288 selectionDetails.containFiles = true; 289 selectionDetails.containDirectories = true; 290 mgr.inflateContextMenuForDocs(testMenu, inflater, selectionDetails); 291 292 assertEquals(R.menu.mixed_context_menu, inflater.lastInflatedMenuId); 293 } 294 295 @Test 296 public void testContextMenu_EmptyArea() { 297 mgr.updateContextMenuForContainer(testMenu); 298 299 selectAll.assertVisible(); 300 selectAll.assertEnabled(); 301 paste.assertVisible(); 302 paste.assertDisabled(); 303 createDir.assertVisible(); 304 createDir.assertDisabled(); 305 } 306 307 @Test 308 public void testContextMenu_EmptyArea_NoItemToPaste() { 309 dirDetails.hasItemsToPaste = false; 310 dirDetails.canCreateDoc = true; 311 312 mgr.updateContextMenuForContainer(testMenu); 313 314 selectAll.assertVisible(); 315 selectAll.assertEnabled(); 316 paste.assertVisible(); 317 paste.assertDisabled(); 318 createDir.assertVisible(); 319 createDir.assertDisabled(); 320 } 321 322 @Test 323 public void testContextMenu_EmptyArea_CantCreateDoc() { 324 dirDetails.hasItemsToPaste = true; 325 dirDetails.canCreateDoc = false; 326 327 mgr.updateContextMenuForContainer(testMenu); 328 329 selectAll.assertVisible(); 330 selectAll.assertEnabled(); 331 paste.assertVisible(); 332 paste.assertDisabled(); 333 createDir.assertVisible(); 334 createDir.assertDisabled(); 335 } 336 337 @Test 338 public void testContextMenu_EmptyArea_CanPaste() { 339 dirDetails.hasItemsToPaste = true; 340 dirDetails.canCreateDoc = true; 341 342 mgr.updateContextMenuForContainer(testMenu); 343 344 selectAll.assertVisible(); 345 selectAll.assertEnabled(); 346 paste.assertVisible(); 347 paste.assertEnabled(); 348 createDir.assertVisible(); 349 createDir.assertDisabled(); 350 } 351 352 @Test 353 public void testContextMenu_EmptyArea_CanCreateDirectory() { 354 dirDetails.canCreateDirectory = true; 355 356 mgr.updateContextMenuForContainer(testMenu); 357 358 selectAll.assertVisible(); 359 selectAll.assertEnabled(); 360 paste.assertVisible(); 361 paste.assertDisabled(); 362 createDir.assertVisible(); 363 createDir.assertEnabled(); 364 } 365 366 @Test 367 public void testContextMenu_OnFile() { 368 selectionDetails.size = 1; 369 mgr.updateContextMenuForFiles(testMenu, selectionDetails); 370 open.assertVisible(); 371 open.assertEnabled(); 372 cut.assertVisible(); 373 copy.assertVisible(); 374 rename.assertVisible(); 375 createDir.assertVisible(); 376 delete.assertVisible(); 377 } 378 379 @Test 380 public void testContextMenu_OnFile_canOpenWith() { 381 selectionDetails.canOpenWith = true; 382 mgr.updateContextMenuForFiles(testMenu, selectionDetails); 383 openWith.assertVisible(); 384 openWith.assertEnabled(); 385 } 386 387 @Test 388 public void testContextMenu_OnFile_cantOpenWith() { 389 selectionDetails.canOpenWith = false; 390 mgr.updateContextMenuForFiles(testMenu, selectionDetails); 391 openWith.assertVisible(); 392 openWith.assertDisabled(); 393 } 394 395 @Test 396 public void testContextMenu_OnMultipleFiles() { 397 selectionDetails.size = 3; 398 mgr.updateContextMenuForFiles(testMenu, selectionDetails); 399 open.assertVisible(); 400 open.assertDisabled(); 401 } 402 403 @Test 404 public void testContextMenu_OnWritableDirectory() { 405 selectionDetails.size = 1; 406 selectionDetails.canPasteInto = true; 407 dirDetails.hasItemsToPaste = true; 408 mgr.updateContextMenuForDirs(testMenu, selectionDetails); 409 openInNewWindow.assertVisible(); 410 openInNewWindow.assertEnabled(); 411 cut.assertVisible(); 412 copy.assertVisible(); 413 pasteInto.assertVisible(); 414 pasteInto.assertEnabled(); 415 rename.assertVisible(); 416 delete.assertVisible(); 417 } 418 419 @Test 420 public void testContextMenu_OnNonWritableDirectory() { 421 selectionDetails.size = 1; 422 selectionDetails.canPasteInto = false; 423 mgr.updateContextMenuForDirs(testMenu, selectionDetails); 424 openInNewWindow.assertVisible(); 425 openInNewWindow.assertEnabled(); 426 cut.assertVisible(); 427 copy.assertVisible(); 428 pasteInto.assertVisible(); 429 pasteInto.assertDisabled(); 430 rename.assertVisible(); 431 delete.assertVisible(); 432 } 433 434 @Test 435 public void testContextMenu_OnWritableDirectory_NothingToPaste() { 436 selectionDetails.canPasteInto = true; 437 selectionDetails.size = 1; 438 dirDetails.hasItemsToPaste = false; 439 mgr.updateContextMenuForDirs(testMenu, selectionDetails); 440 pasteInto.assertVisible(); 441 pasteInto.assertDisabled(); 442 } 443 444 @Test 445 public void testContextMenu_OnMultipleDirectories() { 446 selectionDetails.size = 3; 447 mgr.updateContextMenuForDirs(testMenu, selectionDetails); 448 openInNewWindow.assertVisible(); 449 openInNewWindow.assertDisabled(); 450 } 451 452 @Test 453 public void testContextMenu_OnMixedDocs() { 454 selectionDetails.containDirectories = true; 455 selectionDetails.containFiles = true; 456 selectionDetails.size = 2; 457 selectionDetails.canDelete = true; 458 mgr.updateContextMenu(testMenu, selectionDetails); 459 cut.assertVisible(); 460 cut.assertEnabled(); 461 copy.assertVisible(); 462 copy.assertEnabled(); 463 delete.assertVisible(); 464 delete.assertEnabled(); 465 } 466 467 @Test 468 public void testContextMenu_OnMixedDocs_hasPartialFile() { 469 selectionDetails.containDirectories = true; 470 selectionDetails.containFiles = true; 471 selectionDetails.size = 2; 472 selectionDetails.containPartial = true; 473 selectionDetails.canDelete = true; 474 mgr.updateContextMenu(testMenu, selectionDetails); 475 cut.assertVisible(); 476 cut.assertDisabled(); 477 copy.assertVisible(); 478 copy.assertDisabled(); 479 delete.assertVisible(); 480 delete.assertEnabled(); 481 } 482 483 @Test 484 public void testContextMenu_OnMixedDocs_hasUndeletableFile() { 485 selectionDetails.containDirectories = true; 486 selectionDetails.containFiles = true; 487 selectionDetails.size = 2; 488 selectionDetails.canDelete = false; 489 mgr.updateContextMenu(testMenu, selectionDetails); 490 cut.assertVisible(); 491 cut.assertDisabled(); 492 copy.assertVisible(); 493 copy.assertEnabled(); 494 delete.assertVisible(); 495 delete.assertDisabled(); 496 } 497 498 @Test 499 public void testRootContextMenu() { 500 testRootInfo.flags = Root.FLAG_SUPPORTS_CREATE; 501 502 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 503 504 eject.assertInvisible(); 505 506 openInNewWindow.assertVisible(); 507 openInNewWindow.assertEnabled(); 508 509 pasteInto.assertVisible(); 510 pasteInto.assertDisabled(); 511 512 settings.assertVisible(); 513 settings.assertDisabled(); 514 } 515 516 @Test 517 public void testRootContextMenu_hasRootSettings() { 518 testRootInfo.flags = Root.FLAG_HAS_SETTINGS; 519 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 520 521 settings.assertEnabled(); 522 } 523 524 @Test 525 public void testRootContextMenu_nonWritableRoot() { 526 dirDetails.hasItemsToPaste = true; 527 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 528 529 pasteInto.assertVisible(); 530 pasteInto.assertDisabled(); 531 } 532 533 @Test 534 public void testRootContextMenu_nothingToPaste() { 535 testRootInfo.flags = Root.FLAG_SUPPORTS_CREATE; 536 testDocInfo.flags = Document.FLAG_DIR_SUPPORTS_CREATE; 537 dirDetails.hasItemsToPaste = false; 538 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 539 540 pasteInto.assertVisible(); 541 pasteInto.assertDisabled(); 542 } 543 544 @Test 545 public void testRootContextMenu_pasteIntoWritableRoot() { 546 testRootInfo.flags = Root.FLAG_SUPPORTS_CREATE; 547 testDocInfo.flags = Document.FLAG_DIR_SUPPORTS_CREATE; 548 dirDetails.hasItemsToPaste = true; 549 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 550 551 pasteInto.assertVisible(); 552 pasteInto.assertEnabled(); 553 } 554 555 @Test 556 public void testRootContextMenu_eject() { 557 testRootInfo.flags = Root.FLAG_SUPPORTS_EJECT; 558 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 559 560 eject.assertEnabled(); 561 } 562 563 @Test 564 public void testRootContextMenu_ejectInProcess() { 565 testRootInfo.flags = Root.FLAG_SUPPORTS_EJECT; 566 testRootInfo.ejecting = true; 567 mgr.updateRootContextMenu(testMenu, testRootInfo, testDocInfo); 568 569 eject.assertDisabled(); 570 } 571} 572