Home | History | Annotate | Download | only in launcher
      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 
     16 namespace {
     17 
     18 bool ControlsWindow(aura::Window* window) {
     19   return chrome::GetHostDesktopTypeForNativeWindow(window) ==
     20          chrome::HOST_DESKTOP_TYPE_ASH;
     21 }
     22 
     23 }  // namespace
     24 
     25 MultiProfileAppWindowLauncherController::
     26     MultiProfileAppWindowLauncherController(ChromeLauncherController* owner)
     27     : AppWindowLauncherController(owner) {}
     28 
     29 MultiProfileAppWindowLauncherController::
     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 
     38 void 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 
     68 void 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 
     77 void 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 
     93 void 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 
    116 void 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 
    128 void 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 
    144 bool 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