blob: de2bb05b13d1414f6d836f693f0495b7dfad524b [file] [log] [blame]
// 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.
}