multi_profile_app_window_launcher_controller.cc revision 010d83a9304c5a91596085d917d248abff47903a
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.h"
6
7#include "apps/app_window.h"
8#include "apps/ui/native_app_window.h"
9#include "chrome/browser/profiles/profile.h"
10#include "chrome/browser/profiles/profile_manager.h"
11#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
12#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
13#include "chrome/browser/ui/host_desktop.h"
14#include "ui/aura/window.h"
15
16namespace {
17
18bool ControlsWindow(aura::Window* window) {
19  return chrome::GetHostDesktopTypeForNativeWindow(window) ==
20         chrome::HOST_DESKTOP_TYPE_ASH;
21}
22
23}  // namespace
24
25MultiProfileAppWindowLauncherController::
26    MultiProfileAppWindowLauncherController(ChromeLauncherController* owner)
27    : AppWindowLauncherController(owner) {}
28
29MultiProfileAppWindowLauncherController::
30    ~MultiProfileAppWindowLauncherController() {
31  // We need to remove all Registry observers for added users.
32  for (AppWindowRegistryList::iterator it = multi_user_registry_.begin();
33       it != multi_user_registry_.end();
34       ++it)
35    (*it)->RemoveObserver(this);
36}
37
38void MultiProfileAppWindowLauncherController::ActiveUserChanged(
39    const std::string& user_email) {
40  // The active user has changed and we need to traverse our list of items to
41  // show / hide them one by one. To avoid that a user dependent state
42  // "survives" in a launcher item, we first delete all items making sure that
43  // nothing remains and then re-create them again.
44  for (AppWindowList::iterator it = app_window_list_.begin();
45       it != app_window_list_.end();
46       ++it) {
47    apps::AppWindow* app_window = *it;
48    Profile* profile =
49        Profile::FromBrowserContext(app_window->browser_context());
50    if (!multi_user_util::IsProfileFromActiveUser(profile) &&
51        IsRegisteredApp(app_window->GetNativeWindow()))
52      UnregisterApp(app_window->GetNativeWindow());
53  }
54  for (AppWindowList::iterator it = app_window_list_.begin();
55       it != app_window_list_.end();
56       ++it) {
57    apps::AppWindow* app_window = *it;
58    Profile* profile =
59        Profile::FromBrowserContext(app_window->browser_context());
60    if (multi_user_util::IsProfileFromActiveUser(profile) &&
61        !IsRegisteredApp(app_window->GetNativeWindow()) &&
62        (app_window->GetBaseWindow()->IsMinimized() ||
63         app_window->GetNativeWindow()->IsVisible()))
64      RegisterApp(*it);
65  }
66}
67
68void MultiProfileAppWindowLauncherController::AdditionalUserAddedToSession(
69    Profile* profile) {
70  // Each users AppWindowRegistry needs to be observed.
71  apps::AppWindowRegistry* registry = apps::AppWindowRegistry::Get(profile);
72  multi_user_registry_.push_back(registry);
73  registry->AddObserver(this);
74}
75
76void MultiProfileAppWindowLauncherController::OnAppWindowAdded(
77    apps::AppWindow* app_window) {
78  if (!ControlsWindow(app_window->GetNativeWindow()))
79    return;
80
81  app_window_list_.push_back(app_window);
82  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
83  // If the window got created for a non active user but the user allowed to
84  // teleport to the current user's desktop, we teleport it now.
85  if (!multi_user_util::IsProfileFromActiveUser(profile) &&
86      UserHasAppOnActiveDesktop(app_window)) {
87    chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
88        app_window->GetNativeWindow(), multi_user_util::GetCurrentUserId());
89  }
90}
91
92void MultiProfileAppWindowLauncherController::OnAppWindowShown(
93    apps::AppWindow* app_window) {
94  if (!ControlsWindow(app_window->GetNativeWindow()))
95    return;
96
97  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
98
99  if (multi_user_util::IsProfileFromActiveUser(profile) &&
100      !IsRegisteredApp(app_window->GetNativeWindow())) {
101    RegisterApp(app_window);
102    return;
103  }
104
105  // The panel layout manager only manages windows which are anchored.
106  // Since this window did never had an anchor, it would stay hidden. We
107  // therefore make it visible now.
108  if (UserHasAppOnActiveDesktop(app_window) &&
109      app_window->GetNativeWindow()->type() == ui::wm::WINDOW_TYPE_PANEL &&
110      !app_window->GetNativeWindow()->layer()->GetTargetOpacity()) {
111    app_window->GetNativeWindow()->layer()->SetOpacity(1.0f);
112  }
113}
114
115void MultiProfileAppWindowLauncherController::OnAppWindowHidden(
116    apps::AppWindow* app_window) {
117  if (!ControlsWindow(app_window->GetNativeWindow()))
118    return;
119
120  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
121  if (multi_user_util::IsProfileFromActiveUser(profile) &&
122      IsRegisteredApp(app_window->GetNativeWindow())) {
123    UnregisterApp(app_window->GetNativeWindow());
124  }
125}
126
127void MultiProfileAppWindowLauncherController::OnAppWindowRemoved(
128    apps::AppWindow* app_window) {
129  if (!ControlsWindow(app_window->GetNativeWindow()))
130    return;
131
132  // If the application is registered with AppWindowLauncher (because the user
133  // is currently active), the OnWindowDestroying observer has already (or will
134  // soon) unregister it independently from the shelf. If it was not registered
135  // we don't need to do anything anyways. As such, all which is left to do here
136  // is to get rid of our own reference.
137  AppWindowList::iterator it =
138      std::find(app_window_list_.begin(), app_window_list_.end(), app_window);
139  DCHECK(it != app_window_list_.end());
140  app_window_list_.erase(it);
141}
142
143bool MultiProfileAppWindowLauncherController::UserHasAppOnActiveDesktop(
144    apps::AppWindow* app_window) {
145  const std::string& app_id = app_window->extension_id();
146  content::BrowserContext* app_context = app_window->browser_context();
147  DCHECK(!app_context->IsOffTheRecord());
148  const std::string& current_user = multi_user_util::GetCurrentUserId();
149  chrome::MultiUserWindowManager* manager =
150      chrome::MultiUserWindowManager::GetInstance();
151  for (AppWindowList::iterator it = app_window_list_.begin();
152       it != app_window_list_.end();
153       ++it) {
154    apps::AppWindow* other_window = *it;
155    DCHECK(!other_window->browser_context()->IsOffTheRecord());
156    if (manager->IsWindowOnDesktopOfUser(other_window->GetNativeWindow(),
157                                         current_user) &&
158        app_id == other_window->extension_id() &&
159        app_context == other_window->browser_context()) {
160      return true;
161    }
162  }
163  return false;
164}
165