Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "apps/app_shim/extension_app_shim_handler_mac.h" | 5 #include "apps/app_shim/extension_app_shim_handler_mac.h" |
| 6 | 6 |
| 7 #include "apps/app_lifetime_monitor_factory.h" | 7 #include "apps/app_lifetime_monitor_factory.h" |
| 8 #include "apps/app_shim/app_shim_messages.h" | 8 #include "apps/app_shim/app_shim_messages.h" |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "chrome/browser/browser_process.h" | 11 #include "chrome/browser/browser_process.h" |
| 12 #include "chrome/browser/extensions/extension_host.h" | 12 #include "chrome/browser/extensions/extension_host.h" |
| 13 #include "chrome/browser/extensions/extension_service.h" | 13 #include "chrome/browser/extensions/extension_service.h" |
| 14 #include "chrome/browser/extensions/extension_system.h" | 14 #include "chrome/browser/extensions/extension_system.h" |
| 15 #include "chrome/browser/extensions/shell_window_registry.h" | 15 #include "chrome/browser/extensions/shell_window_registry.h" |
| 16 #include "chrome/browser/profiles/profile.h" | 16 #include "chrome/browser/profiles/profile.h" |
| 17 #include "chrome/browser/profiles/profile_manager.h" | 17 #include "chrome/browser/profiles/profile_manager.h" |
| 18 #include "chrome/browser/ui/extensions/application_launch.h" | 18 #include "chrome/browser/ui/extensions/application_launch.h" |
| 19 #include "chrome/browser/ui/extensions/native_app_window.h" | 19 #include "chrome/browser/ui/extensions/native_app_window.h" |
| 20 #include "chrome/browser/ui/extensions/shell_window.h" | 20 #include "chrome/browser/ui/extensions/shell_window.h" |
| 21 #include "chrome/browser/ui/web_applications/web_app_ui.h" | 21 #include "chrome/browser/ui/web_applications/web_app_ui.h" |
| 22 #include "chrome/browser/web_applications/web_app_mac.h" | 22 #include "chrome/browser/web_applications/web_app_mac.h" |
| 23 #include "chrome/common/chrome_notification_types.h" | 23 #include "chrome/common/chrome_notification_types.h" |
| 24 #include "content/public/browser/notification_details.h" | 24 #include "content/public/browser/notification_details.h" |
| 25 #include "content/public/browser/notification_service.h" | 25 #include "content/public/browser/notification_service.h" |
| 26 #include "content/public/browser/notification_source.h" | 26 #include "content/public/browser/notification_source.h" |
| 27 #include "ui/base/cocoa/focus_window_set.h" | 27 #include "ui/base/cocoa/focus_window_set.h" |
| 28 | 28 |
| 29 namespace { | 29 namespace apps { |
| 30 | 30 |
| 31 typedef extensions::ShellWindowRegistry::ShellWindowList ShellWindowList; | 31 typedef extensions::ShellWindowRegistry::ShellWindowList ShellWindowList; |
| 32 | 32 |
| 33 ShellWindowList GetWindows(Profile* profile, const std::string& extension_id) { | 33 bool ExtensionAppShimHandler::Delegate::ProfileExistsForPath( |
| 34 return extensions::ShellWindowRegistry::Get(profile)-> | |
| 35 GetShellWindowsForApp(extension_id); | |
| 36 } | |
| 37 | |
| 38 const extensions::Extension* GetExtension(Profile* profile, | |
| 39 const std::string& extension_id) { | |
| 40 return extensions::ExtensionSystem::Get(profile)->extension_service()-> | |
| 41 GetExtensionById(extension_id, false); | |
| 42 } | |
| 43 | |
| 44 } // namespace | |
| 45 | |
| 46 namespace apps { | |
| 47 | |
| 48 bool ExtensionAppShimHandler::ProfileManagerFacade::ProfileExistsForPath( | |
| 49 const base::FilePath& path) { | 34 const base::FilePath& path) { |
| 50 ProfileManager* profile_manager = g_browser_process->profile_manager(); | 35 ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| 51 // Check for the profile name in the profile info cache to ensure that we | 36 // Check for the profile name in the profile info cache to ensure that we |
| 52 // never access any directory that isn't a known profile. | 37 // never access any directory that isn't a known profile. |
| 53 base::FilePath full_path = profile_manager->user_data_dir().Append(path); | 38 base::FilePath full_path = profile_manager->user_data_dir().Append(path); |
| 54 ProfileInfoCache& cache = profile_manager->GetProfileInfoCache(); | 39 ProfileInfoCache& cache = profile_manager->GetProfileInfoCache(); |
| 55 return cache.GetIndexOfProfileWithPath(full_path) != std::string::npos; | 40 return cache.GetIndexOfProfileWithPath(full_path) != std::string::npos; |
| 56 } | 41 } |
| 57 | 42 |
| 58 Profile* ExtensionAppShimHandler::ProfileManagerFacade::ProfileForPath( | 43 Profile* ExtensionAppShimHandler::Delegate::ProfileForPath( |
| 59 const base::FilePath& path) { | 44 const base::FilePath& path) { |
| 60 return g_browser_process->profile_manager()->GetProfile(path); | 45 return g_browser_process->profile_manager()->GetProfile(path); |
| 61 } | 46 } |
| 62 | 47 |
| 48 ShellWindowList ExtensionAppShimHandler::Delegate::GetWindows( | |
| 49 Profile* profile, | |
| 50 const std::string& extension_id) { | |
| 51 return extensions::ShellWindowRegistry::Get(profile)-> | |
| 52 GetShellWindowsForApp(extension_id); | |
| 53 } | |
| 54 | |
| 55 const extensions::Extension* | |
| 56 ExtensionAppShimHandler::Delegate::GetExtension( | |
|
tapted
2013/06/21 04:30:47
since the is_platform_app check is moving in here,
jackhou1
2013/06/21 05:46:27
Done.
| |
| 57 Profile* profile, | |
| 58 const std::string& extension_id) { | |
| 59 const extensions::Extension* extension = | |
| 60 extensions::ExtensionSystem::Get(profile)->extension_service()-> | |
|
tapted
2013/06/21 04:30:47
Should DCHECK here that that extension_service is
jackhou1
2013/06/21 05:46:27
Done.
| |
| 61 GetExtensionById(extension_id, false); | |
| 62 return extension && extension->is_platform_app() ? extension : NULL; | |
| 63 } | |
| 64 | |
| 65 content::WebContents* ExtensionAppShimHandler::Delegate::LaunchApp( | |
| 66 Profile* profile, | |
| 67 const extensions::Extension* extension) { | |
| 68 return chrome::OpenApplication(chrome::AppLaunchParams( | |
| 69 profile, extension, NEW_FOREGROUND_TAB)); | |
| 70 } | |
| 71 | |
| 72 void ExtensionAppShimHandler::Delegate::LaunchShim( | |
| 73 Profile* profile, | |
| 74 const extensions::Extension* extension) { | |
| 75 web_app::MaybeLaunchShortcut( | |
| 76 web_app::ShortcutInfoForExtensionAndProfile(extension, profile)); | |
| 77 } | |
| 78 | |
| 63 ExtensionAppShimHandler::ExtensionAppShimHandler() | 79 ExtensionAppShimHandler::ExtensionAppShimHandler() |
| 64 : profile_manager_facade_(new ProfileManagerFacade) { | 80 : delegate_(new Delegate) { |
| 65 // This is instantiated in BrowserProcessImpl::PreMainMessageLoopRun with | 81 // This is instantiated in BrowserProcessImpl::PreMainMessageLoopRun with |
| 66 // AppShimHostManager. Since PROFILE_CREATED is not fired until | 82 // AppShimHostManager. Since PROFILE_CREATED is not fired until |
| 67 // ProfileManager::GetLastUsedProfile/GetLastOpenedProfiles, this should catch | 83 // ProfileManager::GetLastUsedProfile/GetLastOpenedProfiles, this should catch |
| 68 // notifications for all profiles. | 84 // notifications for all profiles. |
| 69 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, | 85 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, |
| 70 content::NotificationService::AllBrowserContextsAndSources()); | 86 content::NotificationService::AllBrowserContextsAndSources()); |
| 71 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | 87 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
| 72 content::NotificationService::AllBrowserContextsAndSources()); | 88 content::NotificationService::AllBrowserContextsAndSources()); |
| 73 } | 89 } |
| 74 | 90 |
| 75 ExtensionAppShimHandler::~ExtensionAppShimHandler() {} | 91 ExtensionAppShimHandler::~ExtensionAppShimHandler() {} |
| 76 | 92 |
| 77 bool ExtensionAppShimHandler::OnShimLaunch(Host* host, | 93 bool ExtensionAppShimHandler::OnShimLaunch(Host* host, |
| 78 AppShimLaunchType launch_type) { | 94 AppShimLaunchType launch_type) { |
| 79 const base::FilePath& profile_path = host->GetProfilePath(); | 95 const base::FilePath& profile_path = host->GetProfilePath(); |
| 80 DCHECK(!profile_path.empty()); | 96 DCHECK(!profile_path.empty()); |
| 81 | 97 |
| 82 if (!profile_manager_facade_->ProfileExistsForPath(profile_path)) { | 98 if (!delegate_->ProfileExistsForPath(profile_path)) { |
| 83 // User may have deleted the profile this shim was originally created for. | 99 // User may have deleted the profile this shim was originally created for. |
| 84 // TODO(jackhou): Add some UI for this case and remove the LOG. | 100 // TODO(jackhou): Add some UI for this case and remove the LOG. |
| 85 LOG(ERROR) << "Requested directory is not a known profile '" | 101 LOG(ERROR) << "Requested directory is not a known profile '" |
| 86 << profile_path.value() << "'."; | 102 << profile_path.value() << "'."; |
| 87 return false; | 103 return false; |
| 88 } | 104 } |
| 89 | 105 |
| 90 Profile* profile = profile_manager_facade_->ProfileForPath(profile_path); | 106 Profile* profile = delegate_->ProfileForPath(profile_path); |
| 91 | 107 |
| 92 const std::string& app_id = host->GetAppId(); | 108 const std::string& app_id = host->GetAppId(); |
| 93 if (!extensions::Extension::IdIsValid(app_id)) { | 109 if (!extensions::Extension::IdIsValid(app_id)) { |
| 94 LOG(ERROR) << "Bad app ID from app shim launch message."; | 110 LOG(ERROR) << "Bad app ID from app shim launch message."; |
| 95 return false; | 111 return false; |
| 96 } | 112 } |
| 97 | 113 |
| 98 // TODO(jackhou): Add some UI for this case and remove the LOG. | 114 // TODO(jackhou): Add some UI for this case and remove the LOG. |
| 99 if (!LaunchApp(profile, app_id, launch_type)) | 115 const extensions::Extension* extension = |
| 116 delegate_->GetExtension(profile, app_id); | |
| 117 if (!extension) { | |
| 118 LOG(ERROR) << "Attempted to launch nonexistent app with id '" | |
| 119 << app_id << "'."; | |
| 100 return false; | 120 return false; |
| 121 } | |
| 122 | |
| 123 if (launch_type == APP_SHIM_LAUNCH_REGISTER_ONLY && | |
|
tapted
2013/06/21 04:30:47
needs curlies if the condition is multi-line
jackhou1
2013/06/21 05:46:27
Done.
| |
| 124 delegate_->GetWindows(profile, app_id).empty()) | |
|
tapted
2013/06/21 04:30:47
Should this be !empty()?
Maybe a comment, like ~"
jackhou1
2013/06/21 05:46:27
It should be empty(), because it returns false if
| |
| 125 return false; | |
| 126 | |
| 127 // TODO(jeremya): Handle the case that launching the app fails. Probably we | |
| 128 // need to watch for 'app successfully launched' or at least 'background page | |
| 129 // exists/was created' and time out with failure if we don't see that sign of | |
| 130 // life within a certain window. | |
| 131 if (launch_type == APP_SHIM_LAUNCH_NORMAL) | |
| 132 delegate_->LaunchApp(profile, extension); | |
|
tapted
2013/06/21 04:30:47
Should it return false if LaunchApp returns NULL h
jackhou1
2013/06/21 05:46:27
Turns out LaunchApplication always returns NULL fo
| |
| 101 | 133 |
| 102 // The first host to claim this (profile, app_id) becomes the main host. | 134 // The first host to claim this (profile, app_id) becomes the main host. |
| 103 // For any others, focus the app and return false. | 135 // For any others, focus the app and return false. |
| 104 if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) { | 136 if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) { |
| 105 OnShimFocus(host); | 137 OnShimFocus(host); |
| 106 return false; | 138 return false; |
| 107 } | 139 } |
| 108 | 140 |
| 109 return true; | 141 return true; |
| 110 } | 142 } |
| 111 | 143 |
| 112 void ExtensionAppShimHandler::OnShimClose(Host* host) { | 144 void ExtensionAppShimHandler::OnShimClose(Host* host) { |
| 113 DCHECK(profile_manager_facade_->ProfileExistsForPath( | 145 DCHECK(delegate_->ProfileExistsForPath( |
|
tapted
2013/06/21 04:30:47
nit: can this fit on the line above now?
jackhou1
2013/06/21 05:46:27
Done.
| |
| 114 host->GetProfilePath())); | 146 host->GetProfilePath())); |
| 115 Profile* profile = | 147 Profile* profile = |
| 116 profile_manager_facade_->ProfileForPath(host->GetProfilePath()); | 148 delegate_->ProfileForPath(host->GetProfilePath()); |
|
tapted
2013/06/21 04:30:47
nit: one line?
up to 6 more below too
jackhou1
2013/06/21 05:46:27
Done.
| |
| 117 | 149 |
| 118 HostMap::iterator it = hosts_.find(make_pair(profile, host->GetAppId())); | 150 HostMap::iterator it = hosts_.find(make_pair(profile, host->GetAppId())); |
| 119 // Any hosts other than the main host will still call OnShimClose, so ignore | 151 // Any hosts other than the main host will still call OnShimClose, so ignore |
| 120 // them. | 152 // them. |
| 121 if (it != hosts_.end() && it->second == host) | 153 if (it != hosts_.end() && it->second == host) |
| 122 hosts_.erase(it); | 154 hosts_.erase(it); |
| 123 } | 155 } |
| 124 | 156 |
| 125 void ExtensionAppShimHandler::OnShimFocus(Host* host) { | 157 void ExtensionAppShimHandler::OnShimFocus(Host* host) { |
| 126 DCHECK(profile_manager_facade_->ProfileExistsForPath( | 158 DCHECK(delegate_->ProfileExistsForPath( |
| 127 host->GetProfilePath())); | 159 host->GetProfilePath())); |
| 128 Profile* profile = | 160 Profile* profile = |
| 129 profile_manager_facade_->ProfileForPath(host->GetProfilePath()); | 161 delegate_->ProfileForPath(host->GetProfilePath()); |
| 130 | 162 |
| 131 const ShellWindowList windows = GetWindows(profile, host->GetAppId()); | 163 const ShellWindowList windows = |
| 164 delegate_->GetWindows(profile, host->GetAppId()); | |
| 132 std::set<gfx::NativeWindow> native_windows; | 165 std::set<gfx::NativeWindow> native_windows; |
| 133 for (ShellWindowList::const_iterator it = windows.begin(); | 166 for (ShellWindowList::const_iterator it = windows.begin(); |
| 134 it != windows.end(); ++it) { | 167 it != windows.end(); ++it) { |
| 135 native_windows.insert((*it)->GetNativeWindow()); | 168 native_windows.insert((*it)->GetNativeWindow()); |
| 136 } | 169 } |
| 137 ui::FocusWindowSet(native_windows); | 170 ui::FocusWindowSet(native_windows); |
| 138 } | 171 } |
| 139 | 172 |
| 140 void ExtensionAppShimHandler::OnShimQuit(Host* host) { | 173 void ExtensionAppShimHandler::OnShimQuit(Host* host) { |
| 141 DCHECK(profile_manager_facade_->ProfileExistsForPath( | 174 DCHECK(delegate_->ProfileExistsForPath( |
| 142 host->GetProfilePath())); | 175 host->GetProfilePath())); |
| 143 Profile* profile = | 176 Profile* profile = |
| 144 profile_manager_facade_->ProfileForPath(host->GetProfilePath()); | 177 delegate_->ProfileForPath(host->GetProfilePath()); |
| 145 | 178 |
| 146 const ShellWindowList windows = GetWindows(profile, host->GetAppId()); | 179 const ShellWindowList windows = |
| 180 delegate_->GetWindows(profile, host->GetAppId()); | |
| 147 for (extensions::ShellWindowRegistry::const_iterator it = windows.begin(); | 181 for (extensions::ShellWindowRegistry::const_iterator it = windows.begin(); |
| 148 it != windows.end(); ++it) { | 182 it != windows.end(); ++it) { |
| 149 (*it)->GetBaseWindow()->Close(); | 183 (*it)->GetBaseWindow()->Close(); |
| 150 } | 184 } |
| 151 } | 185 } |
| 152 | 186 |
| 153 void ExtensionAppShimHandler::set_profile_manager_facade( | 187 void ExtensionAppShimHandler::set_dependency_facade( |
| 154 ProfileManagerFacade* profile_manager_facade) { | 188 Delegate* dependency_facade) { |
| 155 profile_manager_facade_.reset(profile_manager_facade); | 189 delegate_.reset(dependency_facade); |
| 156 } | |
| 157 | |
| 158 bool ExtensionAppShimHandler::LaunchApp(Profile* profile, | |
| 159 const std::string& app_id, | |
| 160 AppShimLaunchType launch_type) { | |
| 161 const extensions::Extension* extension = GetExtension(profile, app_id); | |
| 162 if (!extension) { | |
| 163 LOG(ERROR) << "Attempted to launch nonexistent app with id '" | |
| 164 << app_id << "'."; | |
| 165 return false; | |
| 166 } | |
| 167 | |
| 168 if (launch_type == APP_SHIM_LAUNCH_REGISTER_ONLY) | |
| 169 return !GetWindows(profile, app_id).empty(); | |
| 170 | |
| 171 // TODO(jeremya): Handle the case that launching the app fails. Probably we | |
| 172 // need to watch for 'app successfully launched' or at least 'background page | |
| 173 // exists/was created' and time out with failure if we don't see that sign of | |
| 174 // life within a certain window. | |
| 175 chrome::OpenApplication(chrome::AppLaunchParams( | |
| 176 profile, extension, NEW_FOREGROUND_TAB)); | |
| 177 return true; | |
| 178 } | 190 } |
| 179 | 191 |
| 180 void ExtensionAppShimHandler::Observe( | 192 void ExtensionAppShimHandler::Observe( |
| 181 int type, | 193 int type, |
| 182 const content::NotificationSource& source, | 194 const content::NotificationSource& source, |
| 183 const content::NotificationDetails& details) { | 195 const content::NotificationDetails& details) { |
| 184 Profile* profile = content::Source<Profile>(source).ptr(); | 196 Profile* profile = content::Source<Profile>(source).ptr(); |
| 185 if (profile->IsOffTheRecord()) | 197 if (profile->IsOffTheRecord()) |
| 186 return; | 198 return; |
| 187 | 199 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 204 NOTREACHED(); // Unexpected notification. | 216 NOTREACHED(); // Unexpected notification. |
| 205 break; | 217 break; |
| 206 } | 218 } |
| 207 } | 219 } |
| 208 | 220 |
| 209 void ExtensionAppShimHandler::OnAppStart(Profile* profile, | 221 void ExtensionAppShimHandler::OnAppStart(Profile* profile, |
| 210 const std::string& app_id) {} | 222 const std::string& app_id) {} |
| 211 | 223 |
| 212 void ExtensionAppShimHandler::OnAppActivated(Profile* profile, | 224 void ExtensionAppShimHandler::OnAppActivated(Profile* profile, |
| 213 const std::string& app_id) { | 225 const std::string& app_id) { |
| 214 const extensions::Extension* extension = GetExtension(profile, app_id); | 226 const extensions::Extension* extension = |
| 215 if (!extension || !extension->is_platform_app()) | 227 delegate_->GetExtension(profile, app_id); |
| 228 if (!extension) | |
| 216 return; | 229 return; |
| 217 | 230 |
| 218 if (hosts_.count(make_pair(profile, extension->id()))) | 231 if (hosts_.count(make_pair(profile, app_id))) |
| 219 return; | 232 return; |
| 220 | 233 |
| 221 web_app::MaybeLaunchShortcut( | 234 delegate_->LaunchShim(profile, extension); |
| 222 web_app::ShortcutInfoForExtensionAndProfile(extension, profile)); | |
| 223 } | 235 } |
| 224 | 236 |
| 225 void ExtensionAppShimHandler::OnAppDeactivated(Profile* profile, | 237 void ExtensionAppShimHandler::OnAppDeactivated(Profile* profile, |
| 226 const std::string& app_id) { | 238 const std::string& app_id) { |
| 227 HostMap::const_iterator it = hosts_.find(make_pair(profile, app_id)); | 239 HostMap::const_iterator it = hosts_.find(make_pair(profile, app_id)); |
| 228 if (it != hosts_.end()) | 240 if (it != hosts_.end()) |
| 229 it->second->OnAppClosed(); | 241 it->second->OnAppClosed(); |
| 230 } | 242 } |
| 231 | 243 |
| 232 void ExtensionAppShimHandler::OnAppStop(Profile* profile, | 244 void ExtensionAppShimHandler::OnAppStop(Profile* profile, |
| 233 const std::string& app_id) {} | 245 const std::string& app_id) {} |
| 234 | 246 |
| 235 void ExtensionAppShimHandler::OnChromeTerminating() {} | 247 void ExtensionAppShimHandler::OnChromeTerminating() {} |
| 236 | 248 |
| 237 } // namespace apps | 249 } // namespace apps |
| OLD | NEW |