blob: 597e7e7d5f3896808576fc5584d65d39638f9655 [file]
// 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/android/restore_entity_tracker_android.h"
#include <memory>
#include <utility>
#include "base/check.h"
#include "base/notimplemented.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/android/tab_android_conversions.h"
#include "chrome/browser/tab/protocol/children.pb.h"
#include "chrome/browser/tab/protocol/token.pb.h"
#include "chrome/browser/tab/storage_id.h"
#include "chrome/browser/tab/storage_loaded_data.h"
#include "chrome/browser/tab/tab_storage_type.h"
#include "chrome/browser/tab/tab_storage_util.h"
namespace tabs {
RestoreEntityTrackerAndroid::RestoreEntityTrackerAndroid(
OnTabAssociation on_tab_association,
OnCollectionAssociation on_collection_association)
: on_tab_association_(on_tab_association),
on_collection_association_(on_collection_association) {}
RestoreEntityTrackerAndroid::~RestoreEntityTrackerAndroid() = default;
void RestoreEntityTrackerAndroid::SetLoadingContext(
StorageLoadingContext* context) {
context_ = context;
}
void RestoreEntityTrackerAndroid::RegisterCollection(
StorageId storage_id,
TabStorageType type,
const tabs_pb::Children& children,
std::optional<base::Token> collection_specific_id,
base::PassKey<TabStateStorageDatabase>) {
DCHECK(context_);
if (type == TabStorageType::kPinned) {
if (pinned_collection_id_) {
context_->AddWarning(StorageLoadWarningCode::kMultipleUniqueNodesError,
"Should only have one pinned collection.");
return;
}
pinned_collection_id_ = storage_id;
} else if (type == TabStorageType::kUnpinned) {
if (unpinned_collection_id_) {
context_->AddWarning(StorageLoadWarningCode::kMultipleUniqueNodesError,
"Should only have one unpinned collection.");
return;
}
unpinned_collection_id_ = storage_id;
} else if (type == TabStorageType::kTabStrip) {
if (tab_strip_collection_id_) {
context_->AddWarning(StorageLoadWarningCode::kMultipleUniqueNodesError,
"Should only have one tab strip collection.");
return;
}
tab_strip_collection_id_ = storage_id;
} else if (type == TabStorageType::kSplit) {
DCHECK(collection_specific_id.has_value());
split_tab_id_to_storage_id_[*collection_specific_id] = storage_id;
} else if (type == TabStorageType::kGroup) {
DCHECK(collection_specific_id.has_value());
tab_group_id_to_storage_id_[*collection_specific_id] = storage_id;
}
}
void RestoreEntityTrackerAndroid::RegisterTab(
StorageId storage_id,
const tabs_pb::TabState& tab_state,
base::PassKey<TabStateStorageDatabase>) {
DCHECK(context_);
tab_android_id_to_storage_id_[tab_state.tab_id()] = storage_id;
}
bool RestoreEntityTrackerAndroid::AssociateTab(const TabInterface* tab) {
DCHECK(context_);
const TabAndroid* tab_android = ToTabAndroidChecked(tab);
TabHandle handle = tab->GetHandle();
if (associated_nodes_.contains(handle)) {
return false;
}
auto it = tab_android_id_to_storage_id_.find(tab_android->GetAndroidId());
if (it == tab_android_id_to_storage_id_.end()) {
return false;
}
StorageId storage_id = it->second;
on_tab_association_.Run(storage_id, tab_android);
associated_nodes_.insert(handle);
return true;
}
bool RestoreEntityTrackerAndroid::AssociateCollection(
const TabCollection* collection) {
DCHECK(context_);
TabStorageType type = TabCollectionTypeToTabStorageType(collection->type());
if (type == TabStorageType::kPinned) {
return AssociatePinnedCollection(
static_cast<const PinnedTabCollection*>(collection));
} else if (type == TabStorageType::kUnpinned) {
return AssociateUnpinnedCollection(
static_cast<const UnpinnedTabCollection*>(collection));
} else if (type == TabStorageType::kTabStrip) {
return AssociateTabStripCollection(
static_cast<const TabStripCollection*>(collection));
} else if (type == TabStorageType::kSplit) {
return AssociateSplitTabCollection(
static_cast<const SplitTabCollection*>(collection));
} else if (type == TabStorageType::kGroup) {
return AssociateTabGroupTabCollection(
static_cast<const TabGroupTabCollection*>(collection));
} else {
context_->AddWarning(StorageLoadWarningCode::kUnknownCollectionTypeError,
"Unknown collection type: " +
base::NumberToString(static_cast<int>(type)));
return false;
}
}
bool RestoreEntityTrackerAndroid::AssociateUniqueCollection(
std::optional<StorageId> storage_id,
const TabCollection* collection) {
TabCollection::Handle handle = collection->GetHandle();
if (storage_id && !associated_nodes_.contains(handle)) {
on_collection_association_.Run(storage_id.value(), collection);
associated_nodes_.insert(handle);
return true;
}
return false;
}
bool RestoreEntityTrackerAndroid::AssociateCollectionUsingId(
absl::flat_hash_map<base::Token, StorageId> id_to_storage_id,
base::Token collection_specific_id,
const TabCollection* collection) {
TabCollection::Handle handle = collection->GetHandle();
if (associated_nodes_.contains(handle)) {
return false;
}
auto it = id_to_storage_id.find(collection_specific_id);
if (it == id_to_storage_id.end()) {
return false;
}
on_collection_association_.Run(it->second, collection);
associated_nodes_.insert(handle);
return true;
}
bool RestoreEntityTrackerAndroid::AssociatePinnedCollection(
const PinnedTabCollection* collection) {
return AssociateUniqueCollection(pinned_collection_id_, collection);
}
bool RestoreEntityTrackerAndroid::AssociateUnpinnedCollection(
const UnpinnedTabCollection* collection) {
return AssociateUniqueCollection(unpinned_collection_id_, collection);
}
bool RestoreEntityTrackerAndroid::AssociateTabStripCollection(
const TabStripCollection* collection) {
return AssociateUniqueCollection(tab_strip_collection_id_, collection);
}
bool RestoreEntityTrackerAndroid::AssociateTabGroupTabCollection(
const TabGroupTabCollection* collection) {
return AssociateCollectionUsingId(tab_group_id_to_storage_id_,
collection->GetTabGroupId().token(),
collection);
}
bool RestoreEntityTrackerAndroid::AssociateSplitTabCollection(
const SplitTabCollection* collection) {
return AssociateCollectionUsingId(split_tab_id_to_storage_id_,
collection->GetSplitTabId().token(),
collection);
}
bool RestoreEntityTrackerAndroid::HasCollectionBeenAssociated(
TabCollection::Handle handle) {
DCHECK(context_);
return associated_nodes_.contains(handle);
}
bool RestoreEntityTrackerAndroid::HasNothingToAssociate() {
// Tab strip collection is the root collection, so if it does not need to be
// associated, none of the other collections do either.
return !tab_strip_collection_id_.has_value();
}
std::optional<StorageId> RestoreEntityTrackerAndroid::GetStorageIdForTab(
int tab_android_id) {
auto it = tab_android_id_to_storage_id_.find(tab_android_id);
if (it == tab_android_id_to_storage_id_.end()) {
return std::nullopt;
}
return it->second;
}
} // namespace tabs