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