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

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

Powered by Google App Engine
This is Rietveld 408576698