blob: c590f065236bba5381d683b6fe0a5dd93f4af5cb [file]
// Copyright 2026 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/android/compositor/tab_underline_manager.h"
#include "chrome/android/chrome_jni_headers/TabUnderlineManager_jni.h"
#include "chrome/browser/android/tab_android.h"
#include "components/tabs/public/tab_interface.h"
namespace android {
class TabUnderlineManager::UiDelegateImpl
: public glic::TabUnderlineController::UiDelegate {
public:
UiDelegateImpl(TabUnderlineManager* manager, int tab_id)
: manager_(manager), tab_id_(tab_id) {}
~UiDelegateImpl() override = default;
void Show() override {
is_showing_ = true;
manager_->SetUnderlineState(tab_id_, /*is_underlined=*/true);
}
void StopShowing() override {
is_showing_ = false;
manager_->SetUnderlineState(tab_id_, /*is_underlined=*/false);
}
void ResetAnimationCycle() override {
manager_->ResetAnimationCycle(tab_id_);
}
void StartRampingDown() override {
// Fallback to StopShowing for Android as animation is not supported yet.
StopShowing();
}
bool IsShowing() const override { return is_showing_; }
private:
raw_ptr<TabUnderlineManager> manager_;
int tab_id_;
bool is_showing_ = false;
};
TabUnderlineManager::TabUnderlineManager(JNIEnv* env,
const jni_zero::JavaRef<jobject>& obj)
: java_obj_(env, obj) {}
TabUnderlineManager::~TabUnderlineManager() = default;
TabUnderlineManager::TabIndicatorContext::TabIndicatorContext() = default;
TabUnderlineManager::TabIndicatorContext::~TabIndicatorContext() = default;
TabUnderlineManager::TabIndicatorContext::TabIndicatorContext(
std::unique_ptr<glic::TabUnderlineController> c,
std::unique_ptr<UiDelegateImpl> d)
: delegate(std::move(d)), controller(std::move(c)) {}
void TabUnderlineManager::Destroy(JNIEnv* env) {
delete this;
}
void TabUnderlineManager::RegisterTab(JNIEnv* env,
const jni_zero::JavaRef<jobject>& jtab) {
// TODO(crbug.com/500128552): Maybe switch to the UserDataHost pattern instead
// of maintaining a map here.
TabAndroid* tab_android = TabAndroid::GetNativeTab(env, jtab);
if (!tab_android) {
return;
}
int tab_id = tab_android->GetAndroidId();
// If already exists, do nothing.
if (tracked_tabs_.find(tab_id) != tracked_tabs_.end()) {
return;
}
auto controller =
std::make_unique<glic::TabUnderlineController>(tab_android->GetHandle());
auto delegate = std::make_unique<UiDelegateImpl>(this, tab_id);
controller->Initialize(delegate.get());
// Call OnUiReady() so it starts observing
controller->OnUiReady();
tracked_tabs_.try_emplace(tab_id, std::move(controller), std::move(delegate));
}
void TabUnderlineManager::UnregisterTab(JNIEnv* env, int32_t tab_id) {
tracked_tabs_.erase(tab_id);
}
void TabUnderlineManager::SetUnderlineState(int tab_id, bool is_underlined) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_TabUnderlineManager_setUnderlineState(env, java_obj_, tab_id,
is_underlined);
}
void TabUnderlineManager::ResetAnimationCycle(int tab_id) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_TabUnderlineManager_resetAnimationCycle(env, java_obj_, tab_id);
}
static int64_t JNI_TabUnderlineManager_Init(
JNIEnv* env,
const jni_zero::JavaRef<jobject>& obj) {
return reinterpret_cast<intptr_t>(new TabUnderlineManager(env, obj));
}
} // namespace android
DEFINE_JNI(TabUnderlineManager)