Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: chrome/browser/chromeos/arc/arc_downloads_watcher_service.cc

Issue 2003533002: arc: Register media files to MediaProvider. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@lkgr
Patch Set: Use size_t. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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/arc/arc_downloads_watcher_service.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/callback.h"
11 #include "base/files/file_enumerator.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_path_watcher.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/download/download_prefs.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "components/arc/arc_bridge_service.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "mojo/public/cpp/bindings/array.h"
22
23 using content::BrowserThread;
24
25 // Mapping from Android file paths to last modified timestamps.
26 using TimestampMap = std::map<base::FilePath, base::Time>;
27
28 static const base::FilePath::CharType kAndroidDownloadDir[] =
29 FILE_PATH_LITERAL("/storage/emulated/0/Download");
30
31 namespace arc {
32
33 namespace {
34
35 // Compares two TimestampMaps and returns the list of file paths added/removed
36 // or whose timestamp have changed.
37 std::vector<base::FilePath> CollectChangedPaths(
38 const TimestampMap& timestamp_map_a,
39 const TimestampMap& timestamp_map_b) {
40 std::vector<base::FilePath> changed_paths;
41
42 TimestampMap::const_iterator iter_a = timestamp_map_a.begin();
43 TimestampMap::const_iterator iter_b = timestamp_map_b.begin();
44 while (iter_a != timestamp_map_a.end() && iter_b != timestamp_map_b.end()) {
45 if (iter_a->first == iter_b->first) {
46 if (iter_a->second != iter_b->second) {
47 changed_paths.emplace_back(iter_a->first);
48 }
49 ++iter_a;
50 ++iter_b;
51 } else if (iter_a->first < iter_b->first) {
52 changed_paths.emplace_back(iter_a->first);
53 ++iter_a;
54 } else { // iter_a->first > iter_b->first
55 changed_paths.emplace_back(iter_b->first);
56 ++iter_b;
57 }
58 }
59
60 while (iter_a != timestamp_map_a.end()) {
61 changed_paths.emplace_back(iter_a->first);
62 ++iter_a;
63 }
64 while (iter_b != timestamp_map_b.end()) {
65 changed_paths.emplace_back(iter_b->first);
66 ++iter_b;
67 }
68
69 return changed_paths;
70 }
71
72 } // namespace
73
74 // The core part of ArcDownloadsWatcherService to watch for file changes in
75 // Downloads directory.
76 class ArcDownloadsWatcherService::DownloadsWatcher {
77 public:
78 using Callback =
79 base::Callback<void(const std::vector<base::FilePath>& paths)>;
80
81 explicit DownloadsWatcher(const Callback& callback);
82 ~DownloadsWatcher();
83
84 // Starts watching Downloads directory.
85 void Start();
86
87 private:
88 // Called by base::FilePathWatcher to notify file changes.
89 void OnFilePathChanged(const base::FilePath& path, bool error);
90
91 // Scans files under |downloads_dir_| recursively and builds a map from file
92 // paths (in Android filesystem) to last modified timestamps.
93 TimestampMap BuildTimestampMap() const;
94
95 Callback callback_;
96 base::FilePath downloads_dir_;
97 std::unique_ptr<base::FilePathWatcher> watcher_;
98 TimestampMap last_timestamp_map_;
99
100 // Note: This should remain the last member so it'll be destroyed and
101 // invalidate the weak pointers before any other members are destroyed.
102 base::WeakPtrFactory<DownloadsWatcher> weak_ptr_factory_;
103
104 DISALLOW_COPY_AND_ASSIGN(DownloadsWatcher);
105 };
106
107 ArcDownloadsWatcherService::DownloadsWatcher::DownloadsWatcher(
108 const Callback& callback)
109 : callback_(callback), weak_ptr_factory_(this) {
110 DCHECK_CURRENTLY_ON(BrowserThread::UI);
111
112 downloads_dir_ = DownloadPrefs(ProfileManager::GetActiveUserProfile())
113 .GetDefaultDownloadDirectoryForProfile()
114 .StripTrailingSeparators();
115 }
116
117 ArcDownloadsWatcherService::DownloadsWatcher::~DownloadsWatcher() {
118 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
119 }
120
121 void ArcDownloadsWatcherService::DownloadsWatcher::Start() {
122 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
123
124 // Initialize with the current timestamp map and avoid initial notification.
125 // It is not needed since MediaProvider scans whole storage area on boot.
126 last_timestamp_map_ = BuildTimestampMap();
127
128 watcher_ = base::MakeUnique<base::FilePathWatcher>();
129 // On Linux, base::FilePathWatcher::Watch() always returns true.
130 watcher_->Watch(downloads_dir_, true,
131 base::Bind(&DownloadsWatcher::OnFilePathChanged,
132 weak_ptr_factory_.GetWeakPtr()));
133 }
134
135 void ArcDownloadsWatcherService::DownloadsWatcher::OnFilePathChanged(
136 const base::FilePath& path,
137 bool error) {
138 // On Linux, |error| is always false. Also, |path| is always the same path
139 // as one given to FilePathWatcher::Watch().
140 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
141
142 TimestampMap current_timestamp_map = BuildTimestampMap();
143
144 std::vector<base::FilePath> changed_paths =
145 CollectChangedPaths(last_timestamp_map_, current_timestamp_map);
146
147 last_timestamp_map_ = std::move(current_timestamp_map);
148
149 callback_.Run(changed_paths);
150 }
151
152 TimestampMap ArcDownloadsWatcherService::DownloadsWatcher::BuildTimestampMap()
153 const {
154 DCHECK(!downloads_dir_.EndsWithSeparator());
155 TimestampMap timestamp_map;
156
157 // Enumerate normal files only; directories and symlinks are skipped.
158 base::FileEnumerator enumerator(downloads_dir_, true,
159 base::FileEnumerator::FILES);
160 for (base::FilePath cros_path = enumerator.Next(); !cros_path.empty();
161 cros_path = enumerator.Next()) {
162 // Android file path can be obtained by replacing |downloads_dir_| prefix
163 // with |kAndroidDownloadDir|.
164 const base::FilePath& android_path =
165 base::FilePath(kAndroidDownloadDir)
166 .Append(
167 cros_path.value().substr(downloads_dir_.value().length() + 1));
168 const base::FileEnumerator::FileInfo& info = enumerator.GetInfo();
169 timestamp_map[android_path] = info.GetLastModifiedTime();
170 }
171 return timestamp_map;
172 }
173
174 ArcDownloadsWatcherService::ArcDownloadsWatcherService(
175 ArcBridgeService* bridge_service)
176 : ArcService(bridge_service), weak_ptr_factory_(this) {
177 DCHECK_CURRENTLY_ON(BrowserThread::UI);
178 arc_bridge_service()->AddObserver(this);
179 }
180
181 ArcDownloadsWatcherService::~ArcDownloadsWatcherService() {
182 DCHECK_CURRENTLY_ON(BrowserThread::UI);
183 arc_bridge_service()->RemoveObserver(this);
184 StopWatchingDownloads();
185 DCHECK(!watcher_.get());
186 }
187
188 void ArcDownloadsWatcherService::OnFileSystemInstanceReady() {
189 DCHECK_CURRENTLY_ON(BrowserThread::UI);
190 StartWatchingDownloads();
191 }
192
193 void ArcDownloadsWatcherService::OnFileSystemInstanceClosed() {
194 DCHECK_CURRENTLY_ON(BrowserThread::UI);
195 StopWatchingDownloads();
196 }
197
198 void ArcDownloadsWatcherService::StartWatchingDownloads() {
199 DCHECK_CURRENTLY_ON(BrowserThread::UI);
200 StopWatchingDownloads();
201 DCHECK(!watcher_.get());
202 watcher_ = base::MakeUnique<DownloadsWatcher>(
203 base::Bind(&ArcDownloadsWatcherService::OnDownloadsChanged,
204 weak_ptr_factory_.GetWeakPtr()));
205 BrowserThread::PostTask(
206 BrowserThread::FILE, FROM_HERE,
207 base::Bind(&DownloadsWatcher::Start, base::Unretained(watcher_.get())));
208 }
209
210 void ArcDownloadsWatcherService::StopWatchingDownloads() {
211 DCHECK_CURRENTLY_ON(BrowserThread::UI);
212 if (watcher_.get()) {
213 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE,
214 watcher_.release());
215 }
216 }
217
218 void ArcDownloadsWatcherService::OnDownloadsChanged(
219 const std::vector<base::FilePath>& paths) {
220 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
221
222 auto instance = arc_bridge_service()->file_system_instance();
223 if (!instance) {
224 return;
225 }
226
227 mojo::Array<mojo::String> mojo_paths(paths.size());
228 for (size_t i = 0; i < paths.size(); ++i) {
229 mojo_paths[i] = paths[i].value();
230 }
231 instance->RequestMediaScan(std::move(mojo_paths));
232 }
233
234 } // namespace arc
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/arc/arc_downloads_watcher_service.h ('k') | chrome/browser/chromeos/arc/arc_service_launcher.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698