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.
5 #import "chrome/browser/storage_monitor/image_capture_device.h"
7 #include "base/file_util.h"
8 #include "content/public/browser/browser_thread.h"
12 base::PlatformFileError RenameFile(const base::FilePath& downloaded_filename,
13 const base::FilePath& desired_filename) {
14 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
15 bool success = base::ReplaceFile(downloaded_filename, desired_filename, NULL);
16 return success ? base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_NOT_FOUND;
19 void ReturnRenameResultToListener(
20 base::WeakPtr<ImageCaptureDeviceListener> listener,
21 const std::string& name,
22 const base::PlatformFileError& result) {
23 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
25 listener->DownloadedFile(name, result);
28 base::Time NSDateToBaseTime(NSDate* date) {
29 return base::Time::FromDoubleT([date timeIntervalSince1970]);
32 base::FilePath PathForCameraItem(ICCameraItem* item) {
33 std::string name = base::SysNSStringToUTF8([item name]);
35 std::vector<std::string> components;
36 ICCameraFolder* folder = [item parentFolder];
37 while (folder != nil) {
38 components.push_back(base::SysNSStringToUTF8([folder name]));
39 folder = [folder parentFolder];
42 for (std::vector<std::string>::reverse_iterator i = components.rbegin();
43 i != components.rend(); ++i) {
44 path = path.Append(*i);
46 path = path.Append(name);
53 @implementation ImageCaptureDevice
55 - (id)initWithCameraDevice:(ICCameraDevice*)cameraDevice {
56 if ((self = [super init])) {
57 camera_.reset([cameraDevice retain]);
58 [camera_ setDelegate:self];
65 // Make sure the session was closed and listener set to null
66 // before destruction.
67 DCHECK(![camera_ delegate]);
72 - (void)setListener:(base::WeakPtr<ImageCaptureDeviceListener>)listener {
73 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
78 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
80 [camera_ requestOpenSession];
84 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
86 [camera_ cancelDownload];
87 [camera_ requestCloseSession];
88 [camera_ setDelegate:nil];
93 [camera_ requestEjectOrDisconnect];
96 - (void)downloadFile:(const std::string&)name
97 localPath:(const base::FilePath&)localPath {
98 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
100 // Find the file with that name and start download.
101 for (ICCameraItem* item in [camera_ mediaFiles]) {
102 std::string itemName = PathForCameraItem(item).value();
103 if (itemName == name) {
104 // To create save options for ImageCapture, we need to
105 // split the target filename into directory/name
106 // and encode the directory as a URL.
107 NSString* saveDirectory =
108 base::mac::FilePathToNSString(localPath.DirName());
109 NSString* saveFilename =
110 base::mac::FilePathToNSString(localPath.BaseName());
112 NSMutableDictionary* options =
113 [NSMutableDictionary dictionaryWithCapacity:3];
114 [options setObject:[NSURL fileURLWithPath:saveDirectory isDirectory:YES]
115 forKey:ICDownloadsDirectoryURL];
116 [options setObject:saveFilename forKey:ICSaveAsFilename];
117 [options setObject:[NSNumber numberWithBool:YES] forKey:ICOverwrite];
119 [camera_ requestDownloadFile:base::mac::ObjCCastStrict<ICCameraFile>(item)
121 downloadDelegate:self
123 @selector(didDownloadFile:error:options:contextInfo:)
130 listener_->DownloadedFile(name, base::PLATFORM_FILE_ERROR_NOT_FOUND);
133 - (void)cameraDevice:(ICCameraDevice*)camera didAddItem:(ICCameraItem*)item {
134 base::PlatformFileInfo info;
135 if ([[item UTI] isEqualToString:base::mac::CFToNSCast(kUTTypeFolder)])
136 info.is_directory = true;
138 info.size = [base::mac::ObjCCastStrict<ICCameraFile>(item) fileSize];
140 base::FilePath path = PathForCameraItem(item);
142 info.last_modified = NSDateToBaseTime([item modificationDate]);
143 info.creation_time = NSDateToBaseTime([item creationDate]);
144 info.last_accessed = info.last_modified;
147 listener_->ItemAdded(path.value(), info);
150 - (void)cameraDevice:(ICCameraDevice*)camera didAddItems:(NSArray*)items {
151 for (ICCameraItem* item in items)
152 [self cameraDevice:camera didAddItem:item];
155 - (void)didRemoveDevice:(ICDevice*)device {
156 device.delegate = NULL;
158 listener_->DeviceRemoved();
161 // Notifies that a session was opened with the given device; potentially
163 - (void)device:(ICDevice*)device didOpenSessionWithError:(NSError*)error {
165 [self didRemoveDevice:camera_];
168 - (void)device:(ICDevice*)device didEncounterError:(NSError*)error {
169 if (error && listener_)
170 listener_->DeviceRemoved();
173 // When this message is received, all media metadata is now loaded.
174 - (void)deviceDidBecomeReadyWithCompleteContentCatalog:(ICDevice*)device {
176 listener_->NoMoreItems();
179 - (void)didDownloadFile:(ICCameraFile*)file
180 error:(NSError*)error
181 options:(NSDictionary*)options
182 contextInfo:(void*)contextInfo {
186 std::string name = PathForCameraItem(file).value();
189 DLOG(INFO) << "error..."
190 << base::SysNSStringToUTF8([error localizedDescription]);
192 listener_->DownloadedFile(name, base::PLATFORM_FILE_ERROR_FAILED);
196 std::string savedFilename =
197 base::SysNSStringToUTF8([options objectForKey:ICSavedFilename]);
198 std::string saveAsFilename =
199 base::SysNSStringToUTF8([options objectForKey:ICSaveAsFilename]);
200 if (savedFilename == saveAsFilename) {
202 listener_->DownloadedFile(name, base::PLATFORM_FILE_OK);
206 // ImageCapture did not save the file into the name we gave it in the
207 // options. It picks a new name according to its best lights, so we need
208 // to rename the file.
209 base::FilePath saveDir(base::SysNSStringToUTF8(
210 [[options objectForKey:ICDownloadsDirectoryURL] path]));
211 base::FilePath saveAsPath = saveDir.Append(saveAsFilename);
212 base::FilePath savedPath = saveDir.Append(savedFilename);
213 // Shared result value from file-copy closure to tell-listener closure.
214 content::BrowserThread::PostTaskAndReplyWithResult(
215 content::BrowserThread::FILE,
217 base::Bind(&RenameFile, savedPath, saveAsPath),
218 base::Bind(&ReturnRenameResultToListener, listener_, name));
221 @end // ImageCaptureDevice