OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 #include "chrome/browser/apps/drive/drive_app_provider.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/logging.h" | |
12 #include "base/message_loop/message_loop.h" | |
13 #include "base/stl_util.h" | |
14 #include "chrome/browser/apps/drive/drive_app_converter.h" | |
15 #include "chrome/browser/apps/drive/drive_app_mapping.h" | |
16 #include "chrome/browser/apps/drive/drive_service_bridge.h" | |
17 #include "chrome/browser/drive/drive_app_registry.h" | |
18 #include "chrome/browser/extensions/extension_service.h" | |
19 #include "chrome/browser/extensions/install_tracker.h" | |
20 #include "chrome/browser/extensions/install_tracker_factory.h" | |
21 #include "chrome/browser/profiles/profile.h" | |
22 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" | |
23 #include "extensions/browser/extension_registry.h" | |
24 #include "extensions/browser/extension_system.h" | |
25 #include "extensions/common/extension.h" | |
26 | |
27 using extensions::Extension; | |
28 using extensions::ExtensionRegistry; | |
29 | |
30 namespace { | |
31 | |
32 void IgnoreUninstallResult(google_apis::GDataErrorCode) { | |
33 } | |
34 | |
35 } // namespace | |
36 | |
37 DriveAppProvider::DriveAppProvider(Profile* profile) | |
38 : profile_(profile), | |
39 service_bridge_(DriveServiceBridge::Create(profile).Pass()), | |
40 mapping_(new DriveAppMapping(profile->GetPrefs())), | |
41 weak_ptr_factory_(this) { | |
42 service_bridge_->GetAppRegistry()->AddObserver(this); | |
43 extensions::InstallTracker::Get(profile_)->AddObserver(this); | |
44 } | |
45 | |
46 DriveAppProvider::~DriveAppProvider() { | |
47 extensions::InstallTracker::Get(profile_)->RemoveObserver(this); | |
48 service_bridge_->GetAppRegistry()->RemoveObserver(this); | |
49 } | |
50 | |
51 // static | |
52 void DriveAppProvider::AppendDependsOnFactories( | |
53 std::set<BrowserContextKeyedServiceFactory*>* factories) { | |
54 factories->insert(extensions::InstallTrackerFactory::GetInstance()); | |
55 DriveServiceBridge::AppendDependsOnFactories(factories); | |
56 } | |
57 | |
58 void DriveAppProvider::SetDriveServiceBridgeForTest( | |
59 scoped_ptr<DriveServiceBridge> test_bridge) { | |
60 service_bridge_->GetAppRegistry()->RemoveObserver(this); | |
61 service_bridge_ = test_bridge.Pass(); | |
62 service_bridge_->GetAppRegistry()->AddObserver(this); | |
63 } | |
64 | |
65 void DriveAppProvider::UpdateMappingAndExtensionSystem( | |
66 const std::string& drive_app_id, | |
67 const Extension* new_app, | |
68 bool is_new_app_generated) { | |
69 const std::string& new_chrome_app_id = new_app->id(); | |
70 | |
71 const std::string existing_chrome_app_id = | |
72 mapping_->GetChromeApp(drive_app_id); | |
73 if (existing_chrome_app_id == new_chrome_app_id) | |
74 return; | |
75 | |
76 const bool is_existing_app_generated = | |
77 mapping_->IsChromeAppGenerated(existing_chrome_app_id); | |
78 mapping_->Add(drive_app_id, new_chrome_app_id, is_new_app_generated); | |
79 | |
80 const Extension* existing_app = | |
81 ExtensionRegistry::Get(profile_)->GetExtensionById( | |
82 existing_chrome_app_id, ExtensionRegistry::EVERYTHING); | |
83 if (existing_app && is_existing_app_generated) { | |
84 extensions::ExtensionSystem::Get(profile_) | |
85 ->extension_service() | |
86 ->UninstallExtension(existing_chrome_app_id, false, NULL); | |
87 } | |
88 } | |
89 | |
90 void DriveAppProvider::ProcessDeferredOnExtensionInstalled( | |
91 const std::string drive_app_id, | |
92 const std::string chrome_app_id) { | |
93 const Extension* app = ExtensionRegistry::Get(profile_)->GetExtensionById( | |
94 chrome_app_id, ExtensionRegistry::EVERYTHING); | |
95 if (!app) | |
96 return; | |
97 | |
98 UpdateMappingAndExtensionSystem(drive_app_id, app, false); | |
99 } | |
100 | |
101 void DriveAppProvider::SchedulePendingConverters() { | |
102 if (pending_converters_.empty()) | |
103 return; | |
104 | |
105 if (!pending_converters_.front()->IsStarted()) | |
106 pending_converters_.front()->Start(); | |
107 } | |
108 | |
109 void DriveAppProvider::OnLocalAppConverted(const DriveAppConverter* converter, | |
110 bool success) { | |
111 DCHECK_EQ(pending_converters_.front(), converter); | |
112 | |
113 if (success) { | |
114 UpdateMappingAndExtensionSystem(converter->app_info().app_id, | |
115 converter->app(), | |
116 converter->is_new_install()); | |
117 } else { | |
118 LOG(WARNING) << "Failed to convert drive app to web app, " | |
119 << "drive app id= " << converter->app_info().app_id | |
120 << ", name=" << converter->app_info().app_name; | |
121 } | |
122 | |
123 pending_converters_.erase(pending_converters_.begin()); | |
124 SchedulePendingConverters(); | |
125 } | |
126 | |
127 bool DriveAppProvider::IsMappedUrlAppUpToDate( | |
128 const drive::DriveAppInfo& drive_app) const { | |
129 const std::string& url_app_id = mapping_->GetChromeApp(drive_app.app_id); | |
130 if (url_app_id.empty()) | |
131 return false; | |
132 | |
133 const Extension* url_app = ExtensionRegistry::Get(profile_)->GetExtensionById( | |
134 url_app_id, ExtensionRegistry::EVERYTHING); | |
135 if (!url_app) | |
136 return false; | |
137 DCHECK(url_app->is_hosted_app() && url_app->from_bookmark()); | |
138 | |
139 return drive_app.app_name == url_app->name() && | |
140 drive_app.create_url == | |
141 extensions::AppLaunchInfo::GetLaunchWebURL(url_app); | |
142 } | |
143 | |
144 void DriveAppProvider::AddOrUpdateDriveApp( | |
145 const drive::DriveAppInfo& drive_app) { | |
146 const Extension* chrome_app = | |
147 ExtensionRegistry::Get(profile_)->GetExtensionById( | |
148 drive_app.product_id, ExtensionRegistry::EVERYTHING); | |
149 if (chrome_app) { | |
150 UpdateMappingAndExtensionSystem(drive_app.app_id, chrome_app, false); | |
151 return; | |
152 } | |
153 | |
154 if (IsMappedUrlAppUpToDate(drive_app)) | |
155 return; | |
156 | |
157 ScopedVector<DriveAppConverter>::iterator it = pending_converters_.begin(); | |
158 while (it != pending_converters_.end()) { | |
159 if (!(*it)->IsStarted() && (*it)->app_info().app_id == drive_app.app_id) { | |
160 it = pending_converters_.erase(it); | |
161 } else { | |
162 ++it; | |
163 } | |
164 } | |
165 | |
166 pending_converters_.push_back( | |
167 new DriveAppConverter(profile_, | |
168 drive_app, | |
169 base::Bind(&DriveAppProvider::OnLocalAppConverted, | |
170 base::Unretained(this)))); | |
171 } | |
172 | |
173 void DriveAppProvider::ProcessRemovedDriveApp(const std::string& drive_app_id) { | |
174 const std::string chrome_app_id = mapping_->GetChromeApp(drive_app_id); | |
175 const bool is_generated = mapping_->IsChromeAppGenerated(chrome_app_id); | |
176 mapping_->Remove(drive_app_id); | |
177 | |
178 if (chrome_app_id.empty() || !is_generated) | |
179 return; | |
180 | |
181 const Extension* existing_app = | |
182 ExtensionRegistry::Get(profile_) | |
183 ->GetExtensionById(chrome_app_id, ExtensionRegistry::EVERYTHING); | |
184 if (!existing_app) | |
185 return; | |
186 | |
187 extensions::ExtensionSystem::Get(profile_) | |
188 ->extension_service() | |
189 ->UninstallExtension(chrome_app_id, false, NULL); | |
190 } | |
191 | |
192 void DriveAppProvider::OnDriveAppRegistryUpdated() { | |
193 service_bridge_->GetAppRegistry()->GetAppList(&drive_apps_); | |
194 | |
195 IdSet current_ids; | |
196 for (size_t i = 0; i < drive_apps_.size(); ++i) | |
197 current_ids.insert(drive_apps_[i].app_id); | |
198 | |
199 const IdSet existing_ids = mapping_->GetDriveAppIds(); | |
200 const IdSet ids_to_remove = | |
201 base::STLSetDifference<IdSet>(existing_ids, current_ids); | |
202 for (IdSet::const_iterator it = ids_to_remove.begin(); | |
203 it != ids_to_remove.end(); | |
204 ++it) { | |
205 ProcessRemovedDriveApp(*it); | |
206 } | |
207 | |
208 for (size_t i = 0; i < drive_apps_.size(); ++i) { | |
209 AddOrUpdateDriveApp(drive_apps_[i]); | |
210 } | |
211 SchedulePendingConverters(); | |
212 } | |
213 | |
214 void DriveAppProvider::OnExtensionInstalled(const Extension* extension) { | |
215 // Bail if the |extension| is installed from a converter. The post install | |
216 // processing will be handled in OnLocalAppConverted. | |
217 if (!pending_converters_.empty() && | |
218 pending_converters_.front()->app() == extension) { | |
219 return; | |
220 } | |
221 | |
222 // Only user installed app reaches here. If it is mapped, make sure it is not | |
223 // tagged as generated. | |
benwells
2014/06/13 02:03:01
I think I understand why this is needed but it fee
xiyuan
2014/06/13 21:01:15
We definitely don't need to continue. "return" add
| |
224 const std::string drive_app_id = mapping_->GetDriveApp(extension->id()); | |
225 if (!drive_app_id.empty() && | |
226 mapping_->IsChromeAppGenerated(extension->id())) { | |
227 mapping_->Add(drive_app_id, extension->id(), false); | |
228 } | |
229 | |
230 for (size_t i = 0; i < drive_apps_.size(); ++i) { | |
231 if (drive_apps_[i].product_id == extension->id()) { | |
232 // Defer the processing because it touches the extensions system and | |
233 // it is better to let the current task finish to avoid unexpected | |
234 // incomplete status. | |
235 base::MessageLoop::current()->PostTask( | |
236 FROM_HERE, | |
237 base::Bind(&DriveAppProvider::ProcessDeferredOnExtensionInstalled, | |
238 weak_ptr_factory_.GetWeakPtr(), | |
239 drive_apps_[i].app_id, | |
240 extension->id())); | |
241 return; | |
242 } | |
243 } | |
244 } | |
245 | |
246 void DriveAppProvider::OnExtensionUninstalled(const Extension* extension) { | |
247 std::string drive_app_id = mapping_->GetDriveApp(extension->id()); | |
248 if (drive_app_id.empty()) | |
249 return; | |
250 | |
251 service_bridge_->GetAppRegistry()->UninstallApp( | |
252 drive_app_id, base::Bind(&IgnoreUninstallResult)); | |
253 } | |
OLD | NEW |