Commit f0c4e5df authored by Min Qin's avatar Min Qin Committed by Chromium LUCI CQ

Fix tile impression counting issue on NTP

This CL fixes a couple issues on counting tile impressions on NTP.
1. NTP calls TileManager::GetTiles() to get both the top and sub tiles.
While Omnibox makes two separate calls of GetTiles() and
GetTile(). This CL fixes the behavior of NTP to match that of Omnibox, so we can
count top level tile impression when
GetTiles() is called, and counts subtile impression when GetTile()
is called.

2. Clicking the home button will often invoke 2 calls to GetTiles(). One
caused by QueryTileSection ctor, one caused by OnLoadUrl() for NTP.
We don't actually need to reload tiles if user never clicked on any
tiles. In most cases, only the call from ctor is necessary. This CL
fixes the issue by checking whether tiles has been clicked before
reloading all tiles.

BUG=1155919

Change-Id: Ief1f4be957d160119c40fec1da71ae79d6258321
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2576504
Commit-Queue: Min Qin <qinmin@chromium.org>
Reviewed-by: default avatarShakti Sahu <shaktisahu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#836218}
parent 2f80be17
......@@ -60,6 +60,7 @@ public class QueryTileSection {
private ImageFetcher mImageFetcher;
private Integer mTileWidth;
private float mAnimationPercent;
private boolean mNeedReload = true;
/**
* Represents the information needed to launch a search query when clicking on a tile.
......@@ -110,8 +111,15 @@ public class QueryTileSection {
* Called to clear the state and reload the top level tiles. Any chip selected will be cleared.
*/
public void reloadTiles() {
mTileProvider.getQueryTiles(this::setTiles);
if (!mNeedReload) {
// No tile changes, just refresh the display.
mTileCoordinator.refreshTiles();
return;
}
// TODO(qinmin): don't return all tiles, just return the top-level tiles.
mTileProvider.getQueryTiles(null, this::setTiles);
mSearchBoxCoordinator.setChipText(null);
mNeedReload = false;
}
private void onTileClicked(ImageTile tile) {
......@@ -121,6 +129,7 @@ public class QueryTileSection {
mTileProvider.onTileClicked(queryTile.id);
}
// TODO(qinmin): make isLastLevelTile a member variable of ImageTile.
boolean isLastLevelTile = queryTile.children.isEmpty();
if (isLastLevelTile) {
if (QueryTileUtils.isQueryEditingEnabled()) {
......@@ -132,7 +141,8 @@ public class QueryTileSection {
return;
}
setTiles(queryTile.children);
mNeedReload = true;
mTileProvider.getQueryTiles(tile.id, this::setTiles);
showQueryChip(queryTile);
}
......
......@@ -24,6 +24,11 @@ public interface ImageTileCoordinator {
*/
void setTiles(List<ImageTile> tiles);
/**
* Refresh tile display. If tiles are scrolled, return them to their original position.
*/
void refreshTiles();
/** A helper interface to support retrieving {@link Bitmap}s asynchronously. */
@FunctionalInterface
interface TileVisualsProvider {
......
......@@ -46,4 +46,10 @@ class TileCoordinatorImpl implements ImageTileCoordinator {
mView.scrollToBeginning();
mView.showAnimation(shouldAnimate);
}
@Override
public void refreshTiles() {
mView.scrollToBeginning();
mView.showAnimation(false);
}
}
......@@ -31,7 +31,7 @@ public class TestTileProvider implements TileProvider {
* matching purposes.
*/
public TestTileProvider(TileProvider realProvider) {
realProvider.getQueryTiles(tiles -> { mTiles = tiles; });
realProvider.getQueryTiles(null, tiles -> { mTiles = tiles; });
}
/**
......@@ -63,10 +63,18 @@ public class TestTileProvider implements TileProvider {
return tile == null ? mTiles : tile.children;
}
// TileProvider implementation.
@Override
public void getQueryTiles(Callback<List<QueryTile>> callback) {
callback.onResult(mTiles);
public void getQueryTiles(String tileId, Callback<List<QueryTile>> callback) {
if (tileId == null) {
callback.onResult(mTiles);
return;
}
for (QueryTile tile : mTiles) {
if (tile.id.equals(tileId)) {
callback.onResult(tile.children);
return;
}
}
}
@Override
......
......@@ -14,11 +14,13 @@ import java.util.List;
*/
public interface TileProvider {
/**
* Called to retrieve all the tiles.
* Called to retrieve all the subtiles for a parent tile with the given Id. If the Id is null,
* all top level tiles will be returned.
* @param tileId ID of the parent tile. If null, all top level tiles will be returned.
* @param callback The {@link Callback} to be notified on completion. Returns an empty list if
* no tiles are found.
*/
void getQueryTiles(Callback<List<QueryTile>> callback);
void getQueryTiles(String tileId, Callback<List<QueryTile>> callback);
/**
* Called when a tile is clicked.
......
......@@ -33,7 +33,7 @@ public class TileUmaLoggerTest {
@Test
public void testTileClicked() {
mTileProvider.getQueryTiles(tiles -> {
mTileProvider.getQueryTiles(null, tiles -> {
mTileUmaLogger.recordTilesLoaded(tiles);
// Click top level tiles.
......
......@@ -35,9 +35,10 @@ public class TileProviderBridge implements TileProvider {
}
@Override
public void getQueryTiles(Callback<List<QueryTile>> callback) {
public void getQueryTiles(String tileId, Callback<List<QueryTile>> callback) {
if (mNativeTileProviderBridge == 0) return;
TileProviderBridgeJni.get().getQueryTiles(mNativeTileProviderBridge, this, callback);
TileProviderBridgeJni.get().getQueryTiles(
mNativeTileProviderBridge, this, tileId, callback);
}
@Override
......@@ -48,7 +49,7 @@ public class TileProviderBridge implements TileProvider {
@NativeMethods
interface Natives {
void getQueryTiles(long nativeTileProviderBridge, TileProviderBridge caller,
void getQueryTiles(long nativeTileProviderBridge, TileProviderBridge caller, String tileId,
Callback<List<QueryTile>> callback);
void onTileClicked(long nativeTileProviderBridge, String tileId);
}
......
......@@ -50,4 +50,15 @@ ScopedJavaLocalRef<jobject> TileConversionBridge::CreateJavaTiles(
return jlist;
}
ScopedJavaLocalRef<jobject> TileConversionBridge::CreateJavaTiles(
JNIEnv* env,
const std::vector<std::unique_ptr<Tile>>& tiles) {
ScopedJavaLocalRef<jobject> jlist = Java_TileConversionBridge_createList(env);
for (const auto& tile : tiles)
CreateJavaTileAndMaybeAddToList(env, jlist, *tile);
return jlist;
}
} // namespace query_tiles
......@@ -20,6 +20,10 @@ class TileConversionBridge {
static ScopedJavaLocalRef<jobject> CreateJavaTiles(
JNIEnv* env,
const std::vector<Tile>& tiles);
static ScopedJavaLocalRef<jobject> CreateJavaTiles(
JNIEnv* env,
const std::vector<std::unique_ptr<Tile>>& tiles);
};
} // namespace query_tiles
......
......@@ -30,6 +30,16 @@ void RunGetTilesCallback(const JavaRef<jobject>& j_callback,
j_callback, TileConversionBridge::CreateJavaTiles(env, std::move(tiles)));
}
void RunGetTileCallback(const JavaRef<jobject>& j_callback,
base::Optional<Tile> tile) {
JNIEnv* env = AttachCurrentThread();
RunObjectCallbackAndroid(
j_callback,
TileConversionBridge::CreateJavaTiles(
env, tile.has_value() ? std::move(tile->sub_tiles)
: std::vector<std::unique_ptr<Tile>>()));
}
} // namespace
// static
......@@ -63,9 +73,19 @@ TileProviderBridge::~TileProviderBridge() {
void TileProviderBridge::GetQueryTiles(JNIEnv* env,
const JavaParamRef<jobject>& jcaller,
const JavaParamRef<jstring>& j_tile_id,
const JavaParamRef<jobject>& jcallback) {
tile_service_->GetQueryTiles(base::BindOnce(
&RunGetTilesCallback, ScopedJavaGlobalRef<jobject>(jcallback)));
// TODO(qinmin): refactor TileService to use a single call to handle both
// cases.
if (j_tile_id.is_null()) {
tile_service_->GetQueryTiles(base::BindOnce(
&RunGetTilesCallback, ScopedJavaGlobalRef<jobject>(jcallback)));
} else {
tile_service_->GetTile(
ConvertJavaStringToUTF8(env, j_tile_id),
base::BindOnce(&RunGetTileCallback,
ScopedJavaGlobalRef<jobject>(jcallback)));
}
}
void TileProviderBridge::OnTileClicked(JNIEnv* env,
......
......@@ -30,6 +30,7 @@ class TileProviderBridge : public base::SupportsUserData::Data {
// Methods called from Java via JNI.
void GetQueryTiles(JNIEnv* env,
const JavaParamRef<jobject>& jcaller,
const JavaParamRef<jstring>& j_tile_id,
const JavaParamRef<jobject>& jcallback);
// Called when a tile is clicked.
......
......@@ -47,6 +47,8 @@ source_set("internal") {
"tile_types.h",
"tile_utils.cc",
"tile_utils.h",
"trending_tile_handler.cc",
"trending_tile_handler.h",
]
public_deps = [ "//components/image_fetcher/core" ]
......
......@@ -35,6 +35,9 @@ struct TileGroup {
// Remove a tile from |tiles| given by its ID.
void RemoveTiles(const std::vector<std::string>& tile_ids);
// Find a tile with the given ID;
Tile* FindTile(const std::string& tile_id);
// Unique id for the group.
std::string id;
......
......@@ -20,6 +20,7 @@
#include "components/query_tiles/internal/tile_iterator.h"
#include "components/query_tiles/internal/tile_manager.h"
#include "components/query_tiles/internal/tile_utils.h"
#include "components/query_tiles/internal/trending_tile_handler.h"
#include "components/query_tiles/switches.h"
namespace query_tiles {
......@@ -28,45 +29,6 @@ namespace {
// A special tile group for tile stats.
constexpr char kTileStatsGroup[] = "tile_stats";
// Class for handling trending tiles. It checks whether a
// trending tile should be displayed, or removed. Construct
// a new instance each time when the caller has a list of
// trending tiles to be displayed.
class TrendingTilesHandler {
public:
// Map between tile ID and tile impression.
using ImpressionMap = std::map<std::string, int>;
explicit TrendingTilesHandler(ImpressionMap* impression_map)
: impression_map_(impression_map) {}
// Add a new trending tile for display, returns true if
// allowed, or returns false otherwise.
bool AddTrendingTileForDisplay(const std::string& tile_id) {
if (base::FeatureList::IsEnabled(
features::kQueryTilesRemoveTrendingTilesAfterInactivity) &&
(*impression_map_)[tile_id] >=
TileConfig::GetMaxTrendingTileImpressions()) {
tiles_to_remove_.push_back(tile_id);
return false;
}
if (++trending_tiles_count_ > TileConfig::GetNumTrendingTilesToDisplay())
return false;
++(*impression_map_)[tile_id];
return true;
}
const std::vector<std::string>& tiles_to_remove() const {
return tiles_to_remove_;
}
private:
std::vector<std::string> tiles_to_remove_;
int trending_tiles_count_ = 0;
ImpressionMap* impression_map_;
};
class TileManagerImpl : public TileManager {
public:
TileManagerImpl(std::unique_ptr<TileStore> store,
......@@ -106,23 +68,22 @@ class TileManagerImpl : public TileManager {
return;
}
std::vector<Tile> tiles;
TrendingTilesHandler handler(&tile_impressions_);
for (const auto& tile : tile_group_->tiles) {
if (IsTrendingTile(tile->id)) {
// Return a limited number of trending tiles, filter out the rest.
if (!handler.AddTrendingTileForDisplay(tile->id))
continue;
}
tiles.emplace_back(*tile.get());
}
// First remove the inactive trending tiles.
RemoveIdleTrendingTiles();
// Now build the tiles to return. Don't filter the subtiles, as they are
// only used for UMA purpose now.
// TODO(qinmin): remove all subtiles before returning the result, as they
// are not used.
std::vector<Tile> tiles =
trending_tile_handler_.FilterExtraTrendingTiles(tile_group_->tiles);
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(tiles)));
RemoveTiles(handler.tiles_to_remove());
}
void GetTile(const std::string& tile_id, TileCallback callback) override {
// First remove the inactive trending tiles.
RemoveIdleTrendingTiles();
// Find the tile.
const Tile* result = nullptr;
if (tile_group_) {
TileIterator it(*tile_group_, TileIterator::kAllTiles);
......@@ -136,23 +97,21 @@ class TileManagerImpl : public TileManager {
}
}
auto result_tile = result ? base::make_optional(*result) : base::nullopt;
TrendingTilesHandler handler(&tile_impressions_);
if (result_tile.has_value()) {
std::vector<std::unique_ptr<Tile>> tiles_to_display;
for (auto& tile : result_tile->sub_tiles) {
if (IsTrendingTile(tile->id)) {
// Return a limited number of trending subtiles, filter out the rest.
if (!handler.AddTrendingTileForDisplay(tile->id))
continue;
}
// Moving the tile to a temporary vector first, and will then
// use the temporary vector to replace |result_tile->sub_tiles|.
tiles_to_display.emplace_back(std::move(tile));
// Get the tiles to display, and convert the result vector.
// TODO(qinmin): make GetTile() return a vector of sub tiles, rather than
// the parent tile so we don't need the conversion below.
std::vector<Tile> sub_tiles =
trending_tile_handler_.FilterExtraTrendingTiles(
result_tile->sub_tiles);
if (!sub_tiles.empty()) {
std::vector<std::unique_ptr<Tile>> sub_tile_ptrs;
for (auto& tile : sub_tiles)
sub_tile_ptrs.emplace_back(std::make_unique<Tile>(std::move(tile)));
result_tile->sub_tiles = std::move(sub_tile_ptrs);
}
result_tile->sub_tiles = std::move(tiles_to_display);
}
RemoveTiles(handler.tiles_to_remove());
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(result_tile)));
}
......@@ -237,6 +196,7 @@ class TileManagerImpl : public TileManager {
&tile_stats_group_->tile_stats);
}
}
trending_tile_handler_.Reset();
// Deletes other groups.
for (const auto& group_to_delete : loaded_groups)
......@@ -283,8 +243,10 @@ class TileManagerImpl : public TileManager {
}
// Only swap the in memory tile group when there is no existing tile group.
if (!tile_group_)
if (!tile_group_) {
tile_group_ = std::move(group);
trending_tile_handler_.Reset();
}
std::move(callback).Run(TileGroupStatus::kSuccess);
}
......@@ -310,7 +272,7 @@ class TileManagerImpl : public TileManager {
// be passed to Update().
store_->Update(kTileStatsGroup, *tile_stats_group_, base::DoNothing());
tile_impressions_.erase(tile_id);
trending_tile_handler_.OnTileClicked(tile_id);
}
void OnQuerySelected(const base::Optional<std::string>& parent_tile_id,
......@@ -338,14 +300,14 @@ class TileManagerImpl : public TileManager {
}
}
void RemoveTiles(const std::vector<std::string>& tile_ids) {
void RemoveIdleTrendingTiles() {
if (!tile_group_)
return;
if (tile_ids.empty())
std::vector<std::string> tiles_to_remove =
trending_tile_handler_.GetInactiveTrendingTiles();
if (tiles_to_remove.empty())
return;
tile_group_->RemoveTiles(tile_ids);
tile_group_->RemoveTiles(tiles_to_remove);
store_->Update(tile_group_->id, *tile_group_, base::DoNothing());
}
......@@ -370,9 +332,8 @@ class TileManagerImpl : public TileManager {
// the same language.
std::string accept_languages_;
// Map tracking how many times tiles are requested.
// TODO(qinmin): move this to |tile_stats_group_|.
std::map<std::string, int> tile_impressions_;
// Object for managing trending tiles.
TrendingTileHandler trending_tile_handler_;
base::WeakPtrFactory<TileManagerImpl> weak_ptr_factory_{this};
};
......
......@@ -378,7 +378,32 @@ TEST_F(TileManagerTest, GetTilesWithTrendingTiles) {
GetTiles(std::move(expected));
}
// Check that the right number of trending subtiles are returned.
// Check that the getTiles() will return all trending subtiles.
TEST_F(TileManagerTest, GetTilesWithTrendingSubTiles) {
EXPECT_CALL(*tile_store(), Update(_, _, _))
.WillOnce(Invoke([](const std::string& id, const TileGroup& group,
MockTileStore::UpdateCallback callback) {
std::move(callback).Run(true);
}));
EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
Init(TileGroupStatus::kNoTiles);
auto parent_tile = std::make_unique<Tile>();
parent_tile->id = "parent";
parent_tile->sub_tiles = test::GetTestTrendingTileList();
// The last subtile will be removed from the result.
std::vector<Tile> expected;
expected.emplace_back(*parent_tile.get());
std::vector<std::unique_ptr<Tile>> tiles_to_save;
tiles_to_save.emplace_back(std::move(parent_tile));
SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
GetTiles(std::move(expected));
}
// Check that GetSingleTile() will filter and return the right number of
// trending subtiles.
TEST_F(TileManagerTest, GetSingleTileWithTrendingSubTiles) {
EXPECT_CALL(*tile_store(), Update(_, _, _))
.WillOnce(Invoke([](const std::string& id, const TileGroup& group,
......@@ -404,7 +429,7 @@ TEST_F(TileManagerTest, GetSingleTileWithTrendingSubTiles) {
}
// Check that trending tiles get removed after inactivity.
TEST_F(TileManagerTest, TrendingTilesRemovedAfterInactivity) {
TEST_F(TileManagerTest, TrendingTopTilesRemovedAfterInactivity) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kQueryTilesRemoveTrendingTilesAfterInactivity);
......@@ -452,6 +477,116 @@ TEST_F(TileManagerTest, TrendingTilesRemovedAfterInactivity) {
GetTiles(expected);
}
// Check that trending subtiles will not be removed if they are not displayed.
TEST_F(TileManagerTest, UnshownTrendingSubTilesNotRemoved) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kQueryTilesRemoveTrendingTilesAfterInactivity);
EXPECT_CALL(*tile_store(), Update(_, _, _))
.WillOnce(Invoke([](const std::string& id, const TileGroup& group,
MockTileStore::UpdateCallback callback) {
std::move(callback).Run(true);
}));
EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
Init(TileGroupStatus::kNoTiles);
auto parent_tile = std::make_unique<Tile>();
parent_tile->id = "parent";
parent_tile->sub_tiles = test::GetTestTrendingTileList();
// The last subtile will be removed from the result.
std::vector<Tile> expected;
expected.emplace_back(*parent_tile.get());
std::vector<std::unique_ptr<Tile>> tiles_to_save;
tiles_to_save.emplace_back(std::move(parent_tile));
SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
GetTiles(expected);
// Click the parent tile and then get top level tiles.
OnTileClicked("parent");
GetTiles(expected);
// Get top level tiles again. Since sub tiles were never shown,
// they will not be removed.
OnTileClicked("parent");
GetTiles(expected);
}
// Check that if OnTileClicked() is followed by GetTile(), impression is
// correctly counted.
TEST_F(TileManagerTest, GetSingleTileAfterOnTileClicked) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kQueryTilesRemoveTrendingTilesAfterInactivity);
EXPECT_CALL(*tile_store(), Update(_, _, _))
.WillOnce(Invoke([](const std::string& id, const TileGroup& group,
MockTileStore::UpdateCallback callback) {
std::move(callback).Run(true);
}));
EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
Init(TileGroupStatus::kNoTiles);
auto parent_tile = std::make_unique<Tile>();
parent_tile->id = "parent";
parent_tile->sub_tiles = test::GetTestTrendingTileList();
// The last subtile will be removed from the result.
std::vector<Tile> expected;
expected.emplace_back(*parent_tile.get());
Tile trending_3 = *(expected[0].sub_tiles[2]).get();
base::Optional<Tile> get_single_tile_expected =
base::make_optional(*parent_tile.get());
get_single_tile_expected->sub_tiles.pop_back();
std::vector<std::unique_ptr<Tile>> tiles_to_save;
tiles_to_save.emplace_back(std::move(parent_tile));
SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
GetTiles(expected);
// Click the parent tile to show the subtiles.
OnTileClicked("parent");
GetSingleTile("parent", get_single_tile_expected);
// Click the parent tile to show the subtiles.
OnTileClicked("parent");
GetSingleTile("parent", get_single_tile_expected);
// Click a trending tile to reset its impression.
OnTileClicked("trending_1");
// The 2nd tile will get removed.
expected[0].sub_tiles.erase(expected[0].sub_tiles.begin() + 1);
EXPECT_CALL(*tile_store(), Update(_, _, _))
.WillOnce(Invoke([](const std::string& id, const TileGroup& group,
MockTileStore::UpdateCallback callback) {
std::move(callback).Run(true);
}));
GetTiles(expected);
get_single_tile_expected->sub_tiles.pop_back();
get_single_tile_expected->sub_tiles.emplace_back(
std::make_unique<Tile>(std::move(trending_3)));
OnTileClicked("parent");
GetSingleTile("parent", get_single_tile_expected);
OnTileClicked("parent");
GetSingleTile("parent", get_single_tile_expected);
// Finally all tiles are removed.
get_single_tile_expected->sub_tiles.clear();
OnTileClicked("parent");
EXPECT_CALL(*tile_store(), Update(_, _, _))
.WillOnce(Invoke([](const std::string& id, const TileGroup& group,
MockTileStore::UpdateCallback callback) {
std::move(callback).Run(true);
}));
GetSingleTile("parent", get_single_tile_expected);
}
} // namespace
} // namespace query_tiles
// Copyright 2020 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 "components/query_tiles/internal/trending_tile_handler.h"
#include "components/query_tiles/internal/tile_config.h"
#include "components/query_tiles/internal/tile_utils.h"
#include "components/query_tiles/switches.h"
namespace query_tiles {
TrendingTileHandler::TrendingTileHandler() = default;
TrendingTileHandler::~TrendingTileHandler() = default;
void TrendingTileHandler::Reset() {
tile_impressions_.clear();
}
std::vector<Tile> TrendingTileHandler::FilterExtraTrendingTiles(
const std::vector<std::unique_ptr<Tile>>& tiles) {
int trending_count = 0;
std::vector<Tile> result;
for (const auto& tile : tiles) {
if (IsTrendingTile(tile->id)) {
if (trending_count >= TileConfig::GetNumTrendingTilesToDisplay())
continue;
++trending_count;
RecordImpression(tile->id);
}
result.emplace_back(*tile);
}
return result;
}
void TrendingTileHandler::OnTileClicked(const std::string& tile_id) {
tile_impressions_.erase(tile_id);
}
std::vector<std::string> TrendingTileHandler::GetInactiveTrendingTiles() {
std::vector<std::string> tile_ids;
if (!base::FeatureList::IsEnabled(
features::kQueryTilesRemoveTrendingTilesAfterInactivity)) {
return tile_ids;
}
ImpressionMap::iterator it = tile_impressions_.begin();
while (it != tile_impressions_.end()) {
if (it->second >= TileConfig::GetMaxTrendingTileImpressions()) {
tile_ids.emplace_back(it->first);
it = tile_impressions_.erase(it);
} else {
++it;
}
}
return tile_ids;
}
void TrendingTileHandler::RecordImpression(const std::string& tile_id) {
++tile_impressions_[tile_id];
}
} // namespace query_tiles
// Copyright 2020 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 COMPONENTS_QUERY_TILES_INTERNAL_TRENDING_TILE_HANDLER_H_
#define COMPONENTS_QUERY_TILES_INTERNAL_TRENDING_TILE_HANDLER_H_
#include <map>
#include <string>
#include <vector>
#include "components/query_tiles/internal/tile_group.h"
#include "components/query_tiles/tile.h"
namespace query_tiles {
// Class for handling trending tiles. It checks whether a trending tile
// should be displayed, hidden or removed.
class TrendingTileHandler {
public:
// Map between tile ID and tile impression.
using ImpressionMap = std::map<std::string, int>;
TrendingTileHandler();
~TrendingTileHandler();
TrendingTileHandler(const TrendingTileHandler& other) = delete;
TrendingTileHandler& operator=(const TrendingTileHandler& other) = delete;
// Resets the impression for all tiles. Must call this before calling other
// methods. If tile group changes, this method need to be called again.
void Reset();
// Given a list of tiles, remove extra trending tiles and return a list
// of tiles for display.
std::vector<Tile> FilterExtraTrendingTiles(
const std::vector<std::unique_ptr<Tile>>& tiles);
// Called when a tile is clicked.
void OnTileClicked(const std::string& tile_id);
// Returns a list of inactive trending tile Ids.
std::vector<std::string> GetInactiveTrendingTiles();
private:
// Record the impression for a tile with the give id.
void RecordImpression(const std::string& tile_id);
// Map to track how many times each tile is requested.
// A tile's impression is cleared after click.
// TODO(qinmin): move this to |tile_stats_group_|.
ImpressionMap tile_impressions_;
};
} // namespace query_tiles
#endif // COMPONENTS_QUERY_TILES_INTERNAL_TRENDING_TILE_HANDLER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment