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

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: Disable GalleryNameMTP test for mac Created 7 years, 10 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 : delegate_(delegate) {}
30 virtual ~DeviceListener() {}
31
32 void OpenCameraSession(const std::string& device_id);
33 void CloseCameraSessionAndDelete();
34
35 void DownloadFile(const std::string& name, const FilePath& local_path);
36
37 // ImageCaptureDeviceListener
38 virtual void ItemAdded(const std::string& name,
39 const base::PlatformFileInfo& info) OVERRIDE;
40 virtual void NoMoreItems() OVERRIDE;
41 virtual void DownloadedFile(const std::string& name,
42 base::PlatformFileError error) OVERRIDE;
43 virtual void DeviceRemoved() OVERRIDE;
44
45 private:
46 scoped_nsobject<ImageCaptureDevice> camera_device_;
47
48 // Weak pointer
49 MTPDeviceDelegateImplMac* delegate_;
50
51 DISALLOW_COPY_AND_ASSIGN(DeviceListener);
52 };
53
54 void MTPDeviceDelegateImplMac::DeviceListener::OpenCameraSession(
55 const std::string& device_id) {
56 camera_device_.reset(
57 [ImageCaptureDeviceManager::deviceForUUID(device_id) retain]);
58 [camera_device_ setListener:AsWeakPtr()];
59 [camera_device_ open];
60 }
61
62 void MTPDeviceDelegateImplMac::DeviceListener::CloseCameraSessionAndDelete() {
63 [camera_device_ close];
64 [camera_device_ setListener:base::WeakPtr<DeviceListener>()];
65
66 delete this;
67 }
68
69 void MTPDeviceDelegateImplMac::DeviceListener::DownloadFile(
70 const std::string& name,
71 const FilePath& local_path) {
72 [camera_device_ downloadFile:name localPath:local_path];
73 }
74
75 void MTPDeviceDelegateImplMac::DeviceListener::ItemAdded(
76 const std::string& name,
77 const base::PlatformFileInfo& info) {
78 delegate_->ItemAdded(name, info);
79 }
80
81 void MTPDeviceDelegateImplMac::DeviceListener::NoMoreItems() {
82 delegate_->NoMoreItems();
83 }
84
85 void MTPDeviceDelegateImplMac::DeviceListener::DownloadedFile(
86 const std::string& name,
87 base::PlatformFileError error) {
88 delegate_->DownloadedFile(name, error);
89 }
90
91 void MTPDeviceDelegateImplMac::DeviceListener::DeviceRemoved() {
92 [camera_device_ close];
93 camera_device_.reset();
94 }
95
96 MTPDeviceDelegateImplMac::MTPDeviceDelegateImplMac(
97 const std::string& device_id,
98 const FilePath::StringType& synthetic_path,
99 base::SequencedTaskRunner* media_task_runner)
100 : device_id_(device_id),
101 root_path_(synthetic_path),
102 media_task_runner_(media_task_runner),
103 enumerator_(NULL),
104 file_download_event_(NULL),
105 file_download_error_(base::PLATFORM_FILE_OK),
106 received_all_files_(false) {
107
108 // Make a synthetic entry for the root of the filesystem.
109 base::PlatformFileInfo info;
110 info.is_directory = true;
111 file_info_[root_path_.value()] = info;
112
113 camera_interface_.reset(new DeviceListener(this));
114 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
115 base::Bind(&DeviceListener::OpenCameraSession,
116 base::Unretained(camera_interface_.get()),
117 device_id_));
118 }
119
120 MTPDeviceDelegateImplMac::~MTPDeviceDelegateImplMac() {
121 DCHECK(media_task_runner_->RunsTasksOnCurrentThread());
122 DCHECK(enumerator_ == NULL);
123 }
124
125 base::PlatformFileError MTPDeviceDelegateImplMac::GetFileInfo(
126 const FilePath& file_path,
127 base::PlatformFileInfo* file_info) {
128 base::AutoLock lock(mutex_);
129 base::hash_map<FilePath::StringType,
130 base::PlatformFileInfo>::const_iterator i =
131 file_info_.find(file_path.value());
132 if (i == file_info_.end())
133 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
134
135 *file_info = i->second;
136 return base::PLATFORM_FILE_OK;
137 }
138
139 scoped_ptr<fileapi::FileSystemFileUtil::AbstractFileEnumerator>
140 MTPDeviceDelegateImplMac::CreateFileEnumerator(const FilePath& root,
141 bool recursive) {
142 base::AutoLock lock(mutex_);
143 DCHECK(!enumerator_);
144 enumerator_ = new Enumerator(this);
145 return make_scoped_ptr(enumerator_)
146 .PassAs<fileapi::FileSystemFileUtil::AbstractFileEnumerator>();
147 }
148
149 base::PlatformFileError MTPDeviceDelegateImplMac::CreateSnapshotFile(
150 const FilePath& device_file_path,
151 const FilePath& local_path,
152 base::PlatformFileInfo* file_info) {
153 base::PlatformFileError error = GetFileInfo(device_file_path, file_info);
154 if (error != base::PLATFORM_FILE_OK)
155 return error;
156
157 // Set up to wait for download. Callers are ensuring this particular function
158 // will not be re-entered.
159 base::WaitableEvent waiter(true, false);
160 {
161 base::AutoLock lock(mutex_);
162 DCHECK(file_download_event_ == NULL);
163 file_download_event_ = &waiter;
164 }
165
166 // Start the download in the UI thread.
167 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
168 base::Bind(&DeviceListener::DownloadFile,
169 base::Unretained(camera_interface_.get()),
170 device_file_path.BaseName().value(), local_path));
171 waiter.Wait();
172 {
173 base::AutoLock lock(mutex_);
174 file_download_event_ = NULL;
175 error = file_download_error_;
176 }
177
178 // Modify the last modified time to null. This prevents the time stamp
179 // verification in LocalFileStreamReader.
180 file_info->last_modified = base::Time();
181
182 return error;
183 }
184
185 void MTPDeviceDelegateImplMac::CancelPendingTasksAndDeleteDelegate() {
186 // Artificially pretend that we have already gotten all items we're going
187 // to get.
188 NoMoreItems();
189
190 {
191 base::AutoLock lock(mutex_);
192 // Artificially wake up any downloads pending with an error code.
193 if (file_download_event_) {
194 file_download_error_ = base::PLATFORM_FILE_ERROR_FAILED;
195 file_download_event_->Signal();
196 }
197 }
198
199 // Schedule the camera session to be closed and the interface deleted.
200 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
201 base::Bind(&DeviceListener::CloseCameraSessionAndDelete,
202 base::Unretained(camera_interface_.release())));
203
204 media_task_runner_->DeleteSoon(FROM_HERE, this);
205 }
206
207 void MTPDeviceDelegateImplMac::ItemAdded(
208 const std::string& name, const base::PlatformFileInfo& info) {
209 base::AutoLock lock(mutex_);
210
211 // Make sure that if we're canceled and an enumerator is awake, that
212 // it will stay consistent. May need to revisit this if we need
213 // notifications of files added after we think we're done.
214 if (received_all_files_)
215 return;
216
217 // TODO(gbillock): Currently we flatten all files into a single
218 // directory. That's pretty much how PTP devices work, but if we want
219 // to support ImageCapture for USB, we need to change this.
220 if (info.is_directory)
221 return;
222
223 FilePath item_filename = root_path_.Append(name);
224 file_info_[item_filename.value()] = info;
225 file_paths_.push_back(item_filename);
226
227 if (enumerator_)
228 enumerator_->ItemsChanged();
229 }
230
231 void MTPDeviceDelegateImplMac::NoMoreItems() {
232 base::AutoLock lock(mutex_);
233 received_all_files_ = true;
234
235 if (enumerator_)
236 enumerator_->ItemsChanged();
237 }
238
239 void MTPDeviceDelegateImplMac::DownloadedFile(
240 const std::string& name, base::PlatformFileError error) {
241 // If we're cancelled and deleting, we have already signaled all enumerators.
242 if (!camera_interface_.get())
243 return;
244
245 base::AutoLock lock(mutex_);
246 file_download_error_ = error;
247 file_download_event_->Signal();
248 }
249
250 FilePath MTPDeviceDelegateImplMac::GetFile(size_t index) {
251 base::AutoLock lock(mutex_);
252 if (index >= file_paths_.size())
253 return FilePath();
254 else
255 return file_paths_[index];
256 }
257
258 bool MTPDeviceDelegateImplMac::ReceivedAllFiles() {
259 base::AutoLock lock(mutex_);
260 return received_all_files_;
261 }
262
263 void MTPDeviceDelegateImplMac::RemoveEnumerator(Enumerator* enumerator) {
264 base::AutoLock lock(mutex_);
265 DCHECK(enumerator_ == enumerator);
266 enumerator_ = NULL;
267 }
268
269 MTPDeviceDelegateImplMac::Enumerator::Enumerator(
270 MTPDeviceDelegateImplMac* delegate)
271 : delegate_(delegate),
272 position_(0),
273 wait_for_items_(false, false) {}
274
275 MTPDeviceDelegateImplMac::Enumerator::~Enumerator() {
276 delegate_->RemoveEnumerator(this);
277 }
278
279 FilePath MTPDeviceDelegateImplMac::Enumerator::Next() {
280 FilePath next_file = delegate_->GetFile(position_);
281 while (next_file.empty() && !delegate_->ReceivedAllFiles()) {
282 wait_for_items_.Wait();
283 next_file = delegate_->GetFile(position_);
284 }
285
286 position_++;
287 return next_file;
288 }
289
290 int64 MTPDeviceDelegateImplMac::Enumerator::Size() {
291 base::PlatformFileInfo info;
292 delegate_->GetFileInfo(delegate_->GetFile(position_ - 1), &info);
293 return info.size;
294 }
295
296 base::Time MTPDeviceDelegateImplMac::Enumerator::LastModifiedTime() {
297 base::PlatformFileInfo info;
298 delegate_->GetFileInfo(delegate_->GetFile(position_ - 1), &info);
299 return info.last_modified;
300 }
301
302 bool MTPDeviceDelegateImplMac::Enumerator::IsDirectory() {
303 base::PlatformFileInfo info;
304 delegate_->GetFileInfo(delegate_->GetFile(position_ - 1), &info);
305 return info.is_directory;
306 }
307
308 void MTPDeviceDelegateImplMac::Enumerator::ItemsChanged() {
309 wait_for_items_.Signal();
310 }
311
312 void CreateMTPDeviceDelegate(const std::string& device_location,
313 base::SequencedTaskRunner* media_task_runner,
314 const CreateMTPDeviceDelegateCallback& cb) {
315 std::string device_name = FilePath(device_location).BaseName().value();
316 std::string device_id;
317 MediaStorageUtil::Type type;
318 bool cracked = MediaStorageUtil::CrackDeviceId(device_name,
319 &type, &device_id);
320 DCHECK(cracked);
321 DCHECK_EQ(MediaStorageUtil::MAC_IMAGE_CAPTURE, type);
322
323 cb.Run(new MTPDeviceDelegateImplMac(device_id, device_location,
324 media_task_runner));
325 }
326
327 } // namespace chrome
328
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698