QUIC - cleanup changes to sync chromium tree with internal source.
[chromium-blink-merge.git] / chrome / browser / media_galleries / media_galleries_scan_result_controller.cc
blob1b791b28747fa702544d482954a50f9633a34ea6
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.
5 #include "chrome/browser/media_galleries/media_galleries_scan_result_controller.h"
7 #include <algorithm>
8 #include <list>
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"
30 using storage_monitor::StorageInfo;
31 using storage_monitor::StorageMonitor;
33 namespace {
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;
49 } // namespace
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();
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)));
79 // Unretained is safe because |this| owns |context_menu_|.
80 context_menu_.reset(new MediaGalleryContextMenu(base::Bind(
81 &MediaGalleriesScanResultController::DidForgetEntry,
82 base::Unretained(this))));
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();
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);
106 base::string16 MediaGalleriesScanResultController::GetHeader() const {
107 return l10n_util::GetStringFUTF16(
108 IDS_MEDIA_GALLERIES_SCAN_RESULT_DIALOG_HEADER,
109 base::UTF8ToUTF16(extension_->name()));
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, &copy_to_param);
121 bool has_delete_permission = permissions_data->CheckAPIPermissionWithParam(
122 extensions::APIPermission::kMediaGalleries, &delete_param);
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;
132 return l10n_util::GetStringFUTF16(id, base::UTF8ToUTF16(extension_->name()));
135 bool MediaGalleriesScanResultController::IsAcceptAllowed() const {
136 return true;
139 bool MediaGalleriesScanResultController::ShouldShowFolderViewer(
140 const Entry& entry) const {
141 return entry.pref_info.IsGalleryAvailable();
144 std::vector<base::string16>
145 MediaGalleriesScanResultController::GetSectionHeaders() const {
146 std::vector<base::string16> result;
147 result.push_back(base::string16());
148 return result;
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);
162 std::sort(result.begin(), result.end(), ScanResultsComparator);
163 return result;
166 base::string16
167 MediaGalleriesScanResultController::GetAuxiliaryButtonText() const {
168 return base::string16();
171 void MediaGalleriesScanResultController::DidClickAuxiliaryButton() {
172 NOTREACHED();
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;
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;
189 platform_util::OpenItem(GetProfile(), entry->second.pref_info.AbsolutePath(),
190 platform_util::OPEN_FOLDER,
191 platform_util::OpenOperationCallback());
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();
202 base::string16 MediaGalleriesScanResultController::GetAcceptButtonText() const {
203 return l10n_util::GetStringUTF16(
204 IDS_MEDIA_GALLERIES_SCAN_RESULT_DIALOG_CONFIRM);
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);
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++;
228 total++;
230 if (total > 0) {
231 UMA_HISTOGRAM_PERCENTAGE("MediaGalleries.ScanGalleriesGranted",
232 (granted * 100 / total));
234 for (MediaGalleryPrefIdSet::const_iterator it = results_to_remove_.begin();
235 it != results_to_remove_.end();
236 ++it) {
237 preferences_->ForgetGalleryById(*it);
239 } else {
240 media_galleries::UsageCount(media_galleries::ADD_SCAN_RESULTS_CANCELLED);
243 on_finish_.Run();
244 delete this;
247 ui::MenuModel* MediaGalleriesScanResultController::GetContextMenu(
248 MediaGalleryPrefId id) {
249 context_menu_->set_pref_id(id);
250 return context_menu_.get();
253 content::WebContents* MediaGalleriesScanResultController::WebContents() {
254 return web_contents_;
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);
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;
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);
303 while (!to_remove.empty()) {
304 scan_results->erase(to_remove.front());
305 to_remove.pop_front();
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_);
319 dialog_.reset(create_dialog_callback_.Run(this));
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();
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;
343 Profile* MediaGalleriesScanResultController::GetProfile() const {
344 return Profile::FromBrowserContext(web_contents_->GetBrowserContext());
347 void MediaGalleriesScanResultController::OnRemovableStorageAttached(
348 const StorageInfo& info) {
349 OnRemovableDeviceUpdate(info.device_id());
352 void MediaGalleriesScanResultController::OnRemovableStorageDetached(
353 const StorageInfo& info) {
354 OnRemovableDeviceUpdate(info.device_id());
357 void MediaGalleriesScanResultController::OnPermissionAdded(
358 MediaGalleriesPreferences* /*pref*/,
359 const std::string& extension_id,
360 MediaGalleryPrefId /*pref_id*/) {
361 OnPreferenceUpdate(extension_id);
364 void MediaGalleriesScanResultController::OnPermissionRemoved(
365 MediaGalleriesPreferences* /*pref*/,
366 const std::string& extension_id,
367 MediaGalleryPrefId /*pref_id*/) {
368 OnPreferenceUpdate(extension_id);
371 void MediaGalleriesScanResultController::OnGalleryAdded(
372 MediaGalleriesPreferences* /*prefs*/,
373 MediaGalleryPrefId /*pref_id*/) {
374 OnPreferenceUpdate(extension_->id());
377 void MediaGalleriesScanResultController::OnGalleryRemoved(
378 MediaGalleriesPreferences* /*prefs*/,
379 MediaGalleryPrefId /*pref_id*/) {
380 OnPreferenceUpdate(extension_->id());
383 void MediaGalleriesScanResultController::OnGalleryInfoUpdated(
384 MediaGalleriesPreferences* /*prefs*/,
385 MediaGalleryPrefId /*pref_id*/) {
386 OnPreferenceUpdate(extension_->id());