• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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.
4 
5 #include "chrome/browser/chromeos/extensions/file_browser_event_router.h"
6 
7 #include "base/json/json_writer.h"
8 #include "base/memory/singleton.h"
9 #include "base/stl_util-inl.h"
10 #include "base/values.h"
11 #include "chrome/browser/chromeos/cros/cros_library.h"
12 #include "chrome/browser/chromeos/login/user_manager.h"
13 #include "chrome/browser/chromeos/notifications/system_notification.h"
14 #include "chrome/browser/extensions/extension_event_names.h"
15 #include "chrome/browser/extensions/extension_event_router.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/extensions/file_manager_util.h"
18 #include "grit/generated_resources.h"
19 #include "grit/theme_resources.h"
20 #include "ui/base/l10n/l10n_util.h"
21 
22 const char kDiskAddedEventType[] = "added";
23 const char kDiskRemovedEventType[] = "removed";
24 
DeviceTypeToString(chromeos::DeviceType type)25 const char* DeviceTypeToString(chromeos::DeviceType type) {
26   switch (type) {
27     case chromeos::FLASH:
28       return "flash";
29     case chromeos::HDD:
30       return "hdd";
31     case chromeos::OPTICAL:
32       return "optical";
33     default:
34       break;
35   }
36   return "undefined";
37 }
38 
DiskToDictionaryValue(const chromeos::MountLibrary::Disk * disk)39 DictionaryValue* DiskToDictionaryValue(
40     const chromeos::MountLibrary::Disk* disk) {
41   DictionaryValue* result = new DictionaryValue();
42   result->SetString("mountPath", disk->mount_path());
43   result->SetString("label", disk->device_label());
44   result->SetString("deviceType", DeviceTypeToString(disk->device_type()));
45   result->SetInteger("totalSizeKB", disk->total_size() / 1024);
46   result->SetBoolean("readOnly", disk->is_read_only());
47   return result;
48 }
49 
ExtensionFileBrowserEventRouter()50 ExtensionFileBrowserEventRouter::ExtensionFileBrowserEventRouter()
51     : profile_(NULL) {
52 }
53 
~ExtensionFileBrowserEventRouter()54 ExtensionFileBrowserEventRouter::~ExtensionFileBrowserEventRouter() {
55 }
56 
ObserveFileSystemEvents(Profile * profile)57 void ExtensionFileBrowserEventRouter::ObserveFileSystemEvents(
58     Profile* profile) {
59   if (!profile)
60     return;
61   profile_ = profile;
62   if (!chromeos::CrosLibrary::Get()->EnsureLoaded())
63     return;
64   if (chromeos::UserManager::Get()->user_is_logged_in()) {
65     chromeos::MountLibrary* lib =
66         chromeos::CrosLibrary::Get()->GetMountLibrary();
67     lib->RemoveObserver(this);
68     lib->AddObserver(this);
69     lib->RequestMountInfoRefresh();
70   }
71 }
72 
StopObservingFileSystemEvents()73 void ExtensionFileBrowserEventRouter::StopObservingFileSystemEvents() {
74   if (!profile_)
75     return;
76   if (!chromeos::CrosLibrary::Get()->EnsureLoaded())
77     return;
78   chromeos::MountLibrary* lib =
79       chromeos::CrosLibrary::Get()->GetMountLibrary();
80   lib->RemoveObserver(this);
81   profile_ = NULL;
82 }
83 
84 // static
85 ExtensionFileBrowserEventRouter*
GetInstance()86     ExtensionFileBrowserEventRouter::GetInstance() {
87   return Singleton<ExtensionFileBrowserEventRouter>::get();
88 }
89 
DiskChanged(chromeos::MountLibraryEventType event,const chromeos::MountLibrary::Disk * disk)90 void ExtensionFileBrowserEventRouter::DiskChanged(
91     chromeos::MountLibraryEventType event,
92     const chromeos::MountLibrary::Disk* disk) {
93   if (event == chromeos::MOUNT_DISK_ADDED) {
94     OnDiskAdded(disk);
95   } else if (event == chromeos::MOUNT_DISK_REMOVED) {
96     OnDiskRemoved(disk);
97   } else if (event == chromeos::MOUNT_DISK_CHANGED) {
98     OnDiskChanged(disk);
99   }
100 }
101 
DeviceChanged(chromeos::MountLibraryEventType event,const std::string & device_path)102 void ExtensionFileBrowserEventRouter::DeviceChanged(
103     chromeos::MountLibraryEventType event,
104     const std::string& device_path) {
105   if (event == chromeos::MOUNT_DEVICE_ADDED) {
106     OnDeviceAdded(device_path);
107   } else if (event == chromeos::MOUNT_DEVICE_REMOVED) {
108     OnDeviceRemoved(device_path);
109   } else if (event == chromeos::MOUNT_DEVICE_SCANNED) {
110     OnDeviceScanned(device_path);
111   }
112 }
113 
DispatchEvent(const chromeos::MountLibrary::Disk * disk,bool added)114 void ExtensionFileBrowserEventRouter::DispatchEvent(
115     const chromeos::MountLibrary::Disk* disk, bool added) {
116   if (!profile_) {
117     NOTREACHED();
118     return;
119   }
120 
121   ListValue args;
122   DictionaryValue* mount_info = new DictionaryValue();
123   args.Append(mount_info);
124   mount_info->SetString("eventType",
125                         added ? kDiskAddedEventType : kDiskRemovedEventType);
126   DictionaryValue* disk_info = DiskToDictionaryValue(disk);
127   mount_info->Set("volumeInfo", disk_info);
128 
129   std::string args_json;
130   base::JSONWriter::Write(&args, false /* pretty_print */, &args_json);
131   profile_->GetExtensionEventRouter()->DispatchEventToRenderers(
132       extension_event_names::kOnFileBrowserDiskChanged, args_json, NULL,
133       GURL());
134 }
135 
OnDiskAdded(const chromeos::MountLibrary::Disk * disk)136 void ExtensionFileBrowserEventRouter::OnDiskAdded(
137     const chromeos::MountLibrary::Disk* disk) {
138   VLOG(1) << "Disk added: " << disk->device_path();
139   if (disk->device_path().empty()) {
140     VLOG(1) << "Empty system path for " << disk->device_path();
141     return;
142   }
143   if (disk->is_parent()) {
144     if (!disk->has_media())
145       HideDeviceNotification(disk->system_path());
146     return;
147   }
148 
149   // If disk is not mounted yet, give it a try.
150   if (disk->mount_path().empty()) {
151     // Initiate disk mount operation.
152     chromeos::MountLibrary* lib =
153         chromeos::CrosLibrary::Get()->GetMountLibrary();
154     lib->MountPath(disk->device_path().c_str());
155   }
156 }
157 
OnDiskRemoved(const chromeos::MountLibrary::Disk * disk)158 void ExtensionFileBrowserEventRouter::OnDiskRemoved(
159     const chromeos::MountLibrary::Disk* disk) {
160   VLOG(1) << "Disk removed: " << disk->device_path();
161   HideDeviceNotification(disk->system_path());
162   MountPointMap::iterator iter = mounted_devices_.find(disk->device_path());
163   if (iter == mounted_devices_.end())
164     return;
165 
166   chromeos::MountLibrary* lib =
167       chromeos::CrosLibrary::Get()->GetMountLibrary();
168   // TODO(zelidrag): This for some reason does not work as advertized.
169   // we might need to clean up mount directory on FILE thread here as well.
170   lib->UnmountPath(disk->device_path().c_str());
171 
172   DispatchEvent(disk, false);
173   mounted_devices_.erase(iter);
174 }
175 
OnDiskChanged(const chromeos::MountLibrary::Disk * disk)176 void ExtensionFileBrowserEventRouter::OnDiskChanged(
177     const chromeos::MountLibrary::Disk* disk) {
178   VLOG(1) << "Disk changed : " << disk->device_path();
179   if (!disk->mount_path().empty()) {
180     HideDeviceNotification(disk->system_path());
181     // Remember this mount point.
182     if (mounted_devices_.find(disk->device_path()) == mounted_devices_.end()) {
183       mounted_devices_.insert(
184           std::pair<std::string, std::string>(disk->device_path(),
185                                               disk->mount_path()));
186       DispatchEvent(disk, true);
187       HideDeviceNotification(disk->system_path());
188       FileManagerUtil::ShowFullTabUrl(profile_, FilePath(disk->mount_path()));
189     }
190   }
191 }
192 
OnDeviceAdded(const std::string & device_path)193 void ExtensionFileBrowserEventRouter::OnDeviceAdded(
194     const std::string& device_path) {
195   VLOG(1) << "Device added : " << device_path;
196   // TODO(zelidrag): Find better icon here.
197   ShowDeviceNotification(device_path, IDR_PAGEINFO_INFO,
198       l10n_util::GetStringUTF16(IDS_REMOVABLE_DEVICE_SCANNING_MESSAGE));
199 
200 }
201 
OnDeviceRemoved(const std::string & system_path)202 void ExtensionFileBrowserEventRouter::OnDeviceRemoved(
203     const std::string& system_path) {
204   HideDeviceNotification(system_path);
205 }
206 
OnDeviceScanned(const std::string & device_path)207 void ExtensionFileBrowserEventRouter::OnDeviceScanned(
208     const std::string& device_path) {
209   VLOG(1) << "Device scanned : " << device_path;
210 }
211 
ShowDeviceNotification(const std::string & system_path,int icon_resource_id,const string16 & message)212 void ExtensionFileBrowserEventRouter::ShowDeviceNotification(
213     const std::string& system_path, int icon_resource_id,
214     const string16& message) {
215   NotificationMap::iterator iter = FindNotificationForPath(system_path);
216   std::string mount_path;
217   if (iter != notifications_.end()) {
218     iter->second->Show(message, false, false);
219   } else {
220     if (!profile_) {
221       NOTREACHED();
222       return;
223     }
224     chromeos::SystemNotification* notification =
225         new chromeos::SystemNotification(
226             profile_,
227             system_path,
228             icon_resource_id,
229             l10n_util::GetStringUTF16(IDS_REMOVABLE_DEVICE_DETECTION_TITLE));
230     notifications_.insert(NotificationMap::value_type(system_path,
231         linked_ptr<chromeos::SystemNotification>(notification)));
232     notification->Show(message, false, false);
233   }
234 }
235 
HideDeviceNotification(const std::string & system_path)236 void ExtensionFileBrowserEventRouter::HideDeviceNotification(
237     const std::string& system_path) {
238   NotificationMap::iterator iter = FindNotificationForPath(system_path);
239   if (iter != notifications_.end()) {
240     iter->second->Hide();
241     notifications_.erase(iter);
242   }
243 }
244 
245 ExtensionFileBrowserEventRouter::NotificationMap::iterator
FindNotificationForPath(const std::string & system_path)246     ExtensionFileBrowserEventRouter::FindNotificationForPath(
247         const std::string& system_path) {
248   for (NotificationMap::iterator iter = notifications_.begin();
249        iter != notifications_.end();
250        ++iter) {
251     const std::string& notification_device_path = iter->first;
252     // Doing a sub string match so that we find if this new one is a subdevice
253     // of another already inserted device.
254     if (StartsWithASCII(system_path, notification_device_path, true)) {
255       return iter;
256     }
257   }
258   return notifications_.end();
259 }
260