| 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 extensions::PermissionsData::ForExtension(extension_); | |
| 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 |