1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_H_ 6 #define CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_H_ 7 8 #include <list> 9 #include <map> 10 #include <set> 11 #include <string> 12 #include <vector> 13 14 #include "ash/display/display_controller.h" 15 #include "ash/launcher/launcher_types.h" 16 #include "ash/shelf/shelf_delegate.h" 17 #include "ash/shelf/shelf_item_delegate.h" 18 #include "ash/shelf/shelf_layout_manager_observer.h" 19 #include "ash/shelf/shelf_model_observer.h" 20 #include "ash/shelf/shelf_types.h" 21 #include "ash/shell_observer.h" 22 #include "base/basictypes.h" 23 #include "base/compiler_specific.h" 24 #include "base/memory/scoped_ptr.h" 25 #include "base/memory/scoped_vector.h" 26 #include "base/prefs/pref_change_registrar.h" 27 #include "chrome/browser/extensions/app_icon_loader.h" 28 #include "chrome/browser/prefs/pref_service_syncable_observer.h" 29 #include "chrome/browser/ui/ash/app_sync_ui_state_observer.h" 30 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item.h" 31 #include "chrome/browser/ui/ash/launcher/chrome_launcher_types.h" 32 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" 33 #include "chrome/common/extensions/extension_constants.h" 34 #include "content/public/browser/notification_observer.h" 35 #include "content/public/browser/notification_registrar.h" 36 #include "ui/aura/window_observer.h" 37 38 class AppSyncUIState; 39 class Browser; 40 class BrowserShortcutLauncherItemController; 41 class BrowserStatusMonitor; 42 class ExtensionEnableFlow; 43 class GURL; 44 class LauncherItemController; 45 class Profile; 46 class ShellWindowLauncherController; 47 class TabContents; 48 49 namespace ash { 50 class ShelfItemDelegateManager; 51 class ShelfModel; 52 } 53 54 namespace aura { 55 class Window; 56 } 57 58 namespace content { 59 class WebContents; 60 } 61 62 namespace extensions { 63 class Extension; 64 } 65 66 namespace ui { 67 class BaseWindow; 68 } 69 70 // A list of the elements which makes up a simple menu description. 71 typedef ScopedVector<ChromeLauncherAppMenuItem> ChromeLauncherAppMenuItems; 72 73 // A class which needs to be overwritten dependent on the used OS to moitor 74 // user switching. 75 class ChromeLauncherControllerUserSwitchObserver { 76 public: 77 ChromeLauncherControllerUserSwitchObserver() {} 78 virtual ~ChromeLauncherControllerUserSwitchObserver() {} 79 80 private: 81 82 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherControllerUserSwitchObserver); 83 }; 84 85 // ChromeLauncherController manages the launcher items needed for content 86 // windows. Launcher items have a type, an optional app id, and a controller. 87 // This incarnation groups running tabs/windows in application specific lists. 88 // * Browser app windows have BrowserLauncherItemController, owned by the 89 // BrowserView instance. 90 // * App shell windows have ShellWindowLauncherItemController, owned by 91 // ShellWindowLauncherController. 92 // * Shortcuts have no LauncherItemController. 93 class ChromeLauncherController : public ash::ShelfDelegate, 94 public ash::ShelfModelObserver, 95 public ash::ShellObserver, 96 public ash::DisplayController::Observer, 97 public content::NotificationObserver, 98 public extensions::AppIconLoader::Delegate, 99 public PrefServiceSyncableObserver, 100 public AppSyncUIStateObserver, 101 public ExtensionEnableFlowDelegate, 102 public ash::ShelfLayoutManagerObserver { 103 public: 104 // Indicates if a launcher item is incognito or not. 105 enum IncognitoState { 106 STATE_INCOGNITO, 107 STATE_NOT_INCOGNITO, 108 }; 109 110 // Used to update the state of non plaform apps, as web contents change. 111 enum AppState { 112 APP_STATE_ACTIVE, 113 APP_STATE_WINDOW_ACTIVE, 114 APP_STATE_INACTIVE, 115 APP_STATE_REMOVED 116 }; 117 118 // Mockable interface to get app ids from tabs. 119 class AppTabHelper { 120 public: 121 virtual ~AppTabHelper() {} 122 123 // Returns the app id of the specified tab, or an empty string if there is 124 // no app. All known profiles will be queried for this. 125 virtual std::string GetAppID(content::WebContents* tab) = 0; 126 127 // Returns true if |id| is valid for the currently active profile. 128 // Used during restore to ignore no longer valid extensions. 129 // Note that already running applications are ignored by the restore 130 // process. 131 virtual bool IsValidIDForCurrentUser(const std::string& id) = 0; 132 133 // Sets the currently active profile for the usage of |GetAppID|. 134 virtual void SetCurrentUser(Profile* profile) = 0; 135 }; 136 137 ChromeLauncherController(Profile* profile, ash::ShelfModel* model); 138 virtual ~ChromeLauncherController(); 139 140 // Initializes this ChromeLauncherController. 141 void Init(); 142 143 // Creates an instance. 144 static ChromeLauncherController* CreateInstance(Profile* profile, 145 ash::ShelfModel* model); 146 147 // Returns the single ChromeLauncherController instance. 148 static ChromeLauncherController* instance() { return instance_; } 149 150 // Creates a new app item on the launcher for |controller|. 151 ash::LauncherID CreateAppLauncherItem(LauncherItemController* controller, 152 const std::string& app_id, 153 ash::LauncherItemStatus status); 154 155 // Updates the running status of an item. It will also update the status of 156 // browsers launcher item if needed. 157 void SetItemStatus(ash::LauncherID id, ash::LauncherItemStatus status); 158 159 // Updates the controller associated with id (which should be a shortcut). 160 // |controller| remains owned by caller. 161 void SetItemController(ash::LauncherID id, 162 LauncherItemController* controller); 163 164 // Closes or unpins the launcher item. 165 void CloseLauncherItem(ash::LauncherID id); 166 167 // Pins the specified id. Currently only supports platform apps. 168 void Pin(ash::LauncherID id); 169 170 // Unpins the specified id, closing if not running. 171 void Unpin(ash::LauncherID id); 172 173 // Returns true if the item identified by |id| is pinned. 174 bool IsPinned(ash::LauncherID id); 175 176 // Pins/unpins the specified id. 177 void TogglePinned(ash::LauncherID id); 178 179 // Returns true if the specified item can be pinned or unpinned. Only apps can 180 // be pinned. 181 bool IsPinnable(ash::LauncherID id) const; 182 183 // If there is no launcher item in the launcher for application |app_id|, one 184 // gets created. The (existing or created) launcher items get then locked 185 // against a users un-pinning removal. 186 void LockV1AppWithID(const std::string& app_id); 187 188 // A previously locked launcher item of type |app_id| gets unlocked. If the 189 // lock count reaches 0 and the item is not pinned it will go away. 190 void UnlockV1AppWithID(const std::string& app_id); 191 192 // Requests that the launcher item controller specified by |id| open a new 193 // instance of the app. |event_flags| holds the flags of the event which 194 // triggered this command. 195 void Launch(ash::LauncherID id, int event_flags); 196 197 // Closes the specified item. 198 void Close(ash::LauncherID id); 199 200 // Returns true if the specified item is open. 201 bool IsOpen(ash::LauncherID id); 202 203 // Returns true if the specified item is for a platform app. 204 bool IsPlatformApp(ash::LauncherID id); 205 206 // Opens a new instance of the application identified by |app_id|. 207 // Used by the app-list, and by pinned-app launcher items. 208 void LaunchApp(const std::string& app_id, 209 ash::LaunchSource source, 210 int event_flags); 211 212 // If |app_id| is running, reactivates the app's most recently active window, 213 // otherwise launches and activates the app. 214 // Used by the app-list, and by pinned-app launcher items. 215 void ActivateApp(const std::string& app_id, 216 ash::LaunchSource source, 217 int event_flags); 218 219 // Returns the launch type of app for the specified id. 220 extensions::LaunchType GetLaunchType(ash::LauncherID id); 221 222 // Set the image for a specific launcher item (e.g. when set by the app). 223 void SetLauncherItemImage(ash::LauncherID launcher_id, 224 const gfx::ImageSkia& image); 225 226 // Find out if the given application |id| is a windowed app item and not a 227 // pinned item in the launcher. 228 bool IsWindowedAppInLauncher(const std::string& app_id); 229 230 // Updates the launch type of the app for the specified id to |launch_type|. 231 void SetLaunchType(ash::LauncherID id, 232 extensions::LaunchType launch_type); 233 234 // Returns true if the user is currently logged in as a guest. 235 // Makes virtual for unittest in LauncherContextMenuTest. 236 virtual bool IsLoggedInAsGuest(); 237 238 // Invoked when user clicks on button in the launcher and there is no last 239 // used window (or CTRL is held with the click). 240 void CreateNewWindow(); 241 242 // Invoked when the user clicks on button in the launcher to create a new 243 // incognito window. 244 void CreateNewIncognitoWindow(); 245 246 // Updates the pinned pref state. The pinned state consists of a list pref. 247 // Each item of the list is a dictionary. The key |kAppIDPath| gives the 248 // id of the app. 249 void PersistPinnedState(); 250 251 ash::ShelfModel* model(); 252 253 // Accessor to the currently loaded profile. Note that in multi profile use 254 // cases this might change over time. 255 Profile* profile(); 256 257 // Gets the shelf auto-hide behavior on |root_window|. 258 ash::ShelfAutoHideBehavior GetShelfAutoHideBehavior( 259 aura::Window* root_window) const; 260 261 // Returns |true| if the user is allowed to modify the shelf auto-hide 262 // behavior on |root_window|. 263 bool CanUserModifyShelfAutoHideBehavior(aura::Window* root_window) const; 264 265 // Toggles the shelf auto-hide behavior on |root_window|. Does nothing if the 266 // user is not allowed to modify the auto-hide behavior. 267 void ToggleShelfAutoHideBehavior(aura::Window* root_window); 268 269 // The tab no longer represents its previously identified application. 270 void RemoveTabFromRunningApp(content::WebContents* tab, 271 const std::string& app_id); 272 273 // Notify the controller that the state of an non platform app's tabs 274 // have changed, 275 void UpdateAppState(content::WebContents* contents, AppState app_state); 276 277 // Returns LauncherID for |contents|. If |contents| is not an app or is not 278 // pinned, returns the id of browser shrotcut. 279 ash::LauncherID GetLauncherIDForWebContents(content::WebContents* contents); 280 281 // Limits application refocusing to urls that match |url| for |id|. 282 void SetRefocusURLPatternForTest(ash::LauncherID id, const GURL& url); 283 284 // Returns the extension identified by |app_id|. 285 const extensions::Extension* GetExtensionForAppID( 286 const std::string& app_id) const; 287 288 // Activates a |window|. If |allow_minimize| is true and the system allows 289 // it, the the window will get minimized instead. 290 void ActivateWindowOrMinimizeIfActive(ui::BaseWindow* window, 291 bool allow_minimize); 292 293 // ash::ShelfDelegate overrides: 294 virtual void OnLauncherCreated(ash::Launcher* launcher) OVERRIDE; 295 virtual void OnLauncherDestroyed(ash::Launcher* launcher) OVERRIDE; 296 virtual ash::LauncherID GetLauncherIDForAppID( 297 const std::string& app_id) OVERRIDE; 298 virtual const std::string& GetAppIDForLauncherID(ash::LauncherID id) OVERRIDE; 299 virtual void PinAppWithID(const std::string& app_id) OVERRIDE; 300 virtual bool IsAppPinned(const std::string& app_id) OVERRIDE; 301 virtual bool CanPin() const OVERRIDE; 302 virtual void UnpinAppWithID(const std::string& app_id) OVERRIDE; 303 304 // ash::ShelfModelObserver overrides: 305 virtual void ShelfItemAdded(int index) OVERRIDE; 306 virtual void ShelfItemRemoved(int index, ash::LauncherID id) OVERRIDE; 307 virtual void ShelfItemMoved(int start_index, int target_index) OVERRIDE; 308 virtual void ShelfItemChanged(int index, 309 const ash::LauncherItem& old_item) OVERRIDE; 310 virtual void ShelfStatusChanged() OVERRIDE; 311 312 // content::NotificationObserver overrides: 313 virtual void Observe(int type, 314 const content::NotificationSource& source, 315 const content::NotificationDetails& details) OVERRIDE; 316 317 // ash::ShellObserver overrides: 318 virtual void OnShelfAlignmentChanged(aura::Window* root_window) OVERRIDE; 319 320 // ash::DisplayController::Observer overrides: 321 virtual void OnDisplayConfigurationChanging() OVERRIDE; 322 virtual void OnDisplayConfigurationChanged() OVERRIDE; 323 324 // PrefServiceSyncableObserver overrides: 325 virtual void OnIsSyncingChanged() OVERRIDE; 326 327 // AppSyncUIStateObserver overrides: 328 virtual void OnAppSyncUIStatusChanged() OVERRIDE; 329 330 // ExtensionEnableFlowDelegate overrides: 331 virtual void ExtensionEnableFlowFinished() OVERRIDE; 332 virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE; 333 334 // extensions::AppIconLoader overrides: 335 virtual void SetAppImage(const std::string& app_id, 336 const gfx::ImageSkia& image) OVERRIDE; 337 338 // ash::ShelfLayoutManagerObserver overrides: 339 virtual void OnAutoHideBehaviorChanged( 340 aura::Window* root_window, 341 ash::ShelfAutoHideBehavior new_behavior) OVERRIDE; 342 343 // Called when the active user has changed. 344 void ActiveUserChanged(const std::string& user_email); 345 346 // Called when a user got added to the session. 347 void AdditionalUserAddedToSession(Profile* profile); 348 349 // Get the list of all running incarnations of this item. 350 // |event_flags| specifies the flags which were set by the event which 351 // triggered this menu generation. It can be used to generate different lists. 352 ChromeLauncherAppMenuItems GetApplicationList(const ash::LauncherItem& item, 353 int event_flags); 354 355 // Get the list of all tabs which belong to a certain application type. 356 std::vector<content::WebContents*> GetV1ApplicationsFromAppId( 357 std::string app_id); 358 359 // Activates a specified shell application. 360 void ActivateShellApp(const std::string& app_id, int index); 361 362 // Checks if a given |web_contents| is known to be associated with an 363 // application of type |app_id|. 364 bool IsWebContentHandledByApplication(content::WebContents* web_contents, 365 const std::string& app_id); 366 367 // Check if the gMail app is loaded and it can handle the given web content. 368 // This special treatment is required to address crbug.com/234268. 369 bool ContentCanBeHandledByGmailApp(content::WebContents* web_contents); 370 371 // Get the favicon for the application list entry for |web_contents|. 372 // Note that for incognito windows the incognito icon will be returned. 373 // If |web_contents| has not loaded, returns the default favicon. 374 gfx::Image GetAppListIcon(content::WebContents* web_contents) const; 375 376 // Get the title for the applicatoin list entry for |web_contents|. 377 // If |web_contents| has not loaded, returns "Net Tab". 378 base::string16 GetAppListTitle(content::WebContents* web_contents) const; 379 380 // Returns the LauncherItemController of BrowserShortcut. 381 BrowserShortcutLauncherItemController* 382 GetBrowserShortcutLauncherItemController(); 383 384 LauncherItemController* GetLauncherItemController(const ash::LauncherID id); 385 386 // Returns true if |browser| is owned by the active user. 387 bool IsBrowserFromActiveUser(Browser* browser); 388 389 // Access to the BrowserStatusMonitor for tests. 390 BrowserStatusMonitor* browser_status_monitor_for_test() { 391 return browser_status_monitor_.get(); 392 } 393 394 // Access to the ShellWindowController for tests. 395 ShellWindowLauncherController* shell_window_controller_for_test() { 396 return shell_window_controller_.get(); 397 } 398 399 protected: 400 // Creates a new app shortcut item and controller on the launcher at |index|. 401 // Use kInsertItemAtEnd to add a shortcut as the last item. 402 ash::LauncherID CreateAppShortcutLauncherItem(const std::string& app_id, 403 int index); 404 405 // Sets the AppTabHelper/AppIconLoader, taking ownership of the helper class. 406 // These are intended for testing. 407 void SetAppTabHelperForTest(AppTabHelper* helper); 408 void SetAppIconLoaderForTest(extensions::AppIconLoader* loader); 409 const std::string& GetAppIdFromLauncherIdForTest(ash::LauncherID id); 410 411 // Sets the ash::ShelfItemDelegateManager only for unittests and doesn't 412 // take an ownership of it. 413 void SetShelfItemDelegateManagerForTest( 414 ash::ShelfItemDelegateManager* manager); 415 416 private: 417 friend class ChromeLauncherControllerTest; 418 friend class LauncherAppBrowserTest; 419 friend class LauncherPlatformAppBrowserTest; 420 421 typedef std::map<ash::LauncherID, LauncherItemController*> 422 IDToItemControllerMap; 423 typedef std::list<content::WebContents*> WebContentsList; 424 typedef std::map<std::string, WebContentsList> AppIDToWebContentsListMap; 425 typedef std::map<content::WebContents*, std::string> WebContentsToAppIDMap; 426 427 // Creates a new app shortcut item and controller on the launcher at |index|. 428 // Use kInsertItemAtEnd to add a shortcut as the last item. 429 ash::LauncherID CreateAppShortcutLauncherItemWithType( 430 const std::string& app_id, 431 int index, 432 ash::LauncherItemType launcher_item_type); 433 434 // Invoked when the associated browser or app is closed. 435 void LauncherItemClosed(ash::LauncherID id); 436 437 // Internal helpers for pinning and unpinning that handle both 438 // client-triggered and internal pinning operations. 439 void DoPinAppWithID(const std::string& app_id); 440 void DoUnpinAppWithID(const std::string& app_id); 441 442 // Pin a running app with |launcher_id| internally to |index|. It returns 443 // the index where the item was pinned. 444 int PinRunningAppInternal(int index, ash::LauncherID launcher_id); 445 446 // Unpin a locked application. This is an internal call which converts the 447 // model type of the given app index from a shortcut into an unpinned running 448 // app. 449 void UnpinRunningAppInternal(int index); 450 451 // Re-syncs launcher model with prefs::kPinnedLauncherApps. 452 void UpdateAppLaunchersFromPref(); 453 454 // Persists the shelf auto-hide behavior to prefs. 455 void SetShelfAutoHideBehaviorPrefs(ash::ShelfAutoHideBehavior behavior, 456 aura::Window* root_window); 457 458 // Sets the shelf auto-hide behavior from prefs. 459 void SetShelfAutoHideBehaviorFromPrefs(); 460 461 // Sets the shelf alignment from prefs. 462 void SetShelfAlignmentFromPrefs(); 463 464 // Sets both of auto-hide behavior and alignment from prefs. 465 void SetShelfBehaviorsFromPrefs(); 466 467 // Returns the most recently active web contents for an app. 468 content::WebContents* GetLastActiveWebContents(const std::string& app_id); 469 470 // Creates an app launcher to insert at |index|. Note that |index| may be 471 // adjusted by the model to meet ordering constraints. 472 // The |launcher_item_type| will be set into the ShelfModel. 473 ash::LauncherID InsertAppLauncherItem( 474 LauncherItemController* controller, 475 const std::string& app_id, 476 ash::LauncherItemStatus status, 477 int index, 478 ash::LauncherItemType launcher_item_type); 479 480 bool HasItemController(ash::LauncherID id) const; 481 482 // Enumerate all Web contents which match a given shortcut |controller|. 483 std::vector<content::WebContents*> GetV1ApplicationsFromController( 484 LauncherItemController* controller); 485 486 // Create LauncherItem for Browser Shortcut. 487 ash::LauncherID CreateBrowserShortcutLauncherItem(); 488 489 // Check if the given |web_contents| is in incognito mode. 490 bool IsIncognito(const content::WebContents* web_contents) const; 491 492 // Update browser shortcut's index. 493 void PersistChromeItemIndex(int index); 494 495 // Get browser shortcut's index from pref. 496 int GetChromeIconIndexFromPref() const; 497 498 // Depending on the provided flags, move either the chrome icon, the app icon 499 // or none to the given |target_index|. The provided |chrome_index| and 500 // |app_list_index| locations will get adjusted within this call to finalize 501 // the action and to make sure that the other item can still be moved 502 // afterwards (index adjustments). 503 void MoveChromeOrApplistToFinalPosition( 504 bool is_chrome, 505 bool is_app_list, 506 int target_index, 507 int* chrome_index, 508 int* app_list_index); 509 510 // Finds the index of where to insert the next item. 511 int FindInsertionPoint(bool is_app_list); 512 513 // Get the browser shortcut's index in the shelf using the current's systems 514 // configuration of pinned and known (but not running) apps. 515 int GetChromeIconIndexForCreation(); 516 517 // Get the list of pinned programs from the preferences. 518 std::vector<std::string> GetListOfPinnedAppsAndBrowser(); 519 520 // Close all windowed V1 applications of a certain extension which was already 521 // deleted. 522 void CloseWindowedAppsFromRemovedExtension(const std::string& app_id); 523 524 // Set ShelfItemDelegate |item_delegate| for |id| and take an ownership. 525 // TODO(simon.hong81): Make this take a scoped_ptr of |item_delegate|. 526 void SetShelfItemDelegate(ash::LauncherID id, 527 ash::ShelfItemDelegate* item_delegate); 528 529 // Attach to a specific profile. 530 void AttachProfile(Profile* proifile); 531 532 // Forget the current profile to allow attaching to a new one. 533 void ReleaseProfile(); 534 535 // Returns true if |app_id| is a Packaged App that has already launched on the 536 // native desktop and, if so, executes it as a desktop shortcut to activate 537 // desktop mode and send another OnLaunched event to the Extension. 538 bool LaunchedInNativeDesktop(const std::string& app_id); 539 540 static ChromeLauncherController* instance_; 541 542 ash::ShelfModel* model_; 543 544 ash::ShelfItemDelegateManager* item_delegate_manager_; 545 546 // Profile used for prefs and loading extensions. This is NOT necessarily the 547 // profile new windows are created with. 548 Profile* profile_; 549 550 IDToItemControllerMap id_to_item_controller_map_; 551 552 // Maintains activation order of web contents for each app. 553 AppIDToWebContentsListMap app_id_to_web_contents_list_; 554 555 // Direct access to app_id for a web contents. 556 WebContentsToAppIDMap web_contents_to_app_id_; 557 558 // Used to track shell windows. 559 scoped_ptr<ShellWindowLauncherController> shell_window_controller_; 560 561 // Used to get app info for tabs. 562 scoped_ptr<AppTabHelper> app_tab_helper_; 563 564 // Used to load the image for an app item. 565 scoped_ptr<extensions::AppIconLoader> app_icon_loader_; 566 567 content::NotificationRegistrar notification_registrar_; 568 569 PrefChangeRegistrar pref_change_registrar_; 570 571 AppSyncUIState* app_sync_ui_state_; 572 573 scoped_ptr<ExtensionEnableFlow> extension_enable_flow_; 574 575 // Launchers that are currently being observed. 576 std::set<ash::Launcher*> launchers_; 577 578 // The owned browser status monitor. 579 scoped_ptr<BrowserStatusMonitor> browser_status_monitor_; 580 581 // A special observer class to detect user switches. 582 scoped_ptr<ChromeLauncherControllerUserSwitchObserver> user_switch_observer_; 583 584 // If true, incoming pinned state changes should be ignored. 585 bool ignore_persist_pinned_state_change_; 586 587 // True if each user has an own desktop. 588 bool multi_profile_desktop_separation_; 589 590 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherController); 591 }; 592 593 #endif // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_H_ 594