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)
71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
81e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
10effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/app_window/app_window.h"
1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "extensions/browser/app_window/native_app_window.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) {
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::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) {
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::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.
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extensions::AppWindowRegistry* registry =
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extensions::AppWindowRegistry::Get(profile);
731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  multi_user_registry_.push_back(registry);
741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  registry->AddObserver(this);
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MultiProfileAppWindowLauncherController::OnAppWindowAdded(
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::AppWindow* app_window) {
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ControlsWindow(app_window->GetNativeWindow()))
801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
81010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  app_window_list_.push_back(app_window);
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // If the window got created for a non active user but the user allowed to
85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // teleport to the current user's desktop, we teleport it now.
86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!multi_user_util::IsProfileFromActiveUser(profile) &&
87010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      UserHasAppOnActiveDesktop(app_window)) {
88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        app_window->GetNativeWindow(), multi_user_util::GetCurrentUserId());
90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MultiProfileAppWindowLauncherController::OnAppWindowShown(
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::AppWindow* app_window) {
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!ControlsWindow(app_window->GetNativeWindow()))
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (multi_user_util::IsProfileFromActiveUser(profile) &&
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      !IsRegisteredApp(app_window->GetNativeWindow())) {
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RegisterApp(app_window);
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // The panel layout manager only manages windows which are anchored.
107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Since this window did never had an anchor, it would stay hidden. We
108010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // therefore make it visible now.
109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (UserHasAppOnActiveDesktop(app_window) &&
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      app_window->GetNativeWindow()->type() == ui::wm::WINDOW_TYPE_PANEL &&
111010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      !app_window->GetNativeWindow()->layer()->GetTargetOpacity()) {
112010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    app_window->GetNativeWindow()->layer()->SetOpacity(1.0f);
113010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
114010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
115010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
116010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void MultiProfileAppWindowLauncherController::OnAppWindowHidden(
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::AppWindow* app_window) {
118010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!ControlsWindow(app_window->GetNativeWindow()))
119010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
120010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
121010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
122010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (multi_user_util::IsProfileFromActiveUser(profile) &&
123010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      IsRegisteredApp(app_window->GetNativeWindow())) {
124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    UnregisterApp(app_window->GetNativeWindow());
125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void MultiProfileAppWindowLauncherController::OnAppWindowRemoved(
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::AppWindow* app_window) {
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!ControlsWindow(app_window->GetNativeWindow()))
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If the application is registered with AppWindowLauncher (because the user
1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // is currently active), the OnWindowDestroying observer has already (or will
1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // soon) unregister it independently from the shelf. If it was not registered
1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // we don't need to do anything anyways. As such, all which is left to do here
1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // is to get rid of our own reference.
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AppWindowList::iterator it =
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::find(app_window_list_.begin(), app_window_list_.end(), app_window);
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(it != app_window_list_.end());
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  app_window_list_.erase(it);
1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochbool MultiProfileAppWindowLauncherController::UserHasAppOnActiveDesktop(
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::AppWindow* app_window) {
146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const std::string& app_id = app_window->extension_id();
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  content::BrowserContext* app_context = app_window->browser_context();
148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(!app_context->IsOffTheRecord());
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const std::string& current_user = multi_user_util::GetCurrentUserId();
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  chrome::MultiUserWindowManager* manager =
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      chrome::MultiUserWindowManager::GetInstance();
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (AppWindowList::iterator it = app_window_list_.begin();
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       it != app_window_list_.end();
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++it) {
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::AppWindow* other_window = *it;
156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK(!other_window->browser_context()->IsOffTheRecord());
157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (manager->IsWindowOnDesktopOfUser(other_window->GetNativeWindow(),
158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                         current_user) &&
159effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        app_id == other_window->extension_id() &&
160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        app_context == other_window->browser_context()) {
161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return true;
162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return false;
165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
166