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

Side by Side Diff: chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc

Issue 223823004: Improving the user transition to add special cases for maximized windows and make the transition "m… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed preferences browser test [disabling animations] Created 6 years, 8 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 | Annotate | Revision Log
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 "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h" 5 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
6 6
7 #include "apps/app_window.h" 7 #include "apps/app_window.h"
8 #include "apps/app_window_registry.h" 8 #include "apps/app_window_registry.h"
9 #include "ash/ash_switches.h" 9 #include "ash/ash_switches.h"
10 #include "ash/desktop_background/user_wallpaper_delegate.h"
11 #include "ash/multi_profile_uma.h" 10 #include "ash/multi_profile_uma.h"
12 #include "ash/root_window_controller.h" 11 #include "ash/root_window_controller.h"
13 #include "ash/session_state_delegate.h" 12 #include "ash/session_state_delegate.h"
14 #include "ash/shelf/shelf.h" 13 #include "ash/shelf/shelf.h"
15 #include "ash/shelf/shelf_layout_manager.h"
16 #include "ash/shell.h" 14 #include "ash/shell.h"
17 #include "ash/shell_delegate.h" 15 #include "ash/shell_delegate.h"
18 #include "ash/shell_window_ids.h" 16 #include "ash/shell_window_ids.h"
19 #include "ash/wm/mru_window_tracker.h"
20 #include "ash/wm/window_positioner.h"
21 #include "ash/wm/window_state.h" 17 #include "ash/wm/window_state.h"
22 #include "base/auto_reset.h" 18 #include "base/auto_reset.h"
23 #include "base/message_loop/message_loop.h" 19 #include "base/message_loop/message_loop.h"
24 #include "base/strings/string_util.h" 20 #include "base/strings/string_util.h"
25 #include "chrome/browser/browser_process.h" 21 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/chrome_notification_types.h" 22 #include "chrome/browser/chrome_notification_types.h"
27 #include "chrome/browser/chromeos/login/user_manager.h" 23 #include "chrome/browser/chromeos/login/user_manager.h"
28 #include "chrome/browser/chromeos/login/wallpaper_manager.h"
29 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/profiles/profile_manager.h" 25 #include "chrome/browser/profiles/profile_manager.h"
31 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
32 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chrom eos.h" 26 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chrom eos.h"
33 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" 27 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
28 #include "chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h"
34 #include "chrome/browser/ui/browser.h" 29 #include "chrome/browser/ui/browser.h"
35 #include "chrome/browser/ui/browser_finder.h" 30 #include "chrome/browser/ui/browser_finder.h"
36 #include "chrome/browser/ui/browser_list.h" 31 #include "chrome/browser/ui/browser_list.h"
37 #include "chrome/browser/ui/browser_window.h" 32 #include "chrome/browser/ui/browser_window.h"
38 #include "content/public/browser/notification_service.h" 33 #include "content/public/browser/notification_service.h"
39 #include "google_apis/gaia/gaia_auth_util.h" 34 #include "google_apis/gaia/gaia_auth_util.h"
40 #include "ui/aura/client/aura_constants.h" 35 #include "ui/aura/client/aura_constants.h"
41 #include "ui/aura/window.h" 36 #include "ui/aura/window.h"
42 #include "ui/aura/window_event_dispatcher.h" 37 #include "ui/aura/window_event_dispatcher.h"
43 #include "ui/base/ui_base_types.h" 38 #include "ui/base/ui_base_types.h"
44 #include "ui/events/event.h" 39 #include "ui/events/event.h"
45 #include "ui/message_center/message_center.h" 40 #include "ui/message_center/message_center.h"
46 #include "ui/wm/core/transient_window_manager.h" 41 #include "ui/wm/core/transient_window_manager.h"
47 #include "ui/wm/core/window_animations.h" 42 #include "ui/wm/core/window_animations.h"
48 #include "ui/wm/core/window_util.h" 43 #include "ui/wm/core/window_util.h"
49 #include "ui/wm/public/activation_client.h"
50 44
51 namespace { 45 namespace {
52 46
53 // The animation time in milliseconds for a single window which is fading 47 // The animation time in milliseconds for a single window which is fading
54 // in / out. 48 // in / out.
55 static int kAnimationTimeMS = 100; 49 const int kAnimationTimeMS = 100;
56
57 // The animation time in millseconds for the fade in and / or out when switching
58 // users.
59 static int kUserFadeTimeMS = 110;
60 50
61 // The animation time in ms for a window which get teleported to another screen. 51 // The animation time in ms for a window which get teleported to another screen.
62 static int kTeleportAnimationTimeMS = 300; 52 const int kTeleportAnimationTimeMS = 300;
63 53
64 // Checks if a given event is a user event. 54 // Checks if a given event is a user event.
65 bool IsUserEvent(ui::Event* e) { 55 bool IsUserEvent(const ui::Event* e) {
66 if (e) { 56 if (e) {
67 ui::EventType type = e->type(); 57 ui::EventType type = e->type();
68 if (type != ui::ET_CANCEL_MODE && 58 if (type != ui::ET_CANCEL_MODE &&
69 type != ui::ET_UMA_DATA && 59 type != ui::ET_UMA_DATA &&
70 type != ui::ET_UNKNOWN) 60 type != ui::ET_UNKNOWN)
71 return true; 61 return true;
72 } 62 }
73 return false; 63 return false;
74 } 64 }
75 65
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 170
181 // Previous animation type. 171 // Previous animation type.
182 const int previous_animation_type_; 172 const int previous_animation_type_;
183 173
184 // Previous animation time. 174 // Previous animation time.
185 const base::TimeDelta previous_animation_time_; 175 const base::TimeDelta previous_animation_time_;
186 176
187 DISALLOW_COPY_AND_ASSIGN(AnimationSetter); 177 DISALLOW_COPY_AND_ASSIGN(AnimationSetter);
188 }; 178 };
189 179
190 // logic while the user gets switched.
191 class UserChangeActionDisabler {
192 public:
193 UserChangeActionDisabler() {
194 ash::WindowPositioner::DisableAutoPositioning(true);
195 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(true);
196 }
197
198 ~UserChangeActionDisabler() {
199 ash::WindowPositioner::DisableAutoPositioning(false);
200 ash::Shell::GetInstance()->mru_window_tracker()->SetIgnoreActivations(
201 false);
202 }
203 private:
204
205 DISALLOW_COPY_AND_ASSIGN(UserChangeActionDisabler);
206 };
207
208 // This class keeps track of all applications which were started for a user. 180 // This class keeps track of all applications which were started for a user.
209 // When an app gets created, the window will be tagged for that user. Note 181 // When an app gets created, the window will be tagged for that user. Note
210 // that the destruction does not need to be tracked here since the universal 182 // that the destruction does not need to be tracked here since the universal
211 // window observer will take care of that. 183 // window observer will take care of that.
212 class AppObserver : public apps::AppWindowRegistry::Observer { 184 class AppObserver : public apps::AppWindowRegistry::Observer {
213 public: 185 public:
214 explicit AppObserver(const std::string& user_id) : user_id_(user_id) {} 186 explicit AppObserver(const std::string& user_id) : user_id_(user_id) {}
215 virtual ~AppObserver() {} 187 virtual ~AppObserver() {}
216 188
217 // AppWindowRegistry::Observer overrides: 189 // AppWindowRegistry::Observer overrides:
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 observers_.AddObserver(observer); 376 observers_.AddObserver(observer);
405 } 377 }
406 378
407 void MultiUserWindowManagerChromeOS::RemoveObserver(Observer* observer) { 379 void MultiUserWindowManagerChromeOS::RemoveObserver(Observer* observer) {
408 observers_.RemoveObserver(observer); 380 observers_.RemoveObserver(observer);
409 } 381 }
410 382
411 void MultiUserWindowManagerChromeOS::ActiveUserChanged( 383 void MultiUserWindowManagerChromeOS::ActiveUserChanged(
412 const std::string& user_id) { 384 const std::string& user_id) {
413 DCHECK(user_id != current_user_id_); 385 DCHECK(user_id != current_user_id_);
386 // This needs to be set before the animation starts.
414 current_user_id_ = user_id; 387 current_user_id_ = user_id;
415 // If there is an animation in progress finish the pending switch which also
416 // kills the timer (if there is one).
417 if (user_changed_animation_timer_.get())
418 TransitionUser(SHOW_NEW_USER);
419 388
420 // Start the animation by hiding the old user. 389 animation_.reset(
421 TransitionUser(HIDE_OLD_USER); 390 new UserSwichAnimatorChromeOS(this, user_id, animations_disabled_));
422
423 // If animations are disabled we immediately switch to the new user, otherwise
424 // we create a timer which will fade in the new user once the other user has
425 // been faded away.
426 if (animations_disabled_) {
427 TransitionUser(SHOW_NEW_USER);
428 } else {
429 user_changed_animation_timer_.reset(new base::Timer(
430 FROM_HERE,
431 base::TimeDelta::FromMilliseconds(kUserFadeTimeMS),
432 base::Bind(&MultiUserWindowManagerChromeOS::TransitionUser,
433 base::Unretained(this),
434 SHOW_NEW_USER),
435 false));
436 user_changed_animation_timer_->Reset();
437 }
438 } 391 }
439 392
440 void MultiUserWindowManagerChromeOS::OnWindowDestroyed(aura::Window* window) { 393 void MultiUserWindowManagerChromeOS::OnWindowDestroyed(aura::Window* window) {
441 if (GetWindowOwner(window).empty()) { 394 if (GetWindowOwner(window).empty()) {
442 // This must be a window in the transient chain - remove it and its 395 // This must be a window in the transient chain - remove it and its
443 // children from the owner. 396 // children from the owner.
444 RemoveTransientOwnerRecursive(window); 397 RemoveTransientOwnerRecursive(window);
445 return; 398 return;
446 } 399 }
447 wm::TransientWindowManager::Get(window)->RemoveObserver(this); 400 wm::TransientWindowManager::Get(window)->RemoveObserver(this);
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 const content::NotificationDetails& details) { 477 const content::NotificationDetails& details) {
525 if (type == NOTIFICATION_BROWSER_WINDOW_READY) 478 if (type == NOTIFICATION_BROWSER_WINDOW_READY)
526 AddBrowserWindow(content::Source<Browser>(source).ptr()); 479 AddBrowserWindow(content::Source<Browser>(source).ptr());
527 } 480 }
528 481
529 void MultiUserWindowManagerChromeOS::SetAnimationsForTest(bool disable) { 482 void MultiUserWindowManagerChromeOS::SetAnimationsForTest(bool disable) {
530 animations_disabled_ = disable; 483 animations_disabled_ = disable;
531 } 484 }
532 485
533 bool MultiUserWindowManagerChromeOS::IsAnimationRunningForTest() { 486 bool MultiUserWindowManagerChromeOS::IsAnimationRunningForTest() {
534 return user_changed_animation_timer_.get() != NULL; 487 return animation_.get() != NULL && !animation_->IsAnimationFinished();
535 } 488 }
536 489
537 const std::string& MultiUserWindowManagerChromeOS::GetCurrentUserForTest() { 490 const std::string& MultiUserWindowManagerChromeOS::GetCurrentUserForTest() {
538 return current_user_id_; 491 return current_user_id_;
539 } 492 }
540 493
541 bool MultiUserWindowManagerChromeOS::ShowWindowForUserIntern( 494 bool MultiUserWindowManagerChromeOS::ShowWindowForUserIntern(
542 aura::Window* window, 495 aura::Window* window,
543 const std::string& user_id) { 496 const std::string& user_id) {
544 // If there is either no owner, or the owner is the current user, no action 497 // If there is either no owner, or the owner is the current user, no action
(...skipping 28 matching lines...) Expand all
573 SetWindowVisibility(window, true, kTeleportAnimationTimeMS); 526 SetWindowVisibility(window, true, kTeleportAnimationTimeMS);
574 } else { 527 } else {
575 SetWindowVisibility(window, false, kTeleportAnimationTimeMS); 528 SetWindowVisibility(window, false, kTeleportAnimationTimeMS);
576 } 529 }
577 530
578 // Notify entry change. 531 // Notify entry change.
579 FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryChanged(window)); 532 FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryChanged(window));
580 return true; 533 return true;
581 } 534 }
582 535
583 void MultiUserWindowManagerChromeOS::TransitionUser(
584 MultiUserWindowManagerChromeOS::AnimationStep animation_step) {
585 TransitionWallpaper(animation_step);
586 TransitionUserShelf(animation_step);
587
588 // Disable the window position manager and the MRU window tracker temporarily.
589 scoped_ptr<UserChangeActionDisabler> disabler(new UserChangeActionDisabler);
590
591 // We need to show/hide the windows in the same order as they were created in
592 // their parent window(s) to keep the layer / window hierarchy in sync. To
593 // achieve that we first collect all parent windows and then enumerate all
594 // windows in those parent windows and show or hide them accordingly.
595
596 // Create a list of all parent windows we have to check and their parents.
597 std::set<aura::Window*> parent_list;
598 for (WindowToEntryMap::iterator it = window_to_entry_.begin();
599 it != window_to_entry_.end(); ++it) {
600 aura::Window* parent = it->first->parent();
601 if (parent_list.find(parent) == parent_list.end())
602 parent_list.insert(parent);
603 }
604
605 // Traverse the found parent windows to handle their child windows in order of
606 // their appearance.
607 for (std::set<aura::Window*>::iterator it_parents = parent_list.begin();
608 it_parents != parent_list.end(); ++it_parents) {
609 const aura::Window::Windows window_list = (*it_parents)->children();
610 for (aura::Window::Windows::const_iterator it_window = window_list.begin();
611 it_window != window_list.end(); ++it_window) {
612 aura::Window* window = *it_window;
613 WindowToEntryMap::iterator it_map = window_to_entry_.find(window);
614 if (it_map != window_to_entry_.end()) {
615 bool should_be_visible =
616 it_map->second->show_for_user() == current_user_id_ &&
617 it_map->second->show();
618 bool is_visible = window->IsVisible();
619 ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
620 if (animation_step == SHOW_NEW_USER &&
621 it_map->second->owner() == current_user_id_ &&
622 it_map->second->show_for_user() != current_user_id_ &&
623 window_state->IsMinimized()) {
624 // Pull back minimized visiting windows to the owners desktop.
625 ShowWindowForUserIntern(window, current_user_id_);
626 window_state->Unminimize();
627 } else if (should_be_visible != is_visible &&
628 should_be_visible == (animation_step == SHOW_NEW_USER)) {
629 SetWindowVisibility(window, should_be_visible, kUserFadeTimeMS);
630 }
631 }
632 }
633 }
634
635 // Activation and real switch are happening after the other user gets shown.
636 if (animation_step == SHOW_NEW_USER) {
637 // Finally we need to restore the previously active window.
638 ash::MruWindowTracker::WindowList mru_list =
639 ash::Shell::GetInstance()->mru_window_tracker()->BuildMruWindowList();
640 if (mru_list.size()) {
641 aura::Window* window = mru_list[0];
642 ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
643 if (IsWindowOnDesktopOfUser(window, current_user_id_) &&
644 !window_state->IsMinimized()) {
645 aura::client::ActivationClient* client =
646 aura::client::GetActivationClient(window->GetRootWindow());
647 // Several unit tests come here without an activation client.
648 if (client)
649 client->ActivateWindow(window);
650 }
651 }
652
653 // This is called directly here to make sure notification_blocker will see
654 // the new window status.
655 notification_blocker_->ActiveUserChanged(current_user_id_);
656
657 // We can reset the timer at this point.
658 // Note: The timer can be destroyed while it is performing its task.
659 user_changed_animation_timer_.reset();
660 }
661 }
662
663 void MultiUserWindowManagerChromeOS::TransitionWallpaper(
664 MultiUserWindowManagerChromeOS::AnimationStep animation_step) {
665 // Handle the wallpaper switch.
666 ash::UserWallpaperDelegate* wallpaper_delegate =
667 ash::Shell::GetInstance()->user_wallpaper_delegate();
668 if (animation_step == HIDE_OLD_USER) {
669 // Set the wallpaper cross dissolve animation duration to our complete
670 // animation cycle for a fade in and fade out.
671 wallpaper_delegate->SetAnimationDurationOverride(2 * kUserFadeTimeMS);
672 chromeos::WallpaperManager::Get()->SetUserWallpaperDelayed(
673 current_user_id_);
674 } else {
675 // Revert the wallpaper cross dissolve animation duration back to the
676 // default.
677 wallpaper_delegate->SetAnimationDurationOverride(0);
678 }
679 }
680
681 void MultiUserWindowManagerChromeOS::TransitionUserShelf(
682 MultiUserWindowManagerChromeOS::AnimationStep animation_step) {
683 // The shelf animation duration override.
684 int duration_override = kUserFadeTimeMS;
685 // Handle the shelf order of items. This is done once the old user is hidden.
686 if (animation_step == SHOW_NEW_USER) {
687 // Some unit tests have no ChromeLauncherController.
688 if (ChromeLauncherController::instance())
689 ChromeLauncherController::instance()->ActiveUserChanged(current_user_id_);
690 // We kicked off the shelf animation in the command above. As such we can
691 // disable the override now again.
692 duration_override = 0;
693 }
694
695 if (animations_disabled_)
696 return;
697
698 ash::Shell::RootWindowControllerList controller =
699 ash::Shell::GetInstance()->GetAllRootWindowControllers();
700 for (ash::Shell::RootWindowControllerList::iterator it1 = controller.begin();
701 it1 != controller.end(); ++it1) {
702 (*it1)->GetShelfLayoutManager()->SetAnimationDurationOverride(
703 duration_override);
704 }
705
706 // For each root window hide the shelf.
707 if (animation_step == HIDE_OLD_USER) {
708 aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
709 for (aura::Window::Windows::const_iterator iter = root_windows.begin();
710 iter != root_windows.end(); ++iter) {
711 ash::Shell::GetInstance()->SetShelfAutoHideBehavior(
712 ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN, *iter);
713 }
714 }
715 }
716
717 void MultiUserWindowManagerChromeOS::AddBrowserWindow(Browser* browser) {
718 // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can
719 // come here with no valid window.
720 if (!browser->window() || !browser->window()->GetNativeWindow())
721 return;
722 SetWindowOwner(browser->window()->GetNativeWindow(),
723 multi_user_util::GetUserIDFromProfile(browser->profile()));
724 }
725
726 void MultiUserWindowManagerChromeOS::SetWindowVisibility( 536 void MultiUserWindowManagerChromeOS::SetWindowVisibility(
727 aura::Window* window, bool visible, int animation_time_in_ms) { 537 aura::Window* window, bool visible, int animation_time_in_ms) {
728 if (window->IsVisible() == visible) 538 if (window->IsVisible() == visible)
729 return; 539 return;
730 540
731 // Hiding a system modal dialog should not be allowed. Instead we switch to 541 // Hiding a system modal dialog should not be allowed. Instead we switch to
732 // the user which is showing the system modal window. 542 // the user which is showing the system modal window.
733 // Note that in some cases (e.g. unit test) windows might not have a root 543 // Note that in some cases (e.g. unit test) windows might not have a root
734 // window. 544 // window.
735 if (!visible && window->GetRootWindow()) { 545 if (!visible && window->GetRootWindow()) {
(...skipping 23 matching lines...) Expand all
759 569
760 if (visible) { 570 if (visible) {
761 ShowWithTransientChildrenRecursive(window, animation_time_in_ms); 571 ShowWithTransientChildrenRecursive(window, animation_time_in_ms);
762 } else { 572 } else {
763 if (window->HasFocus()) 573 if (window->HasFocus())
764 window->Blur(); 574 window->Blur();
765 SetWindowVisible(window, false, animation_time_in_ms); 575 SetWindowVisible(window, false, animation_time_in_ms);
766 } 576 }
767 } 577 }
768 578
579 void MultiUserWindowManagerChromeOS::AddBrowserWindow(Browser* browser) {
580 // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can
581 // come here with no valid window.
582 if (!browser->window() || !browser->window()->GetNativeWindow())
583 return;
584 SetWindowOwner(browser->window()->GetNativeWindow(),
585 multi_user_util::GetUserIDFromProfile(browser->profile()));
586 }
587
769 void MultiUserWindowManagerChromeOS::ShowWithTransientChildrenRecursive( 588 void MultiUserWindowManagerChromeOS::ShowWithTransientChildrenRecursive(
770 aura::Window* window, int animation_time_in_ms) { 589 aura::Window* window, int animation_time_in_ms) {
771 aura::Window::Windows::const_iterator it = 590 aura::Window::Windows::const_iterator it =
772 wm::GetTransientChildren(window).begin(); 591 wm::GetTransientChildren(window).begin();
773 for (; it != wm::GetTransientChildren(window).end(); ++it) 592 for (; it != wm::GetTransientChildren(window).end(); ++it)
774 ShowWithTransientChildrenRecursive(*it, animation_time_in_ms); 593 ShowWithTransientChildrenRecursive(*it, animation_time_in_ms);
775 594
776 // We show all children which were not explicitly hidden. 595 // We show all children which were not explicitly hidden.
777 TransientWindowToVisibility::iterator it2 = 596 TransientWindowToVisibility::iterator it2 =
778 transient_window_to_visibility_.find(window); 597 transient_window_to_visibility_.find(window);
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
863 window->Show(); 682 window->Show();
864 else 683 else
865 window->Hide(); 684 window->Hide();
866 685
867 // Make sure that animations have no influence on the window state after the 686 // Make sure that animations have no influence on the window state after the
868 // call. 687 // call.
869 DCHECK_EQ(visible, window->IsVisible()); 688 DCHECK_EQ(visible, window->IsVisible());
870 } 689 }
871 690
872 } // namespace chrome 691 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698