Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / components / storage_monitor / image_capture_device.mm
1 // Copyright 2014 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 #import "components/storage_monitor/image_capture_device.h"
6
7 #include "base/file_util.h"
8 #include "content/public/browser/browser_thread.h"
9
10 namespace {
11
12 base::File::Error 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::File::FILE_OK : base::File::FILE_ERROR_NOT_FOUND;
17 }
18
19 void ReturnRenameResultToListener(
20     base::WeakPtr<ImageCaptureDeviceListener> listener,
21     const std::string& name,
22     const base::File::Error& result) {
23   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
24   if (listener)
25     listener->DownloadedFile(name, result);
26 }
27
28 base::Time NSDateToBaseTime(NSDate* date) {
29   return base::Time::FromDoubleT([date timeIntervalSince1970]);
30 }
31
32 base::FilePath PathForCameraItem(ICCameraItem* item) {
33   std::string name = base::SysNSStringToUTF8([item name]);
34
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];
40   }
41   base::FilePath path;
42   for (std::vector<std::string>::reverse_iterator i = components.rbegin();
43        i != components.rend(); ++i) {
44     path = path.Append(*i);
45   }
46   path = path.Append(name);
47
48   return path;
49 }
50
51 }  // namespace
52
53 @implementation ImageCaptureDevice
54
55 - (id)initWithCameraDevice:(ICCameraDevice*)cameraDevice {
56   if ((self = [super init])) {
57     camera_.reset([cameraDevice retain]);
58     [camera_ setDelegate:self];
59     closing_ = false;
60   }
61   return self;
62 }
63
64 - (void)dealloc {
65   // Make sure the session was closed and listener set to null
66   // before destruction.
67   DCHECK(![camera_ delegate]);
68   DCHECK(!listener_);
69   [super dealloc];
70 }
71
72 - (void)setListener:(base::WeakPtr<ImageCaptureDeviceListener>)listener {
73   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
74   listener_ = listener;
75 }
76
77 - (void)open {
78   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
79   DCHECK(listener_);
80   [camera_ requestOpenSession];
81 }
82
83 - (void)close {
84   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
85   closing_ = true;
86   [camera_ cancelDownload];
87   [camera_ requestCloseSession];
88   [camera_ setDelegate:nil];
89   listener_.reset();
90 }
91
92 - (void)eject {
93   [camera_ requestEjectOrDisconnect];
94 }
95
96 - (void)downloadFile:(const std::string&)name
97            localPath:(const base::FilePath&)localPath {
98   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
99
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());
111
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];
118
119       [camera_ requestDownloadFile:base::mac::ObjCCastStrict<ICCameraFile>(item)
120                            options:options
121                   downloadDelegate:self
122                didDownloadSelector:
123                    @selector(didDownloadFile:error:options:contextInfo:)
124                        contextInfo:NULL];
125       return;
126     }
127   }
128
129   if (listener_)
130     listener_->DownloadedFile(name, base::File::FILE_ERROR_NOT_FOUND);
131 }
132
133 - (void)cameraDevice:(ICCameraDevice*)camera didAddItem:(ICCameraItem*)item {
134   base::File::Info info;
135   if ([[item UTI] isEqualToString:base::mac::CFToNSCast(kUTTypeFolder)])
136     info.is_directory = true;
137   else
138     info.size = [base::mac::ObjCCastStrict<ICCameraFile>(item) fileSize];
139
140   base::FilePath path = PathForCameraItem(item);
141
142   info.last_modified = NSDateToBaseTime([item modificationDate]);
143   info.creation_time = NSDateToBaseTime([item creationDate]);
144   info.last_accessed = info.last_modified;
145
146   if (listener_)
147     listener_->ItemAdded(path.value(), info);
148 }
149
150 - (void)cameraDevice:(ICCameraDevice*)camera didAddItems:(NSArray*)items {
151   for (ICCameraItem* item in items)
152     [self cameraDevice:camera didAddItem:item];
153 }
154
155 - (void)didRemoveDevice:(ICDevice*)device {
156   device.delegate = NULL;
157   if (listener_)
158     listener_->DeviceRemoved();
159 }
160
161 // Notifies that a session was opened with the given device; potentially
162 // with an error.
163 - (void)device:(ICDevice*)device didOpenSessionWithError:(NSError*)error {
164   if (error)
165     [self didRemoveDevice:camera_];
166 }
167
168 - (void)device:(ICDevice*)device didEncounterError:(NSError*)error {
169   if (error && listener_)
170     listener_->DeviceRemoved();
171 }
172
173 // When this message is received, all media metadata is now loaded.
174 - (void)deviceDidBecomeReadyWithCompleteContentCatalog:(ICDevice*)device {
175   if (listener_)
176     listener_->NoMoreItems();
177 }
178
179 - (void)didDownloadFile:(ICCameraFile*)file
180                   error:(NSError*)error
181                 options:(NSDictionary*)options
182             contextInfo:(void*)contextInfo {
183   if (closing_)
184     return;
185
186   std::string name = PathForCameraItem(file).value();
187
188   if (error) {
189     DVLOG(1) << "error..."
190              << base::SysNSStringToUTF8([error localizedDescription]);
191     if (listener_)
192       listener_->DownloadedFile(name, base::File::FILE_ERROR_FAILED);
193     return;
194   }
195
196   std::string savedFilename =
197       base::SysNSStringToUTF8([options objectForKey:ICSavedFilename]);
198   std::string saveAsFilename =
199       base::SysNSStringToUTF8([options objectForKey:ICSaveAsFilename]);
200   if (savedFilename == saveAsFilename) {
201     if (listener_)
202       listener_->DownloadedFile(name, base::File::FILE_OK);
203     return;
204   }
205
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,
216       FROM_HERE,
217       base::Bind(&RenameFile, savedPath, saveAsPath),
218       base::Bind(&ReturnRenameResultToListener, listener_, name));
219 }
220
221 @end  // ImageCaptureDevice