Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Side by Side Diff: ash/app_list/app_list_presenter_delegate_unittest.cc

Issue 2950913002: Added new features tests to AppListPresenterDelegateUnittests. (Closed)
Patch Set: Added missing test to filter, alphabetized filtered tests. Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | testing/buildbot/filters/ash_unittests_mash.filter » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <memory> 5 #include <memory>
6 6
7 #include "ash/ash_switches.h" 7 #include "ash/ash_switches.h"
8 #include "ash/public/cpp/config.h" 8 #include "ash/public/cpp/config.h"
9 #include "ash/public/cpp/shelf_types.h" 9 #include "ash/public/cpp/shelf_types.h"
10 #include "ash/public/cpp/shell_window_ids.h" 10 #include "ash/public/cpp/shell_window_ids.h"
11 #include "ash/shelf/shelf.h" 11 #include "ash/shelf/shelf.h"
12 #include "ash/shelf/shelf_layout_manager.h" 12 #include "ash/shelf/shelf_layout_manager.h"
13 #include "ash/shell.h" 13 #include "ash/shell.h"
14 #include "ash/shell_port.h"
14 #include "ash/test/ash_test_base.h" 15 #include "ash/test/ash_test_base.h"
15 #include "ash/test/test_app_list_view_presenter_impl.h" 16 #include "ash/test/test_app_list_view_presenter_impl.h"
17 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
16 #include "ash/wm/window_util.h" 18 #include "ash/wm/window_util.h"
17 #include "base/command_line.h" 19 #include "base/command_line.h"
18 #include "base/macros.h" 20 #include "base/macros.h"
19 #include "base/test/scoped_feature_list.h" 21 #include "base/test/scoped_feature_list.h"
20 #include "ui/app_list/app_list_features.h" 22 #include "ui/app_list/app_list_features.h"
21 #include "ui/app_list/app_list_switches.h" 23 #include "ui/app_list/app_list_switches.h"
22 #include "ui/app_list/views/app_list_main_view.h" 24 #include "ui/app_list/views/app_list_main_view.h"
23 #include "ui/app_list/views/app_list_view.h" 25 #include "ui/app_list/views/app_list_view.h"
24 #include "ui/aura/test/test_windows.h" 26 #include "ui/aura/test/test_windows.h"
25 #include "ui/aura/window.h" 27 #include "ui/aura/window.h"
26 #include "ui/display/display.h" 28 #include "ui/display/display.h"
27 #include "ui/display/screen.h" 29 #include "ui/display/screen.h"
28 #include "ui/events/test/event_generator.h" 30 #include "ui/events/test/event_generator.h"
29 31
30 namespace ash { 32 namespace ash {
31 namespace { 33 namespace {
32 34
33 int64_t GetPrimaryDisplayId() { 35 int64_t GetPrimaryDisplayId() {
34 return display::Screen::GetScreen()->GetPrimaryDisplay().id(); 36 return display::Screen::GetScreen()->GetPrimaryDisplay().id();
35 } 37 }
36 38
39 void SetShelfAlignment(ShelfAlignment alignment) {
40 test::AshTestBase::GetPrimaryShelf()->SetAlignment(alignment);
41 }
42
43 void EnableMaximizeMode(bool enable) {
44 Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager(
45 enable);
46 }
47
37 } // namespace 48 } // namespace
38 49
39 class AppListPresenterDelegateTest : public test::AshTestBase, 50 class AppListPresenterDelegateTest : public test::AshTestBase,
40 public testing::WithParamInterface<bool> { 51 public testing::WithParamInterface<bool> {
41 public: 52 public:
42 AppListPresenterDelegateTest() {} 53 AppListPresenterDelegateTest() {}
43 ~AppListPresenterDelegateTest() override {} 54 ~AppListPresenterDelegateTest() override {}
44 55
45 app_list::AppListPresenterImpl* app_list_presenter_impl() { 56 app_list::AppListPresenterImpl* app_list_presenter_impl() {
46 return &app_list_presenter_impl_; 57 return &app_list_presenter_impl_;
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 // which is much bigger than the actual app list size). 196 // which is much bigger than the actual app list size).
186 197
187 app_list::AppListView* app_list = app_list_presenter_impl()->GetView(); 198 app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
188 int app_list_view_top = 199 int app_list_view_top =
189 app_list->anchor_rect().y() - app_list->bounds().height() / 2; 200 app_list->anchor_rect().y() - app_list->bounds().height() / 2;
190 const int kMinimalAppListMargin = 10; 201 const int kMinimalAppListMargin = 10;
191 202
192 EXPECT_GE(app_list_view_top, kMinimalAppListMargin); 203 EXPECT_GE(app_list_view_top, kMinimalAppListMargin);
193 } 204 }
194 205
206 // Tests that the app list initializes in fullscreen with side shelf alignment
207 // and that the state transitions via text input act properly.
208 TEST_F(AppListPresenterDelegateTest, SideShelfAlignmentTextStateTransitions) {
209 // TODO(newcomer): Investigate mash failures crbug.com/726838
210 EnableFullscreenAppList();
211 SetShelfAlignment(ShelfAlignment::SHELF_ALIGNMENT_LEFT);
212
213 // Open the app list with side shelf alignment, then check that it is in
214 // fullscreen mode.
215 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
216 app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
217 EXPECT_TRUE(app_list->is_fullscreen());
218 EXPECT_EQ(app_list->app_list_state(),
219 app_list::AppListView::FULLSCREEN_ALL_APPS);
220
221 // Enter text in the searchbox, the app list should transition to fullscreen
222 // search.
223 ui::test::EventGenerator& generator = GetEventGenerator();
224 generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
225 EXPECT_EQ(app_list->app_list_state(),
226 app_list::AppListView::FULLSCREEN_SEARCH);
227
228 // Delete the text in the searchbox, the app list should transition to
229 // fullscreen all apps.
230 generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0);
231 EXPECT_EQ(app_list->app_list_state(),
232 app_list::AppListView::FULLSCREEN_ALL_APPS);
233 }
234
235 // Tests that the app list initializes in peeking with bottom shelf alignment
236 // and that the state transitions via text input act properly.
237 TEST_F(AppListPresenterDelegateTest, BottomShelfAlignmentTextStateTransitions) {
238 // TODO(newcomer): Investigate mash failures crbug.com/726838
239 EnableFullscreenAppList();
240 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
241 app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
242 EXPECT_FALSE(app_list->is_fullscreen());
243 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING);
244
245 // Enter text in the searchbox, this should transition the app list to half
246 // state.
247 ui::test::EventGenerator& generator = GetEventGenerator();
248 generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
249 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF);
250
251 // Empty the searchbox, this should transition the app list to it's previous
252 // state.
253 generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0);
254 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING);
255 }
256
257 // Tests that the app list initializes in fullscreen with maximize mode active
258 // and that the state transitions via text input act properly.
259 TEST_F(AppListPresenterDelegateTest, MaximizeModeTextStateTransitions) {
260 // TODO(newcomer): Investigate mash failures crbug.com/726838
261 EnableFullscreenAppList();
262 EnableMaximizeMode(true);
263 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
264 app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
265 EXPECT_EQ(app_list->app_list_state(),
266 app_list::AppListView::FULLSCREEN_ALL_APPS);
267
268 // Enter text in the searchbox, the app list should transition to fullscreen
269 // search.
270 ui::test::EventGenerator& generator = GetEventGenerator();
271 generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
272 EXPECT_EQ(app_list->app_list_state(),
273 app_list::AppListView::FULLSCREEN_SEARCH);
274
275 // Delete the text in the searchbox, the app list should transition to
276 // fullscreen all apps. generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0);
277 generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0);
278 EXPECT_EQ(app_list->app_list_state(),
279 app_list::AppListView::FULLSCREEN_ALL_APPS);
280 }
281
282 // Tests that the app list state responds correctly to maximize mode being
283 // enabled while the app list is being shown.
284 TEST_F(AppListPresenterDelegateTest,
285 PeekingToFullscreenWhenMaximizeModeIsActive) {
286 // TODO(newcomer): Investigate mash failures crbug.com/726838
287 EnableFullscreenAppList();
288 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
289 app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
290 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING);
291 // Enable maximize mode, this should force the app list to switch to the
292 // fullscreen equivalent of the current state.
293 EnableMaximizeMode(true);
294 EXPECT_EQ(app_list->app_list_state(),
295 app_list::AppListView::FULLSCREEN_ALL_APPS);
296 // Disable maximize mode, the state of the app list should not change.
297 EnableMaximizeMode(false);
298 EXPECT_EQ(app_list->app_list_state(),
299 app_list::AppListView::FULLSCREEN_ALL_APPS);
300 // Enter text in the searchbox, the app list should transition to fullscreen
301 // search.
302 ui::test::EventGenerator& generator = GetEventGenerator();
303 generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
304 EXPECT_EQ(app_list->app_list_state(),
305 app_list::AppListView::FULLSCREEN_SEARCH);
306
307 // Delete the text in the searchbox, the app list should transition to
308 // fullscreen all apps. generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0);
309 generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0);
310 EXPECT_EQ(app_list->app_list_state(),
311 app_list::AppListView::FULLSCREEN_ALL_APPS);
312 }
313
314 // Tests that the app list state responds correctly to maximize mode being
315 // enabled while the app list is being shown with half launcher.
316 TEST_F(AppListPresenterDelegateTest, HalfToFullscreenWhenMaximizeModeIsActive) {
317 // TODO(newcomer): Investigate mash failures crbug.com/726838
318 EnableFullscreenAppList();
319 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
320 app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
321 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING);
322
323 // Enter text in the search box to transition to half app list.
324 ui::test::EventGenerator& generator = GetEventGenerator();
325 generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
326 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF);
327
328 // Enable maximize mode and force the app list to transition to the fullscreen
329 // equivalent of the current state.
330 EnableMaximizeMode(true);
331 EXPECT_EQ(app_list->app_list_state(),
332 app_list::AppListView::FULLSCREEN_SEARCH);
333 generator.PressKey(ui::KeyboardCode::VKEY_BACK, 0);
334 EXPECT_EQ(app_list->app_list_state(),
335 app_list::AppListView::FULLSCREEN_ALL_APPS);
336 }
337
338 // Tests that the app list view handles drag properly in laptop mode.
339 TEST_F(AppListPresenterDelegateTest, AppListViewDragHandler) {
340 // TODO(newcomer): Investigate mash failures crbug.com/726838
341 EnableFullscreenAppList();
342 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
343 app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
344 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING);
345
346 ui::test::EventGenerator& generator = GetEventGenerator();
347 // Execute a slow short upwards drag this should fail to transition the app
348 // list.
349 int top_of_app_list = app_list_presenter_impl()
350 ->GetView()
351 ->GetWidget()
352 ->GetWindowBoundsInScreen()
353 .y();
354 generator.GestureScrollSequence(gfx::Point(0, top_of_app_list + 20),
355 gfx::Point(0, top_of_app_list - 20),
356 base::TimeDelta::FromMilliseconds(500), 50);
357 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING);
358
359 // Execute a long upwards drag, this should transition the app list.
360 generator.GestureScrollSequence(gfx::Point(10, top_of_app_list + 20),
361 gfx::Point(10, 10),
362 base::TimeDelta::FromMilliseconds(100), 10);
363 EXPECT_EQ(app_list->app_list_state(),
364 app_list::AppListView::FULLSCREEN_ALL_APPS);
365
366 // Execute a short downward drag, this should fail to transition the app list.
367 generator.GestureScrollSequence(gfx::Point(10, 10), gfx::Point(10, 100),
368 base::TimeDelta::FromMilliseconds(100), 10);
369 EXPECT_EQ(app_list->app_list_state(),
370 app_list::AppListView::FULLSCREEN_ALL_APPS);
371
372 // Execute a long downward drag, this should transition the app list.
373 generator.GestureScrollSequence(gfx::Point(10, 10), gfx::Point(10, 900),
374 base::TimeDelta::FromMilliseconds(100), 10);
375 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::PEEKING);
376
377 // Transition to fullscreen.
378 generator.GestureScrollSequence(gfx::Point(10, top_of_app_list + 20),
379 gfx::Point(10, 10),
380 base::TimeDelta::FromMilliseconds(100), 10);
381 EXPECT_EQ(app_list->app_list_state(),
382 app_list::AppListView::FULLSCREEN_ALL_APPS);
383
384 // Enter text to transition to |FULLSCREEN_SEARCH|.
385 generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
386 EXPECT_EQ(app_list->app_list_state(),
387 app_list::AppListView::FULLSCREEN_SEARCH);
388
389 // Execute a short downward drag, this should fail to close the app list.
390 generator.GestureScrollSequence(gfx::Point(10, 10), gfx::Point(10, 100),
391 base::TimeDelta::FromMilliseconds(100), 10);
392 EXPECT_EQ(app_list->app_list_state(),
393 app_list::AppListView::FULLSCREEN_SEARCH);
394
395 // Execute a long downward drag, this should close the app list.
396 generator.GestureScrollSequence(gfx::Point(10, 10), gfx::Point(10, 900),
397 base::TimeDelta::FromMilliseconds(100), 10);
398 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::CLOSED);
399 }
400
401 // Tests that the app list view handles drag properly in maximize mode.
402 TEST_F(AppListPresenterDelegateTest,
403 AppListViewDragHandlerMaximizeModeFromAllApps) {
404 // TODO(newcomer): Investigate mash failures crbug.com/726838
405 EnableFullscreenAppList();
406 EnableMaximizeMode(true);
407 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
408 app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
409 EXPECT_EQ(app_list->app_list_state(),
410 app_list::AppListView::FULLSCREEN_ALL_APPS);
411
412 ui::test::EventGenerator& generator = GetEventGenerator();
413 // Drag down.
414 generator.GestureScrollSequence(gfx::Point(0, 0), gfx::Point(0, 720),
415 base::TimeDelta::FromMilliseconds(100), 10);
416 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::CLOSED);
417 }
418
419 // Tests that the state of the app list changes properly with drag input from
420 // fullscreen search.
421 TEST_F(AppListPresenterDelegateTest,
422 AppListViewDragHandlerMaximizeModeFromSearch) {
423 // TODO(newcomer): Investigate mash failures crbug.com/726838
424 // Reset the app list.
425 EnableFullscreenAppList();
426 EnableMaximizeMode(true);
427 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
428 app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
429 EXPECT_EQ(app_list->app_list_state(),
430 app_list::AppListView::FULLSCREEN_ALL_APPS);
431 // Type in the search box to transition to |FULLSCREEN_SEARCH|.
432 ui::test::EventGenerator& generator = GetEventGenerator();
433 generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
434 EXPECT_EQ(app_list->app_list_state(),
435 app_list::AppListView::FULLSCREEN_SEARCH);
436 // Drag down, this should close the app list.
437 generator.GestureScrollSequence(gfx::Point(0, 0), gfx::Point(0, 720),
438 base::TimeDelta::FromMilliseconds(100), 10);
439 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::CLOSED);
440 }
441
442 // Tests that the bottom shelf background is hidden when the app list is shown
443 // in laptop mode.
444 TEST_F(AppListPresenterDelegateTest,
445 ShelfBackgroundIsHiddenWhenAppListIsShown) {
446 EnableFullscreenAppList();
447 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
448 ShelfLayoutManager* shelf_layout_manager =
449 Shelf::ForWindow(Shell::GetRootWindowForDisplayId(GetPrimaryDisplayId()))
450 ->shelf_layout_manager();
451 EXPECT_TRUE(shelf_layout_manager->GetShelfBackgroundType() ==
452 ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT);
453 }
454
195 // Tests that the peeking app list closes if the user taps outside its 455 // Tests that the peeking app list closes if the user taps outside its
196 // bounds. 456 // bounds.
197 TEST_F(AppListPresenterDelegateTest, TapAndClickOutsideClosesPeekingAppList) { 457 TEST_F(AppListPresenterDelegateTest, TapAndClickOutsideClosesPeekingAppList) {
198 EnableFullscreenAppList(); 458 // TODO(newcomer): Investigate mash failures crbug.com/726838
199 459 EnableFullscreenAppList();
200 app_list_presenter_impl()->Show(GetPrimaryDisplayId()); 460 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
201 EXPECT_TRUE(app_list_presenter_impl()->GetTargetVisibility()); 461 EXPECT_TRUE(app_list_presenter_impl()->GetTargetVisibility());
202 ui::test::EventGenerator& generator = GetEventGenerator(); 462 ui::test::EventGenerator& generator = GetEventGenerator();
203 463
204 // Grab the bounds of the search box, 464 // Grab the bounds of the search box,
205 // which is guaranteed to be inside the app list. 465 // which is guaranteed to be inside the app list.
206 gfx::Point tap_point = app_list_presenter_impl() 466 gfx::Point tap_point = app_list_presenter_impl()
207 ->GetView() 467 ->GetView()
208 ->search_box_widget() 468 ->search_box_widget()
209 ->GetContentsView() 469 ->GetContentsView()
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 // show. 515 // show.
256 GetPrimaryShelf()->SetAlignment(ShelfAlignment::SHELF_ALIGNMENT_LEFT); 516 GetPrimaryShelf()->SetAlignment(ShelfAlignment::SHELF_ALIGNMENT_LEFT);
257 app_list_presenter_impl()->Show(GetPrimaryDisplayId()); 517 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
258 EXPECT_TRUE(app_list::features::IsFullscreenAppListEnabled()); 518 EXPECT_TRUE(app_list::features::IsFullscreenAppListEnabled());
259 EXPECT_FALSE(GetPrimaryShelf()->IsHorizontalAlignment()); 519 EXPECT_FALSE(GetPrimaryShelf()->IsHorizontalAlignment());
260 EXPECT_EQ(GetPrimaryShelf()->shelf_layout_manager()-> 520 EXPECT_EQ(GetPrimaryShelf()->shelf_layout_manager()->
261 GetShelfBackgroundType(), 521 GetShelfBackgroundType(),
262 SHELF_BACKGROUND_DEFAULT); 522 SHELF_BACKGROUND_DEFAULT);
263 } 523 }
264 524
525 // Tests that the half app list closes if the user taps outside its bounds.
526 TEST_F(AppListPresenterDelegateTest, TapAndClickOutsideClosesHalfAppList) {
527 // TODO(newcomer): Investigate mash failures crbug.com/726838
528 EnableFullscreenAppList();
529 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
530 ui::test::EventGenerator& generator = GetEventGenerator();
531
532 // Transition to half app list by entering text.
533 generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
534 app_list::AppListView* app_list = app_list_presenter_impl()->GetView();
535 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF);
536
537 // Grab the bounds of the search box,
538 // which is guaranteed to be inside the app list.
539 gfx::Point tap_point = app_list_presenter_impl()
540 ->GetView()
541 ->search_box_widget()
542 ->GetContentsView()
543 ->GetBoundsInScreen()
544 .CenterPoint();
545
546 // Tapping inside the bounds doesn't close the app list.
547 generator.GestureTapAt(tap_point);
548 EXPECT_TRUE(app_list_presenter_impl()->GetTargetVisibility());
549 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF);
550
551 // Clicking inside the bounds doesn't close the app list.
552 generator.MoveMouseTo(tap_point);
553 generator.ClickLeftButton();
554 EXPECT_TRUE(app_list_presenter_impl()->IsVisible());
555 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF);
556
557 // Tapping outside the bounds closes the app list.
558 generator.GestureTapAt(gfx::Point(10, 10));
559 EXPECT_FALSE(app_list_presenter_impl()->IsVisible());
560
561 // Reset the app list to half state.
562 app_list_presenter_impl()->Show(GetPrimaryDisplayId());
563 generator.PressKey(ui::KeyboardCode::VKEY_0, 0);
564 EXPECT_EQ(app_list->app_list_state(), app_list::AppListView::HALF);
565
566 // Clicking outside the bounds closes the app list.
567 generator.MoveMouseTo(gfx::Point(10, 10));
568 generator.ClickLeftButton();
569 EXPECT_FALSE(app_list_presenter_impl()->IsVisible());
570 }
571
265 } // namespace ash 572 } // namespace ash
OLDNEW
« no previous file with comments | « no previous file | testing/buildbot/filters/ash_unittests_mash.filter » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698