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 const std::string& new_chrome_app_id = new_app->id(); | |
69 | |
70 const std::string existing_chrome_app_id = | |
71 mapping_->GetChromeApp(drive_app_id); | |
72 if (existing_chrome_app_id == new_chrome_app_id) | |
73 return; | |
74 | |
75 mapping_->Add(drive_app_id, new_chrome_app_id); | |
76 | |
77 const Extension* existing_app = | |
78 ExtensionRegistry::Get(profile_)->GetExtensionById( | |
79 existing_chrome_app_id, ExtensionRegistry::EVERYTHING); | |
80 if (existing_app && existing_app->from_bookmark()) { | |
benwells
2014/06/11 00:15:20
This from_bookmark doesn't differentiate between u
xiyuan
2014/06/11 04:52:34
You are correct that the code could uninstall user
benwells
2014/06/12 00:16:02
Actually I didn't think it was possible, and I don
xiyuan
2014/06/12 00:53:19
The id of the URL apps are not random and derived
benwells
2014/06/12 06:28:59
Sorry I still don't get it (I'm probably being dum
xiyuan
2014/06/12 19:30:20
This is where we differ. Suppose user installs an
benwells
2014/06/13 02:03:01
Thanks for the detailed explanation, I get it now
| |
81 extensions::ExtensionSystem::Get(profile_) | |
82 ->extension_service() | |
83 ->UninstallExtension(existing_chrome_app_id, false, NULL); | |
84 } | |
85 } | |
86 | |
87 void DriveAppProvider::ProcessDeferredOnExtensionInstalled( | |
88 const std::string drive_app_id, | |
89 const std::string chrome_app_id) { | |
90 const Extension* app = ExtensionRegistry::Get(profile_)->GetExtensionById( | |
91 chrome_app_id, ExtensionRegistry::EVERYTHING); | |
92 if (!app) | |
93 return; | |
94 | |
95 UpdateMappingAndExtensionSystem(drive_app_id, app); | |
96 } | |
97 | |
98 void DriveAppProvider::SchedulePendingConverters() { | |
99 if (pending_converters_.empty()) | |
100 return; | |
101 | |
102 if (!pending_converters_.front()->IsStarted()) | |
103 pending_converters_.front()->Start(); | |
104 } | |
105 | |
106 void DriveAppProvider::OnLocalAppConverted(const DriveAppConverter* converter, | |
107 bool success) { | |
108 DCHECK_EQ(pending_converters_.front(), converter); | |
109 | |
110 if (success) { | |
111 UpdateMappingAndExtensionSystem(converter->app_info().app_id, | |
112 converter->app()); | |
113 } else { | |
114 LOG(WARNING) << "Failed to convert drive app to web app, " | |
115 << "drive app id= " << converter->app_info().app_id | |
116 << ", name=" << converter->app_info().app_name; | |
117 } | |
118 | |
119 pending_converters_.erase(pending_converters_.begin()); | |
120 SchedulePendingConverters(); | |
121 } | |
122 | |
123 bool DriveAppProvider::IsDriveAppUpToDate( | |
124 const drive::DriveAppInfo& drive_app) const { | |
125 const std::string& url_app_id = mapping_->GetChromeApp(drive_app.app_id); | |
126 if (url_app_id.empty()) | |
127 return false; | |
128 | |
129 const Extension* url_app = ExtensionRegistry::Get(profile_)->GetExtensionById( | |
130 url_app_id, ExtensionRegistry::EVERYTHING); | |
131 if (!url_app) | |
132 return false; | |
133 | |
134 return drive_app.app_name == url_app->name() && | |
benwells
2014/06/11 00:15:20
What if there is a matching app but it is not a UR
xiyuan
2014/06/11 04:52:34
Sounds good. Will rename.
xiyuan
2014/06/11 21:36:43
Renamed to IsMappedUrlAppUpToDate because we shoul
| |
135 drive_app.create_url == | |
136 extensions::AppLaunchInfo::GetLaunchWebURL(url_app); | |
137 } | |
138 | |
139 void DriveAppProvider::AddOrUpdateDriveApp( | |
140 const drive::DriveAppInfo& drive_app) { | |
141 const Extension* chrome_app = | |
142 ExtensionRegistry::Get(profile_)->GetExtensionById( | |
143 drive_app.product_id, ExtensionRegistry::EVERYTHING); | |
144 if (chrome_app) { | |
145 UpdateMappingAndExtensionSystem(drive_app.app_id, chrome_app); | |
146 return; | |
147 } | |
148 | |
149 if (IsDriveAppUpToDate(drive_app)) | |
150 return; | |
151 | |
152 ScopedVector<DriveAppConverter>::iterator it = pending_converters_.begin(); | |
153 while (it != pending_converters_.end()) { | |
154 if (!(*it)->IsStarted() && (*it)->app_info().app_id == drive_app.app_id) { | |
benwells
2014/06/11 00:15:20
What will happen if there is a converter in progre
xiyuan
2014/06/11 04:52:34
The "while" loop here is just an optimization. The
benwells
2014/06/13 02:03:01
If two of these do happen now, the second one will
xiyuan
2014/06/13 21:01:15
The current code does not change the "generated" f
| |
155 it = pending_converters_.erase(it); | |
156 } else { | |
157 ++it; | |
158 } | |
159 } | |
160 | |
161 pending_converters_.push_back( | |
162 new DriveAppConverter(profile_, | |
163 drive_app, | |
164 base::Bind(&DriveAppProvider::OnLocalAppConverted, | |
165 base::Unretained(this)))); | |
166 } | |
167 | |
168 void DriveAppProvider::RemoveDriveApp(const std::string& drive_app_id) { | |
benwells
2014/06/11 00:15:21
Nit: I think a better name would be ProcessRemoved
xiyuan
2014/06/11 04:52:34
Will do.
| |
169 const std::string chrome_app_id = mapping_->GetChromeApp(drive_app_id); | |
170 mapping_->Remove(drive_app_id); | |
171 | |
172 if (chrome_app_id.empty()) | |
173 return; | |
174 | |
175 const Extension* existing_app = | |
176 ExtensionRegistry::Get(profile_) | |
177 ->GetExtensionById(chrome_app_id, ExtensionRegistry::EVERYTHING); | |
178 if (!existing_app || !existing_app->from_bookmark()) | |
179 return; | |
180 | |
181 extensions::ExtensionSystem::Get(profile_) | |
182 ->extension_service() | |
183 ->UninstallExtension(chrome_app_id, false, NULL); | |
184 } | |
185 | |
186 void DriveAppProvider::OnDriveAppRegistryUpdated() { | |
benwells
2014/06/11 00:15:20
This is the only place that drive_apps_ is initial
xiyuan
2014/06/11 04:52:34
It actually ties to the ProfileOAuth2TokenService'
| |
187 service_bridge_->GetAppRegistry()->GetAppList(&drive_apps_); | |
188 | |
189 IdSet current_ids; | |
190 for (size_t i = 0; i < drive_apps_.size(); ++i) | |
191 current_ids.insert(drive_apps_[i].app_id); | |
192 | |
193 const IdSet existing_ids = mapping_->GetDriveAppIds(); | |
194 const IdSet ids_to_remove = | |
195 base::STLSetDifference<IdSet>(existing_ids, current_ids); | |
196 for (IdSet::const_iterator it = ids_to_remove.begin(); | |
197 it != ids_to_remove.end(); | |
198 ++it) { | |
199 RemoveDriveApp(*it); | |
200 } | |
201 | |
202 for (size_t i = 0; i < drive_apps_.size(); ++i) { | |
203 AddOrUpdateDriveApp(drive_apps_[i]); | |
204 } | |
205 SchedulePendingConverters(); | |
206 } | |
207 | |
208 void DriveAppProvider::OnExtensionInstalled(const Extension* extension) { | |
209 for (size_t i = 0; i < drive_apps_.size(); ++i) { | |
210 if (drive_apps_[i].product_id == extension->id()) { | |
211 base::MessageLoop::current()->PostTask( | |
benwells
2014/06/11 00:15:21
Why is this deferred? Could you add a comment expl
xiyuan
2014/06/11 04:52:34
Will add a comment. This is because we touch exten
| |
212 FROM_HERE, | |
213 base::Bind(&DriveAppProvider::ProcessDeferredOnExtensionInstalled, | |
214 weak_ptr_factory_.GetWeakPtr(), | |
215 drive_apps_[i].app_id, | |
216 extension->id())); | |
217 return; | |
218 } | |
219 } | |
220 } | |
221 | |
222 void DriveAppProvider::OnExtensionUninstalled(const Extension* extension) { | |
223 std::string drive_app_id = mapping_->GetDriveApp(extension->id()); | |
224 if (drive_app_id.empty()) | |
225 return; | |
226 | |
227 service_bridge_->GetAppRegistry()->UninstallApp( | |
228 drive_app_id, base::Bind(&IgnoreUninstallResult)); | |
229 } | |
OLD | NEW |