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 "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 
     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     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 
     68 void 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 
     76 void 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 
     92 void 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 
    115 void 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 
    127 void 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 
    143 bool 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