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 ProfileManager* profile_manager = g_browser_process->profile_manager(); | 45 ProfileManager* profile_manager = g_browser_process->profile_manager(); |
61 base::FilePath full_path = profile_manager->user_data_dir().Append(path); | 46 base::FilePath full_path = profile_manager->user_data_dir().Append(path); |
62 return profile_manager->GetProfile(full_path); | 47 return profile_manager->GetProfile(full_path); |
63 } | 48 } |
64 | 49 |
| 50 ShellWindowList ExtensionAppShimHandler::Delegate::GetWindows( |
| 51 Profile* profile, |
| 52 const std::string& extension_id) { |
| 53 return extensions::ShellWindowRegistry::Get(profile)-> |
| 54 GetShellWindowsForApp(extension_id); |
| 55 } |
| 56 |
| 57 const extensions::Extension* |
| 58 ExtensionAppShimHandler::Delegate::GetAppExtension( |
| 59 Profile* profile, |
| 60 const std::string& extension_id) { |
| 61 ExtensionService* extension_service = |
| 62 extensions::ExtensionSystem::Get(profile)->extension_service(); |
| 63 DCHECK(extension_service); |
| 64 const extensions::Extension* extension = |
| 65 extension_service->GetExtensionById(extension_id, false); |
| 66 return extension && extension->is_platform_app() ? extension : NULL; |
| 67 } |
| 68 |
| 69 void ExtensionAppShimHandler::Delegate::LaunchApp( |
| 70 Profile* profile, |
| 71 const extensions::Extension* extension) { |
| 72 chrome::OpenApplication( |
| 73 chrome::AppLaunchParams(profile, extension, NEW_FOREGROUND_TAB)); |
| 74 } |
| 75 |
| 76 void ExtensionAppShimHandler::Delegate::LaunchShim( |
| 77 Profile* profile, |
| 78 const extensions::Extension* extension) { |
| 79 web_app::MaybeLaunchShortcut( |
| 80 web_app::ShortcutInfoForExtensionAndProfile(extension, profile)); |
| 81 } |
| 82 |
65 ExtensionAppShimHandler::ExtensionAppShimHandler() | 83 ExtensionAppShimHandler::ExtensionAppShimHandler() |
66 : profile_manager_facade_(new ProfileManagerFacade) { | 84 : delegate_(new Delegate) { |
67 // This is instantiated in BrowserProcessImpl::PreMainMessageLoopRun with | 85 // This is instantiated in BrowserProcessImpl::PreMainMessageLoopRun with |
68 // AppShimHostManager. Since PROFILE_CREATED is not fired until | 86 // AppShimHostManager. Since PROFILE_CREATED is not fired until |
69 // ProfileManager::GetLastUsedProfile/GetLastOpenedProfiles, this should catch | 87 // ProfileManager::GetLastUsedProfile/GetLastOpenedProfiles, this should catch |
70 // notifications for all profiles. | 88 // notifications for all profiles. |
71 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, | 89 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, |
72 content::NotificationService::AllBrowserContextsAndSources()); | 90 content::NotificationService::AllBrowserContextsAndSources()); |
73 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | 91 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, |
74 content::NotificationService::AllBrowserContextsAndSources()); | 92 content::NotificationService::AllBrowserContextsAndSources()); |
75 } | 93 } |
76 | 94 |
77 ExtensionAppShimHandler::~ExtensionAppShimHandler() {} | 95 ExtensionAppShimHandler::~ExtensionAppShimHandler() {} |
78 | 96 |
79 bool ExtensionAppShimHandler::OnShimLaunch(Host* host, | 97 bool ExtensionAppShimHandler::OnShimLaunch(Host* host, |
80 AppShimLaunchType launch_type) { | 98 AppShimLaunchType launch_type) { |
81 const base::FilePath& profile_path = host->GetProfilePath(); | 99 const base::FilePath& profile_path = host->GetProfilePath(); |
82 DCHECK(!profile_path.empty()); | 100 DCHECK(!profile_path.empty()); |
83 | 101 |
84 if (!profile_manager_facade_->ProfileExistsForPath(profile_path)) { | 102 if (!delegate_->ProfileExistsForPath(profile_path)) { |
85 // User may have deleted the profile this shim was originally created for. | 103 // User may have deleted the profile this shim was originally created for. |
86 // TODO(jackhou): Add some UI for this case and remove the LOG. | 104 // TODO(jackhou): Add some UI for this case and remove the LOG. |
87 LOG(ERROR) << "Requested directory is not a known profile '" | 105 LOG(ERROR) << "Requested directory is not a known profile '" |
88 << profile_path.value() << "'."; | 106 << profile_path.value() << "'."; |
89 return false; | 107 return false; |
90 } | 108 } |
91 | 109 |
92 Profile* profile = profile_manager_facade_->ProfileForPath(profile_path); | 110 Profile* profile = delegate_->ProfileForPath(profile_path); |
93 | 111 |
94 const std::string& app_id = host->GetAppId(); | 112 const std::string& app_id = host->GetAppId(); |
95 if (!extensions::Extension::IdIsValid(app_id)) { | 113 if (!extensions::Extension::IdIsValid(app_id)) { |
96 LOG(ERROR) << "Bad app ID from app shim launch message."; | 114 LOG(ERROR) << "Bad app ID from app shim launch message."; |
97 return false; | 115 return false; |
98 } | 116 } |
99 | 117 |
100 // TODO(jackhou): Add some UI for this case and remove the LOG. | 118 // TODO(jackhou): Add some UI for this case and remove the LOG. |
101 if (!LaunchApp(profile, app_id, launch_type)) | 119 const extensions::Extension* extension = |
| 120 delegate_->GetAppExtension(profile, app_id); |
| 121 if (!extension) { |
| 122 LOG(ERROR) << "Attempted to launch nonexistent app with id '" |
| 123 << app_id << "'."; |
102 return false; | 124 return false; |
| 125 } |
| 126 |
| 127 // If the shim was launched in response to a window appearing, but the window |
| 128 // is closed by the time the shim process launched, return false to close the |
| 129 // shim. |
| 130 if (launch_type == APP_SHIM_LAUNCH_REGISTER_ONLY && |
| 131 delegate_->GetWindows(profile, app_id).empty()) { |
| 132 return false; |
| 133 } |
| 134 |
| 135 // TODO(jeremya): Handle the case that launching the app fails. Probably we |
| 136 // need to watch for 'app successfully launched' or at least 'background page |
| 137 // exists/was created' and time out with failure if we don't see that sign of |
| 138 // life within a certain window. |
| 139 if (launch_type == APP_SHIM_LAUNCH_NORMAL) |
| 140 delegate_->LaunchApp(profile, extension); |
103 | 141 |
104 // The first host to claim this (profile, app_id) becomes the main host. | 142 // The first host to claim this (profile, app_id) becomes the main host. |
105 // For any others, focus the app and return false. | 143 // For any others, focus the app and return false. |
106 if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) { | 144 if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) { |
107 OnShimFocus(host); | 145 OnShimFocus(host); |
108 return false; | 146 return false; |
109 } | 147 } |
110 | 148 |
111 return true; | 149 return true; |
112 } | 150 } |
113 | 151 |
114 void ExtensionAppShimHandler::OnShimClose(Host* host) { | 152 void ExtensionAppShimHandler::OnShimClose(Host* host) { |
115 DCHECK(profile_manager_facade_->ProfileExistsForPath( | 153 DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath())); |
116 host->GetProfilePath())); | 154 Profile* profile = delegate_->ProfileForPath(host->GetProfilePath()); |
117 Profile* profile = | |
118 profile_manager_facade_->ProfileForPath(host->GetProfilePath()); | |
119 | 155 |
120 HostMap::iterator it = hosts_.find(make_pair(profile, host->GetAppId())); | 156 HostMap::iterator it = hosts_.find(make_pair(profile, host->GetAppId())); |
121 // Any hosts other than the main host will still call OnShimClose, so ignore | 157 // Any hosts other than the main host will still call OnShimClose, so ignore |
122 // them. | 158 // them. |
123 if (it != hosts_.end() && it->second == host) | 159 if (it != hosts_.end() && it->second == host) |
124 hosts_.erase(it); | 160 hosts_.erase(it); |
125 } | 161 } |
126 | 162 |
127 void ExtensionAppShimHandler::OnShimFocus(Host* host) { | 163 void ExtensionAppShimHandler::OnShimFocus(Host* host) { |
128 DCHECK(profile_manager_facade_->ProfileExistsForPath( | 164 DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath())); |
129 host->GetProfilePath())); | 165 Profile* profile = delegate_->ProfileForPath(host->GetProfilePath()); |
130 Profile* profile = | |
131 profile_manager_facade_->ProfileForPath(host->GetProfilePath()); | |
132 | 166 |
133 const ShellWindowList windows = GetWindows(profile, host->GetAppId()); | 167 const ShellWindowList windows = |
| 168 delegate_->GetWindows(profile, host->GetAppId()); |
134 std::set<gfx::NativeWindow> native_windows; | 169 std::set<gfx::NativeWindow> native_windows; |
135 for (ShellWindowList::const_iterator it = windows.begin(); | 170 for (ShellWindowList::const_iterator it = windows.begin(); |
136 it != windows.end(); ++it) { | 171 it != windows.end(); ++it) { |
137 native_windows.insert((*it)->GetNativeWindow()); | 172 native_windows.insert((*it)->GetNativeWindow()); |
138 } | 173 } |
139 ui::FocusWindowSet(native_windows); | 174 ui::FocusWindowSet(native_windows); |
140 } | 175 } |
141 | 176 |
142 void ExtensionAppShimHandler::OnShimQuit(Host* host) { | 177 void ExtensionAppShimHandler::OnShimQuit(Host* host) { |
143 DCHECK(profile_manager_facade_->ProfileExistsForPath( | 178 DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath())); |
144 host->GetProfilePath())); | 179 Profile* profile = delegate_->ProfileForPath(host->GetProfilePath()); |
145 Profile* profile = | |
146 profile_manager_facade_->ProfileForPath(host->GetProfilePath()); | |
147 | 180 |
148 const ShellWindowList windows = GetWindows(profile, host->GetAppId()); | 181 const ShellWindowList windows = |
| 182 delegate_->GetWindows(profile, host->GetAppId()); |
149 for (extensions::ShellWindowRegistry::const_iterator it = windows.begin(); | 183 for (extensions::ShellWindowRegistry::const_iterator it = windows.begin(); |
150 it != windows.end(); ++it) { | 184 it != windows.end(); ++it) { |
151 (*it)->GetBaseWindow()->Close(); | 185 (*it)->GetBaseWindow()->Close(); |
152 } | 186 } |
153 } | 187 } |
154 | 188 |
155 void ExtensionAppShimHandler::set_profile_manager_facade( | 189 void ExtensionAppShimHandler::set_delegate(Delegate* delegate) { |
156 ProfileManagerFacade* profile_manager_facade) { | 190 delegate_.reset(delegate); |
157 profile_manager_facade_.reset(profile_manager_facade); | |
158 } | |
159 | |
160 bool ExtensionAppShimHandler::LaunchApp(Profile* profile, | |
161 const std::string& app_id, | |
162 AppShimLaunchType launch_type) { | |
163 const extensions::Extension* extension = GetExtension(profile, app_id); | |
164 if (!extension) { | |
165 LOG(ERROR) << "Attempted to launch nonexistent app with id '" | |
166 << app_id << "'."; | |
167 return false; | |
168 } | |
169 | |
170 if (launch_type == APP_SHIM_LAUNCH_REGISTER_ONLY) | |
171 return !GetWindows(profile, app_id).empty(); | |
172 | |
173 // TODO(jeremya): Handle the case that launching the app fails. Probably we | |
174 // need to watch for 'app successfully launched' or at least 'background page | |
175 // exists/was created' and time out with failure if we don't see that sign of | |
176 // life within a certain window. | |
177 chrome::OpenApplication(chrome::AppLaunchParams( | |
178 profile, extension, NEW_FOREGROUND_TAB)); | |
179 return true; | |
180 } | 191 } |
181 | 192 |
182 void ExtensionAppShimHandler::Observe( | 193 void ExtensionAppShimHandler::Observe( |
183 int type, | 194 int type, |
184 const content::NotificationSource& source, | 195 const content::NotificationSource& source, |
185 const content::NotificationDetails& details) { | 196 const content::NotificationDetails& details) { |
186 Profile* profile = content::Source<Profile>(source).ptr(); | 197 Profile* profile = content::Source<Profile>(source).ptr(); |
187 if (profile->IsOffTheRecord()) | 198 if (profile->IsOffTheRecord()) |
188 return; | 199 return; |
189 | 200 |
(...skipping 16 matching lines...) Expand all Loading... |
206 NOTREACHED(); // Unexpected notification. | 217 NOTREACHED(); // Unexpected notification. |
207 break; | 218 break; |
208 } | 219 } |
209 } | 220 } |
210 | 221 |
211 void ExtensionAppShimHandler::OnAppStart(Profile* profile, | 222 void ExtensionAppShimHandler::OnAppStart(Profile* profile, |
212 const std::string& app_id) {} | 223 const std::string& app_id) {} |
213 | 224 |
214 void ExtensionAppShimHandler::OnAppActivated(Profile* profile, | 225 void ExtensionAppShimHandler::OnAppActivated(Profile* profile, |
215 const std::string& app_id) { | 226 const std::string& app_id) { |
216 const extensions::Extension* extension = GetExtension(profile, app_id); | 227 const extensions::Extension* extension = |
217 if (!extension || !extension->is_platform_app()) | 228 delegate_->GetAppExtension(profile, app_id); |
| 229 if (!extension) |
218 return; | 230 return; |
219 | 231 |
220 if (hosts_.count(make_pair(profile, extension->id()))) | 232 if (hosts_.count(make_pair(profile, app_id))) |
221 return; | 233 return; |
222 | 234 |
223 web_app::MaybeLaunchShortcut( | 235 delegate_->LaunchShim(profile, extension); |
224 web_app::ShortcutInfoForExtensionAndProfile(extension, profile)); | |
225 } | 236 } |
226 | 237 |
227 void ExtensionAppShimHandler::OnAppDeactivated(Profile* profile, | 238 void ExtensionAppShimHandler::OnAppDeactivated(Profile* profile, |
228 const std::string& app_id) { | 239 const std::string& app_id) { |
229 HostMap::const_iterator it = hosts_.find(make_pair(profile, app_id)); | 240 HostMap::const_iterator it = hosts_.find(make_pair(profile, app_id)); |
230 if (it != hosts_.end()) | 241 if (it != hosts_.end()) |
231 it->second->OnAppClosed(); | 242 it->second->OnAppClosed(); |
232 } | 243 } |
233 | 244 |
234 void ExtensionAppShimHandler::OnAppStop(Profile* profile, | 245 void ExtensionAppShimHandler::OnAppStop(Profile* profile, |
235 const std::string& app_id) {} | 246 const std::string& app_id) {} |
236 | 247 |
237 void ExtensionAppShimHandler::OnChromeTerminating() {} | 248 void ExtensionAppShimHandler::OnChromeTerminating() {} |
238 | 249 |
239 } // namespace apps | 250 } // namespace apps |
OLD | NEW |