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

Side by Side Diff: chrome/browser/media/native_desktop_media_list.cc

Issue 1503563004: Desktop chrome tab capture-chooseDesktopMedia() (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/media/native_desktop_media_list.h" 5 #include "chrome/browser/media/native_desktop_media_list.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 #include <map> 9 #include <map>
10 #include <set> 10 #include <set>
11 #include <sstream> 11 #include <sstream>
12 #include <utility> 12 #include <utility>
13 #include <vector>
13 14
14 #include "base/hash.h" 15 #include "base/hash.h"
15 #include "base/logging.h" 16 #include "base/logging.h"
16 #include "base/macros.h" 17 #include "base/macros.h"
17 #include "base/strings/utf_string_conversions.h" 18 #include "base/strings/utf_string_conversions.h"
18 #include "base/threading/sequenced_worker_pool.h" 19 #include "base/threading/sequenced_worker_pool.h"
20 #include "chrome/browser/mac/bluetooth_utility.h"
19 #include "chrome/browser/media/desktop_media_list_observer.h" 21 #include "chrome/browser/media/desktop_media_list_observer.h"
22 #include "chrome/browser/profiles/profile_manager.h"
23 #include "chrome/browser/ui/browser_finder.h"
24 #include "chrome/browser/ui/host_desktop.h"
25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/grit/generated_resources.h" 26 #include "chrome/grit/generated_resources.h"
27 #include "components/favicon/content/content_favicon_driver.h"
21 #include "content/public/browser/browser_thread.h" 28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/render_frame_host.h"
30 #include "content/public/browser/render_process_host.h"
22 #include "media/base/video_util.h" 31 #include "media/base/video_util.h"
23 #include "third_party/libyuv/include/libyuv/scale_argb.h" 32 #include "third_party/libyuv/include/libyuv/scale_argb.h"
24 #include "third_party/skia/include/core/SkBitmap.h" 33 #include "third_party/skia/include/core/SkBitmap.h"
25 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 34 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
26 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" 35 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
27 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" 36 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h"
37 #include "ui/aura/window.h"
28 #include "ui/base/l10n/l10n_util.h" 38 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/gfx/skia_util.h" 39 #include "ui/gfx/skia_util.h"
40 #include "ui/snapshot/snapshot.h"
30 41
31 using content::BrowserThread; 42 using content::BrowserThread;
32 using content::DesktopMediaID; 43 using content::DesktopMediaID;
33 44
34 namespace { 45 namespace {
35 46
36 // Update the list every second. 47 // Update the list every second.
37 const int kDefaultUpdatePeriod = 1000; 48 const int kDefaultUpdatePeriod = 1000;
38 49
39 // Returns a hash of a DesktopFrame content to detect when image for a desktop 50 // Returns a hash of a DesktopFrame content to detect when image for a desktop
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 result.unlockPixels(); 86 result.unlockPixels();
76 87
77 return gfx::ImageSkia::CreateFrom1xBitmap(result); 88 return gfx::ImageSkia::CreateFrom1xBitmap(result);
78 } 89 }
79 90
80 } // namespace 91 } // namespace
81 92
82 NativeDesktopMediaList::SourceDescription::SourceDescription( 93 NativeDesktopMediaList::SourceDescription::SourceDescription(
83 DesktopMediaID id, 94 DesktopMediaID id,
84 const base::string16& name) 95 const base::string16& name)
85 : id(id), 96 : id(id), name(name) {}
86 name(name) {
87 }
88 97
89 class NativeDesktopMediaList::Worker 98 class NativeDesktopMediaList::Worker
90 : public webrtc::DesktopCapturer::Callback { 99 : public webrtc::DesktopCapturer::Callback {
91 public: 100 public:
92 Worker(base::WeakPtr<NativeDesktopMediaList> media_list, 101 Worker(base::WeakPtr<NativeDesktopMediaList> media_list,
93 scoped_ptr<webrtc::ScreenCapturer> screen_capturer, 102 scoped_ptr<webrtc::ScreenCapturer> screen_capturer,
94 scoped_ptr<webrtc::WindowCapturer> window_capturer); 103 scoped_ptr<webrtc::WindowCapturer> window_capturer);
95 ~Worker() override; 104 ~Worker() override;
96 105
97 void Refresh(const gfx::Size& thumbnail_size, 106 void Refresh(const gfx::Size& thumbnail_size,
98 content::DesktopMediaID::Id view_dialog_id); 107 content::DesktopMediaID::Id view_dialog_id,
108 const std::vector<SourceDescription>& tab_sources);
99 109
100 private: 110 private:
101 typedef std::map<DesktopMediaID, uint32_t> ImageHashesMap; 111 typedef std::map<DesktopMediaID, uint32_t> ImageHashesMap;
102 112
103 // webrtc::DesktopCapturer::Callback interface. 113 // webrtc::DesktopCapturer::Callback interface.
104 webrtc::SharedMemory* CreateSharedMemory(size_t size) override; 114 webrtc::SharedMemory* CreateSharedMemory(size_t size) override;
105 void OnCaptureCompleted(webrtc::DesktopFrame* frame) override; 115 void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
106 116
107 base::WeakPtr<NativeDesktopMediaList> media_list_; 117 base::WeakPtr<NativeDesktopMediaList> media_list_;
108 118
(...skipping 17 matching lines...) Expand all
126 if (screen_capturer_) 136 if (screen_capturer_)
127 screen_capturer_->Start(this); 137 screen_capturer_->Start(this);
128 if (window_capturer_) 138 if (window_capturer_)
129 window_capturer_->Start(this); 139 window_capturer_->Start(this);
130 } 140 }
131 141
132 NativeDesktopMediaList::Worker::~Worker() {} 142 NativeDesktopMediaList::Worker::~Worker() {}
133 143
134 void NativeDesktopMediaList::Worker::Refresh( 144 void NativeDesktopMediaList::Worker::Refresh(
135 const gfx::Size& thumbnail_size, 145 const gfx::Size& thumbnail_size,
136 content::DesktopMediaID::Id view_dialog_id) { 146 content::DesktopMediaID::Id view_dialog_id,
147 const std::vector<SourceDescription>& tab_sources) {
137 std::vector<SourceDescription> sources; 148 std::vector<SourceDescription> sources;
138 149
139 if (screen_capturer_) { 150 if (screen_capturer_) {
140 webrtc::ScreenCapturer::ScreenList screens; 151 webrtc::ScreenCapturer::ScreenList screens;
141 if (screen_capturer_->GetScreenList(&screens)) { 152 if (screen_capturer_->GetScreenList(&screens)) {
142 bool mutiple_screens = screens.size() > 1; 153 bool mutiple_screens = screens.size() > 1;
143 base::string16 title; 154 base::string16 title;
144 for (size_t i = 0; i < screens.size(); ++i) { 155 for (size_t i = 0; i < screens.size(); ++i) {
145 if (mutiple_screens) { 156 if (mutiple_screens) {
146 title = l10n_util::GetStringFUTF16Int( 157 title = l10n_util::GetStringFUTF16Int(
(...skipping 16 matching lines...) Expand all
163 it != windows.end(); ++it) { 174 it != windows.end(); ++it) {
164 // Skip the picker dialog window. 175 // Skip the picker dialog window.
165 if (it->id != view_dialog_id) { 176 if (it->id != view_dialog_id) {
166 sources.push_back(SourceDescription( 177 sources.push_back(SourceDescription(
167 DesktopMediaID(DesktopMediaID::TYPE_WINDOW, it->id), 178 DesktopMediaID(DesktopMediaID::TYPE_WINDOW, it->id),
168 base::UTF8ToUTF16(it->title))); 179 base::UTF8ToUTF16(it->title)));
169 } 180 }
170 } 181 }
171 } 182 }
172 } 183 }
184
185 // Add tab sources to all media sources
Avi (use Gerrit) 2016/01/08 17:11:38 Full sentences; end with a .
GeorgeZ 2016/01/08 19:39:02 Done.
186 sources.insert(sources.end(), tab_sources.begin(), tab_sources.end());
187
173 // Update list of windows before updating thumbnails. 188 // Update list of windows before updating thumbnails.
174 BrowserThread::PostTask( 189 BrowserThread::PostTask(
175 BrowserThread::UI, FROM_HERE, 190 BrowserThread::UI, FROM_HERE,
176 base::Bind(&NativeDesktopMediaList::OnSourcesList, 191 base::Bind(&NativeDesktopMediaList::OnSourcesList,
177 media_list_, sources)); 192 media_list_, sources));
178 193
179 ImageHashesMap new_image_hashes; 194 ImageHashesMap new_image_hashes;
180 195
181 // Get a thumbnail for each source. 196 // Get a thumbnail for each source.
182 for (size_t i = 0; i < sources.size(); ++i) { 197 for (size_t i = 0; i < sources.size(); ++i) {
183 SourceDescription& source = sources[i]; 198 SourceDescription& source = sources[i];
184 switch (source.id.type) { 199 switch (source.id.type) {
185 case DesktopMediaID::TYPE_SCREEN: 200 case DesktopMediaID::TYPE_SCREEN:
186 if (!screen_capturer_->SelectScreen(source.id.id)) 201 if (!screen_capturer_->SelectScreen(source.id.id))
187 continue; 202 continue;
188 screen_capturer_->Capture(webrtc::DesktopRegion()); 203 screen_capturer_->Capture(webrtc::DesktopRegion());
189 break; 204 break;
190 205
191 case DesktopMediaID::TYPE_WINDOW: 206 case DesktopMediaID::TYPE_WINDOW:
192 if (!window_capturer_->SelectWindow(source.id.id)) 207 if (!window_capturer_->SelectWindow(source.id.id))
193 continue; 208 continue;
194 window_capturer_->Capture(webrtc::DesktopRegion()); 209 window_capturer_->Capture(webrtc::DesktopRegion());
195 break; 210 break;
211 case DesktopMediaID::TYPE_TAB:
212 // Favicon has already captured for tabs.
213 break;
196 214
197 default: 215 default:
198 NOTREACHED(); 216 NOTREACHED();
199 } 217 }
200 218
219 // Use captured tab favicon as thumbnail.
220 if (source.id.type == DesktopMediaID::TYPE_TAB) {
221 BrowserThread::PostTask(
222 BrowserThread::UI, FROM_HERE,
223 base::Bind(&NativeDesktopMediaList::OnSourceTabThumbnail, media_list_,
224 source));
225 continue;
226 }
227
201 // Expect that DesktopCapturer to always captures frames synchronously. 228 // Expect that DesktopCapturer to always captures frames synchronously.
202 // |current_frame_| may be NULL if capture failed (e.g. because window has 229 // |current_frame_| may be NULL if capture failed (e.g. because window has
203 // been closed). 230 // been closed).
204 if (current_frame_) { 231 if (current_frame_) {
205 uint32_t frame_hash = GetFrameHash(current_frame_.get()); 232 uint32_t frame_hash = GetFrameHash(current_frame_.get());
206 new_image_hashes[source.id] = frame_hash; 233 new_image_hashes[source.id] = frame_hash;
207 234
208 // Scale the image only if it has changed. 235 // Scale the image only if it has changed.
209 ImageHashesMap::iterator it = image_hashes_.find(source.id); 236 ImageHashesMap::iterator it = image_hashes_.find(source.id);
210 if (it == image_hashes_.end() || it->second != frame_hash) { 237 if (it == image_hashes_.end() || it->second != frame_hash) {
211 gfx::ImageSkia thumbnail = 238 gfx::ImageSkia thumbnail =
212 ScaleDesktopFrame(std::move(current_frame_), thumbnail_size); 239 ScaleDesktopFrame(std::move(current_frame_), thumbnail_size);
213 BrowserThread::PostTask( 240 BrowserThread::PostTask(
214 BrowserThread::UI, FROM_HERE, 241 BrowserThread::UI, FROM_HERE,
215 base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, 242 base::Bind(&NativeDesktopMediaList::OnSourceThumbnail, media_list_,
216 media_list_, i, thumbnail)); 243 i, thumbnail));
217 } 244 }
218 } 245 }
219 } 246 }
220 247
221 image_hashes_.swap(new_image_hashes); 248 image_hashes_.swap(new_image_hashes);
222 249
223 BrowserThread::PostTask( 250 BrowserThread::PostTask(
224 BrowserThread::UI, FROM_HERE, 251 BrowserThread::UI, FROM_HERE,
225 base::Bind(&NativeDesktopMediaList::OnRefreshFinished, media_list_)); 252 base::Bind(&NativeDesktopMediaList::OnRefreshFinished, media_list_));
226 } 253 }
227 254
228 webrtc::SharedMemory* NativeDesktopMediaList::Worker::CreateSharedMemory( 255 webrtc::SharedMemory* NativeDesktopMediaList::Worker::CreateSharedMemory(
229 size_t size) { 256 size_t size) {
230 return NULL; 257 return NULL;
231 } 258 }
232 259
233 void NativeDesktopMediaList::Worker::OnCaptureCompleted( 260 void NativeDesktopMediaList::Worker::OnCaptureCompleted(
234 webrtc::DesktopFrame* frame) { 261 webrtc::DesktopFrame* frame) {
235 current_frame_.reset(frame); 262 current_frame_.reset(frame);
236 } 263 }
237 264
238 NativeDesktopMediaList::NativeDesktopMediaList( 265 NativeDesktopMediaList::NativeDesktopMediaList(
239 scoped_ptr<webrtc::ScreenCapturer> screen_capturer, 266 scoped_ptr<webrtc::ScreenCapturer> screen_capturer,
240 scoped_ptr<webrtc::WindowCapturer> window_capturer) 267 scoped_ptr<webrtc::WindowCapturer> window_capturer,
268 bool tab_capture_enabled)
241 : screen_capturer_(std::move(screen_capturer)), 269 : screen_capturer_(std::move(screen_capturer)),
242 window_capturer_(std::move(window_capturer)), 270 window_capturer_(std::move(window_capturer)),
271 tab_capture_enabled_(tab_capture_enabled),
243 update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)), 272 update_period_(base::TimeDelta::FromMilliseconds(kDefaultUpdatePeriod)),
244 thumbnail_size_(100, 100), 273 thumbnail_size_(100, 100),
245 view_dialog_id_(content::DesktopMediaID::TYPE_NONE, -1), 274 view_dialog_id_(content::DesktopMediaID::TYPE_NONE, -1),
246 observer_(NULL), 275 observer_(NULL),
247 weak_factory_(this) { 276 weak_factory_(this) {
248 base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool(); 277 base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool();
249 capture_task_runner_ = worker_pool->GetSequencedTaskRunner( 278 capture_task_runner_ = worker_pool->GetSequencedTaskRunner(
250 worker_pool->GetSequenceToken()); 279 worker_pool->GetSequenceToken());
251 } 280 }
252 281
(...skipping 11 matching lines...) Expand all
264 thumbnail_size_ = thumbnail_size; 293 thumbnail_size_ = thumbnail_size;
265 } 294 }
266 295
267 void NativeDesktopMediaList::SetViewDialogWindowId( 296 void NativeDesktopMediaList::SetViewDialogWindowId(
268 content::DesktopMediaID dialog_id) { 297 content::DesktopMediaID dialog_id) {
269 view_dialog_id_ = dialog_id; 298 view_dialog_id_ = dialog_id;
270 } 299 }
271 300
272 void NativeDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) { 301 void NativeDesktopMediaList::StartUpdating(DesktopMediaListObserver* observer) {
273 DCHECK(!observer_); 302 DCHECK(!observer_);
274 DCHECK(screen_capturer_ || window_capturer_); 303 DCHECK(screen_capturer_ || window_capturer_ || tab_capture_enabled_);
275 304
276 observer_ = observer; 305 observer_ = observer;
277 306
278 worker_.reset(new Worker(weak_factory_.GetWeakPtr(), 307 worker_.reset(new Worker(weak_factory_.GetWeakPtr(),
279 std::move(screen_capturer_), 308 std::move(screen_capturer_),
280 std::move(window_capturer_))); 309 std::move(window_capturer_)));
281 Refresh(); 310 Refresh();
282 } 311 }
283 312
284 int NativeDesktopMediaList::GetSourceCount() const { 313 int NativeDesktopMediaList::GetSourceCount() const {
285 return sources_.size(); 314 return sources_.size();
286 } 315 }
287 316
288 const DesktopMediaList::Source& NativeDesktopMediaList::GetSource( 317 const DesktopMediaList::Source& NativeDesktopMediaList::GetSource(
289 int index) const { 318 int index) const {
290 return sources_[index]; 319 return sources_[index];
291 } 320 }
292 321
293 void NativeDesktopMediaList::Refresh() { 322 void NativeDesktopMediaList::Refresh() {
323 // Get tab source list
Avi (use Gerrit) 2016/01/08 17:11:38 .
GeorgeZ 2016/01/08 19:39:02 Done.
324 std::vector<SourceDescription> tab_sources;
325 if (tab_capture_enabled_)
326 GetTabSourceDescriptions(&tab_sources);
327
294 capture_task_runner_->PostTask( 328 capture_task_runner_->PostTask(
295 FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()), 329 FROM_HERE, base::Bind(&Worker::Refresh, base::Unretained(worker_.get()),
296 thumbnail_size_, view_dialog_id_.id)); 330 thumbnail_size_, view_dialog_id_.id, tab_sources));
331 }
332
333 void NativeDesktopMediaList::GetTabSourceDescriptions(
334 std::vector<SourceDescription>* tab_sources) {
335 // Clear old favicon map.
336 tab_icon_map_.clear();
337
338 // Use to sort tabs based on their last active time stamps.
339 std::map<base::TimeTicks, SourceDescription> tab_map;
340
341 // Get all tabs/webcontents' ids for a user profile
342 Profile* profile = ProfileManager::GetLastUsedProfileAllowedByPolicy();
343 std::vector<Browser*> browsers = FindAllTabbedBrowsersWithProfile(
344 profile, chrome::HOST_DESKTOP_TYPE_NATIVE);
345
346 std::vector<scoped_ptr<MediaListWebContentsObserver>> observers;
347 for (auto browser : browsers) {
348 TabStripModel* tab_strip_model = browser->tab_strip_model();
349 DCHECK(tab_strip_model);
350
351 for (int i = 0; i < tab_strip_model->count(); i++) {
352 content::WebContents* contents = tab_strip_model->GetWebContentsAt(i);
353 // Use observer to keep track the state of WebContents.
354 scoped_ptr<MediaListWebContentsObserver> observer(
355 new MediaListWebContentsObserver(contents));
356 observers.push_back(std::move(observer));
357 }
358 }
359
360 // For each tab, get its title and favicon.
361 for (size_t i = 0; i < observers.size(); i++) {
362 // If the WebContent has been destroyed, a nullptr will return;
363 content::WebContents* contents = observers[i]->web_contents();
Avi (use Gerrit) 2016/01/08 17:11:38 Same objection here. This code is useless for the
GeorgeZ 2016/01/08 19:39:02 Done.
364 if (contents == nullptr)
365 continue;
366
367 content::RenderFrameHost* const main_frame = contents->GetMainFrame();
368 DCHECK(main_frame);
369 DesktopMediaID media_id(
370 DesktopMediaID::TYPE_TAB, DesktopMediaID::kNullId,
371 content::WebContentsMediaCaptureId(main_frame->GetProcess()->GetID(),
372 main_frame->GetRoutingID()));
373
374 // Create display tab title.
375 base::string16 title = l10n_util::GetStringFUTF16(
376 IDS_DESKTOP_MEDIA_PICKER_CHROME_TAB_TITLE, contents->GetTitle());
377
378 // Create thumbnail based on favicon for tab.
379 favicon::FaviconDriver* favicon_driver =
380 favicon::ContentFaviconDriver::FromWebContents(contents);
381 if (favicon_driver) {
382 gfx::Image tab_icon = favicon_driver->GetFavicon();
383 tab_icon_map_[std::pair<int, int>(media_id.tab_id.render_process_id,
384 media_id.tab_id.main_render_frame_id)] =
385 CreateEnlargedFaviconImage(thumbnail_size_, tab_icon);
386 }
387
388 // Get tab's last active time stamp.
389 base::TimeTicks t = contents->GetLastActiveTime();
390 tab_map.insert(std::make_pair(t, SourceDescription(media_id, title)));
391 }
392
393 // Add timely sorted tab sources into vector. Most recent one first.
394 tab_sources->clear();
395 for (auto it = tab_map.rbegin(); it != tab_map.rend(); ++it) {
396 tab_sources->push_back(it->second);
397 }
297 } 398 }
298 399
299 void NativeDesktopMediaList::OnSourcesList( 400 void NativeDesktopMediaList::OnSourcesList(
300 const std::vector<SourceDescription>& new_sources) { 401 const std::vector<SourceDescription>& new_sources) {
301 typedef std::set<content::DesktopMediaID> SourceSet; 402 typedef std::set<content::DesktopMediaID> SourceSet;
302 SourceSet new_source_set; 403 SourceSet new_source_set;
303 for (size_t i = 0; i < new_sources.size(); ++i) { 404 for (size_t i = 0; i < new_sources.size(); ++i) {
304 new_source_set.insert(new_sources[i].id); 405 new_source_set.insert(new_sources[i].id);
305 } 406 }
306 // Iterate through the old sources to find the removed sources. 407 // Iterate through the old sources to find the removed sources.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 } 460 }
360 461
361 void NativeDesktopMediaList::OnSourceThumbnail( 462 void NativeDesktopMediaList::OnSourceThumbnail(
362 int index, 463 int index,
363 const gfx::ImageSkia& image) { 464 const gfx::ImageSkia& image) {
364 DCHECK_LT(index, static_cast<int>(sources_.size())); 465 DCHECK_LT(index, static_cast<int>(sources_.size()));
365 sources_[index].thumbnail = image; 466 sources_[index].thumbnail = image;
366 observer_->OnSourceThumbnailChanged(index); 467 observer_->OnSourceThumbnailChanged(index);
367 } 468 }
368 469
470 void NativeDesktopMediaList::OnSourceTabThumbnail(SourceDescription source) {
471 DCHECK(source.id.type == DesktopMediaID::TYPE_TAB);
472
473 for (size_t i = 0; i < sources_.size(); ++i) {
474 if (sources_[i].id == source.id) {
475 // Use favicon as thumbnail for tab.
476 std::pair<int, int> window_id(source.id.tab_id.render_process_id,
477 source.id.tab_id.main_render_frame_id);
478 if (tab_icon_map_.count(window_id)) {
479 // Only do update when there is a change to avoid flickering.
480 if (sources_[i].thumbnail.size() != tab_icon_map_[window_id].size() ||
481 sources_[i].name != source.name) {
482 sources_[i].thumbnail = tab_icon_map_[window_id];
483 observer_->OnSourceThumbnailChanged(i);
484 }
485 }
486 break;
487 }
488 }
489 }
490
369 void NativeDesktopMediaList::OnRefreshFinished() { 491 void NativeDesktopMediaList::OnRefreshFinished() {
370 BrowserThread::PostDelayedTask( 492 BrowserThread::PostDelayedTask(
371 BrowserThread::UI, FROM_HERE, 493 BrowserThread::UI, FROM_HERE,
372 base::Bind(&NativeDesktopMediaList::Refresh, 494 base::Bind(&NativeDesktopMediaList::Refresh,
373 weak_factory_.GetWeakPtr()), 495 weak_factory_.GetWeakPtr()),
374 update_period_); 496 update_period_);
375 } 497 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698