Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(546)

Side by Side Diff: chrome/browser/media_gallery/mac/mtp_device_delegate_impl_mac.mm

Issue 11416089: [Media Galleries] Filesystem interface for Mac PTP/MTP devices using ImageCaptureCore (part 3) (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Defensive enumerator Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/media_gallery/mac/mtp_device_delegate_impl_mac.h"
6
7 #include "base/memory/scoped_nsobject.h"
8 #include "base/sequenced_task_runner.h"
9 #include "base/sequenced_task_runner_helpers.h"
10 #include "base/threading/sequenced_worker_pool.h"
11 #include "chrome/browser/media_gallery/mtp_device_delegate_impl.h"
12 #include "chrome/browser/system_monitor/image_capture_device.h"
13 #include "chrome/browser/system_monitor/image_capture_device_manager.h"
14 #include "chrome/browser/system_monitor/media_storage_util.h"
15 #include "content/public/browser/browser_thread.h"
16
17 namespace chrome {
18
19 // This class handles the UI-thread hand-offs needed to interface
20 // with the ImageCapture library. It will forward callbacks to
21 // its delegate on the task runner with which it is created. All
22 // interactions with it are done on the UI thread, but it may be
23 // created/destroyed on another thread.
24 class MTPDeviceDelegateImplMac::DeviceListener
25 : public ImageCaptureDeviceListener,
26 public base::SupportsWeakPtr<DeviceListener> {
27 public:
28 DeviceListener(MTPDeviceDelegateImplMac* delegate,
29 base::SequencedTaskRunner* task_runner)
30 : delegate_(delegate),
31 task_runner_(task_runner) {}
32 virtual ~DeviceListener() {}
33
34 void OpenCameraSession(const std::string& device_id);
35 void CloseCameraSessionAndDelete();
36
37 void DownloadFile(const std::string& name, const FilePath& local_path);
38
39 // ImageCaptureDeviceListener
40 virtual void ItemAdded(const std::string& name,
41 const base::PlatformFileInfo& info) OVERRIDE;
42 virtual void NoMoreItems() OVERRIDE;
43 virtual void DownloadedFile(const std::string& name,
44 base::PlatformFileError error) OVERRIDE;
45 virtual void DeviceRemoved() OVERRIDE;
46
47 private:
48 scoped_nsobject<ImageCaptureDevice> camera_device_;
49
50 // Weak pointer
51 MTPDeviceDelegateImplMac* delegate_;
52
53 // Weak pointer
54 base::SequencedTaskRunner* task_runner_;
55
56 DISALLOW_COPY_AND_ASSIGN(DeviceListener);
57 };
58
59 void MTPDeviceDelegateImplMac::DeviceListener::OpenCameraSession(
60 const std::string& device_id) {
61 camera_device_.reset(
62 [ImageCaptureDeviceManager::deviceForUUID(device_id) retain]);
63 [camera_device_ setListener:AsWeakPtr()];
64 [camera_device_ open];
65 }
66
67 void MTPDeviceDelegateImplMac::DeviceListener::CloseCameraSessionAndDelete() {
68 [camera_device_ close];
69 [camera_device_ setListener:base::WeakPtr<DeviceListener>()];
70
71 delete this;
72 }
73
74 void MTPDeviceDelegateImplMac::DeviceListener::DownloadFile(
75 const std::string& name,
76 const FilePath& local_path) {
77 [camera_device_ downloadFile:name localPath:local_path];
78 }
79
80 void MTPDeviceDelegateImplMac::DeviceListener::ItemAdded(
81 const std::string& name,
82 const base::PlatformFileInfo& info) {
83 task_runner_->PostTask(FROM_HERE,
84 base::Bind(&MTPDeviceDelegateImplMac::ItemAdded,
85 base::Unretained(delegate_), name, info));
86 }
87
88 void MTPDeviceDelegateImplMac::DeviceListener::NoMoreItems() {
89 task_runner_->PostTask(FROM_HERE,
90 base::Bind(&MTPDeviceDelegateImplMac::NoMoreItems,
91 base::Unretained(delegate_)));
92 }
93
94 void MTPDeviceDelegateImplMac::DeviceListener::DownloadedFile(
95 const std::string& name,
96 base::PlatformFileError error) {
97 task_runner_->PostTask(FROM_HERE,
98 base::Bind(&MTPDeviceDelegateImplMac::DownloadedFile,
99 base::Unretained(delegate_), name, error));
100 }
101
102 void MTPDeviceDelegateImplMac::DeviceListener::DeviceRemoved() {
103 [camera_device_ close];
104 camera_device_.reset();
105 }
106
107 MTPDeviceDelegateImplMac::MTPDeviceDelegateImplMac(
108 const std::string& device_id,
109 const FilePath::StringType& synthetic_path,
110 base::SequencedTaskRunner* media_task_runner)
111 : device_id_(device_id),
112 root_path_(synthetic_path),
113 media_task_runner_(media_task_runner),
114 enumerator_(NULL),
115 file_download_event_(NULL),
116 file_download_error_(base::PLATFORM_FILE_OK),
117 received_all_files_(false) {
118
119 // Make a synthetic entry for the root of the filesystem.
120 base::PlatformFileInfo info;
121 info.is_directory = true;
122 file_info_[root_path_.value()] = info;
123
124 camera_interface_.reset(new DeviceListener(this, media_task_runner));
125 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
126 base::Bind(&DeviceListener::OpenCameraSession,
127 base::Unretained(camera_interface_.get()),
128 device_id_));
129 }
130
131 MTPDeviceDelegateImplMac::~MTPDeviceDelegateImplMac() {
132 DCHECK(media_task_runner_->RunsTasksOnCurrentThread());
133 DCHECK(enumerator_ == NULL);
134 }
135
136 base::PlatformFileError MTPDeviceDelegateImplMac::GetFileInfo(
137 const FilePath& file_path,
138 base::PlatformFileInfo* file_info) {
139 base::AutoLock lock(mutex_);
140 base::hash_map<FilePath::StringType,
141 base::PlatformFileInfo>::const_iterator i =
142 file_info_.find(file_path.value());
143 if (i == file_info_.end())
144 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
145
146 *file_info = i->second;
147 return base::PLATFORM_FILE_OK;
148 }
149
150 scoped_ptr<fileapi::FileSystemFileUtil::AbstractFileEnumerator>
151 MTPDeviceDelegateImplMac::CreateFileEnumerator(const FilePath& root,
152 bool recursive) {
153 base::AutoLock lock(mutex_);
154 DCHECK(!enumerator_);
155 enumerator_ = new Enumerator(this);
156 return make_scoped_ptr(enumerator_)
157 .PassAs<fileapi::FileSystemFileUtil::AbstractFileEnumerator>();
158 }
159
160 base::PlatformFileError MTPDeviceDelegateImplMac::CreateSnapshotFile(
161 const FilePath& device_file_path,
162 const FilePath& local_path,
163 base::PlatformFileInfo* file_info) {
164 base::PlatformFileError error = GetFileInfo(device_file_path, file_info);
165 if (error != base::PLATFORM_FILE_OK)
166 return error;
167
168 // Set up to wait for download. Callers are ensuring this particular function
169 // will not be re-entered.
170 base::WaitableEvent waiter(true, false);
171 {
172 base::AutoLock lock(mutex_);
173 DCHECK(file_download_event_ == NULL);
174 file_download_event_ = &waiter;
175 }
176
177 // Start the download in the UI thread.
178 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
179 base::Bind(&DeviceListener::DownloadFile,
180 base::Unretained(camera_interface_.get()),
181 device_file_path.BaseName().value(), local_path));
182 waiter.Wait();
183 {
184 base::AutoLock lock(mutex_);
185 file_download_event_ = NULL;
186 error = file_download_error_;
187 }
188
189 // Modify the last modified time to null. This prevents the time stamp
190 // verification in LocalFileStreamReader.
191 file_info->last_modified = base::Time();
192
193 return error;
194 }
195
196 void MTPDeviceDelegateImplMac::CancelPendingTasksAndDeleteDelegate() {
Lei Zhang 2013/01/25 23:51:20 DCHECK(content::BrowserThread::CurrentlyOn(content
Greg Billock 2013/01/26 01:29:44 Done.
197 // Artificially pretend that we have already gotten all items we're going
198 // to get.
199 NoMoreItems();
200
201 {
202 base::AutoLock lock(mutex_);
203 // Artificially wake up any downloads pending with an error code.
204 if (file_download_event_) {
205 file_download_error_ = base::PLATFORM_FILE_ERROR_FAILED;
206 file_download_event_->Signal();
207 }
208 }
209
210 // Schedule the camera session to be closed and the interface deleted.
211 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
212 base::Bind(&DeviceListener::CloseCameraSessionAndDelete,
213 base::Unretained(camera_interface_.release())));
214
215 media_task_runner_->DeleteSoon(FROM_HERE, this);
216 }
217
218 void MTPDeviceDelegateImplMac::ItemAdded(
219 const std::string& name, const base::PlatformFileInfo& info) {
220 base::AutoLock lock(mutex_);
221
222 // Make sure that if we're canceled and an enumerator is awake, that
223 // it will stay consistent. May need to revisit this if we need
224 // notifications of files added after we think we're done.
225 if (received_all_files_)
226 return;
227
228 // TODO(gbillock): Currently we flatten all files into a single
229 // directory. That's pretty much how PTP devices work, but if we want
230 // to support ImageCapture for USB, we need to change this.
231 if (info.is_directory)
232 return;
233
234 FilePath item_filename = root_path_.Append(name);
235 file_info_[item_filename.value()] = info;
236 file_paths_.push_back(item_filename);
237
238 if (enumerator_)
239 enumerator_->ItemsChanged();
240 }
241
242 void MTPDeviceDelegateImplMac::NoMoreItems() {
243 base::AutoLock lock(mutex_);
244 received_all_files_ = true;
245
246 if (enumerator_)
247 enumerator_->ItemsChanged();
248 }
249
250 void MTPDeviceDelegateImplMac::DownloadedFile(
251 const std::string& name, base::PlatformFileError error) {
252 // If we're cancelled and deleting, we have already signaled all enumerators.
253 if (!camera_interface_.get())
254 return;
255
256 base::AutoLock lock(mutex_);
257 file_download_error_ = error;
258 file_download_event_->Signal();
259 }
260
261 FilePath MTPDeviceDelegateImplMac::GetFile(size_t index) {
262 base::AutoLock lock(mutex_);
263 if (index >= file_paths_.size())
264 return FilePath();
265 else
266 return file_paths_[index];
267 }
268
269 bool MTPDeviceDelegateImplMac::ReceivedAllFiles() {
270 base::AutoLock lock(mutex_);
271 return received_all_files_;
272 }
273
274 void MTPDeviceDelegateImplMac::RemoveEnumerator(Enumerator* enumerator) {
275 base::AutoLock lock(mutex_);
276 DCHECK(enumerator_ == enumerator);
277 enumerator_ = NULL;
278 }
279
280 MTPDeviceDelegateImplMac::Enumerator::Enumerator(
281 MTPDeviceDelegateImplMac* delegate)
282 : delegate_(delegate),
283 position_(0),
284 done_(false),
285 wait_for_items_(false, false) {}
286
287 MTPDeviceDelegateImplMac::Enumerator::~Enumerator() {
288 delegate_->RemoveEnumerator(this);
289 }
290
291 FilePath MTPDeviceDelegateImplMac::Enumerator::Next() {
292 FilePath next_file = delegate_->GetFile(position_);
293 while (next_file.empty() && !delegate_->ReceivedAllFiles()) {
294 wait_for_items_.Wait();
295 next_file = delegate_->GetFile(position_);
296 }
297
298 position_++;
299 if (next_file == FilePath())
Lei Zhang 2013/01/25 23:51:20 You can just write this as: next_file.empty()
Greg Billock 2013/01/26 01:29:44 Done.
300 done_ = true;
301
302 return next_file;
303 }
304
305 int64 MTPDeviceDelegateImplMac::Enumerator::Size() {
306 if (position_ <= 0 || done_)
Lei Zhang 2013/01/25 23:51:20 size_t position can't ever be < 0, ditto below.
Greg Billock 2013/01/26 01:29:44 Done.
307 return 0;
308
309 base::PlatformFileInfo info;
310 delegate_->GetFileInfo(delegate_->GetFile(position_ - 1), &info);
311 return info.size;
312 }
313
314 base::Time MTPDeviceDelegateImplMac::Enumerator::LastModifiedTime() {
315 if (position_ <= 0 || done_)
316 return base::Time();
317
318 base::PlatformFileInfo info;
319 delegate_->GetFileInfo(delegate_->GetFile(position_ - 1), &info);
320 return info.last_modified;
321 }
322
323 bool MTPDeviceDelegateImplMac::Enumerator::IsDirectory() {
324 if (position_ <= 0 || done_)
325 return false;
326
327 base::PlatformFileInfo info;
328 delegate_->GetFileInfo(delegate_->GetFile(position_ - 1), &info);
329 return info.is_directory;
330 }
331
332 void MTPDeviceDelegateImplMac::Enumerator::ItemsChanged() {
333 wait_for_items_.Signal();
334 }
335
336 void CreateMTPDeviceDelegate(const FilePath::StringType& device_location,
337 base::SequencedTaskRunner* media_task_runner,
338 const CreateMTPDeviceDelegateCallback& cb) {
339 std::string device_name = FilePath(device_location).BaseName().value();
340 std::string device_id;
341 MediaStorageUtil::Type type;
342 bool cracked = MediaStorageUtil::CrackDeviceId(device_name,
343 &type, &device_id);
344 DCHECK(cracked);
345 DCHECK_EQ(MediaStorageUtil::MAC_IMAGE_CAPTURE, type);
346
347 cb.Run(new MTPDeviceDelegateImplMac(device_id, device_location,
348 media_task_runner));
349 }
350
351 } // namespace chrome
352
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698