blob: bb5a2c5d651dda6bc3044ccd30ca44549400e06d [file] [log] [blame]
// Copyright 2025 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/ui/android/toolbar/extension_actions_bridge.h"
#include "base/android/jni_string.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/android/toolbar/extension_actions_bridge_factory.h"
#include "extensions/browser/extension_action.h"
#include "extensions/browser/extension_action_manager.h"
#include "extensions/browser/extension_registry.h"
#include "ui/gfx/android/java_bitmap.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/browser/ui/android/toolbar/jni_headers/ExtensionAction_jni.h"
#include "chrome/browser/ui/android/toolbar/jni_headers/ExtensionActionsBridge_jni.h"
using base::android::AttachCurrentThread;
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using extensions::Extension;
using extensions::ExtensionAction;
using extensions::ExtensionActionManager;
using extensions::ExtensionRegistry;
ExtensionActionsBridge::IconObserver::IconObserver(
ExtensionActionsBridge* bridge,
const extensions::Extension& extension,
extensions::ExtensionAction& action)
: bridge_(bridge),
action_id_(extension.id()),
icon_factory_(&extension, &action, this) {}
ExtensionActionsBridge::IconObserver::~IconObserver() = default;
gfx::Image ExtensionActionsBridge::IconObserver::GetIcon(int tab_id) {
return icon_factory_.GetIcon(tab_id);
}
void ExtensionActionsBridge::IconObserver::OnIconUpdated() {
bridge_->OnToolbarIconUpdated(action_id_);
}
ExtensionActionsBridge::ExtensionActionsBridge(Profile* profile)
: profile_(profile), model_(ToolbarActionsModel::Get(profile)) {
java_object_ = Java_ExtensionActionsBridge_Constructor(
AttachCurrentThread(), reinterpret_cast<jlong>(this));
model_observation_.Observe(model_);
}
ExtensionActionsBridge::~ExtensionActionsBridge() {
Java_ExtensionActionsBridge_destroy(AttachCurrentThread(), java_object_);
}
// static
ExtensionActionsBridge* ExtensionActionsBridge::Get(Profile* profile) {
return ExtensionActionsBridgeFactory::GetForProfile(profile);
}
ScopedJavaLocalRef<jobject> ExtensionActionsBridge::GetJavaObject() {
return java_object_.AsLocalRef(AttachCurrentThread());
}
jboolean ExtensionActionsBridge::AreActionsInitialized(JNIEnv* env) {
return static_cast<jboolean>(model_->actions_initialized());
}
std::vector<std::string> ExtensionActionsBridge::GetActionIds(JNIEnv* env) {
const auto& ids = model_->action_ids();
return std::vector(ids.begin(), ids.end());
}
ScopedJavaLocalRef<jobject> ExtensionActionsBridge::GetAction(
JNIEnv* env,
const std::string& action_id,
jint tab_id) {
ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
DCHECK(registry);
ExtensionActionManager* manager = ExtensionActionManager::Get(profile_);
DCHECK(manager);
const Extension* extension =
registry->enabled_extensions().GetByID(action_id);
if (extension == nullptr) {
return nullptr;
}
ExtensionAction* action = manager->GetExtensionAction(*extension);
if (action == nullptr) {
return nullptr;
}
return Java_ExtensionAction_Constructor(
env, action_id, action->GetTitle(static_cast<int>(tab_id)));
}
ScopedJavaLocalRef<jobject> ExtensionActionsBridge::GetActionIcon(
JNIEnv* env,
const std::string& action_id,
jint tab_id) {
IconObserver* icon_observer = EnsureIconObserver(action_id);
if (!icon_observer) {
return nullptr;
}
gfx::Image image = icon_observer->GetIcon(static_cast<int>(tab_id));
return gfx::ConvertToJavaBitmap(*image.ToSkBitmap());
}
void ExtensionActionsBridge::OnToolbarActionAdded(
const ToolbarActionsModel::ActionId& id) {
Java_ExtensionActionsBridge_onActionAdded(AttachCurrentThread(), java_object_,
id);
}
void ExtensionActionsBridge::OnToolbarActionRemoved(
const ToolbarActionsModel::ActionId& id) {
RemoveIconObserver(id);
Java_ExtensionActionsBridge_onActionRemoved(AttachCurrentThread(),
java_object_, id);
}
void ExtensionActionsBridge::OnToolbarActionUpdated(
const ToolbarActionsModel::ActionId& id) {
Java_ExtensionActionsBridge_onActionUpdated(AttachCurrentThread(),
java_object_, id);
}
void ExtensionActionsBridge::OnToolbarModelInitialized() {
Java_ExtensionActionsBridge_onActionModelInitialized(AttachCurrentThread(),
java_object_);
}
void ExtensionActionsBridge::OnToolbarPinnedActionsChanged() {
Java_ExtensionActionsBridge_onPinnedActionsChanged(AttachCurrentThread(),
java_object_);
}
ExtensionActionsBridge::IconObserver*
ExtensionActionsBridge::EnsureIconObserver(
const ToolbarActionsModel::ActionId& action_id) {
if (!icon_observers_.contains(action_id)) {
ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
DCHECK(registry);
ExtensionActionManager* manager = ExtensionActionManager::Get(profile_);
DCHECK(manager);
const Extension* extension =
registry->enabled_extensions().GetByID(action_id);
if (extension == nullptr) {
return nullptr;
}
ExtensionAction* action = manager->GetExtensionAction(*extension);
if (action == nullptr) {
return nullptr;
}
icon_observers_.emplace(
action_id, std::make_unique<IconObserver>(this, *extension, *action));
}
auto it = icon_observers_.find(action_id);
if (it == icon_observers_.end()) {
return nullptr;
}
return it->second.get();
}
void ExtensionActionsBridge::RemoveIconObserver(
const ToolbarActionsModel::ActionId& action_id) {
icon_observers_.erase(action_id);
}
void ExtensionActionsBridge::OnToolbarIconUpdated(
const ToolbarActionsModel::ActionId& action_id) {
Java_ExtensionActionsBridge_onActionIconUpdated(AttachCurrentThread(),
java_object_, action_id);
}
static ScopedJavaLocalRef<jobject> JNI_ExtensionActionsBridge_Get(
JNIEnv* env,
Profile* profile) {
ExtensionActionsBridge* bridge = ExtensionActionsBridge::Get(profile);
DCHECK(bridge);
return bridge->GetJavaObject();
}