// Copyright 2021 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/optimization_guide/android/optimization_guide_tab_url_provider_android.h"
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/android/tab_model/tab_model.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
#include "content/public/browser/web_contents.h"
namespace optimization_guide {
namespace android {
OptimizationGuideTabUrlProviderAndroid::OptimizationGuideTabUrlProviderAndroid(
Profile* profile)
: profile_(profile) {}
OptimizationGuideTabUrlProviderAndroid::
~OptimizationGuideTabUrlProviderAndroid() = default;
const std::vector<GURL>
OptimizationGuideTabUrlProviderAndroid::GetUrlsOfActiveTabs(
const base::TimeDelta& duration_since_last_shown) {
std::vector<TabRepresentation> tabs;
const TabModelList::TabModelVector& tab_models = TabModelList::models();
for (size_t tab_model_idx = 0; tab_model_idx < tab_models.size();
tab_model_idx++) {
const TabModel* tab_model = tab_models[tab_model_idx];
if (tab_model->GetProfile() != profile_)
continue;
size_t tab_count = static_cast<size_t>(tab_model->GetTabCount());
for (size_t tab_idx = 0; tab_idx < tab_count; tab_idx++) {
TabRepresentation tab;
tab.tab_model_index = tab_model_idx;
tab.tab_index = tab_idx;
content::WebContents* web_contents = tab_model->GetWebContentsAt(tab_idx);
if (web_contents) {
if ((base::TimeTicks::Now() - web_contents->GetLastActiveTimeTicks()) <
duration_since_last_shown) {
tab.url = web_contents->GetLastCommittedURL();
tab.last_active_time = web_contents->GetLastActiveTimeTicks();
tabs.push_back(tab);
}
continue;
}
// Fall back to the tab if there isn't a WebContents created for the tab.
TabAndroid* tab_android = tab_model->GetTabAt(tab_idx);
if (tab_android) {
// Just push back the URL even though we have no idea if it was shown
// before. TabAndroid does not expose the last active time.
tab.url = tab_android->GetURL();
tabs.push_back(tab);
}
}
}
SortTabs(&tabs);
std::vector<GURL> urls;
urls.reserve(tabs.size());
for (const auto& tab : tabs) {
urls.emplace_back(tab.url);
}
return urls;
}
void OptimizationGuideTabUrlProviderAndroid::SortTabs(
std::vector<TabRepresentation>* tabs) {
std::sort(tabs->begin(), tabs->end(),
[](const TabRepresentation& a, const TabRepresentation& b) {
// Attempt to sort by last active time if both are present.
if (a.last_active_time && b.last_active_time)
return *a.last_active_time > *b.last_active_time;
// If both are not present, sort by its position in the tab model
// list, assuming that the earlier it appears, the more likely it
// will get revisited.
if (!a.last_active_time && !b.last_active_time) {
return (a.tab_model_index != b.tab_model_index)
? (a.tab_model_index < b.tab_model_index)
: (a.tab_index < b.tab_index);
}
// Otherwise, if one of the tabs has an active time, put that
// first.
return a.last_active_time.value_or(base::TimeTicks::Min()) >
b.last_active_time.value_or(base::TimeTicks::Min());
});
}
OptimizationGuideTabUrlProviderAndroid::TabRepresentation::TabRepresentation() =
default;
OptimizationGuideTabUrlProviderAndroid::TabRepresentation::
~TabRepresentation() = default;
OptimizationGuideTabUrlProviderAndroid::TabRepresentation::TabRepresentation(
const TabRepresentation&) = default;
} // namespace android
} // namespace optimization_guide