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/media_galleries/media_galleries_scan_result_controller.
h" | |
6 | |
7 #include <algorithm> | |
8 #include <list> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/logging.h" | |
12 #include "base/metrics/histogram.h" | |
13 #include "base/stl_util.h" | |
14 #include "base/strings/utf_string_conversions.h" | |
15 #include "chrome/browser/browser_process.h" | |
16 #include "chrome/browser/media_galleries/media_file_system_registry.h" | |
17 #include "chrome/browser/media_galleries/media_galleries_histograms.h" | |
18 #include "chrome/browser/media_galleries/media_gallery_context_menu.h" | |
19 #include "chrome/browser/platform_util.h" | |
20 #include "chrome/browser/profiles/profile.h" | |
21 #include "chrome/grit/generated_resources.h" | |
22 #include "components/storage_monitor/storage_info.h" | |
23 #include "components/storage_monitor/storage_monitor.h" | |
24 #include "content/public/browser/web_contents.h" | |
25 #include "extensions/common/extension.h" | |
26 #include "extensions/common/permissions/media_galleries_permission.h" | |
27 #include "extensions/common/permissions/permissions_data.h" | |
28 #include "ui/base/l10n/l10n_util.h" | |
29 | |
30 using storage_monitor::StorageInfo; | |
31 using storage_monitor::StorageMonitor; | |
32 | |
33 namespace { | |
34 | |
35 // Comparator for sorting Entries -- more files first and then sorts by | |
36 // absolute path. | |
37 bool ScanResultsComparator( | |
38 const MediaGalleriesDialogController::Entry& a, | |
39 const MediaGalleriesDialogController::Entry& b) { | |
40 int a_media_count = a.pref_info.audio_count + a.pref_info.image_count + | |
41 a.pref_info.video_count; | |
42 int b_media_count = b.pref_info.audio_count + b.pref_info.image_count + | |
43 b.pref_info.video_count; | |
44 if (a_media_count == b_media_count) | |
45 return a.pref_info.AbsolutePath() < b.pref_info.AbsolutePath(); | |
46 return a_media_count > b_media_count; | |
47 } | |
48 | |
49 } // namespace | |
50 | |
51 // static | |
52 size_t MediaGalleriesScanResultController::ScanResultCountForExtension( | |
53 MediaGalleriesPreferences* preferences, | |
54 const extensions::Extension* extension) { | |
55 ScanResults scan_results; | |
56 UpdateScanResultsFromPreferences(preferences, extension, | |
57 MediaGalleryPrefIdSet(), &scan_results); | |
58 return scan_results.size(); | |
59 } | |
60 | |
61 MediaGalleriesScanResultController::MediaGalleriesScanResultController( | |
62 content::WebContents* web_contents, | |
63 const extensions::Extension& extension, | |
64 const base::Closure& on_finish) | |
65 : web_contents_(web_contents), | |
66 extension_(&extension), | |
67 on_finish_(on_finish), | |
68 create_dialog_callback_(base::Bind(&MediaGalleriesDialog::Create)) { | |
69 preferences_ = | |
70 g_browser_process->media_file_system_registry()->GetPreferences( | |
71 GetProfile()); | |
72 // Passing unretained pointer is safe, since the dialog controller | |
73 // is self-deleting, and so won't be deleted until it can be shown | |
74 // and then closed. | |
75 preferences_->EnsureInitialized(base::Bind( | |
76 &MediaGalleriesScanResultController::OnPreferencesInitialized, | |
77 base::Unretained(this))); | |
78 | |
79 // Unretained is safe because |this| owns |context_menu_|. | |
80 context_menu_.reset(new MediaGalleryContextMenu(base::Bind( | |
81 &MediaGalleriesScanResultController::DidForgetEntry, | |
82 base::Unretained(this)))); | |
83 } | |
84 | |
85 MediaGalleriesScanResultController::MediaGalleriesScanResultController( | |
86 const extensions::Extension& extension, | |
87 MediaGalleriesPreferences* preferences, | |
88 const CreateDialogCallback& create_dialog_callback, | |
89 const base::Closure& on_finish) | |
90 : web_contents_(NULL), | |
91 extension_(&extension), | |
92 on_finish_(on_finish), | |
93 preferences_(preferences), | |
94 create_dialog_callback_(create_dialog_callback) { | |
95 OnPreferencesInitialized(); | |
96 } | |
97 | |
98 MediaGalleriesScanResultController::~MediaGalleriesScanResultController() { | |
99 // |preferences_| may be NULL in tests. | |
100 if (preferences_) | |
101 preferences_->RemoveGalleryChangeObserver(this); | |
102 if (StorageMonitor::GetInstance()) | |
103 StorageMonitor::GetInstance()->RemoveObserver(this); | |
104 } | |
105 | |
106 base::string16 MediaGalleriesScanResultController::GetHeader() const { | |
107 return l10n_util::GetStringFUTF16( | |
108 IDS_MEDIA_GALLERIES_SCAN_RESULT_DIALOG_HEADER, | |
109 base::UTF8ToUTF16(extension_->name())); | |
110 } | |
111 | |
112 base::string16 MediaGalleriesScanResultController::GetSubtext() const { | |
113 extensions::MediaGalleriesPermission::CheckParam copy_to_param( | |
114 extensions::MediaGalleriesPermission::kCopyToPermission); | |
115 extensions::MediaGalleriesPermission::CheckParam delete_param( | |
116 extensions::MediaGalleriesPermission::kDeletePermission); | |
117 const extensions::PermissionsData* permissions_data = | |
118 extension_->permissions_data(); | |
119 bool has_copy_to_permission = permissions_data->CheckAPIPermissionWithParam( | |
120 extensions::APIPermission::kMediaGalleries, ©_to_param); | |
121 bool has_delete_permission = permissions_data->CheckAPIPermissionWithParam( | |
122 extensions::APIPermission::kMediaGalleries, &delete_param); | |
123 | |
124 int id; | |
125 if (has_copy_to_permission) | |
126 id = IDS_MEDIA_GALLERIES_SCAN_RESULT_DIALOG_SUBTEXT_READ_WRITE; | |
127 else if (has_delete_permission) | |
128 id = IDS_MEDIA_GALLERIES_SCAN_RESULT_DIALOG_SUBTEXT_READ_DELETE; | |
129 else | |
130 id = IDS_MEDIA_GALLERIES_SCAN_RESULT_DIALOG_SUBTEXT_READ_ONLY; | |
131 | |
132 return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension_->name())); | |
133 } | |
134 | |
135 bool MediaGalleriesScanResultController::IsAcceptAllowed() const { | |
136 return true; | |
137 } | |
138 | |
139 bool MediaGalleriesScanResultController::ShouldShowFolderViewer( | |
140 const Entry& entry) const { | |
141 return entry.pref_info.IsGalleryAvailable(); | |
142 } | |
143 | |
144 std::vector<base::string16> | |
145 MediaGalleriesScanResultController::GetSectionHeaders() const { | |
146 std::vector<base::string16> result; | |
147 result.push_back(base::string16()); | |
148 return result; | |
149 } | |
150 | |
151 MediaGalleriesDialogController::Entries | |
152 MediaGalleriesScanResultController::GetSectionEntries( | |
153 size_t index) const { | |
154 DCHECK_EQ(0U, index); | |
155 Entries result; | |
156 result.reserve(scan_results_.size()); | |
157 for (ScanResults::const_iterator it = scan_results_.begin(); | |
158 it != scan_results_.end(); | |
159 ++it) { | |
160 result.push_back(it->second); | |
161 } | |
162 std::sort(result.begin(), result.end(), ScanResultsComparator); | |
163 return result; | |
164 } | |
165 | |
166 base::string16 | |
167 MediaGalleriesScanResultController::GetAuxiliaryButtonText() const { | |
168 return base::string16(); | |
169 } | |
170 | |
171 void MediaGalleriesScanResultController::DidClickAuxiliaryButton() { | |
172 NOTREACHED(); | |
173 } | |
174 | |
175 void MediaGalleriesScanResultController::DidToggleEntry( | |
176 MediaGalleryPrefId pref_id, bool selected) { | |
177 DCHECK(ContainsKey(scan_results_, pref_id)); | |
178 ScanResults::iterator entry = scan_results_.find(pref_id); | |
179 entry->second.selected = selected; | |
180 } | |
181 | |
182 void MediaGalleriesScanResultController::DidClickOpenFolderViewer( | |
183 MediaGalleryPrefId pref_id) { | |
184 ScanResults::const_iterator entry = scan_results_.find(pref_id); | |
185 if (entry == scan_results_.end()) { | |
186 NOTREACHED(); | |
187 return; | |
188 } | |
189 platform_util::OpenItem(GetProfile(), entry->second.pref_info.AbsolutePath(), | |
190 platform_util::OPEN_FOLDER, | |
191 platform_util::OpenOperationCallback()); | |
192 } | |
193 | |
194 void MediaGalleriesScanResultController::DidForgetEntry( | |
195 MediaGalleryPrefId pref_id) { | |
196 media_galleries::UsageCount(media_galleries::ADD_SCAN_RESULTS_FORGET_GALLERY); | |
197 results_to_remove_.insert(pref_id); | |
198 scan_results_.erase(pref_id); | |
199 dialog_->UpdateGalleries(); | |
200 } | |
201 | |
202 base::string16 MediaGalleriesScanResultController::GetAcceptButtonText() const { | |
203 return l10n_util::GetStringUTF16( | |
204 IDS_MEDIA_GALLERIES_SCAN_RESULT_DIALOG_CONFIRM); | |
205 } | |
206 | |
207 void MediaGalleriesScanResultController::DialogFinished(bool accepted) { | |
208 // No longer interested in preference updates (and the below code generates | |
209 // some). | |
210 // |preferences_| may be NULL in tests. | |
211 if (preferences_) | |
212 preferences_->RemoveGalleryChangeObserver(this); | |
213 | |
214 if (accepted) { | |
215 DCHECK(preferences_); | |
216 media_galleries::UsageCount(media_galleries::ADD_SCAN_RESULTS_ACCEPTED); | |
217 int granted = 0; | |
218 int total = 0; | |
219 for (ScanResults::const_iterator it = scan_results_.begin(); | |
220 it != scan_results_.end(); | |
221 ++it) { | |
222 if (it->second.selected) { | |
223 bool changed = preferences_->SetGalleryPermissionForExtension( | |
224 *extension_, it->first, true); | |
225 DCHECK(changed); | |
226 granted++; | |
227 } | |
228 total++; | |
229 } | |
230 if (total > 0) { | |
231 UMA_HISTOGRAM_PERCENTAGE("MediaGalleries.ScanGalleriesGranted", | |
232 (granted * 100 / total)); | |
233 } | |
234 for (MediaGalleryPrefIdSet::const_iterator it = results_to_remove_.begin(); | |
235 it != results_to_remove_.end(); | |
236 ++it) { | |
237 preferences_->ForgetGalleryById(*it); | |
238 } | |
239 } else { | |
240 media_galleries::UsageCount(media_galleries::ADD_SCAN_RESULTS_CANCELLED); | |
241 } | |
242 | |
243 on_finish_.Run(); | |
244 delete this; | |
245 } | |
246 | |
247 ui::MenuModel* MediaGalleriesScanResultController::GetContextMenu( | |
248 MediaGalleryPrefId id) { | |
249 context_menu_->set_pref_id(id); | |
250 return context_menu_.get(); | |
251 } | |
252 | |
253 content::WebContents* MediaGalleriesScanResultController::WebContents() { | |
254 return web_contents_; | |
255 } | |
256 | |
257 // static | |
258 void MediaGalleriesScanResultController::UpdateScanResultsFromPreferences( | |
259 MediaGalleriesPreferences* preferences, | |
260 const extensions::Extension* extension, | |
261 MediaGalleryPrefIdSet ignore_list, | |
262 ScanResults* scan_results) { | |
263 DCHECK(preferences->IsInitialized()); | |
264 const MediaGalleriesPrefInfoMap& galleries = preferences->known_galleries(); | |
265 MediaGalleryPrefIdSet permitted = | |
266 preferences->GalleriesForExtension(*extension); | |
267 | |
268 // Add or update any scan results that the extension doesn't already have | |
269 // access to or isn't in |ignore_list|. | |
270 for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin(); | |
271 it != galleries.end(); | |
272 ++it) { | |
273 const MediaGalleryPrefInfo& gallery = it->second; | |
274 if ((gallery.audio_count || gallery.image_count || gallery.video_count) && | |
275 !gallery.IsBlackListedType() && | |
276 !ContainsKey(permitted, gallery.pref_id) && | |
277 !ContainsKey(ignore_list, gallery.pref_id)) { | |
278 ScanResults::iterator existing = scan_results->find(gallery.pref_id); | |
279 if (existing == scan_results->end()) { | |
280 // Default to selected. | |
281 (*scan_results)[gallery.pref_id] = Entry(gallery, true); | |
282 } else { | |
283 // Update pref_info, in case anything has been updated. | |
284 existing->second.pref_info = gallery; | |
285 } | |
286 } | |
287 } | |
288 | |
289 // Remove anything from |scan_results| that's no longer valid or the user | |
290 // already has access to. | |
291 std::list<ScanResults::iterator> to_remove; | |
292 for (ScanResults::iterator it = scan_results->begin(); | |
293 it != scan_results->end(); | |
294 ++it) { | |
295 MediaGalleriesPrefInfoMap::const_iterator pref_gallery = | |
296 galleries.find(it->first); | |
297 if (pref_gallery == galleries.end() || | |
298 pref_gallery->second.IsBlackListedType() || | |
299 ContainsKey(permitted, it->first)) { | |
300 to_remove.push_back(it); | |
301 } | |
302 } | |
303 while (!to_remove.empty()) { | |
304 scan_results->erase(to_remove.front()); | |
305 to_remove.pop_front(); | |
306 } | |
307 } | |
308 | |
309 void MediaGalleriesScanResultController::OnPreferencesInitialized() { | |
310 // These may be NULL in tests. | |
311 if (StorageMonitor::GetInstance()) | |
312 StorageMonitor::GetInstance()->AddObserver(this); | |
313 if (preferences_) { | |
314 preferences_->AddGalleryChangeObserver(this); | |
315 UpdateScanResultsFromPreferences(preferences_, extension_, | |
316 results_to_remove_, &scan_results_); | |
317 } | |
318 | |
319 dialog_.reset(create_dialog_callback_.Run(this)); | |
320 } | |
321 | |
322 void MediaGalleriesScanResultController::OnPreferenceUpdate( | |
323 const std::string& extension_id) { | |
324 if (extension_id == extension_->id()) { | |
325 UpdateScanResultsFromPreferences(preferences_, extension_, | |
326 results_to_remove_, &scan_results_); | |
327 dialog_->UpdateGalleries(); | |
328 } | |
329 } | |
330 | |
331 void MediaGalleriesScanResultController::OnRemovableDeviceUpdate( | |
332 const std::string& device_id) { | |
333 for (ScanResults::const_iterator it = scan_results_.begin(); | |
334 it != scan_results_.end(); | |
335 ++it) { | |
336 if (it->second.pref_info.device_id == device_id) { | |
337 dialog_->UpdateGalleries(); | |
338 return; | |
339 } | |
340 } | |
341 } | |
342 | |
343 Profile* MediaGalleriesScanResultController::GetProfile() const { | |
344 return Profile::FromBrowserContext(web_contents_->GetBrowserContext()); | |
345 } | |
346 | |
347 void MediaGalleriesScanResultController::OnRemovableStorageAttached( | |
348 const StorageInfo& info) { | |
349 OnRemovableDeviceUpdate(info.device_id()); | |
350 } | |
351 | |
352 void MediaGalleriesScanResultController::OnRemovableStorageDetached( | |
353 const StorageInfo& info) { | |
354 OnRemovableDeviceUpdate(info.device_id()); | |
355 } | |
356 | |
357 void MediaGalleriesScanResultController::OnPermissionAdded( | |
358 MediaGalleriesPreferences* /*pref*/, | |
359 const std::string& extension_id, | |
360 MediaGalleryPrefId /*pref_id*/) { | |
361 OnPreferenceUpdate(extension_id); | |
362 } | |
363 | |
364 void MediaGalleriesScanResultController::OnPermissionRemoved( | |
365 MediaGalleriesPreferences* /*pref*/, | |
366 const std::string& extension_id, | |
367 MediaGalleryPrefId /*pref_id*/) { | |
368 OnPreferenceUpdate(extension_id); | |
369 } | |
370 | |
371 void MediaGalleriesScanResultController::OnGalleryAdded( | |
372 MediaGalleriesPreferences* /*prefs*/, | |
373 MediaGalleryPrefId /*pref_id*/) { | |
374 OnPreferenceUpdate(extension_->id()); | |
375 } | |
376 | |
377 void MediaGalleriesScanResultController::OnGalleryRemoved( | |
378 MediaGalleriesPreferences* /*prefs*/, | |
379 MediaGalleryPrefId /*pref_id*/) { | |
380 OnPreferenceUpdate(extension_->id()); | |
381 } | |
382 | |
383 void MediaGalleriesScanResultController::OnGalleryInfoUpdated( | |
384 MediaGalleriesPreferences* /*prefs*/, | |
385 MediaGalleryPrefId /*pref_id*/) { | |
386 OnPreferenceUpdate(extension_->id()); | |
387 } | |
OLD | NEW |