| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/device_notifications/device_system_tray_icon.h" |
| #include "chrome/browser/device_notifications/device_system_tray_icon_renderer.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "content/public/browser/browser_thread.h" |
| |
| DeviceSystemTrayIcon::DeviceSystemTrayIcon( |
| std::unique_ptr<DeviceSystemTrayIconRenderer> icon_renderer) |
| : icon_renderer_(std::move(icon_renderer)) {} |
| DeviceSystemTrayIcon::~DeviceSystemTrayIcon() = default; |
| |
| void DeviceSystemTrayIcon::StageProfile(Profile* profile) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| auto it = profiles_.find(profile); |
| if (it != profiles_.end()) { |
| // If the |profile| is tracked, it must be unstaging. |
| CHECK(!it->second); |
| // Connection tracker's connection count is updated even the profile is |
| // just moved from unstaging to staging. |
| NotifyConnectionCountUpdated(profile); |
| it->second = true; |
| return; |
| } |
| profiles_[profile] = true; |
| ProfileAdded(profile); |
| } |
| |
| void DeviceSystemTrayIcon::UnstageProfile(Profile* profile, bool immediate) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| auto it = profiles_.find(profile); |
| // The |profile| must be tracked. However, it can be unstaging. For example, |
| // A profile is scheduled to be removed followed by profile destruction. |
| CHECK(it != profiles_.end()); |
| |
| if (immediate) { |
| profiles_.erase(it); |
| ProfileRemoved(profile); |
| return; |
| } |
| |
| // For non-immediate case, the |profile| must be staging. |
| CHECK(it->second); |
| it->second = false; |
| // In order to avoid bouncing the system tray icon, schedule |profile| to be |
| // removed from the system tray icon later. |
| content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI) |
| ->PostDelayedTask( |
| FROM_HERE, |
| // This class is supposedly safe as it is owned by |
| // g_browser_process. However, to avoid corner |
| // scenarios in tests, use weak ptr just to be safe. |
| base::BindOnce(&DeviceSystemTrayIcon::CleanUpProfile, |
| weak_factory_.GetWeakPtr(), profile->GetWeakPtr()), |
| kProfileUnstagingTime); |
| // Connection tracker's connection count is updated even in scheduled |
| // removal case. |
| NotifyConnectionCountUpdated(profile); |
| } |
| |
| void DeviceSystemTrayIcon::ProfileAdded(Profile* profile) { |
| if (icon_renderer_) { |
| icon_renderer_->AddProfile(profile); |
| } |
| } |
| |
| void DeviceSystemTrayIcon::ProfileRemoved(Profile* profile) { |
| if (icon_renderer_) { |
| icon_renderer_->RemoveProfile(profile); |
| } |
| } |
| |
| void DeviceSystemTrayIcon::NotifyConnectionCountUpdated(Profile* profile) { |
| if (icon_renderer_) { |
| icon_renderer_->NotifyConnectionUpdated(profile); |
| } |
| } |
| |
| void DeviceSystemTrayIcon::CleanUpProfile(base::WeakPtr<Profile> profile) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| if (profile) { |
| auto it = profiles_.find(profile.get()); |
| if (it != profiles_.end() && !it->second) { |
| profiles_.erase(it); |
| ProfileRemoved(profile.get()); |
| } |
| return; |
| } |
| // If the |profile| is destroyed, |profiles_| shouldn't have an entry for |
| // |profile|. This is because DeviceConnectionTracker::CleanUp() is called on |
| // browser context (i.e. profile) shutdown and calls UnstageProfile() with |
| // immediate set to true so the entry will be removed from |profiles_| |
| // immediately. |
| } |