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 "chrome/browser/profiles/profile.h" 8#include "chrome/browser/profiles/profile_manager.h" 9#include "chrome/browser/ui/ash/multi_user/multi_user_util.h" 10#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" 11#include "chrome/browser/ui/host_desktop.h" 12#include "extensions/browser/app_window/app_window.h" 13#include "extensions/browser/app_window/native_app_window.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 extensions::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 extensions::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 extensions::AppWindowRegistry* registry = 72 extensions::AppWindowRegistry::Get(profile); 73 multi_user_registry_.push_back(registry); 74 registry->AddObserver(this); 75} 76 77void MultiProfileAppWindowLauncherController::OnAppWindowAdded( 78 extensions::AppWindow* app_window) { 79 if (!ControlsWindow(app_window->GetNativeWindow())) 80 return; 81 82 app_window_list_.push_back(app_window); 83 Profile* profile = Profile::FromBrowserContext(app_window->browser_context()); 84 // If the window got created for a non active user but the user allowed to 85 // teleport to the current user's desktop, we teleport it now. 86 if (!multi_user_util::IsProfileFromActiveUser(profile) && 87 UserHasAppOnActiveDesktop(app_window)) { 88 chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser( 89 app_window->GetNativeWindow(), multi_user_util::GetCurrentUserId()); 90 } 91} 92 93void MultiProfileAppWindowLauncherController::OnAppWindowShown( 94 extensions::AppWindow* app_window) { 95 if (!ControlsWindow(app_window->GetNativeWindow())) 96 return; 97 98 Profile* profile = Profile::FromBrowserContext(app_window->browser_context()); 99 100 if (multi_user_util::IsProfileFromActiveUser(profile) && 101 !IsRegisteredApp(app_window->GetNativeWindow())) { 102 RegisterApp(app_window); 103 return; 104 } 105 106 // The panel layout manager only manages windows which are anchored. 107 // Since this window did never had an anchor, it would stay hidden. We 108 // therefore make it visible now. 109 if (UserHasAppOnActiveDesktop(app_window) && 110 app_window->GetNativeWindow()->type() == ui::wm::WINDOW_TYPE_PANEL && 111 !app_window->GetNativeWindow()->layer()->GetTargetOpacity()) { 112 app_window->GetNativeWindow()->layer()->SetOpacity(1.0f); 113 } 114} 115 116void MultiProfileAppWindowLauncherController::OnAppWindowHidden( 117 extensions::AppWindow* app_window) { 118 if (!ControlsWindow(app_window->GetNativeWindow())) 119 return; 120 121 Profile* profile = Profile::FromBrowserContext(app_window->browser_context()); 122 if (multi_user_util::IsProfileFromActiveUser(profile) && 123 IsRegisteredApp(app_window->GetNativeWindow())) { 124 UnregisterApp(app_window->GetNativeWindow()); 125 } 126} 127 128void MultiProfileAppWindowLauncherController::OnAppWindowRemoved( 129 extensions::AppWindow* app_window) { 130 if (!ControlsWindow(app_window->GetNativeWindow())) 131 return; 132 133 // If the application is registered with AppWindowLauncher (because the user 134 // is currently active), the OnWindowDestroying observer has already (or will 135 // soon) unregister it independently from the shelf. If it was not registered 136 // we don't need to do anything anyways. As such, all which is left to do here 137 // is to get rid of our own reference. 138 AppWindowList::iterator it = 139 std::find(app_window_list_.begin(), app_window_list_.end(), app_window); 140 DCHECK(it != app_window_list_.end()); 141 app_window_list_.erase(it); 142} 143 144bool MultiProfileAppWindowLauncherController::UserHasAppOnActiveDesktop( 145 extensions::AppWindow* app_window) { 146 const std::string& app_id = app_window->extension_id(); 147 content::BrowserContext* app_context = app_window->browser_context(); 148 DCHECK(!app_context->IsOffTheRecord()); 149 const std::string& current_user = multi_user_util::GetCurrentUserId(); 150 chrome::MultiUserWindowManager* manager = 151 chrome::MultiUserWindowManager::GetInstance(); 152 for (AppWindowList::iterator it = app_window_list_.begin(); 153 it != app_window_list_.end(); 154 ++it) { 155 extensions::AppWindow* other_window = *it; 156 DCHECK(!other_window->browser_context()->IsOffTheRecord()); 157 if (manager->IsWindowOnDesktopOfUser(other_window->GetNativeWindow(), 158 current_user) && 159 app_id == other_window->extension_id() && 160 app_context == other_window->browser_context()) { 161 return true; 162 } 163 } 164 return false; 165} 166