Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: navigator.setAppBadge/clearAppBadge #27431

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/api/app.md 100644 → 100755
Expand Up @@ -1174,9 +1174,9 @@ For `infoType` equal to `basic`:

Using `basic` should be preferred if only basic information like `vendorId` or `driverId` is needed.

### `app.setBadgeCount(count)` _Linux_ _macOS_
### `app.setBadgeCount([count])` _Linux_ _macOS_

* `count` Integer
* `count` Integer (optional) - If a value is provided, set the badge to the provided value otherwise, on macOS, display a plain white dot (e.g. unknown number of notifications). On Linux, if a value is not provided the badge will not display.

Returns `Boolean` - Whether the call succeeded.

Expand Down
15 changes: 14 additions & 1 deletion electron_strings.grdp
Expand Up @@ -83,5 +83,18 @@
<message name="IDS_DOWNLOAD_MORE_ACTIONS"
desc="Tooltip of a button on the downloads page that shows a menu with actions like 'Open downloads folder' or 'Clear all'">
More actions
</message>
</message>
<!-- Badging -->
<message name="IDS_SATURATED_BADGE_CONTENT" desc="The content to display when the application's badge is too large to display to indicate that the badge is more than a given maximum. This string should be as short as possible, preferably only one character beyond the content">
<ph name="MAXIMUM_VALUE">$1<ex>99</ex></ph>+
</message>
<message name="IDS_BADGE_UNREAD_NOTIFICATIONS_SATURATED" desc="The accessibility text which will be read by a screen reader when the notification count is too large to display (e.g. greater than 99).">
{MAX_UNREAD_NOTIFICATIONS, plural, =1 {More than 1 unread notification} other {More than # unread notifications}}
</message>
<message name="IDS_BADGE_UNREAD_NOTIFICATIONS_UNSPECIFIED" desc="The accessibility text which will be read by a screen reader when there are some unspecified number of notifications, or user attention is required">
Unread Notifications
</message>
<message name="IDS_BADGE_UNREAD_NOTIFICATIONS" desc="The accessibility text which will be read by a screen reader when there are notifcatications">
{UNREAD_NOTIFICATIONS, plural, =1 {1 Unread Notification} other {# Unread Notifications}}
</message>
</grit-part>
4 changes: 4 additions & 0 deletions filenames.gni
Expand Up @@ -328,6 +328,10 @@ filenames = {
"shell/browser/api/ui_event.h",
"shell/browser/auto_updater.cc",
"shell/browser/auto_updater.h",
"shell/browser/badging/badge_manager.cc",
"shell/browser/badging/badge_manager.h",
"shell/browser/badging/badge_manager_factory.cc",
"shell/browser/badging/badge_manager_factory.h",
"shell/browser/browser.cc",
"shell/browser/browser.h",
"shell/browser/browser_observer.h",
Expand Down
81 changes: 81 additions & 0 deletions shell/browser/badging/badge_manager.cc
@@ -0,0 +1,81 @@
// 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 "shell/browser/badging/badge_manager.h"

#include <tuple>
#include <utility>

#include "base/i18n/number_formatting.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "shell/browser/badging/badge_manager_factory.h"
#include "shell/browser/browser.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/strings/grit/ui_strings.h"

namespace badging {

BadgeManager::BadgeManager() = default;
BadgeManager::~BadgeManager() = default;

// static
void BadgeManager::BindFrameReceiver(
content::RenderFrameHost* frame,
mojo::PendingReceiver<blink::mojom::BadgeService> receiver) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

auto* browser_context =
content::WebContents::FromRenderFrameHost(frame)->GetBrowserContext();

auto* badge_manager =
badging::BadgeManagerFactory::GetInstance()->GetForBrowserContext(
browser_context);
if (!badge_manager)
return;

auto context = std::make_unique<FrameBindingContext>(
frame->GetProcess()->GetID(), frame->GetRoutingID());

badge_manager->receivers_.Add(badge_manager, std::move(receiver),
std::move(context));
}

std::string BadgeManager::GetBadgeString(base::Optional<int> 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()));
}

void BadgeManager::SetBadge(blink::mojom::BadgeValuePtr mojo_value) {
if (mojo_value->is_number() && mojo_value->get_number() == 0) {
mojo::ReportBadMessage(
"|value| should not be zero when it is |number| (ClearBadge should be "
"called instead)!");
return;
}

base::Optional<int> value =
mojo_value->is_flag() ? base::nullopt
: base::make_optional(mojo_value->get_number());

electron::Browser::Get()->SetBadgeCount(value);
}

void BadgeManager::ClearBadge() {
electron::Browser::Get()->SetBadgeCount(0);
}

} // namespace badging
90 changes: 90 additions & 0 deletions shell/browser/badging/badge_manager.h
@@ -0,0 +1,90 @@
// 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.

#ifndef SHELL_BROWSER_BADGING_BADGE_MANAGER_H_
#define SHELL_BROWSER_BADGING_BADGE_MANAGER_H_

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "base/macros.h"
#include "base/optional.h"
#include "components/keyed_service/core/keyed_service.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "third_party/blink/public/mojom/badging/badging.mojom.h"
#include "url/gurl.h"

namespace content {
class RenderFrameHost;
class RenderProcessHost;
} // namespace content

namespace badging {

// The maximum value of badge contents before saturation occurs.
constexpr int kMaxBadgeContent = 99;

// Maintains a record of badge contents and dispatches badge changes to a
// delegate.
class BadgeManager : public KeyedService, public blink::mojom::BadgeService {
public:
BadgeManager();
~BadgeManager() override;

static void BindFrameReceiver(
content::RenderFrameHost* frame,
mojo::PendingReceiver<blink::mojom::BadgeService> receiver);

// Determines the text to put on the badge based on some badge_content.
static std::string GetBadgeString(base::Optional<int> badge_content);

private:
// The BindingContext of a mojo request. Allows mojo calls to be tied back
// to the execution context they belong to without trusting the renderer for
// that information. This is an abstract base class that different types of
// execution contexts derive.
class BindingContext {
public:
virtual ~BindingContext() = default;
};

// The BindingContext for Window execution contexts.
class FrameBindingContext final : public BindingContext {
public:
FrameBindingContext(int process_id, int frame_id)
: process_id_(process_id), frame_id_(frame_id) {}
~FrameBindingContext() override = default;

int GetProcessId() { return process_id_; }
int GetFrameId() { return frame_id_; }

private:
int process_id_;
int frame_id_;
};

// blink::mojom::BadgeService:
// Note: These are private to stop them being called outside of mojo as they
// require a mojo binding context.
void SetBadge(blink::mojom::BadgeValuePtr value) override;
void ClearBadge() override;

// All the mojo receivers for the BadgeManager. Keeps track of the
// render_frame the binding is associated with, so as to not have to rely
// on the renderer passing it in.
mojo::ReceiverSet<blink::mojom::BadgeService, std::unique_ptr<BindingContext>>
receivers_;

// Delegate which handles actual setting and clearing of the badge.
// Note: This is currently only set on Windows and MacOS.
// std::unique_ptr<BadgeManagerDelegate> delegate_;

DISALLOW_COPY_AND_ASSIGN(BadgeManager);
};

} // namespace badging

#endif // SHELL_BROWSER_BADGING_BADGE_MANAGER_H_
41 changes: 41 additions & 0 deletions shell/browser/badging/badge_manager_factory.cc
@@ -0,0 +1,41 @@
// 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 "shell/browser/badging/badge_manager_factory.h"

#include <memory>

#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "shell/browser/badging/badge_manager.h"

namespace badging {

// static
BadgeManager* BadgeManagerFactory::GetForBrowserContext(
content::BrowserContext* context) {
return static_cast<badging::BadgeManager*>(
GetInstance()->GetServiceForBrowserContext(context, true));
}

// static
BadgeManagerFactory* BadgeManagerFactory::GetInstance() {
return base::Singleton<BadgeManagerFactory>::get();
}

BadgeManagerFactory::BadgeManagerFactory()
: BrowserContextKeyedServiceFactory(
"BadgeManager",
BrowserContextDependencyManager::GetInstance()) {}

BadgeManagerFactory::~BadgeManagerFactory() {}

KeyedService* BadgeManagerFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new BadgeManager();
}

} // namespace badging
44 changes: 44 additions & 0 deletions shell/browser/badging/badge_manager_factory.h
@@ -0,0 +1,44 @@
// 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.

#ifndef SHELL_BROWSER_BADGING_BADGE_MANAGER_FACTORY_H_
#define SHELL_BROWSER_BADGING_BADGE_MANAGER_FACTORY_H_

#include "base/macros.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"

namespace base {
template <typename T>
struct DefaultSingletonTraits;
}

namespace badging {

class BadgeManager;

// Singleton that provides access to context specific BadgeManagers.
class BadgeManagerFactory : public BrowserContextKeyedServiceFactory {
public:
// Gets the BadgeManager for the specified context
static BadgeManager* GetForBrowserContext(content::BrowserContext* context);

// Returns the BadgeManagerFactory singleton.
static BadgeManagerFactory* GetInstance();

private:
friend struct base::DefaultSingletonTraits<BadgeManagerFactory>;

BadgeManagerFactory();
~BadgeManagerFactory() override;

// BrowserContextKeyedServiceFactory
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;

DISALLOW_COPY_AND_ASSIGN(BadgeManagerFactory);
};

} // namespace badging

#endif // SHELL_BROWSER_BADGING_BADGE_MANAGER_FACTORY_H_
Empty file modified shell/browser/browser.cc 100644 → 100755
Empty file.
12 changes: 11 additions & 1 deletion shell/browser/browser.h 100644 → 100755
Expand Up @@ -23,6 +23,7 @@
#if defined(OS_WIN)
#include <windows.h>
#include "base/files/file_path.h"
#include "shell/browser/ui/win/taskbar_host.h"
#endif

#if defined(OS_MAC)
Expand Down Expand Up @@ -107,7 +108,7 @@ class Browser : public WindowListObserver {
#endif

// Set/Get the badge count.
bool SetBadgeCount(int count);
bool SetBadgeCount(base::Optional<int> count);
int GetBadgeCount();

#if defined(OS_WIN)
Expand Down Expand Up @@ -364,6 +365,15 @@ class Browser : public WindowListObserver {
base::DictionaryValue about_panel_options_;
#endif

#if defined(OS_WIN)
void UpdateBadgeContents(HWND hwnd,
const base::Optional<std::string>& badge_content,
const std::string& badge_alt_string);

// In charge of running taskbar related APIs.
TaskbarHost taskbar_host_;
#endif

DISALLOW_COPY_AND_ASSIGN(Browser);
};

Expand Down
8 changes: 4 additions & 4 deletions shell/browser/browser_linux.cc
Expand Up @@ -140,10 +140,10 @@ base::string16 Browser::GetApplicationNameForProtocol(const GURL& url) {
return base::ASCIIToUTF16(GetXdgAppOutput(argv).value_or(std::string()));
}

bool Browser::SetBadgeCount(int count) {
if (IsUnityRunning()) {
unity::SetDownloadCount(count);
badge_count_ = count;
bool Browser::SetBadgeCount(base::Optional<int> count) {
if (IsUnityRunning() && count.has_value()) {
unity::SetDownloadCount(count.value());
badge_count_ = count.value();
return true;
} else {
return false;
Expand Down
13 changes: 10 additions & 3 deletions shell/browser/browser_mac.mm
Expand Up @@ -15,6 +15,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include "net/base/mac/url_conversions.h"
#include "shell/browser/badging/badge_manager.h"
#include "shell/browser/mac/dict_util.h"
#include "shell/browser/mac/electron_application.h"
#include "shell/browser/mac/electron_application_delegate.h"
Expand Down Expand Up @@ -219,9 +220,15 @@

void Browser::SetAppUserModelID(const base::string16& name) {}

bool Browser::SetBadgeCount(int count) {
DockSetBadgeText(count != 0 ? base::NumberToString(count) : "");
badge_count_ = count;
bool Browser::SetBadgeCount(base::Optional<int> count) {
DockSetBadgeText(!count.has_value() || count.value() != 0
? badging::BadgeManager::GetBadgeString(count)
: "");
if (count.has_value()) {
badge_count_ = count.value();
} else {
badge_count_ = 0;
}
return true;
}

Expand Down