blob: 414c4bbb26a96ecdd3e3ca6d7eb6810c312df7ce [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/badging/badge_manager.h"
#include <utility>
#include "base/i18n/number_formatting.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/badging/badge_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/strings/grit/ui_strings.h"
#if defined(OS_MACOSX)
#include "chrome/browser/badging/badge_manager_delegate_mac.h"
#elif defined(OS_WIN)
#include "chrome/browser/badging/badge_manager_delegate_win.h"
#endif
namespace badging {
std::string GetBadgeString(base::Optional<uint64_t> badge_content) {
if (!badge_content)
return "•";
if (badge_content > kMaxBadgeContent) {
return base::UTF16ToUTF8(l10n_util::GetStringFUTF16(
IDS_SATURATED_BADGE_CONTENT, base::FormatNumber(kMaxBadgeContent)));
}
return base::UTF16ToUTF8(base::FormatNumber(badge_content.value()));
}
BadgeManager::BadgeManager(Profile* profile) {
#if defined(OS_MACOSX)
SetDelegate(std::make_unique<BadgeManagerDelegateMac>(profile));
#elif defined(OS_WIN)
SetDelegate(std::make_unique<BadgeManagerDelegateWin>(profile));
#endif
}
BadgeManager::~BadgeManager() = default;
void BadgeManager::SetDelegate(std::unique_ptr<BadgeManagerDelegate> delegate) {
delegate_ = std::move(delegate);
}
void BadgeManager::BindRequest(blink::mojom::BadgeServiceRequest request,
content::RenderFrameHost* frame) {
// TODO(crbug.com/983929): Remove these CHECKs once the cause of the bug has
// been determined.
CHECK(request);
CHECK(frame);
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(frame);
CHECK(web_contents);
CHECK(web_contents->GetBrowserContext());
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
CHECK(profile);
badging::BadgeManager* badge_manager =
badging::BadgeManagerFactory::GetInstance()->GetForProfile(profile);
CHECK(badge_manager);
CHECK(frame->GetProcess());
CHECK(frame->GetProcess()->GetID());
CHECK(frame->GetRoutingID());
BindingContext context(frame->GetProcess()->GetID(), frame->GetRoutingID());
badge_manager->bindings_.AddBinding(badge_manager, std::move(request),
std::move(context));
}
void BadgeManager::UpdateAppBadge(const base::Optional<std::string>& app_id,
base::Optional<uint64_t> content) {
// Badge content should never be 0 (it should be translated into a clear).
DCHECK_NE(content.value_or(1), 0u);
if (!app_id) {
BadgeChangeIgnored();
return;
}
badged_apps_[app_id.value()] = content;
if (!delegate_)
return;
delegate_->OnBadgeSet(app_id.value(), content);
}
void BadgeManager::ClearAppBadge(const base::Optional<std::string>& app_id) {
if (!app_id) {
BadgeChangeIgnored();
return;
}
badged_apps_.erase(app_id.value());
if (!delegate_)
return;
delegate_->OnBadgeCleared(app_id.value());
}
void BadgeManager::BadgeChangeIgnored() {
if (!delegate_)
return;
delegate_->OnBadgeChangeIgnoredForTesting();
}
void BadgeManager::SetInteger(uint64_t content) {
UpdateAppBadge(GetAppIdToBadge(bindings_.dispatch_context()), content);
}
void BadgeManager::SetFlag() {
UpdateAppBadge(GetAppIdToBadge(bindings_.dispatch_context()), base::nullopt);
}
void BadgeManager::ClearBadge() {
ClearAppBadge(GetAppIdToBadge(bindings_.dispatch_context()));
}
base::Optional<std::string> BadgeManager::GetAppIdToBadge(
const BindingContext& context) {
content::RenderFrameHost* frame =
content::RenderFrameHost::FromID(context.process_id, context.frame_id);
if (!frame)
return base::nullopt;
content::WebContents* contents =
content::WebContents::FromRenderFrameHost(frame);
Browser* browser = chrome::FindBrowserWithWebContents(contents);
if (!browser)
return base::nullopt;
web_app::AppBrowserController* app_controller = browser->app_controller();
if (!app_controller)
return base::nullopt;
// If the frame is not in scope, don't apply a badge.
if (!app_controller->IsUrlInAppScope(frame->GetLastCommittedURL())) {
return base::nullopt;
}
return app_controller->GetAppId();
}
} // namespace badging