[M120 Migration][VD] Enable direct rendering for TVPlus
[platform/framework/web/chromium-efl.git] / components / storage_monitor / image_capture_device.mm
1 // Copyright 2014 The Chromium Authors
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 <ImageCaptureCore/ImageCaptureCore.h>
8 #import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
9
10 #include "base/apple/bridging.h"
11 #include "base/apple/foundation_util.h"
12 #include "base/containers/adapters.h"
13 #include "base/files/file_util.h"
14 #include "base/functional/bind.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/task/task_traits.h"
17 #include "base/task/thread_pool.h"
18 #include "content/public/browser/browser_thread.h"
19
20 namespace storage_monitor {
21
22 namespace {
23
24 base::File::Error RenameFile(const base::FilePath& downloaded_filename,
25                              const base::FilePath& desired_filename) {
26   bool success =
27       base::ReplaceFile(downloaded_filename, desired_filename, nullptr);
28   return success ? base::File::FILE_OK : base::File::FILE_ERROR_NOT_FOUND;
29 }
30
31 void ReturnRenameResultToListener(
32     base::WeakPtr<ImageCaptureDeviceListener> listener,
33     const std::string& name,
34     const base::File::Error& result) {
35   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
36   if (listener) {
37     listener->DownloadedFile(name, result);
38   }
39 }
40
41 base::FilePath PathForCameraItem(ICCameraItem* item) {
42   std::string name = base::SysNSStringToUTF8(item.name);
43
44   std::vector<std::string> components;
45   ICCameraFolder* folder = item.parentFolder;
46   while (folder != nil) {
47     components.push_back(base::SysNSStringToUTF8(folder.name));
48     folder = folder.parentFolder;
49   }
50   base::FilePath path;
51   for (const std::string& component : base::Reversed(components)) {
52     path = path.Append(component);
53   }
54   path = path.Append(name);
55
56   return path;
57 }
58
59 }  // namespace
60
61 }  // namespace storage_monitor
62
63 @implementation ImageCaptureDevice {
64   ICCameraDevice* __strong _camera;
65   base::WeakPtr<storage_monitor::ImageCaptureDeviceListener> _listener;
66   bool _closing;
67 }
68
69 - (instancetype)initWithCameraDevice:(ICCameraDevice*)cameraDevice {
70   if ((self = [super init])) {
71     _camera = cameraDevice;
72     _camera.delegate = self;
73   }
74   return self;
75 }
76
77 - (void)dealloc {
78   // Make sure the session was closed and listener set to null
79   // before destruction.
80   DCHECK(!_camera.delegate);
81   DCHECK(!_listener);
82 }
83
84 - (void)setListener:(base::WeakPtr<storage_monitor::ImageCaptureDeviceListener>)
85         listener {
86   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
87   _listener = listener;
88 }
89
90 - (void)open {
91   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
92   DCHECK(_listener);
93   [_camera requestOpenSession];
94 }
95
96 - (void)close {
97   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
98   _closing = true;
99   [_camera cancelDownload];
100   [_camera requestCloseSession];
101   _camera.delegate = nil;
102   _listener.reset();
103 }
104
105 - (void)eject {
106   [_camera requestEject];
107 }
108
109 - (void)downloadFile:(const std::string&)name
110            localPath:(const base::FilePath&)localPath {
111   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
112
113   // Find the file with that name and start download.
114   for (ICCameraItem* item in _camera.mediaFiles) {
115     std::string itemName = storage_monitor::PathForCameraItem(item).value();
116     if (itemName == name) {
117       // To create save options for ImageCapture, we need to split the target
118       // filename into directory/name and encode the directory as a URL.
119       NSURL* saveDirectory = base::apple::FilePathToNSURL(localPath.DirName());
120       NSString* saveFilename =
121           base::apple::FilePathToNSString(localPath.BaseName());
122
123       NSDictionary* options = @{
124         ICDownloadsDirectoryURL : saveDirectory,
125         ICSaveAsFilename : saveFilename,
126         ICOverwrite : @YES,
127       };
128
129       [_camera
130           requestDownloadFile:base::apple::ObjCCastStrict<ICCameraFile>(item)
131                       options:options
132              downloadDelegate:self
133           didDownloadSelector:@selector(didDownloadFile:
134                                                   error:options:contextInfo:)
135                   contextInfo:nullptr];
136       return;
137     }
138   }
139
140   if (_listener) {
141     _listener->DownloadedFile(name, base::File::FILE_ERROR_NOT_FOUND);
142   }
143 }
144
145 // ----- ICDeviceDelegate (super-protocol of ICCameraDeviceDelegate) -----
146
147 - (void)didRemoveDevice:(ICDevice*)device {
148   device.delegate = nullptr;
149   if (_listener) {
150     _listener->DeviceRemoved();
151   }
152 }
153
154 // Notifies that a session was opened with the given device; potentially
155 // with an error.
156 - (void)device:(ICDevice*)device didOpenSessionWithError:(NSError*)error {
157   if (error) {
158     [self didRemoveDevice:_camera];
159   }
160 }
161
162 - (void)device:(ICDevice*)device didEncounterError:(NSError*)error {
163   if (error && _listener) {
164     _listener->DeviceRemoved();
165   }
166 }
167
168 // Various ICDeviceDelegate calls that are not used but need to exist as part of
169 // a full delegate implementation.
170
171 - (void)device:(ICDevice*)device didCloseSessionWithError:(NSError*)error {
172 }
173
174 // ----- ICCameraDeviceDelegate -----
175
176 - (void)cameraDevice:(ICCameraDevice*)camera
177          didAddItems:(NSArray<ICCameraItem*>*)items {
178   NSString* folderIdentifier;
179   if (@available(macOS 11, *)) {
180     folderIdentifier = UTTypeFolder.identifier;
181   } else {
182     folderIdentifier = base::apple::CFToNSPtrCast(kUTTypeFolder);
183   }
184
185   for (ICCameraItem* item in items) {
186     base::File::Info info;
187     if ([item.UTI isEqualToString:folderIdentifier]) {
188       info.is_directory = true;
189     } else {
190       info.size = base::apple::ObjCCastStrict<ICCameraFile>(item).fileSize;
191     }
192
193     base::FilePath path = storage_monitor::PathForCameraItem(item);
194
195     info.last_modified = base::Time::FromNSDate(item.modificationDate);
196     info.creation_time = base::Time::FromNSDate(item.creationDate);
197     info.last_accessed = info.last_modified;
198
199     if (_listener) {
200       _listener->ItemAdded(path.value(), info);
201     }
202   }
203 }
204
205 // When this message is received, all media metadata is now loaded.
206 - (void)deviceDidBecomeReadyWithCompleteContentCatalog:(ICDevice*)device {
207   if (_listener) {
208     _listener->NoMoreItems();
209   }
210 }
211
212 // Various ICCameraDeviceDelegate calls that are not used but need to exist as
213 // part of a full delegate implementation.
214
215 - (void)cameraDevice:(ICCameraDevice*)camera didRemoveItems:(NSArray*)items {
216 }
217
218 - (void)cameraDevice:(ICCameraDevice*)camera
219     didReceiveThumbnail:(CGImageRef)thumbnail
220                 forItem:(ICCameraItem*)item
221                   error:(NSError*)error {
222 }
223
224 - (void)cameraDevice:(ICCameraDevice*)camera
225     didReceiveMetadata:(NSDictionary*)metadata
226                forItem:(ICCameraItem*)item
227                  error:(NSError*)error {
228 }
229
230 - (void)cameraDevice:(ICCameraDevice*)camera
231       didRenameItems:(NSArray<ICCameraItem*>*)items {
232 }
233
234 - (void)cameraDeviceDidChangeCapability:(ICCameraDevice*)camera {
235 }
236
237 - (void)cameraDevice:(ICCameraDevice*)camera
238     didReceivePTPEvent:(NSData*)eventData {
239 }
240
241 - (void)cameraDeviceDidRemoveAccessRestriction:(ICDevice*)device {
242 }
243
244 - (void)cameraDeviceDidEnableAccessRestriction:(ICDevice*)device {
245 }
246
247 // ----- ICCameraDeviceDownloadDelegate -----
248
249 - (void)didDownloadFile:(ICCameraFile*)file
250                   error:(NSError*)error
251                 options:(NSDictionary*)options
252             contextInfo:(void*)contextInfo {
253   if (_closing) {
254     return;
255   }
256
257   std::string name = storage_monitor::PathForCameraItem(file).value();
258
259   if (error) {
260     DVLOG(1) << "error..."
261              << base::SysNSStringToUTF8(error.localizedDescription);
262     if (_listener) {
263       _listener->DownloadedFile(name, base::File::FILE_ERROR_FAILED);
264     }
265     return;
266   }
267
268   std::string savedFilename = base::SysNSStringToUTF8(options[ICSavedFilename]);
269   std::string saveAsFilename =
270       base::SysNSStringToUTF8(options[ICSaveAsFilename]);
271   if (savedFilename == saveAsFilename) {
272     if (_listener) {
273       _listener->DownloadedFile(name, base::File::FILE_OK);
274     }
275     return;
276   }
277
278   // ImageCapture did not save the file into the name we gave it in the
279   // options. It picks a new name according to its best lights, so we need
280   // to rename the file.
281   base::FilePath saveDir(
282       base::SysNSStringToUTF8([options[ICDownloadsDirectoryURL] path]));
283   base::FilePath saveAsPath = saveDir.Append(saveAsFilename);
284   base::FilePath savedPath = saveDir.Append(savedFilename);
285   // Shared result value from file-copy closure to tell-listener closure.
286   // This is worth blocking shutdown, as otherwise a file that has been
287   // downloaded will be incorrectly named.
288   base::ThreadPool::PostTaskAndReplyWithResult(
289       FROM_HERE,
290       {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
291        base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
292       base::BindOnce(&storage_monitor::RenameFile, savedPath, saveAsPath),
293       base::BindOnce(&storage_monitor::ReturnRenameResultToListener, _listener,
294                      name));
295 }
296
297 @end  // ImageCaptureDevice