Cancel on-going scan when change directory is requested.
[chromium-blink-merge.git] / components / storage_monitor / media_transfer_protocol_device_observer_linux.cc
blobe44fe0919e3eb837e4e63800fc631abe7748f6ff
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/media_transfer_protocol_device_observer_linux.h"
7 #include <vector>
9 #include "base/files/file_path.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "components/storage_monitor/media_storage_util.h"
15 #include "components/storage_monitor/removable_device_constants.h"
16 #include "device/media_transfer_protocol/mtp_storage_info.pb.h"
18 namespace storage_monitor {
20 namespace {
22 // Device root path constant.
23 const char kRootPath[] = "/";
25 // Constructs and returns the location of the device using the |storage_name|.
26 std::string GetDeviceLocationFromStorageName(const std::string& storage_name) {
27 // Construct a dummy device path using the storage name. This is only used
28 // for registering device media file system.
29 // E.g.: If the |storage_name| is "usb:2,2:12345" then "/usb:2,2:12345" is the
30 // device location.
31 DCHECK(!storage_name.empty());
32 return kRootPath + storage_name;
35 // Returns the storage identifier of the device from the given |storage_name|.
36 // E.g. If the |storage_name| is "usb:2,2:65537", the storage identifier is
37 // "65537".
38 std::string GetStorageIdFromStorageName(const std::string& storage_name) {
39 std::vector<std::string> name_parts;
40 base::SplitString(storage_name, ':', &name_parts);
41 return name_parts.size() == 3 ? name_parts[2] : std::string();
44 // Returns a unique device id from the given |storage_info|.
45 std::string GetDeviceIdFromStorageInfo(const MtpStorageInfo& storage_info) {
46 const std::string storage_id =
47 GetStorageIdFromStorageName(storage_info.storage_name());
48 if (storage_id.empty())
49 return std::string();
51 // Some devices have multiple data stores. Therefore, include storage id as
52 // part of unique id along with vendor, model and volume information.
53 const std::string vendor_id = base::UintToString(storage_info.vendor_id());
54 const std::string model_id = base::UintToString(storage_info.product_id());
55 return StorageInfo::MakeDeviceId(
56 StorageInfo::MTP_OR_PTP,
57 kVendorModelVolumeStoragePrefix + vendor_id + ":" + model_id + ":" +
58 storage_info.volume_identifier() + ":" + storage_id);
61 // Returns the |data_store_id| string in the required format.
62 // If the |data_store_id| is 65537, this function returns " (65537)".
63 std::string GetFormattedIdString(const std::string& data_store_id) {
64 return ("(" + data_store_id + ")");
67 // Helper function to get device label from storage information.
68 base::string16 GetDeviceLabelFromStorageInfo(
69 const MtpStorageInfo& storage_info) {
70 std::string device_label;
71 const std::string& vendor_name = storage_info.vendor();
72 device_label = vendor_name;
74 const std::string& product_name = storage_info.product();
75 if (!product_name.empty()) {
76 if (!device_label.empty())
77 device_label += " ";
78 device_label += product_name;
81 // Add the data store id to the device label.
82 if (!device_label.empty()) {
83 const std::string& volume_id = storage_info.volume_identifier();
84 if (!volume_id.empty()) {
85 device_label += GetFormattedIdString(volume_id);
86 } else {
87 const std::string data_store_id =
88 GetStorageIdFromStorageName(storage_info.storage_name());
89 if (!data_store_id.empty())
90 device_label += GetFormattedIdString(data_store_id);
93 return base::UTF8ToUTF16(device_label);
96 // Helper function to get the device storage details such as device id, label
97 // and location. On success and fills in |id|, |label|, |location|,
98 // |vendor_name|, and |product_name|.
99 void GetStorageInfo(const std::string& storage_name,
100 device::MediaTransferProtocolManager* mtp_manager,
101 std::string* id,
102 base::string16* label,
103 std::string* location,
104 base::string16* vendor_name,
105 base::string16* product_name) {
106 DCHECK(!storage_name.empty());
107 const MtpStorageInfo* storage_info =
108 mtp_manager->GetStorageInfo(storage_name);
110 if (!storage_info)
111 return;
113 *id = GetDeviceIdFromStorageInfo(*storage_info);
114 *label = GetDeviceLabelFromStorageInfo(*storage_info);
115 *location = GetDeviceLocationFromStorageName(storage_name);
116 *vendor_name = base::UTF8ToUTF16(storage_info->vendor());
117 *product_name = base::UTF8ToUTF16(storage_info->product());
120 } // namespace
122 MediaTransferProtocolDeviceObserverLinux::
123 MediaTransferProtocolDeviceObserverLinux(
124 StorageMonitor::Receiver* receiver,
125 device::MediaTransferProtocolManager* mtp_manager)
126 : mtp_manager_(mtp_manager),
127 get_storage_info_func_(&GetStorageInfo),
128 notifications_(receiver) {
129 mtp_manager_->AddObserver(this);
130 EnumerateStorages();
133 // This constructor is only used by unit tests.
134 MediaTransferProtocolDeviceObserverLinux::
135 MediaTransferProtocolDeviceObserverLinux(
136 StorageMonitor::Receiver* receiver,
137 device::MediaTransferProtocolManager* mtp_manager,
138 GetStorageInfoFunc get_storage_info_func)
139 : mtp_manager_(mtp_manager),
140 get_storage_info_func_(get_storage_info_func),
141 notifications_(receiver) {
144 MediaTransferProtocolDeviceObserverLinux::
145 ~MediaTransferProtocolDeviceObserverLinux() {
146 mtp_manager_->RemoveObserver(this);
149 bool MediaTransferProtocolDeviceObserverLinux::GetStorageInfoForPath(
150 const base::FilePath& path,
151 StorageInfo* storage_info) const {
152 DCHECK(storage_info);
154 if (!path.IsAbsolute())
155 return false;
157 std::vector<base::FilePath::StringType> path_components;
158 path.GetComponents(&path_components);
159 if (path_components.size() < 2)
160 return false;
162 // First and second component of the path specifies the device location.
163 // E.g.: If |path| is "/usb:2,2:65537/DCIM/Folder_a", "/usb:2,2:65537" is the
164 // device location.
165 StorageLocationToInfoMap::const_iterator info_it =
166 storage_map_.find(GetDeviceLocationFromStorageName(path_components[1]));
167 if (info_it == storage_map_.end())
168 return false;
170 *storage_info = info_it->second;
171 return true;
174 void MediaTransferProtocolDeviceObserverLinux::EjectDevice(
175 const std::string& device_id,
176 base::Callback<void(StorageMonitor::EjectStatus)> callback) {
177 std::string location;
178 if (!GetLocationForDeviceId(device_id, &location)) {
179 callback.Run(StorageMonitor::EJECT_NO_SUCH_DEVICE);
180 return;
183 // TODO(thestig): Change this to tell the mtp manager to eject the device.
185 StorageChanged(false, location);
186 callback.Run(StorageMonitor::EJECT_OK);
189 // device::MediaTransferProtocolManager::Observer override.
190 void MediaTransferProtocolDeviceObserverLinux::StorageChanged(
191 bool is_attached,
192 const std::string& storage_name) {
193 DCHECK(!storage_name.empty());
195 // New storage is attached.
196 if (is_attached) {
197 std::string device_id;
198 base::string16 storage_label;
199 std::string location;
200 base::string16 vendor_name;
201 base::string16 product_name;
202 get_storage_info_func_(storage_name, mtp_manager_,
203 &device_id, &storage_label, &location,
204 &vendor_name, &product_name);
206 // Keep track of device id and device name to see how often we receive
207 // empty values.
208 MediaStorageUtil::RecordDeviceInfoHistogram(false, device_id,
209 storage_label);
210 if (device_id.empty() || storage_label.empty())
211 return;
213 DCHECK(!ContainsKey(storage_map_, location));
215 StorageInfo storage_info(device_id, location, storage_label,
216 vendor_name, product_name, 0);
217 storage_map_[location] = storage_info;
218 notifications_->ProcessAttach(storage_info);
219 } else {
220 // Existing storage is detached.
221 StorageLocationToInfoMap::iterator it =
222 storage_map_.find(GetDeviceLocationFromStorageName(storage_name));
223 if (it == storage_map_.end())
224 return;
225 notifications_->ProcessDetach(it->second.device_id());
226 storage_map_.erase(it);
230 void MediaTransferProtocolDeviceObserverLinux::EnumerateStorages() {
231 typedef std::vector<std::string> StorageList;
232 StorageList storages = mtp_manager_->GetStorages();
233 for (StorageList::const_iterator storage_iter = storages.begin();
234 storage_iter != storages.end(); ++storage_iter) {
235 StorageChanged(true, *storage_iter);
239 bool MediaTransferProtocolDeviceObserverLinux::GetLocationForDeviceId(
240 const std::string& device_id, std::string* location) const {
241 for (StorageLocationToInfoMap::const_iterator it = storage_map_.begin();
242 it != storage_map_.end(); ++it) {
243 if (it->second.device_id() == device_id) {
244 *location = it->first;
245 return true;
249 return false;
252 } // namespace storage_monitor