13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include <vector>
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/ash_switches.h"
10d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ash/desktop_background/desktop_background_controller.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/multi_profile_uma.h"
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ash/root_window_controller.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/shelf/shelf.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ash/shelf/shelf_item_delegate_manager.h"
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ash/shelf/shelf_layout_manager.h"
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shelf/shelf_model.h"
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ash/shelf/shelf_widget.h"
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ash/shell.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/system/tray/system_tray_delegate.h"
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ash/wm/window_util.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h"
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/values.h"
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/app_mode/app_mode_utils.h"
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/defaults.h"
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/extensions/app_icon_loader_impl.h"
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/extensions/extension_util.h"
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/extensions/launch_util.h"
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/favicon/favicon_tab_helper.h"
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/prefs/incognito_mode_prefs.h"
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/prefs/pref_service_syncable.h"
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/ash/app_sync_ui_state.h"
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/ash/chrome_launcher_prefs.h"
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.h"
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/app_window_launcher_controller.h"
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h"
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
44424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/browser_status_monitor.h"
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h"
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_browser.h"
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_tab.h"
4868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_types.h"
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/launcher_app_tab_helper.h"
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/launcher_item_controller.h"
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_commands.h"
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h"
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_tabstrip.h"
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/extensions/application_launch.h"
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/extensions/extension_enable_flow.h"
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/web_applications/web_app.h"
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
6568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/common/pref_names.h"
673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/common/url_constants.h"
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/navigation_entry.h"
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/notification_registrar.h"
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/notification_service.h"
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/public/browser/web_contents.h"
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_util.h"
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/extension_resource.h"
77c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/manifest_handlers/icons_handler.h"
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/url_pattern.h"
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "grit/ash_resources.h"
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "grit/chromium_strings.h"
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "grit/generated_resources.h"
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "grit/theme_resources.h"
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "grit/ui_resources.h"
8468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "net/base/url_util.h"
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/aura/window.h"
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/keyboard/keyboard_util.h"
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/window_animations.h"
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#if defined(OS_CHROMEOS)
921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/browser_process.h"
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/chromeos/login/users/user_manager.h"
94d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/ui/ash/chrome_shell_delegate.h"
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.h"
961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.h"
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#endif
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)using extensions::Extension;
1001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)using extensions::UnloadedExtensionInfo;
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)using extension_misc::kGmailAppId;
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)using content::WebContents;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// static
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ChromeLauncherController* ChromeLauncherController::instance_ = NULL;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace {
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// This will be used as placeholder in the list of the pinned applciatons.
11068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Note that this is NOT a valid extension identifier so that pre M31 versions
11168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// will ignore it.
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const char kAppShelfIdPlaceholder[] = "AppShelfIDPlaceholder--------";
11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)std::string GetPrefKeyForRootWindow(aura::Window* root_window) {
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  gfx::Display display = gfx::Screen::GetScreenFor(
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      root_window)->GetDisplayNearestWindow(root_window);
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(display.is_valid());
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return base::Int64ToString(display.id());
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void UpdatePerDisplayPref(PrefService* pref_service,
1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                          aura::Window* root_window,
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                          const char* pref_key,
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                          const std::string& value) {
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string key = GetPrefKeyForRootWindow(root_window);
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (key.empty())
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DictionaryPrefUpdate update(pref_service, prefs::kShelfPreferences);
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::DictionaryValue* shelf_prefs = update.Get();
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  base::DictionaryValue* prefs = NULL;
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!shelf_prefs->GetDictionary(key, &prefs)) {
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    prefs = new base::DictionaryValue();
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    shelf_prefs->Set(key, prefs);
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  prefs->SetStringWithoutPathExpansion(pref_key, value);
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Returns a pref value in |pref_service| for the display of |root_window|. The
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// pref value is stored in |local_path| and |path|, but |pref_service| may have
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// per-display preferences and the value can be specified by policy. Here is
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// the priority:
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//  * A value managed by policy. This is a single value that applies to all
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//    displays.
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//  * A user-set value for the specified display.
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//  * A user-set value in |local_path| or |path|, if no per-display settings are
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//    ever specified (see http://crbug.com/173719 for why). |local_path| is
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//    preferred. See comment in |kShelfAlignment| as to why we consider two
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//    prefs and why |local_path| is preferred.
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//  * A value recommended by policy. This is a single value that applies to all
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//    root windows.
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//  * The default value for |local_path| if the value is not recommended by
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)//    policy.
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)std::string GetPrefForRootWindow(PrefService* pref_service,
1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                 aura::Window* root_window,
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 const char* local_path,
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 const char* path) {
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const PrefService::Preference* local_pref =
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      pref_service->FindPreference(local_path);
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const std::string value(pref_service->GetString(local_path));
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (local_pref->IsManaged())
1633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return value;
1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string pref_key = GetPrefKeyForRootWindow(root_window);
1663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool has_per_display_prefs = false;
1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!pref_key.empty()) {
1683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::DictionaryValue* shelf_prefs = pref_service->GetDictionary(
1693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        prefs::kShelfPreferences);
1703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::DictionaryValue* display_pref = NULL;
1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string per_display_value;
1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (shelf_prefs->GetDictionary(pref_key, &display_pref) &&
1733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        display_pref->GetString(path, &per_display_value))
1743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return per_display_value;
1753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // If the pref for the specified display is not found, scan the whole prefs
1773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // and check if the prefs for other display is already specified.
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string unused_value;
1793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    for (base::DictionaryValue::Iterator iter(*shelf_prefs);
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         !iter.IsAtEnd(); iter.Advance()) {
1813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      const base::DictionaryValue* display_pref = NULL;
1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (iter.value().GetAsDictionary(&display_pref) &&
1833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          display_pref->GetString(path, &unused_value)) {
1843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        has_per_display_prefs = true;
1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        break;
1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
1873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (local_pref->IsRecommended() || !has_per_display_prefs)
1913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return value;
1923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const base::Value* default_value =
1943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      pref_service->GetDefaultPrefValue(local_path);
1953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::string default_string;
1963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  default_value->GetAsString(&default_string);
1973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return default_string;
1983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// If prefs have synced and no user-set value exists at |local_path|, the value
2013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// from |synced_path| is copied to |local_path|.
2023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void MaybePropagatePrefToLocal(PrefServiceSyncable* pref_service,
2033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                               const char* local_path,
2043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                               const char* synced_path) {
2053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!pref_service->FindPreference(local_path)->HasUserSetting() &&
2063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      pref_service->IsSyncing()) {
2073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // First time the user is using this machine, propagate from remote to
2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // local.
2093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    pref_service->SetString(local_path, pref_service->GetString(synced_path));
2103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
2123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
21368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::string GetSourceFromAppListSource(ash::LaunchSource source) {
21468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  switch (source) {
21568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    case ash::LAUNCH_FROM_APP_LIST:
21668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      return std::string(extension_urls::kLaunchSourceAppList);
21768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    case ash::LAUNCH_FROM_APP_LIST_SEARCH:
21868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      return std::string(extension_urls::kLaunchSourceAppListSearch);
21968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    default: return std::string();
22068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
22168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
22268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}  // namespace
2243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#if defined(OS_CHROMEOS)
2261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// A class to get events from ChromeOS when a user gets changed or added.
227d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class ChromeLauncherControllerUserSwitchObserverChromeOS
228d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    : public ChromeLauncherControllerUserSwitchObserver,
2291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      public chromeos::UserManager::UserSessionStateObserver,
2301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      content::NotificationObserver {
231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public:
232d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ChromeLauncherControllerUserSwitchObserverChromeOS(
233d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ChromeLauncherController* controller)
234d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      : controller_(controller) {
235d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    DCHECK(chromeos::UserManager::IsInitialized());
236d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    chromeos::UserManager::Get()->AddSessionStateObserver(this);
2371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // A UserAddedToSession notification can be sent before a profile is loaded.
2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Since our observers require that we have already a profile, we might have
2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // to postpone the notification until the ProfileManager lets us know that
2401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // the profile for that newly added user was added to the ProfileManager.
2411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    registrar_.Add(this, chrome::NOTIFICATION_PROFILE_ADDED,
2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   content::NotificationService::AllSources());
243d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
244d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  virtual ~ChromeLauncherControllerUserSwitchObserverChromeOS() {
245d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    chromeos::UserManager::Get()->RemoveSessionStateObserver(this);
246d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
247d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
248d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // chromeos::UserManager::UserSessionStateObserver overrides:
2491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual void UserAddedToSession(const chromeos::User* added_user) OVERRIDE;
2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // content::NotificationObserver overrides:
2521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual void Observe(int type,
2531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               const content::NotificationSource& source,
2541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               const content::NotificationDetails& details) OVERRIDE;
255d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
256d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private:
2571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Add a user to the session.
2581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  void AddUser(Profile* profile);
2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
260d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // The owning ChromeLauncherController.
261d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ChromeLauncherController* controller_;
262d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // The notification registrar to track the Profile creations after a user got
2641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // added to the session (if required).
2651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  content::NotificationRegistrar registrar_;
2661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Users which were just added to the system, but which profiles were not yet
2681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // (fully) loaded.
2691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::set<std::string> added_user_ids_waiting_for_profiles_;
2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
271d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerUserSwitchObserverChromeOS);
272d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)};
273d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ChromeLauncherControllerUserSwitchObserverChromeOS::UserAddedToSession(
2751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const chromeos::User* active_user) {
276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  Profile* profile = multi_user_util::GetProfileFromUserID(
2771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      active_user->email());
2781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // If we do not have a profile yet, we postpone forwarding the notification
2791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // until it is loaded.
2801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!profile)
2811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    added_user_ids_waiting_for_profiles_.insert(active_user->email());
2821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  else
2831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    AddUser(profile);
2841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ChromeLauncherControllerUserSwitchObserverChromeOS::Observe(
2871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    int type,
2881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const content::NotificationSource& source,
2891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const content::NotificationDetails& details) {
2901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (type == chrome::NOTIFICATION_PROFILE_ADDED &&
2911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      !added_user_ids_waiting_for_profiles_.empty()) {
2921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Check if the profile is from a user which was on the waiting list.
2931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    Profile* profile = content::Source<Profile>(source).ptr();
294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string user_id = multi_user_util::GetUserIDFromProfile(profile);
2951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    std::set<std::string>::iterator it = std::find(
2961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        added_user_ids_waiting_for_profiles_.begin(),
2971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        added_user_ids_waiting_for_profiles_.end(),
2981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        user_id);
2991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (it != added_user_ids_waiting_for_profiles_.end()) {
3001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      added_user_ids_waiting_for_profiles_.erase(it);
3011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      AddUser(profile->GetOriginalProfile());
3021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
3031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
3041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ChromeLauncherControllerUserSwitchObserverChromeOS::AddUser(
3071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    Profile* profile) {
3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
3091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED)
3101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    chrome::MultiUserWindowManager::GetInstance()->AddUser(profile);
3111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  controller_->AdditionalUserAddedToSession(profile->GetOriginalProfile());
3121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
313d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#endif
314d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ChromeLauncherController::ChromeLauncherController(Profile* profile,
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                                   ash::ShelfModel* model)
3173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    : model_(model),
3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      item_delegate_manager_(NULL),
3193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      profile_(profile),
3203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      app_sync_ui_state_(NULL),
3213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      ignore_persist_pinned_state_change_(false) {
3223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!profile_) {
323a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // If no profile was passed, we take the currently active profile and use it
324a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // as the owner of the current desktop.
3253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Use the original profile as on chromeos we may get a temporary off the
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // record profile, unless in guest session (where off the record profile is
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // the right one).
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Profile* active_profile = ProfileManager::GetActiveUserProfile();
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    profile_ = active_profile->IsGuestSession() ? active_profile :
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        active_profile->GetOriginalProfile();
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    app_sync_ui_state_ = AppSyncUIState::Get(profile_);
3333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (app_sync_ui_state_)
3343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      app_sync_ui_state_->AddObserver(this);
3353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
337d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // All profile relevant settings get bound to the current profile.
338d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  AttachProfile(profile_);
3391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  model_->AddObserver(this);
340d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
3411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // In multi profile mode we might have a window manager. We try to create it
3421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // here. If the instantiation fails, the manager is not needed.
3431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  chrome::MultiUserWindowManager::CreateInstance();
3441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_CHROMEOS)
3461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // On Chrome OS using multi profile we want to switch the content of the shelf
3471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // with a user change. Note that for unit tests the instance can be NULL.
3481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (chrome::MultiUserWindowManager::GetMultiProfileMode() !=
3491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_OFF) {
3501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    user_switch_observer_.reset(
3511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        new ChromeLauncherControllerUserSwitchObserverChromeOS(this));
3521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
3531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Create our v1/v2 application / browser monitors which will inform the
3551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // launcher of status changes.
3561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
3571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) {
3581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // If running in separated destkop mode, we create the multi profile version
3591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // of status monitor.
3601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    browser_status_monitor_.reset(new MultiProfileBrowserStatusMonitor(this));
361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    app_window_controller_.reset(
362a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        new MultiProfileAppWindowLauncherController(this));
3631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  } else {
3641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Create our v1/v2 application / browser monitors which will inform the
3651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // launcher of status changes.
3661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    browser_status_monitor_.reset(new BrowserStatusMonitor(this));
367a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    app_window_controller_.reset(new AppWindowLauncherController(this));
3681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
3691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#else
3701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Create our v1/v2 application / browser monitors which will inform the
3711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // launcher of status changes.
372424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  browser_status_monitor_.reset(new BrowserStatusMonitor(this));
373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  app_window_controller_.reset(new AppWindowLauncherController(this));
3741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif
3751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Right now ash::Shell isn't created for tests.
3773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(mukai): Allows it to observe display change and write tests.
3784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (ash::Shell::HasInstance()) {
3793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ash::Shell::GetInstance()->display_controller()->AddObserver(this);
3804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    item_delegate_manager_ =
381a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ash::Shell::GetInstance()->shelf_item_delegate_manager();
3824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
3833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  notification_registrar_.Add(this,
3850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                              chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
3860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                              content::Source<Profile>(profile_));
38723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  notification_registrar_.Add(
38823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      this,
38923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
39023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      content::Source<Profile>(profile_));
3913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
3923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)ChromeLauncherController::~ChromeLauncherController() {
39458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Reset the BrowserStatusMonitor as it has a weak pointer to this.
39558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  browser_status_monitor_.reset();
39658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
397a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Reset the app window controller here since it has a weak pointer to this.
398a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  app_window_controller_.reset();
3993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::set<ash::Shelf*>::iterator iter = shelves_.begin();
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       iter != shelves_.end();
4023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       ++iter)
4033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    (*iter)->shelf_widget()->shelf_layout_manager()->RemoveObserver(this);
4043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  model_->RemoveObserver(this);
4063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (ash::Shell::HasInstance())
4073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
4083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
4093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       i != id_to_item_controller_map_.end(); ++i) {
4103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int index = model_->ItemIndexByID(i->first);
4113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // A "browser proxy" is not known to the model and this removal does
4123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // therefore not need to be propagated to the model.
4133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (index != -1 &&
4143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        model_->items()[index].type != ash::TYPE_BROWSER_SHORTCUT)
4153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      model_->RemoveItemAt(index);
4163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (ash::Shell::HasInstance())
4193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ash::Shell::GetInstance()->RemoveShellObserver(this);
4203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
421d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Release all profile dependent resources.
422d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ReleaseProfile();
4233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (instance_ == this)
4243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    instance_ = NULL;
425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Get rid of the multi user window manager instance.
4274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  chrome::MultiUserWindowManager::DeleteInstance();
4283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeLauncherController* ChromeLauncherController::CreateInstance(
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Profile* profile,
433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ash::ShelfModel* model) {
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We do not check here for re-creation of the ChromeLauncherController since
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it appears that it might be intentional that the ChromeLauncherController
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // can be re-created.
4373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  instance_ = new ChromeLauncherController(profile, model);
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return instance_;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::Init() {
4423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CreateBrowserShortcutLauncherItem();
44368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  UpdateAppLaunchersFromPref();
4443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(sky): update unit test so that this test isn't necessary.
4463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (ash::Shell::HasInstance()) {
4473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    SetShelfAutoHideBehaviorFromPrefs();
4483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    SetShelfAlignmentFromPrefs();
4496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#if defined(OS_CHROMEOS)
4506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    SetVirtualKeyboardBehaviorFromPrefs();
4516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#endif  // defined(OS_CHROMEOS)
4523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
4533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!prefs->FindPreference(prefs::kShelfAlignmentLocal)->HasUserSetting() ||
4543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        !prefs->FindPreference(prefs::kShelfAutoHideBehaviorLocal)->
4553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            HasUserSetting()) {
4563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // This causes OnIsSyncingChanged to be called when the value of
4573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // PrefService::IsSyncing() changes.
4583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      prefs->AddObserver(this);
4593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
4603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ash::Shell::GetInstance()->AddShellObserver(this);
4613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ash::ShelfID ChromeLauncherController::CreateAppLauncherItem(
4653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LauncherItemController* controller,
4663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& app_id,
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfItemStatus status) {
4683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(controller);
4693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int index = 0;
4703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Panels are inserted on the left so as not to push all existing panels over.
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (controller->GetShelfItemType() != ash::TYPE_APP_PANEL)
4723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    index = model_->item_count();
4733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return InsertAppLauncherItem(controller,
4743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                               app_id,
4753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                               status,
4763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                               index,
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               controller->GetShelfItemType());
4783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::SetItemStatus(ash::ShelfID id,
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                             ash::ShelfItemStatus status) {
4823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int index = model_->ItemIndexByID(id);
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItemStatus old_status = model_->items()[index].status;
4843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Since ordinary browser windows are not registered, we might get a negative
4853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // index here.
4864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (index >= 0 && old_status != status) {
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfItem item = model_->items()[index];
4883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    item.status = status;
4893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    model_->Set(index, item);
4903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
4913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
4923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
4933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::SetItemController(
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfID id,
4953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LauncherItemController* controller) {
4963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(controller);
4973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
4983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(iter != id_to_item_controller_map_.end());
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controller->set_shelf_id(id);
5004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  iter->second = controller;
5014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Existing controller is destroyed and replaced by registering again.
502a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SetShelfItemDelegate(id, controller);
5033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::CloseLauncherItem(ash::ShelfID id) {
5063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(id);
5073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (IsPinned(id)) {
5083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Create a new shortcut controller.
5093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
5103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CHECK(iter != id_to_item_controller_map_.end());
5113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    SetItemStatus(id, ash::STATUS_CLOSED);
5123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string app_id = iter->second->app_id();
5133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    iter->second = new AppShortcutLauncherItemController(app_id, this);
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    iter->second->set_shelf_id(id);
5154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Existing controller is destroyed and replaced by registering again.
516a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SetShelfItemDelegate(id, iter->second);
5173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
5183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LauncherItemClosed(id);
5193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
5203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::Pin(ash::ShelfID id) {
5233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(HasItemController(id));
5243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int index = model_->ItemIndexByID(id);
5263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK_GE(index, 0);
5273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItem item = model_->items()[index];
5293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (item.type == ash::TYPE_PLATFORM_APP ||
5313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      item.type == ash::TYPE_WINDOWED_APP) {
5323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    item.type = ash::TYPE_APP_SHORTCUT;
5333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    model_->Set(index, item);
5343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else if (item.type != ash::TYPE_APP_SHORTCUT) {
5353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
5363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
5373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (CanPin())
5393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    PersistPinnedState();
5403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::Unpin(ash::ShelfID id) {
5433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(HasItemController(id));
5443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  LauncherItemController* controller = id_to_item_controller_map_[id];
54668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (controller->type() == LauncherItemController::TYPE_APP ||
54768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      controller->locked()) {
54868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    UnpinRunningAppInternal(model_->ItemIndexByID(id));
5493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
55068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    LauncherItemClosed(id);
5513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
5523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (CanPin())
5533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    PersistPinnedState();
5543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ChromeLauncherController::IsPinned(ash::ShelfID id) {
5573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int index = model_->ItemIndexByID(id);
5583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (index < 0)
5593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItemType type = model_->items()[index].type;
5613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_BROWSER_SHORTCUT);
5623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::TogglePinned(ash::ShelfID id) {
5653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!HasItemController(id))
5663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;  // May happen if item closed with menu open.
5673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (IsPinned(id))
5693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    Unpin(id);
5703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  else
5713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    Pin(id);
5723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ChromeLauncherController::IsPinnable(ash::ShelfID id) const {
5753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int index = model_->ItemIndexByID(id);
5763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (index == -1)
5773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
5783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItemType type = model_->items()[index].type;
5803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return ((type == ash::TYPE_APP_SHORTCUT ||
5813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           type == ash::TYPE_PLATFORM_APP ||
5823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           type == ash::TYPE_WINDOWED_APP) &&
5833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          CanPin());
5843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
5853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
586cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ChromeLauncherController::Install(ash::ShelfID id) {
587cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!HasItemController(id))
588cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
589cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
590cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string app_id = GetAppIDForShelfID(id);
591cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (extensions::util::IsExtensionInstalledPermanently(app_id, profile_))
592cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
593cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
594cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LauncherItemController* controller = id_to_item_controller_map_[id];
595cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (controller->type() == LauncherItemController::TYPE_APP) {
596cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    AppWindowLauncherItemController* app_window_controller =
597cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        static_cast<AppWindowLauncherItemController*>(controller);
598cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    app_window_controller->InstallApp();
599cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
600cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
601cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
602cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool ChromeLauncherController::CanInstall(ash::ShelfID id) {
603cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int index = model_->ItemIndexByID(id);
604cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (index == -1)
605cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
606cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
607cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ash::ShelfItemType type = model_->items()[index].type;
608cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (type != ash::TYPE_PLATFORM_APP)
609cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
610cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
611cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return extensions::util::IsEphemeralApp(GetAppIDForShelfID(id), profile_);
612cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
613cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
6143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::LockV1AppWithID(
6153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& app_id) {
6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID id = GetShelfIDForAppID(app_id);
6173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!IsPinned(id) && !IsWindowedAppInLauncher(app_id)) {
6183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CreateAppShortcutLauncherItemWithType(app_id,
6193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                          model_->item_count(),
6203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                          ash::TYPE_WINDOWED_APP);
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    id = GetShelfIDForAppID(app_id);
6223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
6233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(id);
6243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  id_to_item_controller_map_[id]->lock();
6253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
6263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::UnlockV1AppWithID(const std::string& app_id) {
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID id = GetShelfIDForAppID(app_id);
6293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(IsPinned(id) || IsWindowedAppInLauncher(app_id));
6303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(id);
6313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  LauncherItemController* controller = id_to_item_controller_map_[id];
6323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  controller->unlock();
6333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!controller->locked() && !IsPinned(id))
6343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CloseLauncherItem(id);
6353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
6363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::Launch(ash::ShelfID id, int event_flags) {
6383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!HasItemController(id))
6393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;  // In case invoked from menu and item closed while menu up.
64068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  id_to_item_controller_map_[id]->Launch(ash::LAUNCH_FROM_UNKNOWN, event_flags);
6413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
6423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::Close(ash::ShelfID id) {
6443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!HasItemController(id))
6453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;  // May happen if menu closed.
6463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  id_to_item_controller_map_[id]->Close();
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
648c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ChromeLauncherController::IsOpen(ash::ShelfID id) {
6503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!HasItemController(id))
651c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
6523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return id_to_item_controller_map_[id]->IsOpen();
6533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
6543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ChromeLauncherController::IsPlatformApp(ash::ShelfID id) {
6563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!HasItemController(id))
6573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
6583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string app_id = GetAppIDForShelfID(id);
6603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const Extension* extension = GetExtensionForAppID(app_id);
6613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // An extension can be synced / updated at any time and therefore not be
6623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // available.
6633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return extension ? extension->is_platform_app() : false;
6643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
6653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::LaunchApp(const std::string& app_id,
66768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                         ash::LaunchSource source,
66868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                         int event_flags) {
6693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // |extension| could be NULL when it is being unloaded for updating.
6703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const Extension* extension = GetExtensionForAppID(app_id);
6713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!extension)
6723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
6733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!extensions::util::IsAppLaunchableWithoutEnabling(app_id, profile_)) {
6753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Do nothing if there is already a running enable flow.
6763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (extension_enable_flow_)
6773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return;
6783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
6793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    extension_enable_flow_.reset(
6803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        new ExtensionEnableFlow(profile_, app_id, this));
6813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    extension_enable_flow_->StartForNativeWindow(NULL);
6823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
6833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
6843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
685cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(OS_WIN)
686f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (LaunchedInNativeDesktop(app_id))
687f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
688cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif
689f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
690a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The app will be created for the currently active profile.
691a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AppLaunchParams params(profile_,
692a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                         extension,
693a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                         event_flags,
694a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                         chrome::HOST_DESKTOP_TYPE_ASH);
69568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (source != ash::LAUNCH_FROM_UNKNOWN &&
69668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      app_id == extension_misc::kWebStoreAppId) {
69768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Get the corresponding source string.
69868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    std::string source_value = GetSourceFromAppListSource(source);
69968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
70068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Set an override URL to include the source.
70168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    GURL extension_url = extensions::AppLaunchInfo::GetFullLaunchURL(extension);
70268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    params.override_url = net::AppendQueryParameter(
70368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        extension_url, extension_urls::kWebstoreSourceField, source_value);
70468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
70568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
7064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  OpenApplication(params);
7073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
7083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::ActivateApp(const std::string& app_id,
71068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                           ash::LaunchSource source,
71168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                           int event_flags) {
7123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If there is an existing non-shortcut controller for this app, open it.
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID id = GetShelfIDForAppID(app_id);
7143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (id) {
7153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LauncherItemController* controller = id_to_item_controller_map_[id];
71668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    controller->Activate(source);
7173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
7183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
7193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Create a temporary application launcher item and use it to see if there are
7213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // running instances.
7223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  scoped_ptr<AppShortcutLauncherItemController> app_controller(
7233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      new AppShortcutLauncherItemController(app_id, this));
7243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!app_controller->GetRunningApplications().empty())
72568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    app_controller->Activate(source);
7263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  else
72768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    LaunchApp(app_id, source, event_flags);
7283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
7293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
730a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)extensions::LaunchType ChromeLauncherController::GetLaunchType(
7315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfID id) {
7323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(HasItemController(id));
7333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const Extension* extension = GetExtensionForAppID(
7353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      id_to_item_controller_map_[id]->app_id());
7363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // An extension can be unloaded/updated/unavailable at any time.
7383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!extension)
739a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return extensions::LAUNCH_TYPE_DEFAULT;
7403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
741a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return extensions::GetLaunchType(extensions::ExtensionPrefs::Get(profile_),
742a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   extension);
7433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
7443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ash::ShelfID ChromeLauncherController::GetShelfIDForAppID(
7463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& app_id) {
7473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (IDToItemControllerMap::const_iterator i =
7483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           id_to_item_controller_map_.begin();
7493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       i != id_to_item_controller_map_.end(); ++i) {
7503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (i->second->type() == LauncherItemController::TYPE_APP_PANEL)
7513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;  // Don't include panels
7523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (i->second->app_id() == app_id)
7533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return i->first;
7543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
7553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return 0;
7563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
7573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const std::string& ChromeLauncherController::GetAppIDForShelfID(
7595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfID id) {
7603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(HasItemController(id));
7613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return id_to_item_controller_map_[id]->app_id();
7623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
7633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::SetAppImage(const std::string& id,
7653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                           const gfx::ImageSkia& image) {
7663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO: need to get this working for shortcuts.
7673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (IDToItemControllerMap::const_iterator i =
7683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           id_to_item_controller_map_.begin();
7693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       i != id_to_item_controller_map_.end(); ++i) {
7703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LauncherItemController* controller = i->second;
7713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (controller->app_id() != id)
7723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
7733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (controller->image_set_by_controller())
7743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
7753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int index = model_->ItemIndexByID(i->first);
7763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (index == -1)
7773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      continue;
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfItem item = model_->items()[index];
7793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    item.image = image;
7803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    model_->Set(index, item);
7813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // It's possible we're waiting on more than one item, so don't break.
7823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
7833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
7843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::OnAutoHideBehaviorChanged(
7861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    aura::Window* root_window,
7873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ash::ShelfAutoHideBehavior new_behavior) {
7883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  SetShelfAutoHideBehaviorPrefs(new_behavior, root_window);
7893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
7903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::SetLauncherItemImage(
7925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfID shelf_id,
7933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const gfx::ImageSkia& image) {
7945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int index = model_->ItemIndexByID(shelf_id);
7953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (index == -1)
7963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItem item = model_->items()[index];
7983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  item.image = image;
7993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  model_->Set(index, item);
8003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
8013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
80258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool ChromeLauncherController::CanPin() const {
80358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const PrefService::Preference* pref =
80458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      profile_->GetPrefs()->FindPreference(prefs::kPinnedLauncherApps);
80558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return pref && pref->IsUserModifiable();
80658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
80758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ChromeLauncherController::IsAppPinned(const std::string& app_id) {
8093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (IDToItemControllerMap::const_iterator i =
8103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           id_to_item_controller_map_.begin();
8113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       i != id_to_item_controller_map_.end(); ++i) {
8123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (IsPinned(i->first) && i->second->app_id() == app_id)
8133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return true;
8143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
8153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return false;
8163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
8173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ChromeLauncherController::IsWindowedAppInLauncher(
8193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& app_id) {
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int index = model_->ItemIndexByID(GetShelfIDForAppID(app_id));
8213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (index < 0)
8223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
8233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItemType type = model_->items()[index].type;
8253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return type == ash::TYPE_WINDOWED_APP;
8263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
8273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::PinAppWithID(const std::string& app_id) {
8293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (CanPin())
8303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DoPinAppWithID(app_id);
8313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  else
8323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NOTREACHED();
8333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
8343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::SetLaunchType(
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfID id,
837a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    extensions::LaunchType launch_type) {
8383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!HasItemController(id))
8393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
8403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  extensions::SetLaunchType(profile_->GetExtensionService(),
842a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            id_to_item_controller_map_[id]->app_id(),
843a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            launch_type);
8443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
8453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
846424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void ChromeLauncherController::UnpinAppWithID(const std::string& app_id) {
8473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (CanPin())
848424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    DoUnpinAppWithID(app_id);
8493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  else
8503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NOTREACHED();
8513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
8523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ChromeLauncherController::IsLoggedInAsGuest() {
854a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return profile_->IsGuestSession();
8553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
8563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::CreateNewWindow() {
858a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Use the currently active user.
859a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  chrome::NewEmptyWindow(profile_, chrome::HOST_DESKTOP_TYPE_ASH);
8603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
8613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::CreateNewIncognitoWindow() {
863a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Use the currently active user.
864a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  chrome::NewEmptyWindow(profile_->GetOffTheRecordProfile(),
8653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                         chrome::HOST_DESKTOP_TYPE_ASH);
8663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
8673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
8683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::PersistPinnedState() {
8693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (ignore_persist_pinned_state_change_)
8703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
8713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // It is a coding error to call PersistPinnedState() if the pinned apps are
8723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // not user-editable. The code should check earlier and not perform any
8733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // modification actions that trigger persisting the state.
8743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!CanPin()) {
8753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NOTREACHED() << "Can't pin but pinned state being updated";
8763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
8773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
8783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Mutating kPinnedLauncherApps is going to notify us and trigger us to
8793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // process the change. We don't want that to happen so remove ourselves as a
8803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // listener.
8813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  pref_change_registrar_.Remove(prefs::kPinnedLauncherApps);
8823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  {
8833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ListPrefUpdate updater(profile_->GetPrefs(), prefs::kPinnedLauncherApps);
8843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    updater->Clear();
8853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    for (size_t i = 0; i < model_->items().size(); ++i) {
8863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (model_->items()[i].type == ash::TYPE_APP_SHORTCUT) {
8875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ash::ShelfID id = model_->items()[i].id;
8883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (HasItemController(id) && IsPinned(id)) {
8893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          base::DictionaryValue* app_value = ash::CreateAppDict(
8903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)              id_to_item_controller_map_[id]->app_id());
8913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          if (app_value)
8923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            updater->Append(app_value);
8933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
8943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      } else if (model_->items()[i].type == ash::TYPE_BROWSER_SHORTCUT) {
8953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        PersistChromeItemIndex(i);
89668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      } else if (model_->items()[i].type == ash::TYPE_APP_LIST) {
89768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        base::DictionaryValue* app_value = ash::CreateAppDict(
8985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            kAppShelfIdPlaceholder);
89968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        if (app_value)
90068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          updater->Append(app_value);
9013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
9023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
9033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
9043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  pref_change_registrar_.Add(
9053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      prefs::kPinnedLauncherApps,
9063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref,
9073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                 base::Unretained(this)));
9083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
9093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
910f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ash::ShelfModel* ChromeLauncherController::model() {
9113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return model_;
9123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
9133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Profile* ChromeLauncherController::profile() {
9153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return profile_;
9163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
9173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)ash::ShelfAutoHideBehavior ChromeLauncherController::GetShelfAutoHideBehavior(
9191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    aura::Window* root_window) const {
9203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Don't show the shelf in app mode.
9213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (chrome::IsRunningInAppMode())
9223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN;
9233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // See comment in |kShelfAlignment| as to why we consider two prefs.
9253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const std::string behavior_value(
9263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      GetPrefForRootWindow(profile_->GetPrefs(),
9273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           root_window,
9283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           prefs::kShelfAutoHideBehaviorLocal,
9293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                           prefs::kShelfAutoHideBehavior));
9303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Note: To maintain sync compatibility with old images of chrome/chromeos
9323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // the set of values that may be encountered includes the now-extinct
9333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // "Default" as well as "Never" and "Always", "Default" should now
9343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // be treated as "Never" (http://crbug.com/146773).
9353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (behavior_value == ash::kShelfAutoHideBehaviorAlways)
9363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
9373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER;
9383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
9393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ChromeLauncherController::CanUserModifyShelfAutoHideBehavior(
9411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    aura::Window* root_window) const {
94246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return profile_->GetPrefs()->
94346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      FindPreference(prefs::kShelfAutoHideBehaviorLocal)->IsUserModifiable();
9443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
9453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::ToggleShelfAutoHideBehavior(
9471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    aura::Window* root_window) {
9483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ash::ShelfAutoHideBehavior behavior = GetShelfAutoHideBehavior(root_window) ==
9493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS ?
9503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER :
9513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
9523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  SetShelfAutoHideBehaviorPrefs(behavior, root_window);
9533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return;
9543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
9553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::UpdateAppState(content::WebContents* contents,
9573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                              AppState app_state) {
9584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string app_id = app_tab_helper_->GetAppID(contents);
9593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Check if the gMail app is loaded and it matches the given content.
9613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // This special treatment is needed to address crbug.com/234268.
9623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (app_id.empty() && ContentCanBeHandledByGmailApp(contents))
9633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    app_id = kGmailAppId;
9643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Check the old |app_id| for a tab. If the contents has changed we need to
9663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // remove it from the previous app.
9673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (web_contents_to_app_id_.find(contents) != web_contents_to_app_id_.end()) {
9683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string last_app_id = web_contents_to_app_id_[contents];
969effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (last_app_id != app_id) {
970effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      ash::ShelfID id = GetShelfIDForAppID(last_app_id);
971effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (id) {
972effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // Since GetAppState() will use |web_contents_to_app_id_| we remove
973effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // the connection before calling it.
974effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        web_contents_to_app_id_.erase(contents);
975effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        SetItemStatus(id, GetAppState(last_app_id));
9763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
9774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
978effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
9794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
980effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (app_state == APP_STATE_REMOVED)
981effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    web_contents_to_app_id_.erase(contents);
982effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  else
983effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    web_contents_to_app_id_[contents] = app_id;
9844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
985effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ash::ShelfID id = GetShelfIDForAppID(app_id);
986effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (id) {
987effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    SetItemStatus(id, (app_state == APP_STATE_WINDOW_ACTIVE ||
988effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                       app_state == APP_STATE_ACTIVE) ? ash::STATUS_ACTIVE :
989effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                                        GetAppState(app_id));
9903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
9913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
9923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
9935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ash::ShelfID ChromeLauncherController::GetShelfIDForWebContents(
994f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    content::WebContents* contents) {
995f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(contents);
996f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
997f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string app_id = app_tab_helper_->GetAppID(contents);
998f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
999f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (app_id.empty() && ContentCanBeHandledByGmailApp(contents))
1000f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    app_id = kGmailAppId;
1001f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
10025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID id = GetShelfIDForAppID(app_id);
1003f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1004f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (app_id.empty() || !id) {
1005f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    int browser_index = model_->GetItemIndexForType(ash::TYPE_BROWSER_SHORTCUT);
1006f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return model_->items()[browser_index].id;
1007f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
1008f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1009f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return id;
1010f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
1011f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
10125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::SetRefocusURLPatternForTest(ash::ShelfID id,
10133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                           const GURL& url) {
10143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(HasItemController(id));
10153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  LauncherItemController* controller = id_to_item_controller_map_[id];
10163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int index = model_->ItemIndexByID(id);
10183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (index == -1) {
10193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NOTREACHED() << "Invalid launcher id";
10203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
10213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
10223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItemType type = model_->items()[index].type;
10243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (type == ash::TYPE_APP_SHORTCUT || type == ash::TYPE_WINDOWED_APP) {
10253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    AppShortcutLauncherItemController* app_controller =
10263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        static_cast<AppShortcutLauncherItemController*>(controller);
10273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    app_controller->set_refocus_url(url);
10283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
10293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    NOTREACHED() << "Invalid launcher type";
10303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
10313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
10323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)const Extension* ChromeLauncherController::GetExtensionForAppID(
10343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& app_id) const {
10353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Some unit tests do not have a real extension.
10363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return (profile_->GetExtensionService()) ?
10373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      profile_->GetExtensionService()->GetInstalledExtension(app_id) : NULL;
10383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
10393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::ActivateWindowOrMinimizeIfActive(
10413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ui::BaseWindow* window,
10423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    bool allow_minimize) {
1043f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // In separated desktop mode we might have to teleport a window back to the
1044f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // current user.
10451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
10461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) {
10471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    aura::Window* native_window = window->GetNativeWindow();
10481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& current_user =
1049f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        multi_user_util::GetUserIDFromProfile(profile());
1050f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    chrome::MultiUserWindowManager* manager =
1051f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        chrome::MultiUserWindowManager::GetInstance();
10521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (!manager->IsWindowOnDesktopOfUser(native_window, current_user)) {
10530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      ash::MultiProfileUMA::RecordTeleportAction(
10540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)          ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_LAUNCHER);
10551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      manager->ShowWindowForUser(native_window, current_user);
10561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      window->Activate();
10571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return;
10581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
10591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1060f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
10613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (window->IsActive() && allow_minimize) {
10623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (CommandLine::ForCurrentProcess()->HasSwitch(
10633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            switches::kDisableMinimizeOnSecondLauncherItemClick)) {
10643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      AnimateWindow(window->GetNativeWindow(),
1065a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                    wm::WINDOW_ANIMATION_TYPE_BOUNCE);
10663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    } else {
10673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      window->Minimize();
10683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
10693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
10703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    window->Show();
10713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    window->Activate();
10723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
10733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
10743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::OnShelfCreated(ash::Shelf* shelf) {
10765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  shelves_.insert(shelf);
10775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  shelf->shelf_widget()->shelf_layout_manager()->AddObserver(this);
10783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
10793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::OnShelfDestroyed(ash::Shelf* shelf) {
10815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  shelves_.erase(shelf);
10823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // RemoveObserver is not called here, since by the time this method is called
10835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Shelf is already in its destructor.
10843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
10853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1086f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeLauncherController::ShelfItemAdded(int index) {
108768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // The app list launcher can get added to the shelf after we applied the
108868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // preferences. In that case the item might be at the wrong spot. As such we
108968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // call the function again.
1090a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (model_->items()[index].type == ash::TYPE_APP_LIST)
109168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    UpdateAppLaunchersFromPref();
10923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
10933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
10945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::ShelfItemRemoved(int index, ash::ShelfID id) {
10953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
10963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1097f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeLauncherController::ShelfItemMoved(int start_index,
1098f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                              int target_index) {
10995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ash::ShelfItem& item = model_->items()[target_index];
110068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // We remember the moved item position if it is either pinnable or
110168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // it is the app list with the alternate shelf layout.
110268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if ((HasItemController(item.id) && IsPinned(item.id)) ||
1103a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch       item.type == ash::TYPE_APP_LIST)
11043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    PersistPinnedState();
11053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
11063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeLauncherController::ShelfItemChanged(
11083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int index,
11095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ash::ShelfItem& old_item) {
11103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
11113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void ChromeLauncherController::ShelfStatusChanged() {
11133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
11143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeLauncherController::ActiveUserChanged(
1116d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::string& user_email) {
11175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Store the order of running applications for the user which gets inactive.
11185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RememberUnpinnedRunningApplicationOrder();
1119d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Coming here the default profile is already switched. All profile specific
1120d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // resources get released and the new profile gets attached instead.
1121d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ReleaseProfile();
1122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // When coming here, the active user has already be changed so that we can
1123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // set it as active.
1124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  AttachProfile(ProfileManager::GetActiveUserProfile());
11251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Update the V1 applications.
11261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  browser_status_monitor_->ActiveUserChanged(user_email);
11271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Switch the running applications to the new user.
1128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  app_window_controller_->ActiveUserChanged(user_email);
1129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Update the user specific shell properties from the new user profile.
1130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  UpdateAppLaunchersFromPref();
1131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SetShelfAlignmentFromPrefs();
1132d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SetShelfAutoHideBehaviorFromPrefs();
1133d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SetShelfBehaviorsFromPrefs();
11346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#if defined(OS_CHROMEOS)
11356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  SetVirtualKeyboardBehaviorFromPrefs();
11366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#endif  // defined(OS_CHROMEOS)
11375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Restore the order of running, but unpinned applications for the activated
11385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // user.
11395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RestoreUnpinnedRunningApplicationOrder(user_email);
11405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Inform the system tray of the change.
11415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::Shell::GetInstance()->system_tray_delegate()->ActiveUserWasChanged();
1142010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Force on-screen keyboard to reset.
1143010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (keyboard::IsKeyboardEnabled())
1144010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ash::Shell::GetInstance()->CreateKeyboard();
11451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
11461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ChromeLauncherController::AdditionalUserAddedToSession(Profile* profile) {
11481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Switch the running applications to the new user.
1149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  app_window_controller_->AdditionalUserAddedToSession(profile);
1150d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
1151d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
11523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::Observe(
11533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int type,
11543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const content::NotificationSource& source,
11553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const content::NotificationDetails& details) {
11563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  switch (type) {
11570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: {
11583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      const Extension* extension =
11593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          content::Details<const Extension>(details).ptr();
11603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (IsAppPinned(extension->id())) {
11613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // Clear and re-fetch to ensure icon is up-to-date.
11623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        app_icon_loader_->ClearImage(extension->id());
11633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        app_icon_loader_->FetchImage(extension->id());
11643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
11653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
11663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      UpdateAppLaunchersFromPref();
11673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
11683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
116923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
11701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      const content::Details<UnloadedExtensionInfo>& unload_info(details);
11713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      const Extension* extension = unload_info->extension;
11723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      const std::string& id = extension->id();
11733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // Since we might have windowed apps of this type which might have
11743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // outstanding locks which needs to be removed.
11755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (GetShelfIDForAppID(id) &&
11761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          unload_info->reason == UnloadedExtensionInfo::REASON_UNINSTALL) {
11773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        CloseWindowedAppsFromRemovedExtension(id);
11783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
11793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
11803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (IsAppPinned(id)) {
11811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        if (unload_info->reason == UnloadedExtensionInfo::REASON_UNINSTALL) {
1182424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          DoUnpinAppWithID(id);
11833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          app_icon_loader_->ClearImage(id);
11843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        } else {
11853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          app_icon_loader_->UpdateImage(id);
11863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
11873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
11883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
11893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
11903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    default:
11913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      NOTREACHED() << "Unexpected notification type=" << type;
11923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
11933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
11943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
11953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::OnShelfAlignmentChanged(
11961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    aura::Window* root_window) {
11973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const char* pref_value = NULL;
11983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  switch (ash::Shell::GetInstance()->GetShelfAlignment(root_window)) {
11993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case ash::SHELF_ALIGNMENT_BOTTOM:
12003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      pref_value = ash::kShelfAlignmentBottom;
12013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
12023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case ash::SHELF_ALIGNMENT_LEFT:
12033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      pref_value = ash::kShelfAlignmentLeft;
12043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
12053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case ash::SHELF_ALIGNMENT_RIGHT:
12063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      pref_value = ash::kShelfAlignmentRight;
12073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
12083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case ash::SHELF_ALIGNMENT_TOP:
12093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      pref_value = ash::kShelfAlignmentTop;
12103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
12113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdatePerDisplayPref(
12133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      profile_->GetPrefs(), root_window, prefs::kShelfAlignment, pref_value);
12143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (root_window == ash::Shell::GetPrimaryRootWindow()) {
12163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // See comment in |kShelfAlignment| about why we have two prefs here.
12173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    profile_->GetPrefs()->SetString(prefs::kShelfAlignmentLocal, pref_value);
12183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    profile_->GetPrefs()->SetString(prefs::kShelfAlignment, pref_value);
12193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
12203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
12213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::OnDisplayConfigurationChanged() {
12233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  SetShelfBehaviorsFromPrefs();
12243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
12253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::OnIsSyncingChanged() {
12273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  PrefServiceSyncable* prefs = PrefServiceSyncable::FromProfile(profile_);
12283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  MaybePropagatePrefToLocal(prefs,
12293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                            prefs::kShelfAlignmentLocal,
12303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                            prefs::kShelfAlignment);
12313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  MaybePropagatePrefToLocal(prefs,
12323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                            prefs::kShelfAutoHideBehaviorLocal,
12333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                            prefs::kShelfAutoHideBehavior);
12343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
12353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::OnAppSyncUIStatusChanged() {
12373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (app_sync_ui_state_->status() == AppSyncUIState::STATUS_SYNCING)
1238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    model_->SetStatus(ash::ShelfModel::STATUS_LOADING);
12393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  else
1240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    model_->SetStatus(ash::ShelfModel::STATUS_NORMAL);
12413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
12423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::ExtensionEnableFlowFinished() {
124468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  LaunchApp(extension_enable_flow_->extension_id(),
124568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            ash::LAUNCH_FROM_UNKNOWN,
124668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            ui::EF_NONE);
12473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  extension_enable_flow_.reset();
12483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
12493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::ExtensionEnableFlowAborted(bool user_initiated) {
12513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  extension_enable_flow_.reset();
12523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
12533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)ChromeLauncherAppMenuItems ChromeLauncherController::GetApplicationList(
12555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ash::ShelfItem& item,
12563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int event_flags) {
12573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Make sure that there is a controller associated with the id and that the
12583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // extension itself is a valid application and not a panel.
12593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!HasItemController(item.id) ||
12605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !GetShelfIDForAppID(id_to_item_controller_map_[item.id]->app_id()))
12613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return ChromeLauncherAppMenuItems().Pass();
12623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return id_to_item_controller_map_[item.id]->GetApplicationList(event_flags);
12643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
12653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)std::vector<content::WebContents*>
12673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)ChromeLauncherController::GetV1ApplicationsFromAppId(std::string app_id) {
12685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID id = GetShelfIDForAppID(app_id);
12693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If there is no such an item pinned to the launcher, no menu gets created.
12713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (id) {
12723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LauncherItemController* controller = id_to_item_controller_map_[id];
12733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    DCHECK(controller);
12743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (controller->type() == LauncherItemController::TYPE_SHORTCUT)
12753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return GetV1ApplicationsFromController(controller);
12763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
12773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return std::vector<content::WebContents*>();
12783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
12793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::ActivateShellApp(const std::string& app_id,
12813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                                int index) {
12825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID id = GetShelfIDForAppID(app_id);
12833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (id) {
12843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LauncherItemController* controller = id_to_item_controller_map_[id];
12853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (controller->type() == LauncherItemController::TYPE_APP) {
1286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      AppWindowLauncherItemController* app_window_controller =
1287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          static_cast<AppWindowLauncherItemController*>(controller);
1288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      app_window_controller->ActivateIndexedApp(index);
12893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
12903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
12913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
12923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ChromeLauncherController::IsWebContentHandledByApplication(
12943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    content::WebContents* web_contents,
12953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& app_id) {
12963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if ((web_contents_to_app_id_.find(web_contents) !=
12973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       web_contents_to_app_id_.end()) &&
12983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      (web_contents_to_app_id_[web_contents] == app_id))
12993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return true;
13003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return (app_id == kGmailAppId && ContentCanBeHandledByGmailApp(web_contents));
13013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
13023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
13033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ChromeLauncherController::ContentCanBeHandledByGmailApp(
13043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    content::WebContents* web_contents) {
13055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID id = GetShelfIDForAppID(kGmailAppId);
13063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (id) {
13073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const GURL url = web_contents->GetURL();
13083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // We need to extend the application matching for the gMail app beyond the
13093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // manifest file's specification. This is required because of the namespace
13103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // overlap with the offline app ("/mail/mu/").
13113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!MatchPattern(url.path(), "/mail/mu/*") &&
13123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        MatchPattern(url.path(), "/mail/*") &&
13133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        GetExtensionForAppID(kGmailAppId) &&
13143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        GetExtensionForAppID(kGmailAppId)->OverlapsWithOrigin(url))
13153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return true;
13163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
13173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return false;
13183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
13193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
13203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)gfx::Image ChromeLauncherController::GetAppListIcon(
13213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    content::WebContents* web_contents) const {
1322c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
13233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (IsIncognito(web_contents))
1324c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return rb.GetImageNamed(IDR_ASH_SHELF_LIST_INCOGNITO_BROWSER);
13253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  FaviconTabHelper* favicon_tab_helper =
13263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      FaviconTabHelper::FromWebContents(web_contents);
13273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  gfx::Image result = favicon_tab_helper->GetFavicon();
13283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (result.IsEmpty())
13293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return rb.GetImageNamed(IDR_DEFAULT_FAVICON);
13303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return result;
13313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
13323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
13335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 ChromeLauncherController::GetAppListTitle(
13343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    content::WebContents* web_contents) const {
1335a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 title = web_contents->GetTitle();
13363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!title.empty())
13373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return title;
13383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  WebContentsToAppIDMap::const_iterator iter =
13393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      web_contents_to_app_id_.find(web_contents);
13403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (iter != web_contents_to_app_id_.end()) {
13413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    std::string app_id = iter->second;
13423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const extensions::Extension* extension = GetExtensionForAppID(app_id);
13433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (extension)
13445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return base::UTF8ToUTF16(extension->name());
13453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
13463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
13473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
13483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
13495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ash::ShelfID ChromeLauncherController::CreateAppShortcutLauncherItem(
13503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& app_id,
13513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int index) {
13523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return CreateAppShortcutLauncherItemWithType(app_id,
13533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                               index,
13543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                               ash::TYPE_APP_SHORTCUT);
13553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
13563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
13573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::SetAppTabHelperForTest(AppTabHelper* helper) {
13583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  app_tab_helper_.reset(helper);
13593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
13603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
13613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::SetAppIconLoaderForTest(
13623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    extensions::AppIconLoader* loader) {
13633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  app_icon_loader_.reset(loader);
13643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
13653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
13665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const std::string& ChromeLauncherController::GetAppIdFromShelfIdForTest(
13675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfID id) {
13683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return id_to_item_controller_map_[id]->app_id();
13693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
13703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1371a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ChromeLauncherController::SetShelfItemDelegateManagerForTest(
1372a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ash::ShelfItemDelegateManager* manager) {
13734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  item_delegate_manager_ = manager;
13744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
13754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
13765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::RememberUnpinnedRunningApplicationOrder() {
13775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunningAppListIds list;
13785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = 0; i < model_->item_count(); i++) {
13795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfItemType type = model_->items()[i].type;
13805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (type == ash::TYPE_WINDOWED_APP || type == ash::TYPE_PLATFORM_APP)
13815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      list.push_back(GetAppIDForShelfID(model_->items()[i].id));
13825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
13835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  last_used_running_application_order_[
13845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      multi_user_util::GetUserIDFromProfile(profile_)] = list;
13855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
13865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
13875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::RestoreUnpinnedRunningApplicationOrder(
13885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& user_id) {
13895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const RunningAppListIdMap::iterator app_id_list =
13905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      last_used_running_application_order_.find(user_id);
13915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_id_list == last_used_running_application_order_.end())
13925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
13935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
13945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Find the first insertion point for running applications.
13955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int running_index = model_->FirstRunningAppIndex();
13965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (RunningAppListIds::iterator app_id = app_id_list->second.begin();
13975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       app_id != app_id_list->second.end(); ++app_id) {
13985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfID shelf_id = GetShelfIDForAppID(*app_id);
13995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (shelf_id) {
14005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      int app_index = model_->ItemIndexByID(shelf_id);
14015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DCHECK_GE(app_index, 0);
14025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ash::ShelfItemType type = model_->items()[app_index].type;
14035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (type == ash::TYPE_WINDOWED_APP || type == ash::TYPE_PLATFORM_APP) {
14045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (running_index != app_index)
14055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          model_->Move(running_index, app_index);
14065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        running_index++;
14075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
14085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
14095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
14105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
14115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
14125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ash::ShelfID ChromeLauncherController::CreateAppShortcutLauncherItemWithType(
14133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& app_id,
14143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int index,
14155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfItemType shelf_item_type) {
14163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  AppShortcutLauncherItemController* controller =
14173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      new AppShortcutLauncherItemController(app_id, this);
14185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID shelf_id = InsertAppLauncherItem(
14195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      controller, app_id, ash::STATUS_CLOSED, index, shelf_item_type);
14205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return shelf_id;
14213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
14223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
14234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)LauncherItemController* ChromeLauncherController::GetLauncherItemController(
14245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ash::ShelfID id) {
14254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!HasItemController(id))
14264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return NULL;
14274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return id_to_item_controller_map_[id];
14284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
14294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
14301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool ChromeLauncherController::IsBrowserFromActiveUser(Browser* browser) {
14311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // If running multi user mode with separate desktops, we have to check if the
14321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // browser is from the active user.
14331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (chrome::MultiUserWindowManager::GetMultiProfileMode() !=
14341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED)
14351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return true;
1436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return multi_user_util::IsProfileFromActiveUser(browser->profile());
14371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
14381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
14395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ChromeLauncherController::LauncherItemClosed(ash::ShelfID id) {
14403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  IDToItemControllerMap::iterator iter = id_to_item_controller_map_.find(id);
14413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(iter != id_to_item_controller_map_.end());
14423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(iter->second);
14433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  app_icon_loader_->ClearImage(iter->second->app_id());
14443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  id_to_item_controller_map_.erase(iter);
14453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int index = model_->ItemIndexByID(id);
14463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // A "browser proxy" is not known to the model and this removal does
14473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // therefore not need to be propagated to the model.
14483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (index != -1)
14493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    model_->RemoveItemAt(index);
14503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
14513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
14523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::DoPinAppWithID(const std::string& app_id) {
14533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If there is an item, do nothing and return.
14543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (IsAppPinned(app_id))
14553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
14563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
14575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID shelf_id = GetShelfIDForAppID(app_id);
14585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (shelf_id) {
14593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // App item exists, pin it
14605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Pin(shelf_id);
14613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  } else {
14623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Otherwise, create a shortcut item for it.
14633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    CreateAppShortcutLauncherItem(app_id, model_->item_count());
14643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (CanPin())
14653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      PersistPinnedState();
14663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
14673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
14683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1469424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void ChromeLauncherController::DoUnpinAppWithID(const std::string& app_id) {
14705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID shelf_id = GetShelfIDForAppID(app_id);
14715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (shelf_id && IsPinned(shelf_id))
14725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Unpin(shelf_id);
14733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
14743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
14755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int ChromeLauncherController::PinRunningAppInternal(int index,
14765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                    ash::ShelfID shelf_id) {
14775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int running_index = model_->ItemIndexByID(shelf_id);
14785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItem item = model_->items()[running_index];
147968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(item.type == ash::TYPE_WINDOWED_APP ||
148068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)         item.type == ash::TYPE_PLATFORM_APP);
148168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  item.type = ash::TYPE_APP_SHORTCUT;
148268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  model_->Set(running_index, item);
1483f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // The |ShelfModel|'s weight system might reposition the item to a
148468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // new index, so we get the index again.
14855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  running_index = model_->ItemIndexByID(shelf_id);
148668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (running_index < index)
148768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    --index;
148868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (running_index != index)
148968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    model_->Move(running_index, index);
149068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return index;
149168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
149268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
149368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void ChromeLauncherController::UnpinRunningAppInternal(int index) {
149468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK_GE(index, 0);
14955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItem item = model_->items()[index];
149668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK_EQ(item.type, ash::TYPE_APP_SHORTCUT);
149768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  item.type = ash::TYPE_WINDOWED_APP;
149868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // A platform app and a windowed app are sharing TYPE_APP_SHORTCUT. As such
149968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // we have to check here what this was before it got a shortcut.
150068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (HasItemController(item.id) &&
150168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      id_to_item_controller_map_[item.id]->type() ==
150268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          LauncherItemController::TYPE_APP)
150368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    item.type = ash::TYPE_PLATFORM_APP;
150468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  model_->Set(index, item);
150568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
150668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
15073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::UpdateAppLaunchersFromPref() {
150868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // There are various functions which will trigger a |PersistPinnedState| call
150968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // like a direct call to |DoPinAppWithID|, or an indirect call to the menu
151068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // model which will use weights to re-arrange the icons to new positions.
151168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Since this function is meant to synchronize the "is state" with the
151268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // "sync state", it makes no sense to store any changes by this function back
151368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // into the pref state. Therefore we tell |persistPinnedState| to ignore any
151468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // invocations while we are running.
151568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  base::AutoReset<bool> auto_reset(&ignore_persist_pinned_state_change_, true);
151668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::vector<std::string> pinned_apps = GetListOfPinnedAppsAndBrowser();
151768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
15183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int index = 0;
15193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int max_index = model_->item_count();
15203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
152168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // When one of the two special items cannot be moved (and we do not know where
152268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // yet), we remember the current location in one of these variables.
152368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int chrome_index = -1;
152468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int app_list_index = -1;
15253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
15263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Walk the model and |pinned_apps| from the pref lockstep, adding and
15273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // removing items as necessary. NB: This code uses plain old indexing instead
15283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // of iterators because of model mutations as part of the loop.
15293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin());
15303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) {
153168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Check if we have an item which we need to handle.
15323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (*pref_app_id == extension_misc::kChromeAppId ||
15335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *pref_app_id == kAppShelfIdPlaceholder ||
15343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        IsAppPinned(*pref_app_id)) {
15353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      for (; index < max_index; ++index) {
15365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        const ash::ShelfItem& item(model_->items()[index]);
153768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        bool is_app_list = item.type == ash::TYPE_APP_LIST;
153868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        bool is_chrome = item.type == ash::TYPE_BROWSER_SHORTCUT;
153968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        if (item.type != ash::TYPE_APP_SHORTCUT && !is_app_list && !is_chrome)
15403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          continue;
15413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        IDToItemControllerMap::const_iterator entry =
15423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            id_to_item_controller_map_.find(item.id);
15435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if ((kAppShelfIdPlaceholder == *pref_app_id && is_app_list) ||
154468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            (extension_misc::kChromeAppId == *pref_app_id && is_chrome) ||
15453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            (entry != id_to_item_controller_map_.end() &&
15463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)             entry->second->app_id() == *pref_app_id)) {
154768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          // Check if an item needs to be moved here.
154868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          MoveChromeOrApplistToFinalPosition(
154968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              is_chrome, is_app_list, index, &chrome_index, &app_list_index);
15503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          ++pref_app_id;
15513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          break;
15523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        } else {
155368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          if (is_chrome || is_app_list) {
155468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            // We cannot delete any of these shortcuts. As such we remember
155568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            // their positions and move them later where they belong.
155668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            if (is_chrome)
155768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              chrome_index = index;
155868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            else
155968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              app_list_index = index;
156068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            // And skip the item - or exit the loop if end is reached (note that
156168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            // in that case we will reduce the index again by one and this only
156268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            // compensates for it).
156368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            if (index >= max_index - 1)
156468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              break;
156568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            ++index;
15663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          } else {
156768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            // Check if this is a platform or a windowed app.
156868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            if (item.type == ash::TYPE_APP_SHORTCUT &&
156968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                (id_to_item_controller_map_[item.id]->locked() ||
157068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                 id_to_item_controller_map_[item.id]->type() ==
157168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                     LauncherItemController::TYPE_APP)) {
157268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              // Note: This will not change the amount of items (|max_index|).
157368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              // Even changes to the actual |index| due to item weighting
157468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              // changes should be fine.
157568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              UnpinRunningAppInternal(index);
157668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            } else {
157768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              LauncherItemClosed(item.id);
157868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              --max_index;
157968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            }
15803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          }
15813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          --index;
15823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
15833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
15843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // If the item wasn't found, that means id_to_item_controller_map_
15853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // is out of sync.
1586d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      DCHECK(index <= max_index);
15873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    } else {
158868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      // Check if the item was already running but not yet pinned.
15895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ash::ShelfID shelf_id = GetShelfIDForAppID(*pref_app_id);
15905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (shelf_id) {
159168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        // This app is running but not yet pinned. So pin and move it.
15925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        index = PinRunningAppInternal(index, shelf_id);
159368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      } else {
159468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        // This app wasn't pinned before, insert a new entry.
15955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        shelf_id = CreateAppShortcutLauncherItem(*pref_app_id, index);
159668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        ++max_index;
15975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        index = model_->ItemIndexByID(shelf_id);
159868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      }
15993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      ++pref_app_id;
16003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
16013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
16023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
16033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Remove any trailing existing items.
16043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  while (index < model_->item_count()) {
16055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ash::ShelfItem& item(model_->items()[index]);
160668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (item.type == ash::TYPE_APP_SHORTCUT) {
160768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      if (id_to_item_controller_map_[item.id]->locked() ||
160868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          id_to_item_controller_map_[item.id]->type() ==
160968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              LauncherItemController::TYPE_APP)
161068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        UnpinRunningAppInternal(index);
161168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      else
161268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        LauncherItemClosed(item.id);
161368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    } else {
161468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      if (item.type == ash::TYPE_BROWSER_SHORTCUT)
161568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        chrome_index = index;
161668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      else if (item.type == ash::TYPE_APP_LIST)
161768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        app_list_index = index;
16183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      ++index;
161968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
16203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
16213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
16223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Append unprocessed items from the pref to the end of the model.
16233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (; pref_app_id != pinned_apps.end(); ++pref_app_id) {
162468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // All items but the chrome and / or app list shortcut needs to be added.
162568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    bool is_chrome = *pref_app_id == extension_misc::kChromeAppId;
16265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool is_app_list = *pref_app_id == kAppShelfIdPlaceholder;
162768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // Coming here we know the next item which can be finalized, either the
162868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // chrome item or the app launcher. The final position is the end of the
162968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // list. The menu model will make sure that the item is grouped according
163068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // to its weight (which we do not know here).
163168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (!is_chrome && !is_app_list) {
16323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      DoPinAppWithID(*pref_app_id);
163368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      int target_index = FindInsertionPoint(false);
16345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ash::ShelfID id = GetShelfIDForAppID(*pref_app_id);
163568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      int source_index = model_->ItemIndexByID(id);
163668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      if (source_index != target_index)
163768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        model_->Move(source_index, target_index);
163868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
163968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      // Needed for the old layout - the weight might force it to be lower in
164068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      // rank.
164168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      if (app_list_index != -1 && target_index <= app_list_index)
164268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        ++app_list_index;
164368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    } else {
164468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      int target_index = FindInsertionPoint(is_app_list);
164568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      MoveChromeOrApplistToFinalPosition(
164668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          is_chrome, is_app_list, target_index, &chrome_index, &app_list_index);
164768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
16483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
16493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
16503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
16513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::SetShelfAutoHideBehaviorPrefs(
16523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ash::ShelfAutoHideBehavior behavior,
16531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    aura::Window* root_window) {
16543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const char* value = NULL;
16553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  switch (behavior) {
16563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
16573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      value = ash::kShelfAutoHideBehaviorAlways;
16583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
16593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case ash::SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
16603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      value = ash::kShelfAutoHideBehaviorNever;
16613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      break;
16623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    case ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
16633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // This one should not be a valid preference option for now. We only want
16645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // to completely hide it when we run in app mode - or while we temporarily
16655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // hide the shelf as part of an animation (e.g. the multi user change).
16663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return;
16673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
16683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
16693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdatePerDisplayPref(
16703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      profile_->GetPrefs(), root_window, prefs::kShelfAutoHideBehavior, value);
16713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
16723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (root_window == ash::Shell::GetPrimaryRootWindow()) {
16733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // See comment in |kShelfAlignment| about why we have two prefs here.
16743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehaviorLocal, value);
16753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    profile_->GetPrefs()->SetString(prefs::kShelfAutoHideBehavior, value);
16763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
16773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
16783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
16793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::SetShelfAutoHideBehaviorFromPrefs() {
1680f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
16813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1682f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (aura::Window::Windows::const_iterator iter = root_windows.begin();
16833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       iter != root_windows.end(); ++iter) {
16843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ash::Shell::GetInstance()->SetShelfAutoHideBehavior(
16853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        GetShelfAutoHideBehavior(*iter), *iter);
16863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
16873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
16883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
16893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::SetShelfAlignmentFromPrefs() {
16903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!ash::ShelfWidget::ShelfAlignmentAllowed())
16913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
16923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1693f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
16943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1695f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (aura::Window::Windows::const_iterator iter = root_windows.begin();
16963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       iter != root_windows.end(); ++iter) {
16973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // See comment in |kShelfAlignment| as to why we consider two prefs.
16983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string alignment_value(
16993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        GetPrefForRootWindow(profile_->GetPrefs(),
17003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                             *iter,
17013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                             prefs::kShelfAlignmentLocal,
17023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                             prefs::kShelfAlignment));
17033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ash::ShelfAlignment alignment = ash::SHELF_ALIGNMENT_BOTTOM;
17043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (alignment_value == ash::kShelfAlignmentLeft)
17053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      alignment = ash::SHELF_ALIGNMENT_LEFT;
17063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    else if (alignment_value == ash::kShelfAlignmentRight)
17073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      alignment = ash::SHELF_ALIGNMENT_RIGHT;
17083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    else if (alignment_value == ash::kShelfAlignmentTop)
17093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      alignment = ash::SHELF_ALIGNMENT_TOP;
17103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    ash::Shell::GetInstance()->SetShelfAlignment(alignment, *iter);
17113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
17123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
17133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
17143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::SetShelfBehaviorsFromPrefs() {
17153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  SetShelfAutoHideBehaviorFromPrefs();
17163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  SetShelfAlignmentFromPrefs();
17173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
17183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
17196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#if defined(OS_CHROMEOS)
17206d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void ChromeLauncherController::SetVirtualKeyboardBehaviorFromPrefs() {
17216d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const PrefService* service = profile_->GetPrefs();
17226d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (!service->HasPrefPath(prefs::kTouchVirtualKeyboardEnabled)) {
17236d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    keyboard::SetKeyboardShowOverride(keyboard::KEYBOARD_SHOW_OVERRIDE_NONE);
17246d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  } else {
17256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    const bool enabled = service->GetBoolean(
17266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        prefs::kTouchVirtualKeyboardEnabled);
17276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    keyboard::SetKeyboardShowOverride(
17286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        enabled ? keyboard::KEYBOARD_SHOW_OVERRIDE_ENABLED
17296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                : keyboard::KEYBOARD_SHOW_OVERRIDE_DISABLED);
17306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
17316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)}
17326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#endif //  defined(OS_CHROMEOS)
17336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1734effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochash::ShelfItemStatus ChromeLauncherController::GetAppState(
1735effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const::std::string& app_id) {
1736effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ash::ShelfItemStatus status = ash::STATUS_CLOSED;
1737effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (WebContentsToAppIDMap::iterator it = web_contents_to_app_id_.begin();
1738effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       it != web_contents_to_app_id_.end();
1739effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++it) {
1740effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (it->second == app_id) {
1741effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      Browser* browser = chrome::FindBrowserWithWebContents(it->first);
1742c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      // Usually there should never be an item in our |web_contents_to_app_id_|
1743c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      // list which got deleted already. However - in some situations e.g.
1744c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      // Browser::SwapTabContent there is temporarily no associated browser.
1745c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      if (!browser)
1746c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        continue;
1747effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (browser->window()->IsActive()) {
1748effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        return browser->tab_strip_model()->GetActiveWebContents() == it->first ?
1749effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            ash::STATUS_ACTIVE : ash::STATUS_RUNNING;
1750effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      } else {
1751effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        status = ash::STATUS_RUNNING;
1752effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      }
1753effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
17545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1755effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return status;
17563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
17573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
17585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ash::ShelfID ChromeLauncherController::InsertAppLauncherItem(
17593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LauncherItemController* controller,
17603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& app_id,
17615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfItemStatus status,
17623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int index,
17635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfItemType shelf_item_type) {
17645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID id = model_->next_id();
17653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(!HasItemController(id));
17663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(controller);
17673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  id_to_item_controller_map_[id] = controller;
17685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  controller->set_shelf_id(id);
17693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
17705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItem item;
17715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  item.type = shelf_item_type;
17725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  item.image = extensions::util::GetDefaultAppIcon();
17733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1774effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ash::ShelfItemStatus new_state = GetAppState(app_id);
1775effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (new_state != ash::STATUS_CLOSED)
1776effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    status = new_state;
1777effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
17783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  item.status = status;
17793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
17803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  model_->AddAt(index, item);
17813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
17823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  app_icon_loader_->FetchImage(app_id);
17833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1784a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SetShelfItemDelegate(id, controller);
17854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
17863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return id;
17873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
17883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
17895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ChromeLauncherController::HasItemController(ash::ShelfID id) const {
17903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return id_to_item_controller_map_.find(id) !=
17913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         id_to_item_controller_map_.end();
17923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
17933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
17943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)std::vector<content::WebContents*>
17953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)ChromeLauncherController::GetV1ApplicationsFromController(
17963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LauncherItemController* controller) {
17973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(controller->type() == LauncherItemController::TYPE_SHORTCUT);
17983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  AppShortcutLauncherItemController* app_controller =
17993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      static_cast<AppShortcutLauncherItemController*>(controller);
18003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return app_controller->GetRunningApplications();
18013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
18023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
180358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)BrowserShortcutLauncherItemController*
18043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)ChromeLauncherController::GetBrowserShortcutLauncherItemController() {
18053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (IDToItemControllerMap::iterator i = id_to_item_controller_map_.begin();
18063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      i != id_to_item_controller_map_.end(); ++i) {
18073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    int index = model_->ItemIndexByID(i->first);
18085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ash::ShelfItem& item = model_->items()[index];
18093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (item.type == ash::TYPE_BROWSER_SHORTCUT)
181058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return static_cast<BrowserShortcutLauncherItemController*>(i->second);
18113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
181258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Create a LauncherItemController for the Browser shortcut if it does not
181358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // exist yet.
18145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID id = CreateBrowserShortcutLauncherItem();
18153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(id_to_item_controller_map_[id]);
181658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return static_cast<BrowserShortcutLauncherItemController*>(
181758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      id_to_item_controller_map_[id]);
18183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
18193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
18205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ash::ShelfID ChromeLauncherController::CreateBrowserShortcutLauncherItem() {
18215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfItem browser_shortcut;
18223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  browser_shortcut.type = ash::TYPE_BROWSER_SHORTCUT;
18233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
18243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  browser_shortcut.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32);
18255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ash::ShelfID id = model_->next_id();
182668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t index = GetChromeIconIndexForCreation();
18273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  model_->AddAt(index, browser_shortcut);
18284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  id_to_item_controller_map_[id] =
18294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      new BrowserShortcutLauncherItemController(this);
18305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  id_to_item_controller_map_[id]->set_shelf_id(id);
1831a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // ShelfItemDelegateManager owns BrowserShortcutLauncherItemController.
1832a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  SetShelfItemDelegate(id, id_to_item_controller_map_[id]);
18333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return id;
18343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
18353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
18363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::PersistChromeItemIndex(int index) {
18373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  profile_->GetPrefs()->SetInteger(prefs::kShelfChromeIconIndex, index);
18383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
18393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
18403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)int ChromeLauncherController::GetChromeIconIndexFromPref() const {
18413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  size_t index = profile_->GetPrefs()->GetInteger(prefs::kShelfChromeIconIndex);
18423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const base::ListValue* pinned_apps_pref =
18433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
18443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return std::max(static_cast<size_t>(0),
18453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                  std::min(pinned_apps_pref->GetSize(), index));
18463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
18473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
184868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void ChromeLauncherController::MoveChromeOrApplistToFinalPosition(
184968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    bool is_chrome,
185068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    bool is_app_list,
185168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    int target_index,
185268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    int* chrome_index,
185368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    int* app_list_index) {
185468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (is_chrome && *chrome_index != -1) {
185568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    model_->Move(*chrome_index, target_index);
185668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (*app_list_index != -1 &&
185768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        *chrome_index < *app_list_index &&
185868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        target_index > *app_list_index)
185968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      --(*app_list_index);
186068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    *chrome_index = -1;
186168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else if (is_app_list && *app_list_index != -1) {
186268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    model_->Move(*app_list_index, target_index);
186368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (*chrome_index != -1 &&
186468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        *app_list_index < *chrome_index &&
186568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        target_index > *chrome_index)
186668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      --(*chrome_index);
186768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    *app_list_index = -1;
186868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
186968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
187068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
187168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)int ChromeLauncherController::FindInsertionPoint(bool is_app_list) {
18725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Keeping this change small to backport to M33&32 (see crbug.com/329597).
18735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(skuhne): With the removal of the legacy shelf layout we should remove
18745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the ability to move the app list item since this was never used. We should
18755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // instead ask the ShelfModel::ValidateInsertionIndex or similir for an index.
1876a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (is_app_list)
18775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 0;
18785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
187968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (int i = model_->item_count() - 1; i > 0; --i) {
18805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfItemType type = model_->items()[i].type;
188168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (type == ash::TYPE_APP_SHORTCUT ||
1882a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        (is_app_list && type == ash::TYPE_APP_LIST) ||
1883effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        type == ash::TYPE_BROWSER_SHORTCUT) {
188468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      return i;
1885effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
188668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
188768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return 0;
188868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
188968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
189068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)int ChromeLauncherController::GetChromeIconIndexForCreation() {
189168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // We get the list of pinned apps as they currently would get pinned.
189268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Within this list the chrome icon will be the correct location.
189368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::vector<std::string> pinned_apps = GetListOfPinnedAppsAndBrowser();
189468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
189568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::vector<std::string>::iterator it =
189668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      std::find(pinned_apps.begin(),
189768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                pinned_apps.end(),
189868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                std::string(extension_misc::kChromeAppId));
189968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  DCHECK(it != pinned_apps.end());
190068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int index = it - pinned_apps.begin();
190168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
190268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // We should do here a comparison between the is state and the "want to be"
190368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // state since some apps might be able to pin but are not yet. Instead - for
190468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // the time being we clamp against the amount of known items and wait for the
190568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // next |UpdateAppLaunchersFromPref()| call to correct it - it will come since
190668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // the pinning will be done then.
190768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return std::min(model_->item_count(), index);
190868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
190968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
191068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::vector<std::string>
191168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)ChromeLauncherController::GetListOfPinnedAppsAndBrowser() {
191268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Adding the app list item to the list of items requires that the ID is not
191368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // a valid and known ID for the extension system. The ID was constructed that
191468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // way - but just to make sure...
19155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!app_tab_helper_->IsValidIDForCurrentUser(kAppShelfIdPlaceholder));
191668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
191768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::vector<std::string> pinned_apps;
191868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
191968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Get the new incarnation of the list.
192068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const base::ListValue* pinned_apps_pref =
192168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      profile_->GetPrefs()->GetList(prefs::kPinnedLauncherApps);
192268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
192368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // Keep track of the addition of the chrome and the app list icon.
192468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool chrome_icon_added = false;
192568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool app_list_icon_added = false;
192668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  size_t chrome_icon_index = GetChromeIconIndexFromPref();
192768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
192868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // See if the chrome string is already in the pinned list and remove it if
192968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // needed.
193068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  base::Value* chrome_app = ash::CreateAppDict(extension_misc::kChromeAppId);
193168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (chrome_app) {
193268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    chrome_icon_added = pinned_apps_pref->Find(*chrome_app) !=
193368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        pinned_apps_pref->end();
193468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    delete chrome_app;
193568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
193668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
193768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (size_t index = 0; index < pinned_apps_pref->GetSize(); ++index) {
193868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // We need to position the chrome icon relative to it's place in the pinned
193968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // preference list - even if an item of that list isn't shown yet.
194068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (index == chrome_icon_index && !chrome_icon_added) {
194168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      pinned_apps.push_back(extension_misc::kChromeAppId);
194268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      chrome_icon_added = true;
194368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
19445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::DictionaryValue* app = NULL;
194568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    std::string app_id;
194668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (pinned_apps_pref->GetDictionary(index, &app) &&
194768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        app->GetString(ash::kPinnedAppsPrefAppIDPath, &app_id) &&
194868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        (std::find(pinned_apps.begin(), pinned_apps.end(), app_id) ==
194968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)             pinned_apps.end())) {
195068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      if (app_id == extension_misc::kChromeAppId) {
195168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        chrome_icon_added = true;
195268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        pinned_apps.push_back(extension_misc::kChromeAppId);
19535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      } else if (app_id == kAppShelfIdPlaceholder) {
195468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        app_list_icon_added = true;
19555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        pinned_apps.push_back(kAppShelfIdPlaceholder);
19564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      } else if (app_tab_helper_->IsValidIDForCurrentUser(app_id)) {
19574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // Note: In multi profile scenarios we only want to show pinnable apps
19584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // here which is correct. Running applications from the other users will
19594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // continue to run. So no need for multi profile modifications.
196068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        pinned_apps.push_back(app_id);
196168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      }
196268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
196368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
196468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
196568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // If not added yet, the chrome item will be the last item in the list.
196668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!chrome_icon_added)
196768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    pinned_apps.push_back(extension_misc::kChromeAppId);
196868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
196968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // If not added yet, add the app list item either at the end or at the
197068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // beginning - depending on the shelf layout.
197168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!app_list_icon_added) {
1972a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    pinned_apps.insert(pinned_apps.begin(), kAppShelfIdPlaceholder);
197368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
197468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return pinned_apps;
197568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
197668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
19773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool ChromeLauncherController::IsIncognito(
197868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const content::WebContents* web_contents) const {
19793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const Profile* profile =
19803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      Profile::FromBrowserContext(web_contents->GetBrowserContext());
19813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return profile->IsOffTheRecord() && !profile->IsGuestSession();
19823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
19833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
19843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ChromeLauncherController::CloseWindowedAppsFromRemovedExtension(
19853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const std::string& app_id) {
19863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // This function cannot rely on the controller's enumeration functionality
19873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // since the extension has already be unloaded.
19883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const BrowserList* ash_browser_list =
19893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
19903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<Browser*> browser_to_close;
19913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  for (BrowserList::const_reverse_iterator
19923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           it = ash_browser_list->begin_last_active();
19933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       it != ash_browser_list->end_last_active(); ++it) {
19943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    Browser* browser = *it;
19953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!browser->is_type_tabbed() &&
19963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        browser->is_type_popup() &&
19973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        browser->is_app() &&
19983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        app_id == web_app::GetExtensionIdFromApplicationName(
19993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            browser->app_name())) {
20003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      browser_to_close.push_back(browser);
20013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
20023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
20033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  while (!browser_to_close.empty()) {
20043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    TabStripModel* tab_strip = browser_to_close.back()->tab_strip_model();
20053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    tab_strip->CloseWebContentsAt(0, TabStripModel::CLOSE_NONE);
20063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    browser_to_close.pop_back();
20073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
20083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
20093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2010a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void ChromeLauncherController::SetShelfItemDelegate(
20115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ash::ShelfID id,
2012a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ash::ShelfItemDelegate* item_delegate) {
20134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_GT(id, 0);
20144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(item_delegate);
20154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(item_delegate_manager_);
2016a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  item_delegate_manager_->SetShelfItemDelegate(
2017a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      id, scoped_ptr<ash::ShelfItemDelegate>(item_delegate).Pass());
2018424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
2019d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2020d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeLauncherController::AttachProfile(Profile* profile) {
2021d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  profile_ = profile;
20224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Either add the profile to the list of known profiles and make it the active
20234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // one for some functions of AppTabHelper or create a new one.
20244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!app_tab_helper_.get())
20254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    app_tab_helper_.reset(new LauncherAppTabHelper(profile_));
20264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  else
20274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    app_tab_helper_->SetCurrentUser(profile_);
2028d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // TODO(skuhne): The AppIconLoaderImpl has the same problem. Each loaded
2029d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // image is associated with a profile (it's loader requires the profile).
2030d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Since icon size changes are possible, the icon could be requested to be
2031d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // reloaded. However - having it not multi profile aware would cause problems
2032d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // if the icon cache gets deleted upon user switch.
2033d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  app_icon_loader_.reset(new extensions::AppIconLoaderImpl(
2034d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      profile_, extension_misc::EXTENSION_ICON_SMALL, this));
2035d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2036d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  pref_change_registrar_.Init(profile_->GetPrefs());
2037d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  pref_change_registrar_.Add(
2038d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kPinnedLauncherApps,
2039d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&ChromeLauncherController::UpdateAppLaunchersFromPref,
2040d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 base::Unretained(this)));
2041d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  pref_change_registrar_.Add(
2042d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kShelfAlignmentLocal,
2043d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&ChromeLauncherController::SetShelfAlignmentFromPrefs,
2044d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 base::Unretained(this)));
2045d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  pref_change_registrar_.Add(
2046d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kShelfAutoHideBehaviorLocal,
2047d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&ChromeLauncherController::
2048d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                     SetShelfAutoHideBehaviorFromPrefs,
2049d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 base::Unretained(this)));
2050d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  pref_change_registrar_.Add(
2051d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      prefs::kShelfPreferences,
2052d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      base::Bind(&ChromeLauncherController::SetShelfBehaviorsFromPrefs,
2053d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 base::Unretained(this)));
20546d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#if defined(OS_CHROMEOS)
20556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  pref_change_registrar_.Add(
20566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      prefs::kTouchVirtualKeyboardEnabled,
20576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      base::Bind(&ChromeLauncherController::SetVirtualKeyboardBehaviorFromPrefs,
20586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 base::Unretained(this)));
20596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#endif  // defined(OS_CHROMEOS)
2060d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
2061d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2062d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void ChromeLauncherController::ReleaseProfile() {
2063d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (app_sync_ui_state_)
2064d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    app_sync_ui_state_->RemoveObserver(this);
2065d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2066d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
2067d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2068d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  pref_change_registrar_.RemoveAll();
2069d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
2070