14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/ash_switches.h"
80f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ash/multi_profile_uma.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/root_window_controller.h"
105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ash/session/session_state_delegate.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/shelf/shelf.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/shell.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/shell_delegate.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shell_window_ids.h"
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ash/system/tray/system_tray_notifier.h"
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "ash/wm/maximize_mode/maximize_mode_controller.h"
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ash/wm/window_state.h"
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/auto_reset.h"
190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "base/message_loop/message_loop.h"
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/strings/string_util.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/browser_process.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h"
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
27c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h"
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/browser.h"
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h"
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/notification_service.h"
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/app_window/app_window.h"
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/app_window/app_window_registry.h"
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "google_apis/gaia/gaia_auth_util.h"
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/aura/client/aura_constants.h"
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/aura/window.h"
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/base/ui_base_types.h"
400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "ui/events/event.h"
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/message_center/message_center.h"
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/transient_window_manager.h"
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/window_animations.h"
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/window_util.h"
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The animation time in milliseconds for a single window which is fading
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// in / out.
50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int kAnimationTimeMS = 100;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
52a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// The animation time in milliseconds for the fade in and / or out when
53a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// switching users.
54a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst int kUserFadeTimeMS = 110;
55a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The animation time in ms for a window which get teleported to another screen.
57c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst int kTeleportAnimationTimeMS = 300;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Checks if a given event is a user event.
60c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool IsUserEvent(const ui::Event* e) {
610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (e) {
620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    ui::EventType type = e->type();
630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (type != ui::ET_CANCEL_MODE &&
640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        type != ui::ET_UMA_DATA &&
650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        type != ui::ET_UNKNOWN)
660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return true;
670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return false;
690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// Test if we are currently processing a user event which might lead to a
720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// browser / app creation.
730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool IsProcessingUserEvent() {
740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // When there is a nested message loop (e.g. active menu or drag and drop
750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // operation) - we are in a nested loop and can ignore this.
760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Note: Unit tests might not have a message loop.
770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  base::MessageLoop* message_loop = base::MessageLoop::current();
780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (message_loop && message_loop->is_running() && message_loop->IsNested())
790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return false;
800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // TODO(skuhne): "Open link in new window" will come here after the menu got
820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // closed, executing the command from the nested menu loop. However at that
830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // time there is no active event processed. A solution for that need to be
840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // found past M-32. A global event handler filter (pre and post) might fix
850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // that problem in conjunction with a depth counter - but - for the menu
860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // execution we come here after the loop was finished (so it's not nested
870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // anymore) and the root window should therefore still have the event which
880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // lead to the menu invocation, but it is not. By fixing that problem this
890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // would "magically work".
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  aura::Window::Windows root_window_list = ash::Shell::GetAllRootWindows();
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (aura::Window::Windows::iterator it = root_window_list.begin();
920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)       it != root_window_list.end();
930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)       ++it) {
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (IsUserEvent((*it)->GetHost()->dispatcher()->current_event()))
950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return true;
960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return false;
980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Records the type of window which was transferred to another desktop.
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void RecordUMAForTransferredWindowType(aura::Window* window) {
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // We need to figure out what kind of window this is to record the transfer.
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Browser* browser = chrome::FindBrowserWithWindow(window);
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ash::MultiProfileUMA::TeleportWindowType window_type =
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      ash::MultiProfileUMA::TELEPORT_WINDOW_UNKNOWN;
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (browser) {
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (browser->profile()->IsOffTheRecord()) {
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_INCOGNITO_BROWSER;
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (browser->is_app()) {
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_V1_APP;
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else if (browser->is_type_popup()) {
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_POPUP;
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    } else {
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_BROWSER;
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  } else {
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Unit tests might come here without a profile manager.
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!g_browser_process->profile_manager())
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return;
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // If it is not a browser, it is probably be a V2 application. In that case
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // one of the AppWindowRegistry instances should know about it.
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::AppWindow* app_window = NULL;
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    std::vector<Profile*> profiles =
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        g_browser_process->profile_manager()->GetLoadedProfiles();
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    for (std::vector<Profile*>::iterator it = profiles.begin();
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         it != profiles.end() && app_window == NULL;
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         it++) {
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      app_window = extensions::AppWindowRegistry::Get(*it)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       ->GetAppWindowForNativeWindow(window);
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (app_window) {
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (app_window->window_type() ==
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          extensions::AppWindow::WINDOW_TYPE_PANEL ||
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          app_window->window_type() ==
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          extensions::AppWindow::WINDOW_TYPE_V1_PANEL) {
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_PANEL;
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      } else {
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        window_type = ash::MultiProfileUMA::TELEPORT_WINDOW_V2_APP;
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ash::MultiProfileUMA::RecordTeleportWindowType(window_type);
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace chrome {
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// A class to temporarily change the animation properties for a window.
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class AnimationSetter {
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AnimationSetter(aura::Window* window, int animation_time_in_ms)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : window_(window),
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        previous_animation_type_(
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            wm::GetWindowVisibilityAnimationType(window_)),
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        previous_animation_time_(
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            wm::GetWindowVisibilityAnimationDuration(*window_)) {
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    wm::SetWindowVisibilityAnimationType(
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        window_,
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    wm::SetWindowVisibilityAnimationDuration(
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        window_,
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::TimeDelta::FromMilliseconds(animation_time_in_ms));
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~AnimationSetter() {
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    wm::SetWindowVisibilityAnimationType(window_,
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                    previous_animation_type_);
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    wm::SetWindowVisibilityAnimationDuration(
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        window_,
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        previous_animation_time_);
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The window which gets used.
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  aura::Window* window_;
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Previous animation type.
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const int previous_animation_type_;
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Previous animation time.
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::TimeDelta previous_animation_time_;
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AnimationSetter);
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// This class keeps track of all applications which were started for a user.
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// When an app gets created, the window will be tagged for that user. Note
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// that the destruction does not need to be tracked here since the universal
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// window observer will take care of that.
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass AppObserver : public extensions::AppWindowRegistry::Observer {
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public:
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  explicit AppObserver(const std::string& user_id) : user_id_(user_id) {}
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual ~AppObserver() {}
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // AppWindowRegistry::Observer overrides:
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual void OnAppWindowAdded(extensions::AppWindow* app_window) OVERRIDE {
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    aura::Window* window = app_window->GetNativeWindow();
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DCHECK(window);
200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    MultiUserWindowManagerChromeOS::GetInstance()->SetWindowOwner(window,
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                                  user_id_);
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private:
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string user_id_;
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AppObserver);
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)MultiUserWindowManagerChromeOS::MultiUserWindowManagerChromeOS(
211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& current_user_id)
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    : current_user_id_(current_user_id),
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      notification_blocker_(new MultiUserNotificationBlockerChromeOS(
2140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          message_center::MessageCenter::Get(), current_user_id)),
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      suppress_visibility_changes_(false),
216a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      animation_speed_(ANIMATION_SPEED_NORMAL) {
217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Add a session state observer to be able to monitor session changes.
218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (ash::Shell::HasInstance())
219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ash::Shell::GetInstance()->session_state_delegate()->
220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        AddSessionStateObserver(this);
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // The BrowserListObserver would have been better to use then the old
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // notification system, but that observer fires before the window got created.
224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  registrar_.Add(this, NOTIFICATION_BROWSER_WINDOW_READY,
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 content::NotificationService::AllSources());
2261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Add an app window observer & all already running apps.
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Profile* profile = multi_user_util::GetProfileFromUserID(current_user_id);
229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (profile)
230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    AddUser(profile);
2311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)MultiUserWindowManagerChromeOS::~MultiUserWindowManagerChromeOS() {
234c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // When the MultiUserWindowManager gets destroyed, ash::Shell is mostly gone.
235c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // As such we should not try to finalize any outstanding user animations.
236c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Note that the destruction of the object can be done later.
237c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (animation_.get())
238c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    animation_->CancelAnimation();
239c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Remove all window observers.
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WindowToEntryMap::iterator window = window_to_entry_.begin();
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (window != window_to_entry_.end()) {
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnWindowDestroyed(window->first);
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    window = window_to_entry_.begin();
245f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
2461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Remove all app observers.
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UserIDToAppWindowObserver::iterator app_observer_iterator =
249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      user_id_to_app_observer_.begin();
250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  while (app_observer_iterator != user_id_to_app_observer_.end()) {
251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    Profile* profile = multi_user_util::GetProfileFromUserID(
252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        app_observer_iterator->first);
253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK(profile);
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::AppWindowRegistry::Get(profile)
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ->RemoveObserver(app_observer_iterator->second);
256f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    delete app_observer_iterator->second;
257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    user_id_to_app_observer_.erase(app_observer_iterator);
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    app_observer_iterator = user_id_to_app_observer_.begin();
2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (ash::Shell::HasInstance())
262f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ash::Shell::GetInstance()->session_state_delegate()->
263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        RemoveSessionStateObserver(this);
2648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::SetWindowOwner(
267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window* window,
268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& user_id) {
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Make sure the window is valid and there was no owner yet.
2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(window);
2714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(!user_id.empty());
2724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (GetWindowOwner(window) == user_id)
2734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(GetWindowOwner(window).empty());
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  window_to_entry_[window] = new WindowEntry(user_id);
2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Remember the initial visibility of the window.
2780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  window_to_entry_[window]->set_show(window->IsVisible());
2790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Add observers to track state changes.
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  window->AddObserver(this);
282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  wm::TransientWindowManager::Get(window)->AddObserver(this);
2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Check if this window was created due to a user interaction. If it was,
2850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // transfer it to the current user.
2860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (IsProcessingUserEvent())
2870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    window_to_entry_[window]->set_show_for_user(current_user_id_);
2880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Add all transient children to our set of windows. Note that the function
2900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // will add the children but not the owner to the transient children map.
2910f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  AddTransientOwnerRecursive(window, window);
2920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Notify entry adding.
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryAdded(window));
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!IsWindowOnDesktopOfUser(window, current_user_id_))
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetWindowVisibility(window, false, 0);
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const std::string& MultiUserWindowManagerChromeOS::GetWindowOwner(
301010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    aura::Window* window) const {
302010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  WindowToEntryMap::const_iterator it = window_to_entry_.find(window);
303a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return it != window_to_entry_.end() ? it->second->owner()
304a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                      : base::EmptyString();
3054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::ShowWindowForUser(
308f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window* window,
309f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& user_id) {
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string previous_owner(GetUserPresentingWindow(window));
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ShowWindowForUserIntern(window, user_id))
3124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The window switched to a new desktop and we have to switch to that desktop,
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // but only when it was on the visible desktop and the the target is not the
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // visible desktop.
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (user_id == current_user_id_ || previous_owner != current_user_id_)
3174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_id);
3214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
323010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool MultiUserWindowManagerChromeOS::AreWindowsSharedAmongUsers() const {
324010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  WindowToEntryMap::const_iterator it = window_to_entry_.begin();
3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (; it != window_to_entry_.end(); ++it) {
3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (it->second->owner() != it->second->show_for_user())
3274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return true;
3284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
3294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return false;
3304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MultiUserWindowManagerChromeOS::GetOwnersOfVisibleWindows(
333010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    std::set<std::string>* user_ids) const {
334010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (WindowToEntryMap::const_iterator it = window_to_entry_.begin();
335010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       it != window_to_entry_.end();
336010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       ++it) {
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (it->first->IsVisible())
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_ids->insert(it->second->owner());
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool MultiUserWindowManagerChromeOS::IsWindowOnDesktopOfUser(
3434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    aura::Window* window,
344010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const std::string& user_id) const {
3454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const std::string& presenting_user = GetUserPresentingWindow(window);
3464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return presenting_user.empty() || presenting_user == user_id;
3474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
349f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const std::string& MultiUserWindowManagerChromeOS::GetUserPresentingWindow(
350010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    aura::Window* window) const {
351010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  WindowToEntryMap::const_iterator it = window_to_entry_.find(window);
3524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // If the window is not owned by anyone it is shown on all desktops and we
3534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // return the empty string.
3544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (it == window_to_entry_.end())
355a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return base::EmptyString();
3564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Otherwise we ask the object for its desktop.
3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return it->second->show_for_user();
3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
360a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MultiUserWindowManagerChromeOS::AddUser(content::BrowserContext* context) {
361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(context);
362f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const std::string& user_id = multi_user_util::GetUserIDFromProfile(profile);
363f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (user_id_to_app_observer_.find(user_id) != user_id_to_app_observer_.end())
364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
366f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  user_id_to_app_observer_[user_id] = new AppObserver(user_id);
3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extensions::AppWindowRegistry::Get(profile)
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ->AddObserver(user_id_to_app_observer_[user_id]);
369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Account all existing application windows of this user accordingly.
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const extensions::AppWindowRegistry::AppWindowList& app_windows =
3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extensions::AppWindowRegistry::Get(profile)->app_windows();
3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extensions::AppWindowRegistry::AppWindowList::const_iterator it =
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_windows.begin();
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (; it != app_windows.end(); ++it)
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    user_id_to_app_observer_[user_id]->OnAppWindowAdded(*it);
377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Account all existing browser windows of this user accordingly.
379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BrowserList* browser_list = BrowserList::GetInstance(HOST_DESKTOP_TYPE_ASH);
380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  BrowserList::const_iterator browser_it = browser_list->begin();
381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (; browser_it != browser_list->end(); ++browser_it) {
382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if ((*browser_it)->profile()->GetOriginalProfile() == profile)
383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      AddBrowserWindow(*browser_it);
384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
385f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MultiUserWindowManagerChromeOS::AddObserver(Observer* observer) {
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  observers_.AddObserver(observer);
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MultiUserWindowManagerChromeOS::RemoveObserver(Observer* observer) {
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  observers_.RemoveObserver(observer);
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::ActiveUserChanged(
396f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& user_id) {
3974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(user_id != current_user_id_);
398c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // This needs to be set before the animation starts.
3994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  current_user_id_ = user_id;
400c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
401c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  animation_.reset(
402a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      new UserSwichAnimatorChromeOS(
403a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          this, user_id, GetAdjustedAnimationTimeInMS(kUserFadeTimeMS)));
404010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Call notifier here instead of observing ActiveUserChanged because
405010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // this must happen after MultiUserWindowManagerChromeOS is notified.
406010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  ash::Shell::GetInstance()
407010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      ->system_tray_notifier()
408010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      ->NotifyMediaCaptureChanged();
4094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::OnWindowDestroyed(aura::Window* window) {
4120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (GetWindowOwner(window).empty()) {
4130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // This must be a window in the transient chain - remove it and its
4140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // children from the owner.
4150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    RemoveTransientOwnerRecursive(window);
4160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
4170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
418a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  wm::TransientWindowManager::Get(window)->RemoveObserver(this);
4194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Remove the window from the owners list.
4204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  delete window_to_entry_[window];
4214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  window_to_entry_.erase(window);
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Notify entry change.
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryRemoved(window));
4254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::OnWindowVisibilityChanging(
4284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    aura::Window* window, bool visible) {
4294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // This command gets called first and immediately when show or hide gets
4304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // called. We remember here the desired state for restoration IF we were
4314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // not ourselves issuing the call.
4324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Note also that using the OnWindowVisibilityChanged callback cannot be
4334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // used for this.
4340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (suppress_visibility_changes_)
4350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
4360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  WindowToEntryMap::iterator it = window_to_entry_.find(window);
4380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // If the window is not owned by anyone it is shown on all desktops.
4390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (it != window_to_entry_.end()) {
4400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // Remember what was asked for so that we can restore this when the user's
4410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // desktop gets restored.
4420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    it->second->set_show(visible);
4430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else {
4440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    TransientWindowToVisibility::iterator it =
4450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        transient_window_to_visibility_.find(window);
4460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (it != transient_window_to_visibility_.end())
4470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      it->second = visible;
4484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
4494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
451f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::OnWindowVisibilityChanged(
4524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    aura::Window* window, bool visible) {
4530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (suppress_visibility_changes_)
4540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
4550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Don't allow to make the window visible if it shouldn't be.
4570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (visible && !IsWindowOnDesktopOfUser(window, current_user_id_)) {
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetWindowVisibility(window, false, 0);
4590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
4600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  aura::Window* owned_parent = GetOwningWindowInTransientChain(window);
4620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (owned_parent && owned_parent != window && visible &&
4630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      !IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetWindowVisibility(window, false, 0);
4650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
4660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MultiUserWindowManagerChromeOS::OnTransientChildAdded(
4680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    aura::Window* window,
4690f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    aura::Window* transient_window) {
4700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!GetWindowOwner(window).empty()) {
4710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    AddTransientOwnerRecursive(transient_window, window);
4720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
4730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
4740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  aura::Window* owned_parent =
4750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      GetOwningWindowInTransientChain(transient_window);
4760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!owned_parent)
4770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
4780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4790f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  AddTransientOwnerRecursive(transient_window, owned_parent);
4800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
4810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MultiUserWindowManagerChromeOS::OnTransientChildRemoved(
4830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    aura::Window* window,
4840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    aura::Window* transient_window) {
4850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Remove the transient child if the window itself is owned, or one of the
4860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // windows in its transient parents chain.
4870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!GetWindowOwner(window).empty() ||
4880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      GetOwningWindowInTransientChain(window))
4890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    RemoveTransientOwnerRecursive(transient_window);
4904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
492f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::Observe(
4934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    int type,
4944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const content::NotificationSource& source,
4954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const content::NotificationDetails& details) {
496f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (type == NOTIFICATION_BROWSER_WINDOW_READY)
4974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    AddBrowserWindow(content::Source<Browser>(source).ptr());
4984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
500a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid MultiUserWindowManagerChromeOS::SetAnimationSpeedForTest(
501a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    MultiUserWindowManagerChromeOS::AnimationSpeed speed) {
502a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  animation_speed_ = speed;
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool MultiUserWindowManagerChromeOS::IsAnimationRunningForTest() {
506c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return animation_.get() != NULL && !animation_->IsAnimationFinished();
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
509010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)const std::string& MultiUserWindowManagerChromeOS::GetCurrentUserForTest()
510010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const {
5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return current_user_id_;
5125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool MultiUserWindowManagerChromeOS::ShowWindowForUserIntern(
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    aura::Window* window,
5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& user_id) {
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If there is either no owner, or the owner is the current user, no action
5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // is required.
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string& owner = GetWindowOwner(window);
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (owner.empty() ||
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (owner == user_id && IsWindowOnDesktopOfUser(window, user_id)))
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
5235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool minimized = ash::wm::GetWindowState(window)->IsMinimized();
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Check that we are not trying to transfer ownership of a minimized window.
5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (user_id != owner && minimized)
5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (minimized) {
5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If it is minimized it falls back to the original desktop.
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::MultiProfileUMA::RecordTeleportAction(
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_MINIMIZE);
5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If the window was transferred without getting minimized, we should record
5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // the window type.
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RecordUMAForTransferredWindowType(window);
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WindowToEntryMap::iterator it = window_to_entry_.find(window);
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  it->second->set_show_for_user(user_id);
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Show the window if the added user is the current one.
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (user_id == current_user_id_) {
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Only show the window if it should be shown according to its state.
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (it->second->show())
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      SetWindowVisibility(window, true, kTeleportAnimationTimeMS);
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetWindowVisibility(window, false, kTeleportAnimationTimeMS);
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Notify entry change.
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryChanged(window));
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return true;
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
556f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::SetWindowVisibility(
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    aura::Window* window, bool visible, int animation_time_in_ms) {
5584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (window->IsVisible() == visible)
5594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
5604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
561f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Hiding a system modal dialog should not be allowed. Instead we switch to
562f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // the user which is showing the system modal window.
563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Note that in some cases (e.g. unit test) windows might not have a root
564f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // window.
565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!visible && window->GetRootWindow()) {
566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Get the system modal container for the window's root window.
567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window* system_modal_container =
568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        window->GetRootWindow()->GetChildById(
569c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            ash::kShellWindowId_SystemModalContainer);
570f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (window->parent() == system_modal_container) {
571f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // The window is system modal and we need to find the parent which owns
572f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      // it so that we can switch to the desktop accordingly.
573f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      std::string user_id = GetUserPresentingWindow(window);
574f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (user_id.empty()) {
575f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        aura::Window* owning_window = GetOwningWindowInTransientChain(window);
576f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        DCHECK(owning_window);
577f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        user_id = GetUserPresentingWindow(owning_window);
578f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        DCHECK(!user_id.empty());
579f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      }
580f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
581f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          user_id);
582f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return;
583f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
584f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
585f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // To avoid that these commands are recorded as any other commands, we are
5874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // suppressing any window entry changes while this is going on.
5884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true);
5894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (visible) {
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShowWithTransientChildrenRecursive(window, animation_time_in_ms);
5920f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  } else {
5930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (window->HasFocus())
5940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      window->Blur();
5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetWindowVisible(window, false, animation_time_in_ms);
5960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
5970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
5980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
599c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid MultiUserWindowManagerChromeOS::AddBrowserWindow(Browser* browser) {
600c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can
601c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // come here with no valid window.
602c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!browser->window() || !browser->window()->GetNativeWindow())
603c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return;
604c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  SetWindowOwner(browser->window()->GetNativeWindow(),
605c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 multi_user_util::GetUserIDFromProfile(browser->profile()));
606c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
607c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
608f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::ShowWithTransientChildrenRecursive(
6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    aura::Window* window, int animation_time_in_ms) {
6100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  aura::Window::Windows::const_iterator it =
611a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      wm::GetTransientChildren(window).begin();
612a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (; it != wm::GetTransientChildren(window).end(); ++it)
6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ShowWithTransientChildrenRecursive(*it, animation_time_in_ms);
6140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // We show all children which were not explicitly hidden.
6160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  TransientWindowToVisibility::iterator it2 =
6170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      transient_window_to_visibility_.find(window);
6180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (it2 == transient_window_to_visibility_.end() || it2->second)
6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetWindowVisible(window, true, animation_time_in_ms);
6200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
6210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
622f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)aura::Window* MultiUserWindowManagerChromeOS::GetOwningWindowInTransientChain(
623010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    aura::Window* window) const {
6240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!GetWindowOwner(window).empty())
6250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return NULL;
626a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  aura::Window* parent = wm::GetTransientParent(window);
6270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  while (parent) {
6280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (!GetWindowOwner(parent).empty())
6290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      return parent;
630a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    parent = wm::GetTransientParent(parent);
6310f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
6320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return NULL;
6330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
6340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
635f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::AddTransientOwnerRecursive(
6360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    aura::Window* window,
6370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    aura::Window* owned_parent) {
6380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // First add all child windows.
6390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  aura::Window::Windows::const_iterator it =
640a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      wm::GetTransientChildren(window).begin();
641a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (; it != wm::GetTransientChildren(window).end(); ++it)
6420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    AddTransientOwnerRecursive(*it, owned_parent);
6430f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // If this window is the owned window, we do not have to handle it again.
6450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (window == owned_parent)
6460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return;
6470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Remember the current visibility.
6490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(transient_window_to_visibility_.find(window) ==
6500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)             transient_window_to_visibility_.end());
6510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  transient_window_to_visibility_[window] = window->IsVisible();
6520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Add observers to track state changes.
6540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  window->AddObserver(this);
655a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  wm::TransientWindowManager::Get(window)->AddObserver(this);
6560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Hide the window if it should not be shown. Note that this hide operation
6580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // will hide recursively this and all children - but we have already collected
6590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // their initial view state.
6600f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
6615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetWindowVisibility(window, false, kAnimationTimeMS);
6620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
6630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
664f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MultiUserWindowManagerChromeOS::RemoveTransientOwnerRecursive(
6650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    aura::Window* window) {
6660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // First remove all child windows.
6670f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  aura::Window::Windows::const_iterator it =
668a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      wm::GetTransientChildren(window).begin();
669a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (; it != wm::GetTransientChildren(window).end(); ++it)
6700f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    RemoveTransientOwnerRecursive(*it);
6710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Find from transient window storage the visibility for the given window,
6730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // set the visibility accordingly and delete the window from the map.
6740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  TransientWindowToVisibility::iterator visibility_item =
6750f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      transient_window_to_visibility_.find(window);
6760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(visibility_item != transient_window_to_visibility_.end());
6770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  window->RemoveObserver(this);
679a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  wm::TransientWindowManager::Get(window)->RemoveObserver(this);
6800f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
6810f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  bool unowned_view_state = visibility_item->second;
6820f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  transient_window_to_visibility_.erase(visibility_item);
6830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (unowned_view_state && !window->IsVisible()) {
6840f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // To prevent these commands from being recorded as any other commands, we
6850f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // are suppressing any window entry changes while this is going on.
6860f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // Instead of calling SetWindowVisible, only show gets called here since all
6870f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // dependents have been shown previously already.
6880f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    base::AutoReset<bool> suppressor(&suppress_visibility_changes_, true);
6890f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    window->Show();
6900f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
6914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
6924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MultiUserWindowManagerChromeOS::SetWindowVisible(
6945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    aura::Window* window,
6955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool visible,
6965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int animation_time_in_ms) {
6975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // The MaximizeModeWindowManager will not handle invisible windows since they
6985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // are not user activatable. Since invisible windows are not being tracked,
6995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // we tell it to maximize / track this window now before it gets shown, to
7005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // reduce animation jank from multiple resizes.
7015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (visible)
7025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ash::Shell::GetInstance()->maximize_mode_controller()->AddWindow(window);
7035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AnimationSetter animation_setter(
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      window,
706a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      GetAdjustedAnimationTimeInMS(animation_time_in_ms));
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (visible)
7095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    window->Show();
7105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
7115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    window->Hide();
7125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Make sure that animations have no influence on the window state after the
7145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // call.
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(visible, window->IsVisible());
7165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
718a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochint MultiUserWindowManagerChromeOS::GetAdjustedAnimationTimeInMS(
719010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    int default_time_in_ms) const {
720a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return animation_speed_ == ANIMATION_SPEED_NORMAL ? default_time_in_ms :
721a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      (animation_speed_ == ANIMATION_SPEED_FAST ? 10 : 0);
722a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
723a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
7244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace chrome
725