OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/storage_monitor/removable_device_notifications_mac.h" | |
6 | |
7 #include "chrome/browser/storage_monitor/media_device_notifications_utils.h" | |
8 #include "content/public/browser/browser_thread.h" | |
9 | |
10 namespace chrome { | |
11 | |
12 namespace { | |
13 | |
14 const char kDiskImageModelName[] = "Disk Image"; | |
15 | |
16 void GetDiskInfoAndUpdateOnFileThread( | |
17 const scoped_refptr<RemovableDeviceNotificationsMac>& notifications, | |
18 base::mac::ScopedCFTypeRef<CFDictionaryRef> dict, | |
19 RemovableDeviceNotificationsMac::UpdateType update_type) { | |
20 DiskInfoMac info = DiskInfoMac::BuildDiskInfoOnFileThread(dict); | |
21 if (info.device_id().empty()) | |
22 return; | |
23 | |
24 content::BrowserThread::PostTask( | |
25 content::BrowserThread::UI, | |
26 FROM_HERE, | |
27 base::Bind(&RemovableDeviceNotificationsMac::UpdateDisk, | |
28 notifications, | |
29 info, | |
30 update_type)); | |
31 } | |
32 | |
33 void GetDiskInfoAndUpdate( | |
34 const scoped_refptr<RemovableDeviceNotificationsMac>& notifications, | |
35 DADiskRef disk, | |
36 RemovableDeviceNotificationsMac::UpdateType update_type) { | |
37 base::mac::ScopedCFTypeRef<CFDictionaryRef> dict(DADiskCopyDescription(disk)); | |
38 content::BrowserThread::PostTask( | |
39 content::BrowserThread::FILE, | |
40 FROM_HERE, | |
41 base::Bind(GetDiskInfoAndUpdateOnFileThread, | |
42 notifications, | |
43 dict, | |
44 update_type)); | |
45 } | |
46 | |
47 } // namespace | |
48 | |
49 RemovableDeviceNotificationsMac::RemovableDeviceNotificationsMac() { | |
50 session_.reset(DASessionCreate(NULL)); | |
51 | |
52 DASessionScheduleWithRunLoop( | |
53 session_, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); | |
54 | |
55 // Register for callbacks for attached, changed, and removed devices. | |
56 // This will send notifications for existing devices too. | |
57 DARegisterDiskAppearedCallback( | |
58 session_, | |
59 kDADiskDescriptionMatchVolumeMountable, | |
60 DiskAppearedCallback, | |
61 this); | |
62 DARegisterDiskDisappearedCallback( | |
63 session_, | |
64 kDADiskDescriptionMatchVolumeMountable, | |
65 DiskDisappearedCallback, | |
66 this); | |
67 DARegisterDiskDescriptionChangedCallback( | |
68 session_, | |
69 kDADiskDescriptionMatchVolumeMountable, | |
70 kDADiskDescriptionWatchVolumePath, | |
71 DiskDescriptionChangedCallback, | |
72 this); | |
73 } | |
74 | |
75 RemovableDeviceNotificationsMac::~RemovableDeviceNotificationsMac() { | |
76 DASessionUnscheduleFromRunLoop( | |
77 session_, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); | |
78 } | |
79 | |
80 void RemovableDeviceNotificationsMac::UpdateDisk( | |
81 const DiskInfoMac& info, | |
82 UpdateType update_type) { | |
83 if (info.bsd_name().empty()) | |
84 return; | |
85 | |
86 std::map<std::string, DiskInfoMac>::iterator it = | |
87 disk_info_map_.find(info.bsd_name()); | |
88 if (it != disk_info_map_.end()) { | |
89 // If an attached notification was previously posted then post a detached | |
90 // notification now. This is used for devices that are being removed or | |
91 // devices that have changed. | |
92 if (ShouldPostNotificationForDisk(it->second)) { | |
93 receiver()->ProcessDetach(it->second.device_id()); | |
94 } | |
95 } | |
96 | |
97 if (update_type == UPDATE_DEVICE_REMOVED) { | |
98 if (it != disk_info_map_.end()) | |
99 disk_info_map_.erase(it); | |
100 } else { | |
101 disk_info_map_[info.bsd_name()] = info; | |
102 MediaStorageUtil::RecordDeviceInfoHistogram(true, info.device_id(), | |
103 info.device_name()); | |
104 if (ShouldPostNotificationForDisk(info)) { | |
105 string16 display_name = GetDisplayNameForDevice( | |
106 info.total_size_in_bytes(), info.device_name()); | |
107 receiver()->ProcessAttach(StorageInfo( | |
108 info.device_id(), display_name, info.mount_point().value())); | |
109 } | |
110 } | |
111 } | |
112 | |
113 bool RemovableDeviceNotificationsMac::GetStorageInfoForPath( | |
114 const base::FilePath& path, | |
115 StorageInfo* device_info) const { | |
116 if (!path.IsAbsolute()) | |
117 return false; | |
118 | |
119 base::FilePath current = path; | |
120 const base::FilePath root(base::FilePath::kSeparators); | |
121 while (current != root) { | |
122 DiskInfoMac info; | |
123 if (FindDiskWithMountPoint(current, &info)) { | |
124 device_info->device_id = info.device_id(); | |
125 device_info->name = info.device_name(); | |
126 device_info->location = info.mount_point().value(); | |
127 return true; | |
128 } | |
129 current = current.DirName(); | |
130 } | |
131 | |
132 return false; | |
133 } | |
134 | |
135 uint64 RemovableDeviceNotificationsMac::GetStorageSize( | |
136 const std::string& location) const { | |
137 DiskInfoMac info; | |
138 if (!FindDiskWithMountPoint(base::FilePath(location), &info)) | |
139 return 0; | |
140 return info.total_size_in_bytes(); | |
141 } | |
142 | |
143 // static | |
144 void RemovableDeviceNotificationsMac::DiskAppearedCallback( | |
145 DADiskRef disk, | |
146 void* context) { | |
147 RemovableDeviceNotificationsMac* notifications = | |
148 static_cast<RemovableDeviceNotificationsMac*>(context); | |
149 GetDiskInfoAndUpdate(notifications, | |
150 disk, | |
151 UPDATE_DEVICE_ADDED); | |
152 } | |
153 | |
154 // static | |
155 void RemovableDeviceNotificationsMac::DiskDisappearedCallback( | |
156 DADiskRef disk, | |
157 void* context) { | |
158 RemovableDeviceNotificationsMac* notifications = | |
159 static_cast<RemovableDeviceNotificationsMac*>(context); | |
160 GetDiskInfoAndUpdate(notifications, | |
161 disk, | |
162 UPDATE_DEVICE_REMOVED); | |
163 } | |
164 | |
165 // static | |
166 void RemovableDeviceNotificationsMac::DiskDescriptionChangedCallback( | |
167 DADiskRef disk, | |
168 CFArrayRef keys, | |
169 void *context) { | |
170 RemovableDeviceNotificationsMac* notifications = | |
171 static_cast<RemovableDeviceNotificationsMac*>(context); | |
172 GetDiskInfoAndUpdate(notifications, | |
173 disk, | |
174 UPDATE_DEVICE_CHANGED); | |
175 } | |
176 | |
177 bool RemovableDeviceNotificationsMac::ShouldPostNotificationForDisk( | |
178 const DiskInfoMac& info) const { | |
179 // Only post notifications about disks that have no empty fields and | |
180 // are removable. Also exclude disk images (DMGs). | |
181 return !info.bsd_name().empty() && | |
182 !info.device_id().empty() && | |
183 !info.device_name().empty() && | |
184 !info.mount_point().empty() && | |
185 info.model_name() != kDiskImageModelName && | |
186 (info.type() == MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM || | |
187 info.type() == MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM); | |
188 } | |
189 | |
190 bool RemovableDeviceNotificationsMac::FindDiskWithMountPoint( | |
191 const base::FilePath& mount_point, | |
192 DiskInfoMac* info) const { | |
193 for (std::map<std::string, DiskInfoMac>::const_iterator | |
194 it = disk_info_map_.begin(); it != disk_info_map_.end(); ++it) { | |
195 if (it->second.mount_point() == mount_point) { | |
196 *info = it->second; | |
197 return true; | |
198 } | |
199 } | |
200 return false; | |
201 } | |
202 | |
203 } // namespace chrome | |
OLD | NEW |