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/shelf/shelf_delegate.h" 16 #include "ash/shelf/shelf_item_delegate.h" 17 #include "ash/shelf/shelf_item_types.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 AppWindowLauncherController; 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 windows have AppWindowLauncherItemController, owned by 91 // AppWindowLauncherController. 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 shelf 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 shelf for |controller|. 151 ash::ShelfID CreateAppLauncherItem(LauncherItemController* controller, 152 const std::string& app_id, 153 ash::ShelfItemStatus status); 154 155 // Updates the running status of an item. It will also update the status of 156 // browsers shelf item if needed. 157 void SetItemStatus(ash::ShelfID id, ash::ShelfItemStatus status); 158 159 // Updates the controller associated with id (which should be a shortcut). 160 // |controller| remains owned by caller. 161 void SetItemController(ash::ShelfID id, LauncherItemController* controller); 162 163 // Closes or unpins the shelf item. 164 void CloseLauncherItem(ash::ShelfID id); 165 166 // Pins the specified id. Currently only supports platform apps. 167 void Pin(ash::ShelfID id); 168 169 // Unpins the specified id, closing if not running. 170 void Unpin(ash::ShelfID id); 171 172 // Returns true if the item identified by |id| is pinned. 173 bool IsPinned(ash::ShelfID id); 174 175 // Pins/unpins the specified id. 176 void TogglePinned(ash::ShelfID id); 177 178 // Returns true if the specified item can be pinned or unpinned. Only apps can 179 // be pinned. 180 bool IsPinnable(ash::ShelfID id) const; 181 182 // Installs the specified id. Only valid if the id corresponds to an ephemeral 183 // app. 184 void Install(ash::ShelfID id); 185 186 // Returns true if the specified item can be installed. Only true for 187 // ephemeral apps. 188 bool CanInstall(ash::ShelfID id); 189 190 // If there is no shelf item in the shelf for application |app_id|, one 191 // gets created. The (existing or created) shelf items get then locked 192 // against a users un-pinning removal. 193 void LockV1AppWithID(const std::string& app_id); 194 195 // A previously locked shelf item of type |app_id| gets unlocked. If the 196 // lock count reaches 0 and the item is not pinned it will go away. 197 void UnlockV1AppWithID(const std::string& app_id); 198 199 // Requests that the shelf item controller specified by |id| open a new 200 // instance of the app. |event_flags| holds the flags of the event which 201 // triggered this command. 202 void Launch(ash::ShelfID id, int event_flags); 203 204 // Closes the specified item. 205 void Close(ash::ShelfID id); 206 207 // Returns true if the specified item is open. 208 bool IsOpen(ash::ShelfID id); 209 210 // Returns true if the specified item is for a platform app. 211 bool IsPlatformApp(ash::ShelfID id); 212 213 // Opens a new instance of the application identified by |app_id|. 214 // Used by the app-list, and by pinned-app shelf items. 215 void LaunchApp(const std::string& app_id, 216 ash::LaunchSource source, 217 int event_flags); 218 219 // If |app_id| is running, reactivates the app's most recently active window, 220 // otherwise launches and activates the app. 221 // Used by the app-list, and by pinned-app shelf items. 222 void ActivateApp(const std::string& app_id, 223 ash::LaunchSource source, 224 int event_flags); 225 226 // Returns the launch type of app for the specified id. 227 extensions::LaunchType GetLaunchType(ash::ShelfID id); 228 229 // Set the image for a specific shelf item (e.g. when set by the app). 230 void SetLauncherItemImage(ash::ShelfID shelf_id, const gfx::ImageSkia& image); 231 232 // Find out if the given application |id| is a windowed app item and not a 233 // pinned item in the shelf. 234 bool IsWindowedAppInLauncher(const std::string& app_id); 235 236 // Updates the launch type of the app for the specified id to |launch_type|. 237 void SetLaunchType(ash::ShelfID id, extensions::LaunchType launch_type); 238 239 // Returns true if the user is currently logged in as a guest. 240 // Makes virtual for unittest in LauncherContextMenuTest. 241 virtual bool IsLoggedInAsGuest(); 242 243 // Invoked when user clicks on button in the shelf and there is no last 244 // used window (or CTRL is held with the click). 245 void CreateNewWindow(); 246 247 // Invoked when the user clicks on button in the shelf to create a new 248 // incognito window. 249 void CreateNewIncognitoWindow(); 250 251 // Updates the pinned pref state. The pinned state consists of a list pref. 252 // Each item of the list is a dictionary. The key |kAppIDPath| gives the 253 // id of the app. 254 void PersistPinnedState(); 255 256 ash::ShelfModel* model(); 257 258 // Accessor to the currently loaded profile. Note that in multi profile use 259 // cases this might change over time. 260 Profile* profile(); 261 262 // Gets the shelf auto-hide behavior on |root_window|. 263 ash::ShelfAutoHideBehavior GetShelfAutoHideBehavior( 264 aura::Window* root_window) const; 265 266 // Returns |true| if the user is allowed to modify the shelf auto-hide 267 // behavior on |root_window|. 268 bool CanUserModifyShelfAutoHideBehavior(aura::Window* root_window) const; 269 270 // Toggles the shelf auto-hide behavior on |root_window|. Does nothing if the 271 // user is not allowed to modify the auto-hide behavior. 272 void ToggleShelfAutoHideBehavior(aura::Window* root_window); 273 274 // Notify the controller that the state of an non platform app's tabs 275 // have changed, 276 void UpdateAppState(content::WebContents* contents, AppState app_state); 277 278 // Returns ShelfID for |contents|. If |contents| is not an app or is not 279 // pinned, returns the id of browser shrotcut. 280 ash::ShelfID GetShelfIDForWebContents(content::WebContents* contents); 281 282 // Limits application refocusing to urls that match |url| for |id|. 283 void SetRefocusURLPatternForTest(ash::ShelfID id, const GURL& url); 284 285 // Returns the extension identified by |app_id|. 286 const extensions::Extension* GetExtensionForAppID( 287 const std::string& app_id) const; 288 289 // Activates a |window|. If |allow_minimize| is true and the system allows 290 // it, the the window will get minimized instead. 291 void ActivateWindowOrMinimizeIfActive(ui::BaseWindow* window, 292 bool allow_minimize); 293 294 // ash::ShelfDelegate overrides: 295 virtual void OnShelfCreated(ash::Shelf* shelf) OVERRIDE; 296 virtual void OnShelfDestroyed(ash::Shelf* shelf) OVERRIDE; 297 virtual ash::ShelfID GetShelfIDForAppID(const std::string& app_id) OVERRIDE; 298 virtual const std::string& GetAppIDForShelfID(ash::ShelfID 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::ShelfID id) OVERRIDE; 307 virtual void ShelfItemMoved(int start_index, int target_index) OVERRIDE; 308 virtual void ShelfItemChanged(int index, 309 const ash::ShelfItem& 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 OnDisplayConfigurationChanged() OVERRIDE; 322 323 // PrefServiceSyncableObserver overrides: 324 virtual void OnIsSyncingChanged() OVERRIDE; 325 326 // AppSyncUIStateObserver overrides: 327 virtual void OnAppSyncUIStatusChanged() OVERRIDE; 328 329 // ExtensionEnableFlowDelegate overrides: 330 virtual void ExtensionEnableFlowFinished() OVERRIDE; 331 virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE; 332 333 // extensions::AppIconLoader overrides: 334 virtual void SetAppImage(const std::string& app_id, 335 const gfx::ImageSkia& image) OVERRIDE; 336 337 // ash::ShelfLayoutManagerObserver overrides: 338 virtual void OnAutoHideBehaviorChanged( 339 aura::Window* root_window, 340 ash::ShelfAutoHideBehavior new_behavior) OVERRIDE; 341 342 // Called when the active user has changed. 343 void ActiveUserChanged(const std::string& user_email); 344 345 // Called when a user got added to the session. 346 void AdditionalUserAddedToSession(Profile* profile); 347 348 // Get the list of all running incarnations of this item. 349 // |event_flags| specifies the flags which were set by the event which 350 // triggered this menu generation. It can be used to generate different lists. 351 ChromeLauncherAppMenuItems GetApplicationList(const ash::ShelfItem& item, 352 int event_flags); 353 354 // Get the list of all tabs which belong to a certain application type. 355 std::vector<content::WebContents*> GetV1ApplicationsFromAppId( 356 std::string app_id); 357 358 // Activates a specified shell application. 359 void ActivateShellApp(const std::string& app_id, int index); 360 361 // Checks if a given |web_contents| is known to be associated with an 362 // application of type |app_id|. 363 bool IsWebContentHandledByApplication(content::WebContents* web_contents, 364 const std::string& app_id); 365 366 // Check if the gMail app is loaded and it can handle the given web content. 367 // This special treatment is required to address crbug.com/234268. 368 bool ContentCanBeHandledByGmailApp(content::WebContents* web_contents); 369 370 // Get the favicon for the application list entry for |web_contents|. 371 // Note that for incognito windows the incognito icon will be returned. 372 // If |web_contents| has not loaded, returns the default favicon. 373 gfx::Image GetAppListIcon(content::WebContents* web_contents) const; 374 375 // Get the title for the applicatoin list entry for |web_contents|. 376 // If |web_contents| has not loaded, returns "Net Tab". 377 base::string16 GetAppListTitle(content::WebContents* web_contents) const; 378 379 // Returns the LauncherItemController of BrowserShortcut. 380 BrowserShortcutLauncherItemController* 381 GetBrowserShortcutLauncherItemController(); 382 383 LauncherItemController* GetLauncherItemController(const ash::ShelfID id); 384 385 // Returns true if |browser| is owned by the active user. 386 bool IsBrowserFromActiveUser(Browser* browser); 387 388 // Access to the BrowserStatusMonitor for tests. 389 BrowserStatusMonitor* browser_status_monitor_for_test() { 390 return browser_status_monitor_.get(); 391 } 392 393 // Access to the AppWindowLauncherController for tests. 394 AppWindowLauncherController* app_window_controller_for_test() { 395 return app_window_controller_.get(); 396 } 397 398 protected: 399 // Creates a new app shortcut item and controller on the shelf at |index|. 400 // Use kInsertItemAtEnd to add a shortcut as the last item. 401 ash::ShelfID CreateAppShortcutLauncherItem(const std::string& app_id, 402 int index); 403 404 // Sets the AppTabHelper/AppIconLoader, taking ownership of the helper class. 405 // These are intended for testing. 406 void SetAppTabHelperForTest(AppTabHelper* helper); 407 void SetAppIconLoaderForTest(extensions::AppIconLoader* loader); 408 const std::string& GetAppIdFromShelfIdForTest(ash::ShelfID id); 409 410 // Sets the ash::ShelfItemDelegateManager only for unittests and doesn't 411 // take an ownership of it. 412 void SetShelfItemDelegateManagerForTest( 413 ash::ShelfItemDelegateManager* manager); 414 415 private: 416 friend class ChromeLauncherControllerTest; 417 friend class ShelfAppBrowserTest; 418 friend class LauncherPlatformAppBrowserTest; 419 420 typedef std::map<ash::ShelfID, LauncherItemController*> IDToItemControllerMap; 421 typedef std::map<content::WebContents*, std::string> WebContentsToAppIDMap; 422 423 // Remembers / restores list of running applications. 424 // Note that this order will neither be stored in the preference nor will it 425 // remember the order of closed applications since it is only temporary. 426 void RememberUnpinnedRunningApplicationOrder(); 427 void RestoreUnpinnedRunningApplicationOrder(const std::string& user_id); 428 429 // Creates a new app shortcut item and controller on the shelf at |index|. 430 // Use kInsertItemAtEnd to add a shortcut as the last item. 431 ash::ShelfID CreateAppShortcutLauncherItemWithType( 432 const std::string& app_id, 433 int index, 434 ash::ShelfItemType shelf_item_type); 435 436 // Invoked when the associated browser or app is closed. 437 void LauncherItemClosed(ash::ShelfID id); 438 439 // Internal helpers for pinning and unpinning that handle both 440 // client-triggered and internal pinning operations. 441 void DoPinAppWithID(const std::string& app_id); 442 void DoUnpinAppWithID(const std::string& app_id); 443 444 // Pin a running app with |shelf_id| internally to |index|. It returns 445 // the index where the item was pinned. 446 int PinRunningAppInternal(int index, ash::ShelfID shelf_id); 447 448 // Unpin a locked application. This is an internal call which converts the 449 // model type of the given app index from a shortcut into an unpinned running 450 // app. 451 void UnpinRunningAppInternal(int index); 452 453 // Re-syncs shelf model with prefs::kPinnedLauncherApps. 454 void UpdateAppLaunchersFromPref(); 455 456 // Persists the shelf auto-hide behavior to prefs. 457 void SetShelfAutoHideBehaviorPrefs(ash::ShelfAutoHideBehavior behavior, 458 aura::Window* root_window); 459 460 // Sets the shelf auto-hide behavior from prefs. 461 void SetShelfAutoHideBehaviorFromPrefs(); 462 463 // Sets the shelf alignment from prefs. 464 void SetShelfAlignmentFromPrefs(); 465 466 // Sets both of auto-hide behavior and alignment from prefs. 467 void SetShelfBehaviorsFromPrefs(); 468 469 #if defined(OS_CHROMEOS) 470 // Sets whether the virtual keyboard is enabled from prefs. 471 void SetVirtualKeyboardBehaviorFromPrefs(); 472 #endif // defined(OS_CHROMEOS) 473 474 // Returns the shelf item status for the given |app_id|, which can be either 475 // STATUS_ACTIVE (if the app is active), STATUS_RUNNING (if there is such an 476 // app) or STATUS_CLOSED. 477 ash::ShelfItemStatus GetAppState(const::std::string& app_id); 478 479 // Creates an app launcher to insert at |index|. Note that |index| may be 480 // adjusted by the model to meet ordering constraints. 481 // The |shelf_item_type| will be set into the ShelfModel. 482 ash::ShelfID InsertAppLauncherItem(LauncherItemController* controller, 483 const std::string& app_id, 484 ash::ShelfItemStatus status, 485 int index, 486 ash::ShelfItemType shelf_item_type); 487 488 bool HasItemController(ash::ShelfID id) const; 489 490 // Enumerate all Web contents which match a given shortcut |controller|. 491 std::vector<content::WebContents*> GetV1ApplicationsFromController( 492 LauncherItemController* controller); 493 494 // Create ShelfItem for Browser Shortcut. 495 ash::ShelfID CreateBrowserShortcutLauncherItem(); 496 497 // Check if the given |web_contents| is in incognito mode. 498 bool IsIncognito(const content::WebContents* web_contents) const; 499 500 // Update browser shortcut's index. 501 void PersistChromeItemIndex(int index); 502 503 // Get browser shortcut's index from pref. 504 int GetChromeIconIndexFromPref() const; 505 506 // Depending on the provided flags, move either the chrome icon, the app icon 507 // or none to the given |target_index|. The provided |chrome_index| and 508 // |app_list_index| locations will get adjusted within this call to finalize 509 // the action and to make sure that the other item can still be moved 510 // afterwards (index adjustments). 511 void MoveChromeOrApplistToFinalPosition( 512 bool is_chrome, 513 bool is_app_list, 514 int target_index, 515 int* chrome_index, 516 int* app_list_index); 517 518 // Finds the index of where to insert the next item. 519 int FindInsertionPoint(bool is_app_list); 520 521 // Get the browser shortcut's index in the shelf using the current's systems 522 // configuration of pinned and known (but not running) apps. 523 int GetChromeIconIndexForCreation(); 524 525 // Get the list of pinned programs from the preferences. 526 std::vector<std::string> GetListOfPinnedAppsAndBrowser(); 527 528 // Close all windowed V1 applications of a certain extension which was already 529 // deleted. 530 void CloseWindowedAppsFromRemovedExtension(const std::string& app_id); 531 532 // Set ShelfItemDelegate |item_delegate| for |id| and take an ownership. 533 // TODO(simon.hong81): Make this take a scoped_ptr of |item_delegate|. 534 void SetShelfItemDelegate(ash::ShelfID id, 535 ash::ShelfItemDelegate* item_delegate); 536 537 // Attach to a specific profile. 538 void AttachProfile(Profile* proifile); 539 540 // Forget the current profile to allow attaching to a new one. 541 void ReleaseProfile(); 542 543 // Returns true if |app_id| is a Packaged App that has already launched on the 544 // native desktop and, if so, executes it as a desktop shortcut to activate 545 // desktop mode and send another OnLaunched event to the Extension. 546 bool LaunchedInNativeDesktop(const std::string& app_id); 547 548 static ChromeLauncherController* instance_; 549 550 ash::ShelfModel* model_; 551 552 ash::ShelfItemDelegateManager* item_delegate_manager_; 553 554 // Profile used for prefs and loading extensions. This is NOT necessarily the 555 // profile new windows are created with. 556 Profile* profile_; 557 558 IDToItemControllerMap id_to_item_controller_map_; 559 560 // Direct access to app_id for a web contents. 561 WebContentsToAppIDMap web_contents_to_app_id_; 562 563 // Used to track app windows. 564 scoped_ptr<AppWindowLauncherController> app_window_controller_; 565 566 // Used to get app info for tabs. 567 scoped_ptr<AppTabHelper> app_tab_helper_; 568 569 // Used to load the image for an app item. 570 scoped_ptr<extensions::AppIconLoader> app_icon_loader_; 571 572 content::NotificationRegistrar notification_registrar_; 573 574 PrefChangeRegistrar pref_change_registrar_; 575 576 AppSyncUIState* app_sync_ui_state_; 577 578 scoped_ptr<ExtensionEnableFlow> extension_enable_flow_; 579 580 // Shelves that are currently being observed. 581 std::set<ash::Shelf*> shelves_; 582 583 // The owned browser status monitor. 584 scoped_ptr<BrowserStatusMonitor> browser_status_monitor_; 585 586 // A special observer class to detect user switches. 587 scoped_ptr<ChromeLauncherControllerUserSwitchObserver> user_switch_observer_; 588 589 // If true, incoming pinned state changes should be ignored. 590 bool ignore_persist_pinned_state_change_; 591 592 // True if each user has an own desktop. 593 bool multi_profile_desktop_separation_; 594 595 // The list of running & un-pinned applications for different users on hidden 596 // desktops. 597 typedef std::vector<std::string> RunningAppListIds; 598 typedef std::map<std::string, RunningAppListIds> RunningAppListIdMap; 599 RunningAppListIdMap last_used_running_application_order_; 600 601 DISALLOW_COPY_AND_ASSIGN(ChromeLauncherController); 602 }; 603 604 #endif // CHROME_BROWSER_UI_ASH_LAUNCHER_CHROME_LAUNCHER_CONTROLLER_H_ 605