Run VM apptests on Android; disable fixtures failing or timing out.
[chromium-blink-merge.git] / components / storage_monitor / image_capture_device.mm
blob29285d938cad61058bfd9d70103ba9abd953a541
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.
5 #import "components/storage_monitor/image_capture_device.h"
7 #include "base/files/file_util.h"
8 #include "content/public/browser/browser_thread.h"
10 namespace storage_monitor {
12 namespace {
14 base::File::Error RenameFile(const base::FilePath& downloaded_filename,
15                              const base::FilePath& desired_filename) {
16   DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
17   bool success = base::ReplaceFile(downloaded_filename, desired_filename, NULL);
18   return success ? base::File::FILE_OK : base::File::FILE_ERROR_NOT_FOUND;
21 void ReturnRenameResultToListener(
22     base::WeakPtr<ImageCaptureDeviceListener> listener,
23     const std::string& name,
24     const base::File::Error& result) {
25   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
26   if (listener)
27     listener->DownloadedFile(name, result);
30 base::Time NSDateToBaseTime(NSDate* date) {
31   return base::Time::FromDoubleT([date timeIntervalSince1970]);
34 base::FilePath PathForCameraItem(ICCameraItem* item) {
35   std::string name = base::SysNSStringToUTF8([item name]);
37   std::vector<std::string> components;
38   ICCameraFolder* folder = [item parentFolder];
39   while (folder != nil) {
40     components.push_back(base::SysNSStringToUTF8([folder name]));
41     folder = [folder parentFolder];
42   }
43   base::FilePath path;
44   for (std::vector<std::string>::reverse_iterator i = components.rbegin();
45        i != components.rend(); ++i) {
46     path = path.Append(*i);
47   }
48   path = path.Append(name);
50   return path;
53 }  // namespace
55 }  // namespace storage_monitor
57 @implementation ImageCaptureDevice
59 - (id)initWithCameraDevice:(ICCameraDevice*)cameraDevice {
60   if ((self = [super init])) {
61     camera_.reset([cameraDevice retain]);
62     [camera_ setDelegate:self];
63     closing_ = false;
64   }
65   return self;
68 - (void)dealloc {
69   // Make sure the session was closed and listener set to null
70   // before destruction.
71   DCHECK(![camera_ delegate]);
72   DCHECK(!listener_);
73   [super dealloc];
76 - (void)setListener:(base::WeakPtr<storage_monitor::ImageCaptureDeviceListener>)
77         listener {
78   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
79   listener_ = listener;
82 - (void)open {
83   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
84   DCHECK(listener_);
85   [camera_ requestOpenSession];
88 - (void)close {
89   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
90   closing_ = true;
91   [camera_ cancelDownload];
92   [camera_ requestCloseSession];
93   [camera_ setDelegate:nil];
94   listener_.reset();
97 - (void)eject {
98   [camera_ requestEjectOrDisconnect];
101 - (void)downloadFile:(const std::string&)name
102            localPath:(const base::FilePath&)localPath {
103   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
105   // Find the file with that name and start download.
106   for (ICCameraItem* item in [camera_ mediaFiles]) {
107     std::string itemName = storage_monitor::PathForCameraItem(item).value();
108     if (itemName == name) {
109       // To create save options for ImageCapture, we need to
110       // split the target filename into directory/name
111       // and encode the directory as a URL.
112       NSString* saveDirectory =
113           base::mac::FilePathToNSString(localPath.DirName());
114       NSString* saveFilename =
115           base::mac::FilePathToNSString(localPath.BaseName());
117       NSMutableDictionary* options =
118           [NSMutableDictionary dictionaryWithCapacity:3];
119       [options setObject:[NSURL fileURLWithPath:saveDirectory isDirectory:YES]
120                   forKey:ICDownloadsDirectoryURL];
121       [options setObject:saveFilename forKey:ICSaveAsFilename];
122       [options setObject:[NSNumber numberWithBool:YES] forKey:ICOverwrite];
124       [camera_ requestDownloadFile:base::mac::ObjCCastStrict<ICCameraFile>(item)
125                            options:options
126                   downloadDelegate:self
127                didDownloadSelector:
128                    @selector(didDownloadFile:error:options:contextInfo:)
129                        contextInfo:NULL];
130       return;
131     }
132   }
134   if (listener_)
135     listener_->DownloadedFile(name, base::File::FILE_ERROR_NOT_FOUND);
138 - (void)cameraDevice:(ICCameraDevice*)camera didAddItem:(ICCameraItem*)item {
139   base::File::Info info;
140   if ([[item UTI] isEqualToString:base::mac::CFToNSCast(kUTTypeFolder)])
141     info.is_directory = true;
142   else
143     info.size = [base::mac::ObjCCastStrict<ICCameraFile>(item) fileSize];
145   base::FilePath path = storage_monitor::PathForCameraItem(item);
147   info.last_modified =
148       storage_monitor::NSDateToBaseTime([item modificationDate]);
149   info.creation_time = storage_monitor::NSDateToBaseTime([item creationDate]);
150   info.last_accessed = info.last_modified;
152   if (listener_)
153     listener_->ItemAdded(path.value(), info);
156 - (void)cameraDevice:(ICCameraDevice*)camera didAddItems:(NSArray*)items {
157   for (ICCameraItem* item in items)
158     [self cameraDevice:camera didAddItem:item];
161 - (void)didRemoveDevice:(ICDevice*)device {
162   device.delegate = NULL;
163   if (listener_)
164     listener_->DeviceRemoved();
167 // Notifies that a session was opened with the given device; potentially
168 // with an error.
169 - (void)device:(ICDevice*)device didOpenSessionWithError:(NSError*)error {
170   if (error)
171     [self didRemoveDevice:camera_];
174 - (void)device:(ICDevice*)device didEncounterError:(NSError*)error {
175   if (error && listener_)
176     listener_->DeviceRemoved();
179 // When this message is received, all media metadata is now loaded.
180 - (void)deviceDidBecomeReadyWithCompleteContentCatalog:(ICDevice*)device {
181   if (listener_)
182     listener_->NoMoreItems();
185 - (void)didDownloadFile:(ICCameraFile*)file
186                   error:(NSError*)error
187                 options:(NSDictionary*)options
188             contextInfo:(void*)contextInfo {
189   if (closing_)
190     return;
192   std::string name = storage_monitor::PathForCameraItem(file).value();
194   if (error) {
195     DVLOG(1) << "error..."
196              << base::SysNSStringToUTF8([error localizedDescription]);
197     if (listener_)
198       listener_->DownloadedFile(name, base::File::FILE_ERROR_FAILED);
199     return;
200   }
202   std::string savedFilename =
203       base::SysNSStringToUTF8([options objectForKey:ICSavedFilename]);
204   std::string saveAsFilename =
205       base::SysNSStringToUTF8([options objectForKey:ICSaveAsFilename]);
206   if (savedFilename == saveAsFilename) {
207     if (listener_)
208       listener_->DownloadedFile(name, base::File::FILE_OK);
209     return;
210   }
212   // ImageCapture did not save the file into the name we gave it in the
213   // options. It picks a new name according to its best lights, so we need
214   // to rename the file.
215   base::FilePath saveDir(base::SysNSStringToUTF8(
216       [[options objectForKey:ICDownloadsDirectoryURL] path]));
217   base::FilePath saveAsPath = saveDir.Append(saveAsFilename);
218   base::FilePath savedPath = saveDir.Append(savedFilename);
219   // Shared result value from file-copy closure to tell-listener closure.
220   content::BrowserThread::PostTaskAndReplyWithResult(
221       content::BrowserThread::FILE,
222       FROM_HERE,
223       base::Bind(&storage_monitor::RenameFile, savedPath, saveAsPath),
224       base::Bind(
225           &storage_monitor::ReturnRenameResultToListener, listener_, name));
228 @end  // ImageCaptureDevice