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

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: Cancel in UI thread, etc. 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
sail 2013/01/26 02:11:38 no new line
Greg Billock 2013/01/28 18:57:07 Done.
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() {
197 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
198
199 // Artificially pretend that we have already gotten all items we're going
200 // to get.
201 NoMoreItems();
202
203 {
204 base::AutoLock lock(mutex_);
205 // Artificially wake up any downloads pending with an error code.
206 if (file_download_event_) {
207 file_download_error_ = base::PLATFORM_FILE_ERROR_FAILED;
208 file_download_event_->Signal();
209 }
210 }
211
212 // Schedule the camera session to be closed and the interface deleted.
213 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
214 base::Bind(&DeviceListener::CloseCameraSessionAndDelete,
215 base::Unretained(camera_interface_.release())));
216
217 media_task_runner_->DeleteSoon(FROM_HERE, this);
218 }
219
220 void MTPDeviceDelegateImplMac::ItemAdded(
221 const std::string& name, const base::PlatformFileInfo& info) {
222 base::AutoLock lock(mutex_);
223
224 // Make sure that if we're canceled and an enumerator is awake, that
225 // it will stay consistent. May need to revisit this if we need
226 // notifications of files added after we think we're done.
227 if (received_all_files_)
228 return;
229
230 // TODO(gbillock): Currently we flatten all files into a single
231 // directory. That's pretty much how PTP devices work, but if we want
232 // to support ImageCapture for USB, we need to change this.
233 if (info.is_directory)
234 return;
235
236 FilePath item_filename = root_path_.Append(name);
237 file_info_[item_filename.value()] = info;
238 file_paths_.push_back(item_filename);
239
240 if (enumerator_)
241 enumerator_->ItemsChanged();
242 }
243
244 void MTPDeviceDelegateImplMac::NoMoreItems() {
245 base::AutoLock lock(mutex_);
246 received_all_files_ = true;
247
248 if (enumerator_)
249 enumerator_->ItemsChanged();
250 }
251
252 void MTPDeviceDelegateImplMac::DownloadedFile(
253 const std::string& name, base::PlatformFileError error) {
254 // If we're cancelled and deleting, we have already signaled all enumerators.
255 if (!camera_interface_.get())
256 return;
257
258 base::AutoLock lock(mutex_);
259 file_download_error_ = error;
260 file_download_event_->Signal();
261 }
262
263 FilePath MTPDeviceDelegateImplMac::GetFile(size_t index) {
264 base::AutoLock lock(mutex_);
265 if (index >= file_paths_.size())
266 return FilePath();
267 else
sail 2013/01/26 02:11:38 should remove
Greg Billock 2013/01/28 18:57:07 Done.
268 return file_paths_[index];
269 }
270
271 bool MTPDeviceDelegateImplMac::ReceivedAllFiles() {
272 base::AutoLock lock(mutex_);
273 return received_all_files_;
274 }
275
276 void MTPDeviceDelegateImplMac::RemoveEnumerator(Enumerator* enumerator) {
277 base::AutoLock lock(mutex_);
278 DCHECK(enumerator_ == enumerator);
279 enumerator_ = NULL;
280 }
281
282 MTPDeviceDelegateImplMac::Enumerator::Enumerator(
283 MTPDeviceDelegateImplMac* delegate)
284 : delegate_(delegate),
285 position_(0),
286 done_(false),
287 wait_for_items_(false, false) {}
288
289 MTPDeviceDelegateImplMac::Enumerator::~Enumerator() {
290 delegate_->RemoveEnumerator(this);
291 }
292
293 FilePath MTPDeviceDelegateImplMac::Enumerator::Next() {
294 FilePath next_file = delegate_->GetFile(position_);
295 while (next_file.empty() && !delegate_->ReceivedAllFiles()) {
296 wait_for_items_.Wait();
297 next_file = delegate_->GetFile(position_);
298 }
299
300 position_++;
301 if (next_file.empty())
302 done_ = true;
303
304 return next_file;
305 }
306
307 int64 MTPDeviceDelegateImplMac::Enumerator::Size() {
308 if (position_ == 0 || done_)
309 return 0;
310
311 base::PlatformFileInfo info;
312 delegate_->GetFileInfo(delegate_->GetFile(position_ - 1), &info);
313 return info.size;
314 }
315
316 base::Time MTPDeviceDelegateImplMac::Enumerator::LastModifiedTime() {
317 if (position_ == 0 || done_)
318 return base::Time();
319
320 base::PlatformFileInfo info;
321 delegate_->GetFileInfo(delegate_->GetFile(position_ - 1), &info);
322 return info.last_modified;
323 }
324
325 bool MTPDeviceDelegateImplMac::Enumerator::IsDirectory() {
326 if (position_ <= 0 || done_)
327 return false;
328
329 base::PlatformFileInfo info;
330 delegate_->GetFileInfo(delegate_->GetFile(position_ - 1), &info);
331 return info.is_directory;
332 }
333
334 void MTPDeviceDelegateImplMac::Enumerator::ItemsChanged() {
335 wait_for_items_.Signal();
336 }
337
338 void CreateMTPDeviceDelegate(const FilePath::StringType& device_location,
339 base::SequencedTaskRunner* media_task_runner,
340 const CreateMTPDeviceDelegateCallback& cb) {
341 std::string device_name = FilePath(device_location).BaseName().value();
342 std::string device_id;
343 MediaStorageUtil::Type type;
344 bool cracked = MediaStorageUtil::CrackDeviceId(device_name,
345 &type, &device_id);
346 DCHECK(cracked);
347 DCHECK_EQ(MediaStorageUtil::MAC_IMAGE_CAPTURE, type);
348
349 cb.Run(new MTPDeviceDelegateImplMac(device_id, device_location,
350 media_task_runner));
351 }
352
353 } // namespace chrome
354
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698