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 ICDeviceTypeMaskCamera | ICDeviceLocationTypeMaskLocal];
58 [deviceBrowser_ start];
63 - (void)setNotifications:
64 (storage_monitor::StorageMonitor::Receiver*)notifications {
65 notifications_ = notifications;
69 [deviceBrowser_ setDelegate:nil];
70 [deviceBrowser_ stop];
71 deviceBrowser_.reset();
75 - (ImageCaptureDevice*) deviceForUUID:(const std::string&)uuid {
76 for (ICCameraDevice* camera in cameras_.get()) {
77 NSString* camera_id = [camera UUIDString];
78 if (base::SysNSStringToUTF8(camera_id) == uuid) {
79 return [[[ImageCaptureDevice alloc]
80 initWithCameraDevice:camera] autorelease];
86 - (void)deviceBrowser:(ICDeviceBrowser*)browser
87 didAddDevice:(ICDevice*)addedDevice
88 moreComing:(BOOL)moreComing {
89 if (!(addedDevice.type & ICDeviceTypeCamera))
92 // Ignore mass storage attaches -- those will be handled
93 // by Mac's removable storage watcher.
94 if ([addedDevice.transportType isEqualToString:ICTransportTypeMassStorage])
97 ICCameraDevice* cameraDevice =
98 base::mac::ObjCCastStrict<ICCameraDevice>(addedDevice);
100 [cameras_ addObject:addedDevice];
102 // TODO(gbillock): use [cameraDevice mountPoint] here when possible.
103 storage_monitor::StorageInfo info(
104 storage_monitor::StorageInfo::MakeDeviceId(
105 storage_monitor::StorageInfo::MAC_IMAGE_CAPTURE,
106 base::SysNSStringToUTF8([cameraDevice UUIDString])),
108 base::SysNSStringToUTF16([cameraDevice name]),
112 notifications_->ProcessAttach(info);
115 - (void)deviceBrowser:(ICDeviceBrowser*)browser
116 didRemoveDevice:(ICDevice*)device
117 moreGoing:(BOOL)moreGoing {
118 if (!(device.type & ICDeviceTypeCamera))
121 std::string uuid = base::SysNSStringToUTF8([device UUIDString]);
123 // May delete |device|.
124 [cameras_ removeObject:device];
126 notifications_->ProcessDetach(storage_monitor::StorageInfo::MakeDeviceId(
127 storage_monitor::StorageInfo::MAC_IMAGE_CAPTURE, uuid));
130 @end // ImageCaptureDeviceManagerImpl
132 namespace storage_monitor {
134 ImageCaptureDeviceManager::ImageCaptureDeviceManager() {
135 device_browser_.reset([[ImageCaptureDeviceManagerImpl alloc] init]);
136 g_image_capture_device_manager = this;
139 ImageCaptureDeviceManager::~ImageCaptureDeviceManager() {
140 g_image_capture_device_manager = NULL;
141 [device_browser_ close];
144 void ImageCaptureDeviceManager::SetNotifications(
145 StorageMonitor::Receiver* notifications) {
146 [device_browser_ setNotifications:notifications];
149 void ImageCaptureDeviceManager::EjectDevice(
150 const std::string& uuid,
151 base::Callback<void(StorageMonitor::EjectStatus)> callback) {
152 base::scoped_nsobject<ImageCaptureDevice> camera_device(
153 [[device_browser_ deviceForUUID:uuid] retain]);
154 [camera_device eject];
155 [camera_device close];
156 callback.Run(StorageMonitor::EJECT_OK);
160 ImageCaptureDevice* ImageCaptureDeviceManager::deviceForUUID(
161 const std::string& uuid) {
162 ImageCaptureDeviceManagerImpl* manager =
163 g_image_capture_device_manager->device_browser_;
164 return [manager deviceForUUID:uuid];
167 id<ICDeviceBrowserDelegate> ImageCaptureDeviceManager::device_browser() {
168 return device_browser_.get();
171 } // namespace storage_monitor