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 #include "components/storage_monitor/image_capture_device_manager.h"
7 #import <ImageCaptureCore/ImageCaptureCore.h>
9 #import "components/storage_monitor/image_capture_device.h"
10 #include "components/storage_monitor/storage_info.h"
14 storage_monitor::ImageCaptureDeviceManager* g_image_capture_device_manager =
19 // This class is the surface for the Mac ICDeviceBrowser ImageCaptureCore API.
20 // Owned by the ChromeBrowserParts and has browser process lifetime. Upon
21 // creation, it gets a list of attached media volumes (asynchronously) which
22 // it will eventually forward to StorageMonitor. It will also
23 // set up an ImageCaptureCore listener to be told when new devices/volumes
24 // are discovered and existing ones are removed.
25 @interface ImageCaptureDeviceManagerImpl
26 : NSObject<ICDeviceBrowserDelegate> {
28 base::scoped_nsobject<ICDeviceBrowser> deviceBrowser_;
29 base::scoped_nsobject<NSMutableArray> cameras_;
31 // Guaranteed to outlive this class.
32 // TODO(gbillock): Update when ownership chains go up through
33 // a StorageMonitor subclass.
34 storage_monitor::StorageMonitor::Receiver* notifications_;
37 - (void)setNotifications:
38 (storage_monitor::StorageMonitor::Receiver*)notifications;
41 // The UUIDs passed here are available in the device attach notifications.
42 // They're gotten by cracking the device ID and taking the unique ID output.
43 - (ImageCaptureDevice*)deviceForUUID:(const std::string&)uuid;
47 @implementation ImageCaptureDeviceManagerImpl
50 if ((self = [super init])) {
51 cameras_.reset([[NSMutableArray alloc] init]);
52 notifications_ = NULL;
54 deviceBrowser_.reset([[ICDeviceBrowser alloc] init]);
55 [deviceBrowser_ setDelegate:self];
56 [deviceBrowser_ setBrowsedDeviceTypeMask:
57 static_cast<ICDeviceTypeMask>(
58 ICDeviceTypeMaskCamera | ICDeviceLocationTypeMaskLocal)];
59 [deviceBrowser_ start];
64 - (void)setNotifications:
65 (storage_monitor::StorageMonitor::Receiver*)notifications {
66 notifications_ = notifications;
70 [deviceBrowser_ setDelegate:nil];
71 [deviceBrowser_ stop];
72 deviceBrowser_.reset();
76 - (ImageCaptureDevice*) deviceForUUID:(const std::string&)uuid {
77 for (ICCameraDevice* camera in cameras_.get()) {
78 NSString* camera_id = [camera UUIDString];
79 if (base::SysNSStringToUTF8(camera_id) == uuid) {
80 return [[[ImageCaptureDevice alloc]
81 initWithCameraDevice:camera] autorelease];
87 - (void)deviceBrowser:(ICDeviceBrowser*)browser
88 didAddDevice:(ICDevice*)addedDevice
89 moreComing:(BOOL)moreComing {
90 if (!(addedDevice.type & ICDeviceTypeCamera))
93 // Ignore mass storage attaches -- those will be handled
94 // by Mac's removable storage watcher.
95 if ([addedDevice.transportType isEqualToString:ICTransportTypeMassStorage])
98 ICCameraDevice* cameraDevice =
99 base::mac::ObjCCastStrict<ICCameraDevice>(addedDevice);
101 [cameras_ addObject:addedDevice];
103 // TODO(gbillock): use [cameraDevice mountPoint] here when possible.
104 storage_monitor::StorageInfo info(
105 storage_monitor::StorageInfo::MakeDeviceId(
106 storage_monitor::StorageInfo::MAC_IMAGE_CAPTURE,
107 base::SysNSStringToUTF8([cameraDevice UUIDString])),
109 base::SysNSStringToUTF16([cameraDevice name]),
113 notifications_->ProcessAttach(info);
116 - (void)deviceBrowser:(ICDeviceBrowser*)browser
117 didRemoveDevice:(ICDevice*)device
118 moreGoing:(BOOL)moreGoing {
119 if (!(device.type & ICDeviceTypeCamera))
122 std::string uuid = base::SysNSStringToUTF8([device UUIDString]);
124 // May delete |device|.
125 [cameras_ removeObject:device];
127 notifications_->ProcessDetach(storage_monitor::StorageInfo::MakeDeviceId(
128 storage_monitor::StorageInfo::MAC_IMAGE_CAPTURE, uuid));
131 @end // ImageCaptureDeviceManagerImpl
133 namespace storage_monitor {
135 ImageCaptureDeviceManager::ImageCaptureDeviceManager() {
136 device_browser_.reset([[ImageCaptureDeviceManagerImpl alloc] init]);
137 g_image_capture_device_manager = this;
140 ImageCaptureDeviceManager::~ImageCaptureDeviceManager() {
141 g_image_capture_device_manager = NULL;
142 [device_browser_ close];
145 void ImageCaptureDeviceManager::SetNotifications(
146 StorageMonitor::Receiver* notifications) {
147 [device_browser_ setNotifications:notifications];
150 void ImageCaptureDeviceManager::EjectDevice(
151 const std::string& uuid,
152 base::Callback<void(StorageMonitor::EjectStatus)> callback) {
153 base::scoped_nsobject<ImageCaptureDevice> camera_device(
154 [[device_browser_ deviceForUUID:uuid] retain]);
155 [camera_device eject];
156 [camera_device close];
157 callback.Run(StorageMonitor::EJECT_OK);
161 ImageCaptureDevice* ImageCaptureDeviceManager::deviceForUUID(
162 const std::string& uuid) {
163 ImageCaptureDeviceManagerImpl* manager =
164 g_image_capture_device_manager->device_browser_;
165 return [manager deviceForUUID:uuid];
168 id<ICDeviceBrowserDelegate> ImageCaptureDeviceManager::device_browser() {
169 return device_browser_.get();
172 } // namespace storage_monitor