1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
21e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
31e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// found in the LICENSE file.
41e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.h"
61e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "apps/app_window.h"
8010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "apps/ui/native_app_window.h"
91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
14effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/aura/window.h"
151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)namespace {
171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool ControlsWindow(aura::Window* window) {
191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return chrome::GetHostDesktopTypeForNativeWindow(window) ==
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)         chrome::HOST_DESKTOP_TYPE_ASH;
211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}  // namespace
241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)MultiProfileAppWindowLauncherController::
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    MultiProfileAppWindowLauncherController(ChromeLauncherController* owner)
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : AppWindowLauncherController(owner) {}
281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)MultiProfileAppWindowLauncherController::
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ~MultiProfileAppWindowLauncherController() {
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // We need to remove all Registry observers for added users.
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AppWindowRegistryList::iterator it = multi_user_registry_.begin();
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != multi_user_registry_.end();
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it)
351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    (*it)->RemoveObserver(this);
361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MultiProfileAppWindowLauncherController::ActiveUserChanged(
391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& user_email) {
401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // The active user has changed and we need to traverse our list of items to
411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // show / hide them one by one. To avoid that a user dependent state
421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // "survives" in a launcher item, we first delete all items making sure that
431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // nothing remains and then re-create them again.
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AppWindowList::iterator it = app_window_list_.begin();
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != app_window_list_.end();
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    apps::AppWindow* app_window = *it;
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Profile* profile =
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Profile::FromBrowserContext(app_window->browser_context());
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!multi_user_util::IsProfileFromActiveUser(profile) &&
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        IsRegisteredApp(app_window->GetNativeWindow()))
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      UnregisterApp(app_window->GetNativeWindow());
531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AppWindowList::iterator it = app_window_list_.begin();
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != app_window_list_.end();
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    apps::AppWindow* app_window = *it;
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Profile* profile =
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Profile::FromBrowserContext(app_window->browser_context());
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (multi_user_util::IsProfileFromActiveUser(profile) &&
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        !IsRegisteredApp(app_window->GetNativeWindow()) &&
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        (app_window->GetBaseWindow()->IsMinimized() ||
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)         app_window->GetNativeWindow()->IsVisible()))
641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      RegisterApp(*it);
651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MultiProfileAppWindowLauncherController::AdditionalUserAddedToSession(
691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    Profile* profile) {
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Each users AppWindowRegistry needs to be observed.
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  apps::AppWindowRegistry* registry = apps::AppWindowRegistry::Get(profile);
721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  multi_user_registry_.push_back(registry);
731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  registry->AddObserver(this);
741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MultiProfileAppWindowLauncherController::OnAppWindowAdded(
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    apps::AppWindow* app_window) {
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ControlsWindow(app_window->GetNativeWindow()))
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  app_window_list_.push_back(app_window);
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // If the window got created for a non active user but the user allowed to
84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // teleport to the current user's desktop, we teleport it now.
85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!multi_user_util::IsProfileFromActiveUser(profile) &&
86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      UserHasAppOnActiveDesktop(app_window)) {
87010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        app_window->GetNativeWindow(), multi_user_util::GetCurrentUserId());
89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MultiProfileAppWindowLauncherController::OnAppWindowShown(
93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    apps::AppWindow* app_window) {
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!ControlsWindow(app_window->GetNativeWindow()))
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (multi_user_util::IsProfileFromActiveUser(profile) &&
100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      !IsRegisteredApp(app_window->GetNativeWindow())) {
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RegisterApp(app_window);
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The panel layout manager only manages windows which are anchored.
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Since this window did never had an anchor, it would stay hidden. We
107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // therefore make it visible now.
108010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (UserHasAppOnActiveDesktop(app_window) &&
109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      app_window->GetNativeWindow()->type() == ui::wm::WINDOW_TYPE_PANEL &&
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      !app_window->GetNativeWindow()->layer()->GetTargetOpacity()) {
111010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    app_window->GetNativeWindow()->layer()->SetOpacity(1.0f);
112010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
113010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
114010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
115010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MultiProfileAppWindowLauncherController::OnAppWindowHidden(
116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    apps::AppWindow* app_window) {
117010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!ControlsWindow(app_window->GetNativeWindow()))
118010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
119010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (multi_user_util::IsProfileFromActiveUser(profile) &&
122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      IsRegisteredApp(app_window->GetNativeWindow())) {
123010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    UnregisterApp(app_window->GetNativeWindow());
124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MultiProfileAppWindowLauncherController::OnAppWindowRemoved(
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    apps::AppWindow* app_window) {
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ControlsWindow(app_window->GetNativeWindow()))
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If the application is registered with AppWindowLauncher (because the user
1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // is currently active), the OnWindowDestroying observer has already (or will
1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // soon) unregister it independently from the shelf. If it was not registered
1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // we don't need to do anything anyways. As such, all which is left to do here
1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // is to get rid of our own reference.
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AppWindowList::iterator it =
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::find(app_window_list_.begin(), app_window_list_.end(), app_window);
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(it != app_window_list_.end());
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  app_window_list_.erase(it);
1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool MultiProfileAppWindowLauncherController::UserHasAppOnActiveDesktop(
144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    apps::AppWindow* app_window) {
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const std::string& app_id = app_window->extension_id();
146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  content::BrowserContext* app_context = app_window->browser_context();
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(!app_context->IsOffTheRecord());
148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const std::string& current_user = multi_user_util::GetCurrentUserId();
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  chrome::MultiUserWindowManager* manager =
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      chrome::MultiUserWindowManager::GetInstance();
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (AppWindowList::iterator it = app_window_list_.begin();
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       it != app_window_list_.end();
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++it) {
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    apps::AppWindow* other_window = *it;
155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK(!other_window->browser_context()->IsOffTheRecord());
156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (manager->IsWindowOnDesktopOfUser(other_window->GetNativeWindow(),
157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                         current_user) &&
158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        app_id == other_window->extension_id() &&
159effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        app_context == other_window->browser_context()) {
160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return true;
161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return false;
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
165