Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / ash / multi_user / multi_user_window_manager_chromeos.cc
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
6
7 #include "apps/app_window.h"
8 #include "apps/app_window_registry.h"
9 #include "ash/ash_switches.h"
10 #include "ash/multi_profile_uma.h"
11 #include "ash/root_window_controller.h"
12 #include "ash/session/session_state_delegate.h"
13 #include "ash/shelf/shelf.h"
14 #include "ash/shell.h"
15 #include "ash/shell_delegate.h"
16 #include "ash/shell_window_ids.h"
17 #include "ash/system/tray/system_tray_notifier.h"
18 #include "ash/wm/window_state.h"
19 #include "base/auto_reset.h"
20 #include "base/message_loop/message_loop.h"
21 #include "base/strings/string_util.h"
22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/chrome_notification_types.h"
24 #include "chrome/browser/chromeos/login/user_manager.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/profiles/profile_manager.h"
27 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h"
28 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
29 #include "chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h"
30 #include "chrome/browser/ui/browser.h"
31 #include "chrome/browser/ui/browser_finder.h"
32 #include "chrome/browser/ui/browser_list.h"
33 #include "chrome/browser/ui/browser_window.h"
34 #include "content/public/browser/notification_service.h"
35 #include "google_apis/gaia/gaia_auth_util.h"
36 #include "ui/aura/client/aura_constants.h"
37 #include "ui/aura/window.h"
38 #include "ui/aura/window_event_dispatcher.h"
39 #include "ui/base/ui_base_types.h"
40 #include "ui/events/event.h"
41 #include "ui/message_center/message_center.h"
42 #include "ui/wm/core/transient_window_manager.h"
43 #include "ui/wm/core/window_animations.h"
44 #include "ui/wm/core/window_util.h"
45
46 namespace {
47
48 // The animation time in milliseconds for a single window which is fading
49 // in / out.
50 const int kAnimationTimeMS = 100;
51
52 // The animation time in milliseconds for the fade in and / or out when
53 // switching users.
54 const int kUserFadeTimeMS = 110;
55
56 // The animation time in ms for a window which get teleported to another screen.
57 const int kTeleportAnimationTimeMS = 300;
58
59 // Checks if a given event is a user event.
60 bool IsUserEvent(const ui::Event* e) {
61   if (e) {
62     ui::EventType type = e->type();
63     if (type != ui::ET_CANCEL_MODE &&
64         type != ui::ET_UMA_DATA &&
65         type != ui::ET_UNKNOWN)
66       return true;
67   }
68   return false;
69 }
70
71 // Test if we are currently processing a user event which might lead to a
72 // browser / app creation.
73 bool IsProcessingUserEvent() {
74   // When there is a nested message loop (e.g. active menu or drag and drop
75   // operation) - we are in a nested loop and can ignore this.
76   // Note: Unit tests might not have a message loop.
77   base::MessageLoop* message_loop = base::MessageLoop::current();
78   if (message_loop && message_loop->is_running() && message_loop->IsNested())
79     return false;
80
81   // TODO(skuhne): "Open link in new window" will come here after the menu got
82   // closed, executing the command from the nested menu loop. However at that
83   // time there is no active event processed. A solution for that need to be
84   // found past M-32. A global event handler filter (pre and post) might fix
85   // that problem in conjunction with a depth counter - but - for the menu
86   // execution we come here after the loop was finished (so it's not nested
87   // anymore) and the root window should therefore still have the event which
88   // lead to the menu invocation, but it is not. By fixing that problem this
89   // would "magically work".
90   aura::Window::Windows root_window_list = ash::Shell::GetAllRootWindows();
91   for (aura::Window::Windows::iterator it = root_window_list.begin();
92        it != root_window_list.end();
93        ++it) {
94     if (IsUserEvent((*it)->GetHost()->dispatcher()->current_event()))
95       return true;
96   }
97   return false;
98 }
99
100 // Records the type of window which was transferred to another desktop.
101 void RecordUMAForTransferredWindowType(aura::Window* window) {
102   // We need to figure out what kind of window this is to record the transfer.
103   Browser* browser = chrome::FindBrowserWithWindow(window);
104   ash::MultiProfileUMA::TeleportWindowType window_type =
105       ash::MultiProfileUMA::TELEPORT_WINDOW_UNKNOWN;
106   if (browser) {
107     if (browser->profile()->IsOffTheRecord()) {
108       window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_INCOGNITO_BROWSER;
109     } else if (browser->is_app()) {
110       window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_V1_APP;
111     } else if (browser->is_type_popup()) {
112       window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_POPUP;
113     } else {
114       window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_BROWSER;
115     }
116   } else {
117     // Unit tests might come here without a profile manager.
118     if (!g_browser_process->profile_manager())
119       return;
120     // If it is not a browser, it is probably be a V2 application. In that case
121     // one of the AppWindowRegistry instances should know about it.
122     apps::AppWindow* app_window = NULL;
123     std::vector<Profile*> profiles =
124         g_browser_process->profile_manager()->GetLoadedProfiles();
125     for (std::vector<Profile*>::iterator it = profiles.begin();
126          it != profiles.end() && app_window == NULL;
127          it++) {
128       app_window = apps::AppWindowRegistry::Get(*it)
129                        ->GetAppWindowForNativeWindow(window);
130     }
131     if (app_window) {
132       if (app_window->window_type() == apps::AppWindow::WINDOW_TYPE_PANEL ||
133           app_window->window_type() == apps::AppWindow::WINDOW_TYPE_V1_PANEL) {
134         window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_PANEL;
135       } else {
136         window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_V2_APP;
137       }
138     }
139   }
140   ash::MultiProfileUMA::RecordTeleportWindowType(window_type);
141 }
142
143 }  // namespace
144
145 namespace chrome {
146
147 // A class to temporarily change the animation properties for a window.
148 class AnimationSetter {
149  public:
150   AnimationSetter(aura::Window* window, int animation_time_in_ms)
151       : window_(window),
152         previous_animation_type_(
153             wm::GetWindowVisibilityAnimationType(window_)),
154         previous_animation_time_(
155             wm::GetWindowVisibilityAnimationDuration(*window_)) {
156     wm::SetWindowVisibilityAnimationType(
157         window_,
158         wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
159     wm::SetWindowVisibilityAnimationDuration(
160         window_,
161         base::TimeDelta::FromMilliseconds(animation_time_in_ms));
162   }
163
164   ~AnimationSetter() {
165     wm::SetWindowVisibilityAnimationType(window_,
166                                                     previous_animation_type_);
167     wm::SetWindowVisibilityAnimationDuration(
168         window_,
169         previous_animation_time_);
170   }
171
172  private:
173   // The window which gets used.
174   aura::Window* window_;
175
176   // Previous animation type.
177   const int previous_animation_type_;
178
179   // Previous animation time.
180   const base::TimeDelta previous_animation_time_;
181
182   DISALLOW_COPY_AND_ASSIGN(AnimationSetter);
183 };
184
185 // This class keeps track of all applications which were started for a user.
186 // When an app gets created, the window will be tagged for that user. Note
187 // that the destruction does not need to be tracked here since the universal
188 // window observer will take care of that.
189 class AppObserver : public apps::AppWindowRegistry::Observer {
190  public:
191   explicit AppObserver(const std::string& user_id) : user_id_(user_id) {}
192   virtual ~AppObserver() {}
193
194   // AppWindowRegistry::Observer overrides:
195   virtual void OnAppWindowAdded(apps::AppWindow* app_window) OVERRIDE {
196     aura::Window* window = app_window->GetNativeWindow();
197     DCHECK(window);
198     MultiUserWindowManagerChromeOS::GetInstance()->SetWindowOwner(window,
199                                                                   user_id_);
200   }
201
202  private:
203   std::string user_id_;
204
205   DISALLOW_COPY_AND_ASSIGN(AppObserver);
206 };
207
208 MultiUserWindowManagerChromeOS::MultiUserWindowManagerChromeOS(
209     const std::string& current_user_id)
210     : current_user_id_(current_user_id),
211       notification_blocker_(new MultiUserNotificationBlockerChromeOS(
212           message_center::MessageCenter::Get(), current_user_id)),
213       suppress_visibility_changes_(false),
214       animation_speed_(ANIMATION_SPEED_NORMAL) {
215   // Add a session state observer to be able to monitor session changes.
216   if (ash::Shell::HasInstance())
217     ash::Shell::GetInstance()->session_state_delegate()->
218         AddSessionStateObserver(this);
219
220   // The BrowserListObserver would have been better to use then the old
221   // notification system, but that observer fires before the window got created.
222   registrar_.Add(this, NOTIFICATION_BROWSER_WINDOW_READY,
223                  content::NotificationService::AllSources());
224
225   // Add an app window observer & all already running apps.
226   Profile* profile = multi_user_util::GetProfileFromUserID(current_user_id);
227   if (profile)
228     AddUser(profile);
229 }
230
231 MultiUserWindowManagerChromeOS::~MultiUserWindowManagerChromeOS() {
232   // When the MultiUserWindowManager gets destroyed, ash::Shell is mostly gone.
233   // As such we should not try to finalize any outstanding user animations.
234   // Note that the destruction of the object can be done later.
235   if (animation_.get())
236     animation_->CancelAnimation();
237
238   // Remove all window observers.
239   WindowToEntryMap::iterator window = window_to_entry_.begin();
240   while (window != window_to_entry_.end()) {
241     OnWindowDestroyed(window->first);
242     window = window_to_entry_.begin();
243   }
244
245   // Remove all app observers.
246   UserIDToAppWindowObserver::iterator app_observer_iterator =
247       user_id_to_app_observer_.begin();
248   while (app_observer_iterator != user_id_to_app_observer_.end()) {
249     Profile* profile = multi_user_util::GetProfileFromUserID(
250         app_observer_iterator->first);
251     DCHECK(profile);
252     apps::AppWindowRegistry::Get(profile)
253         ->RemoveObserver(app_observer_iterator->second);
254     delete app_observer_iterator->second;
255     user_id_to_app_observer_.erase(app_observer_iterator);
256     app_observer_iterator = user_id_to_app_observer_.begin();
257   }
258
259   if (ash::Shell::HasInstance())
260     ash::Shell::GetInstance()->session_state_delegate()->
261         RemoveSessionStateObserver(this);
262 }
263
264 void MultiUserWindowManagerChromeOS::SetWindowOwner(
265     aura::Window* window,
266     const std::string& user_id) {
267   // Make sure the window is valid and there was no owner yet.
268   DCHECK(window);
269   DCHECK(!user_id.empty());
270   if (GetWindowOwner(window) == user_id)
271     return;
272   DCHECK(GetWindowOwner(window).empty());
273   window_to_entry_[window] = new WindowEntry(user_id);
274
275   // Remember the initial visibility of the window.
276   window_to_entry_[window]->set_show(window->IsVisible());
277
278   // Add observers to track state changes.
279   window->AddObserver(this);
280   wm::TransientWindowManager::Get(window)->AddObserver(this);
281
282   // Check if this window was created due to a user interaction. If it was,
283   // transfer it to the current user.
284   if (IsProcessingUserEvent())
285     window_to_entry_[window]->set_show_for_user(current_user_id_);
286
287   // Add all transient children to our set of windows. Note that the function
288   // will add the children but not the owner to the transient children map.
289   AddTransientOwnerRecursive(window, window);
290
291   // Notify entry adding.
292   FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryAdded(window));
293
294   if (!IsWindowOnDesktopOfUser(window, current_user_id_))
295     SetWindowVisibility(window, false, 0);
296 }
297
298 const std::string& MultiUserWindowManagerChromeOS::GetWindowOwner(
299     aura::Window* window) const {
300   WindowToEntryMap::const_iterator it = window_to_entry_.find(window);
301   return it != window_to_entry_.end() ? it->second->owner()
302                                       : base::EmptyString();
303 }
304
305 void MultiUserWindowManagerChromeOS::ShowWindowForUser(
306     aura::Window* window,
307     const std::string& user_id) {
308   std::string previous_owner(GetUserPresentingWindow(window));
309   if (!ShowWindowForUserIntern(window, user_id))
310     return;
311   // The window switched to a new desktop and we have to switch to that desktop,
312   // but only when it was on the visible desktop and the the target is not the
313   // visible desktop.
314   if (user_id == current_user_id_ || previous_owner != current_user_id_)
315     return;
316
317   ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
318       user_id);
319 }
320
321 bool MultiUserWindowManagerChromeOS::AreWindowsSharedAmongUsers() const {
322   WindowToEntryMap::const_iterator it = window_to_entry_.begin();
323   for (; it != window_to_entry_.end(); ++it) {
324     if (it->second->owner() != it->second->show_for_user())
325       return true;
326   }
327   return false;
328 }
329
330 void MultiUserWindowManagerChromeOS::GetOwnersOfVisibleWindows(
331     std::set<std::string>* user_ids) const {
332   for (WindowToEntryMap::const_iterator it = window_to_entry_.begin();
333        it != window_to_entry_.end();
334        ++it) {
335     if (it->first->IsVisible())
336       user_ids->insert(it->second->owner());
337   }
338 }
339
340 bool MultiUserWindowManagerChromeOS::IsWindowOnDesktopOfUser(
341     aura::Window* window,
342     const std::string& user_id) const {
343   const std::string& presenting_user = GetUserPresentingWindow(window);
344   return presenting_user.empty() || presenting_user == user_id;
345 }
346
347 const std::string& MultiUserWindowManagerChromeOS::GetUserPresentingWindow(
348     aura::Window* window) const {
349   WindowToEntryMap::const_iterator it = window_to_entry_.find(window);
350   // If the window is not owned by anyone it is shown on all desktops and we
351   // return the empty string.
352   if (it == window_to_entry_.end())
353     return base::EmptyString();
354   // Otherwise we ask the object for its desktop.
355   return it->second->show_for_user();
356 }
357
358 void MultiUserWindowManagerChromeOS::AddUser(content::BrowserContext* context) {
359   Profile* profile = Profile::FromBrowserContext(context);
360   const std::string& user_id = multi_user_util::GetUserIDFromProfile(profile);
361   if (user_id_to_app_observer_.find(user_id) != user_id_to_app_observer_.end())
362     return;
363
364   user_id_to_app_observer_[user_id] = new AppObserver(user_id);
365   apps::AppWindowRegistry::Get(profile)
366       ->AddObserver(user_id_to_app_observer_[user_id]);
367
368   // Account all existing application windows of this user accordingly.
369   const apps::AppWindowRegistry::AppWindowList& app_windows =
370       apps::AppWindowRegistry::Get(profile)->app_windows();
371   apps::AppWindowRegistry::AppWindowList::const_iterator it =
372       app_windows.begin();
373   for (; it != app_windows.end(); ++it)
374     user_id_to_app_observer_[user_id]->OnAppWindowAdded(*it);
375
376   // Account all existing browser windows of this user accordingly.
377   BrowserList* browser_list = BrowserList::GetInstance(HOST_DESKTOP_TYPE_ASH);
378   BrowserList::const_iterator browser_it = browser_list->begin();
379   for (; browser_it != browser_list->end(); ++browser_it) {
380     if ((*browser_it)->profile()->GetOriginalProfile() == profile)
381       AddBrowserWindow(*browser_it);
382   }
383 }
384
385 void MultiUserWindowManagerChromeOS::AddObserver(Observer* observer) {
386   observers_.AddObserver(observer);
387 }
388
389 void MultiUserWindowManagerChromeOS::RemoveObserver(Observer* observer) {
390   observers_.RemoveObserver(observer);
391 }
392
393 void MultiUserWindowManagerChromeOS::ActiveUserChanged(
394     const std::string& user_id) {
395   DCHECK(user_id != current_user_id_);
396   // This needs to be set before the animation starts.
397   current_user_id_ = user_id;
398
399   animation_.reset(
400       new UserSwichAnimatorChromeOS(
401           this, user_id, GetAdjustedAnimationTimeInMS(kUserFadeTimeMS)));
402   // Call notifier here instead of observing ActiveUserChanged because
403   // this must happen after MultiUserWindowManagerChromeOS is notified.
404   ash::Shell::GetInstance()
405       ->system_tray_notifier()
406       ->NotifyMediaCaptureChanged();
407 }
408
409 void MultiUserWindowManagerChromeOS::OnWindowDestroyed(aura::Window* window) {
410   if (GetWindowOwner(window).empty()) {
411     // This must be a window in the transient chain - remove it and its
412     // children from the owner.
413     RemoveTransientOwnerRecursive(window);
414     return;
415   }
416   wm::TransientWindowManager::Get(window)->RemoveObserver(this);
417   // Remove the window from the owners list.
418   delete window_to_entry_[window];
419   window_to_entry_.erase(window);
420
421   // Notify entry change.
422   FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryRemoved(window));
423 }
424
425 void MultiUserWindowManagerChromeOS::OnWindowVisibilityChanging(
426     aura::Window* window, bool visible) {
427   // This command gets called first and immediately when show or hide gets
428   // called. We remember here the desired state for restoration IF we were
429   // not ourselves issuing the call.
430   // Note also that using the OnWindowVisibilityChanged callback cannot be
431   // used for this.
432   if (suppress_visibility_changes_)
433     return;
434
435   WindowToEntryMap::iterator it = window_to_entry_.find(window);
436   // If the window is not owned by anyone it is shown on all desktops.
437   if (it != window_to_entry_.end()) {
438     // Remember what was asked for so that we can restore this when the user's
439     // desktop gets restored.
440     it->second->set_show(visible);
441   } else {
442     TransientWindowToVisibility::iterator it =
443         transient_window_to_visibility_.find(window);
444     if (it != transient_window_to_visibility_.end())
445       it->second = visible;
446   }
447 }
448
449 void MultiUserWindowManagerChromeOS::OnWindowVisibilityChanged(
450     aura::Window* window, bool visible) {
451   if (suppress_visibility_changes_)
452     return;
453
454   // Don't allow to make the window visible if it shouldn't be.
455   if (visible && !IsWindowOnDesktopOfUser(window, current_user_id_)) {
456     SetWindowVisibility(window, false, 0);
457     return;
458   }
459   aura::Window* owned_parent = GetOwningWindowInTransientChain(window);
460   if (owned_parent && owned_parent != window && visible &&
461       !IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
462     SetWindowVisibility(window, false, 0);
463 }
464
465 void MultiUserWindowManagerChromeOS::OnTransientChildAdded(
466     aura::Window* window,
467     aura::Window* transient_window) {
468   if (!GetWindowOwner(window).empty()) {
469     AddTransientOwnerRecursive(transient_window, window);
470     return;
471   }
472   aura::Window* owned_parent =
473       GetOwningWindowInTransientChain(transient_window);
474   if (!owned_parent)
475     return;
476
477   AddTransientOwnerRecursive(transient_window, owned_parent);
478 }
479
480 void MultiUserWindowManagerChromeOS::OnTransientChildRemoved(
481     aura::Window* window,
482     aura::Window* transient_window) {
483   // Remove the transient child if the window itself is owned, or one of the
484   // windows in its transient parents chain.
485   if (!GetWindowOwner(window).empty() ||
486       GetOwningWindowInTransientChain(window))
487     RemoveTransientOwnerRecursive(transient_window);
488 }
489
490 void MultiUserWindowManagerChromeOS::Observe(
491     int type,
492     const content::NotificationSource& source,
493     const content::NotificationDetails& details) {
494   if (type == NOTIFICATION_BROWSER_WINDOW_READY)
495     AddBrowserWindow(content::Source<Browser>(source).ptr());
496 }
497
498 void MultiUserWindowManagerChromeOS::SetAnimationSpeedForTest(
499     MultiUserWindowManagerChromeOS::AnimationSpeed speed) {
500   animation_speed_ = speed;
501 }
502
503 bool MultiUserWindowManagerChromeOS::IsAnimationRunningForTest() {
504   return animation_.get() != NULL && !animation_->IsAnimationFinished();
505 }
506
507 const std::string& MultiUserWindowManagerChromeOS::GetCurrentUserForTest()
508     const {
509   return current_user_id_;
510 }
511
512 bool MultiUserWindowManagerChromeOS::ShowWindowForUserIntern(
513     aura::Window* window,
514     const std::string& user_id) {
515   // If there is either no owner, or the owner is the current user, no action
516   // is required.
517   const std::string& owner = GetWindowOwner(window);
518   if (owner.empty() ||
519       (owner == user_id && IsWindowOnDesktopOfUser(window, user_id)))
520     return false;
521
522   bool minimized = ash::wm::GetWindowState(window)->IsMinimized();
523   // Check that we are not trying to transfer ownership of a minimized window.
524   if (user_id != owner && minimized)
525     return false;
526
527   if (minimized) {
528     // If it is minimized it falls back to the original desktop.
529     ash::MultiProfileUMA::RecordTeleportAction(
530         ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_MINIMIZE);
531   } else {
532     // If the window was transferred without getting minimized, we should record
533     // the window type.
534     RecordUMAForTransferredWindowType(window);
535   }
536
537   WindowToEntryMap::iterator it = window_to_entry_.find(window);
538   it->second->set_show_for_user(user_id);
539
540   // Show the window if the added user is the current one.
541   if (user_id == current_user_id_) {
542     // Only show the window if it should be shown according to its state.
543     if (it->second->show())
544       SetWindowVisibility(window, true, kTeleportAnimationTimeMS);
545   } else {
546     SetWindowVisibility(window, false, kTeleportAnimationTimeMS);
547   }
548
549   // Notify entry change.
550   FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryChanged(window));
551   return true;
552 }
553
554 void MultiUserWindowManagerChromeOS::SetWindowVisibility(
555     aura::Window* window, bool visible, int animation_time_in_ms) {
556   if (window->IsVisible() == visible)
557     return;
558
559   // Hiding a system modal dialog should not be allowed. Instead we switch to
560   // the user which is showing the system modal window.
561   // Note that in some cases (e.g. unit test) windows might not have a root
562   // window.
563   if (!visible && window->GetRootWindow()) {
564     // Get the system modal container for the window's root window.
565     aura::Window* system_modal_container =
566         window->GetRootWindow()->GetChildById(
567             ash::kShellWindowId_SystemModalContainer);
568     if (window->parent() == system_modal_container) {
569       // The window is system modal and we need to find the parent which owns
570       // it so that we can switch to the desktop accordingly.
571       std::string user_id = GetUserPresentingWindow(window);
572       if (user_id.empty()) {
573         aura::Window* owning_window = GetOwningWindowInTransientChain(window);
574         DCHECK(owning_window);
575         user_id = GetUserPresentingWindow(owning_window);
576         DCHECK(!user_id.empty());
577       }
578       ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
579           user_id);
580       return;
581     }
582   }
583
584   // To avoid that these commands are recorded as any other commands, we are
585   // suppressing any window entry changes while this is going on.
586   base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true);
587
588   if (visible) {
589     ShowWithTransientChildrenRecursive(window, animation_time_in_ms);
590   } else {
591     if (window->HasFocus())
592       window->Blur();
593     SetWindowVisible(window, false, animation_time_in_ms);
594   }
595 }
596
597 void MultiUserWindowManagerChromeOS::AddBrowserWindow(Browser* browser) {
598   // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can
599   // come here with no valid window.
600   if (!browser->window() || !browser->window()->GetNativeWindow())
601     return;
602   SetWindowOwner(browser->window()->GetNativeWindow(),
603                  multi_user_util::GetUserIDFromProfile(browser->profile()));
604 }
605
606 void MultiUserWindowManagerChromeOS::ShowWithTransientChildrenRecursive(
607     aura::Window* window, int animation_time_in_ms) {
608   aura::Window::Windows::const_iterator it =
609       wm::GetTransientChildren(window).begin();
610   for (; it != wm::GetTransientChildren(window).end(); ++it)
611     ShowWithTransientChildrenRecursive(*it, animation_time_in_ms);
612
613   // We show all children which were not explicitly hidden.
614   TransientWindowToVisibility::iterator it2 =
615       transient_window_to_visibility_.find(window);
616   if (it2 == transient_window_to_visibility_.end() || it2->second)
617     SetWindowVisible(window, true, animation_time_in_ms);
618 }
619
620 aura::Window* MultiUserWindowManagerChromeOS::GetOwningWindowInTransientChain(
621     aura::Window* window) const {
622   if (!GetWindowOwner(window).empty())
623     return NULL;
624   aura::Window* parent = wm::GetTransientParent(window);
625   while (parent) {
626     if (!GetWindowOwner(parent).empty())
627       return parent;
628     parent = wm::GetTransientParent(parent);
629   }
630   return NULL;
631 }
632
633 void MultiUserWindowManagerChromeOS::AddTransientOwnerRecursive(
634     aura::Window* window,
635     aura::Window* owned_parent) {
636   // First add all child windows.
637   aura::Window::Windows::const_iterator it =
638       wm::GetTransientChildren(window).begin();
639   for (; it != wm::GetTransientChildren(window).end(); ++it)
640     AddTransientOwnerRecursive(*it, owned_parent);
641
642   // If this window is the owned window, we do not have to handle it again.
643   if (window == owned_parent)
644     return;
645
646   // Remember the current visibility.
647   DCHECK(transient_window_to_visibility_.find(window) ==
648              transient_window_to_visibility_.end());
649   transient_window_to_visibility_[window] = window->IsVisible();
650
651   // Add observers to track state changes.
652   window->AddObserver(this);
653   wm::TransientWindowManager::Get(window)->AddObserver(this);
654
655   // Hide the window if it should not be shown. Note that this hide operation
656   // will hide recursively this and all children - but we have already collected
657   // their initial view state.
658   if (!IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
659     SetWindowVisibility(window, false, kAnimationTimeMS);
660 }
661
662 void MultiUserWindowManagerChromeOS::RemoveTransientOwnerRecursive(
663     aura::Window* window) {
664   // First remove all child windows.
665   aura::Window::Windows::const_iterator it =
666       wm::GetTransientChildren(window).begin();
667   for (; it != wm::GetTransientChildren(window).end(); ++it)
668     RemoveTransientOwnerRecursive(*it);
669
670   // Find from transient window storage the visibility for the given window,
671   // set the visibility accordingly and delete the window from the map.
672   TransientWindowToVisibility::iterator visibility_item =
673       transient_window_to_visibility_.find(window);
674   DCHECK(visibility_item != transient_window_to_visibility_.end());
675
676   window->RemoveObserver(this);
677   wm::TransientWindowManager::Get(window)->RemoveObserver(this);
678
679   bool unowned_view_state = visibility_item->second;
680   transient_window_to_visibility_.erase(visibility_item);
681   if (unowned_view_state && !window->IsVisible()) {
682     // To prevent these commands from being recorded as any other commands, we
683     // are suppressing any window entry changes while this is going on.
684     // Instead of calling SetWindowVisible, only show gets called here since all
685     // dependents have been shown previously already.
686     base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true);
687     window->Show();
688   }
689 }
690
691 void MultiUserWindowManagerChromeOS::SetWindowVisible(
692     aura::Window* window,
693     bool visible,
694     int animation_time_in_ms) {
695   AnimationSetter animation_setter(
696       window,
697       GetAdjustedAnimationTimeInMS(animation_time_in_ms));
698
699   if (visible)
700     window->Show();
701   else
702     window->Hide();
703
704   // Make sure that animations have no influence on the window state after the
705   // call.
706   DCHECK_EQ(visible, window->IsVisible());
707 }
708
709 int MultiUserWindowManagerChromeOS::GetAdjustedAnimationTimeInMS(
710     int default_time_in_ms) const {
711   return animation_speed_ == ANIMATION_SPEED_NORMAL ? default_time_in_ms :
712       (animation_speed_ == ANIMATION_SPEED_FAST ? 10 : 0);
713 }
714
715 }  // namespace chrome