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