blob: d82d04d66c21ac2e62a40cc926c2b5e8accba156 [file] [log] [blame]
// 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 "chrome/browser/chromeos/phonehub/browser_tabs_model_provider_impl.h"
#include "chromeos/components/multidevice/remote_device_ref.h"
#include "chromeos/components/phonehub/browser_tabs_metadata_fetcher.h"
#include "chromeos/components/phonehub/browser_tabs_model.h"
#include "components/sync/base/model_type.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync_sessions/open_tabs_ui_delegate.h"
#include "components/sync_sessions/session_sync_service.h"
namespace chromeos {
namespace phonehub {
BrowserTabsModelProviderImpl::BrowserTabsModelProviderImpl(
multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
syncer::SyncService* sync_service,
sync_sessions::SessionSyncService* session_sync_service,
std::unique_ptr<BrowserTabsMetadataFetcher> browser_tabs_metadata_fetcher)
: multidevice_setup_client_(multidevice_setup_client),
sync_service_(sync_service),
session_sync_service_(session_sync_service),
browser_tabs_metadata_fetcher_(std::move(browser_tabs_metadata_fetcher)) {
multidevice_setup_client_->AddObserver(this);
session_updated_subscription_ =
session_sync_service->SubscribeToForeignSessionsChanged(
base::BindRepeating(
&BrowserTabsModelProviderImpl::AttemptBrowserTabsModelUpdate,
base::Unretained(this)));
AttemptBrowserTabsModelUpdate();
}
BrowserTabsModelProviderImpl::~BrowserTabsModelProviderImpl() {
multidevice_setup_client_->RemoveObserver(this);
}
base::Optional<std::string> BrowserTabsModelProviderImpl::GetSessionName()
const {
const multidevice_setup::MultiDeviceSetupClient::HostStatusWithDevice&
host_device_with_status = multidevice_setup_client_->GetHostStatus();
if (!host_device_with_status.second)
return base::nullopt;
// The pii_free_name field of the device matches the session name for
// sync.
return host_device_with_status.second->pii_free_name();
}
void BrowserTabsModelProviderImpl::OnHostStatusChanged(
const multidevice_setup::MultiDeviceSetupClient::HostStatusWithDevice&
host_device_with_status) {
AttemptBrowserTabsModelUpdate();
}
void BrowserTabsModelProviderImpl::TriggerRefresh() {
// crbug/1158480: Currently (January 2021), updates to synced sessions
// sometimes take a long time to arrive. As a workaround,
// SyncService::TriggerRefresh() is used, which bypasses some of the potential
// sources of latency (e.g. for delivering an invalidation), but not others
// (e.g. backend replication delay). I.e SyncService::TriggerRefresh() will
// not guarantee an immediate update.
sync_service_->TriggerRefresh({syncer::SESSIONS});
}
void BrowserTabsModelProviderImpl::AttemptBrowserTabsModelUpdate() {
base::Optional<std::string> session_name = GetSessionName();
sync_sessions::OpenTabsUIDelegate* open_tabs =
session_sync_service_->GetOpenTabsUIDelegate();
// Tab sync is disabled or no valid |pii_free_name_|.
if (!open_tabs || !session_name) {
InvalidateWeakPtrsAndClearTabMetadata(/*is_tab_sync_enabled=*/false);
return;
}
std::vector<const sync_sessions::SyncedSession*> sessions;
bool was_fetch_successful = open_tabs->GetAllForeignSessions(&sessions);
// No tabs were found, clear all tab metadata.
if (!was_fetch_successful) {
InvalidateWeakPtrsAndClearTabMetadata(/*is_tab_sync_enabled=*/true);
return;
}
// |phone_session| should have the same |session_name| as the
// |pii_free_name|. If there is more than one session with the same
// |session_name| as the |pii_free_name|, as would be the case if a user has
// multiple phones of the same type, |phone_session| will have the latest
// |modified_time|.
const sync_sessions::SyncedSession* phone_session = nullptr;
for (const auto* session : sessions) {
if (session->session_name != *session_name)
continue;
if (!phone_session ||
phone_session->modified_time < session->modified_time) {
phone_session = session;
}
}
// No session with the same name as |pii_free_name_| was found, clear all
// tab metadata.
if (!phone_session) {
InvalidateWeakPtrsAndClearTabMetadata(/*is_tab_sync_enabled=*/true);
return;
}
browser_tabs_metadata_fetcher_->Fetch(
phone_session,
base::BindOnce(&BrowserTabsModelProviderImpl::OnMetadataFetched,
weak_ptr_factory_.GetWeakPtr()));
}
void BrowserTabsModelProviderImpl::InvalidateWeakPtrsAndClearTabMetadata(
bool is_tab_sync_enabled) {
weak_ptr_factory_.InvalidateWeakPtrs();
NotifyBrowserTabsUpdated(
/*is_tab_sync_enabled=*/is_tab_sync_enabled, {});
}
void BrowserTabsModelProviderImpl::OnMetadataFetched(
base::Optional<std::vector<BrowserTabsModel::BrowserTabMetadata>>
metadata) {
// The operation to fetch metadata was cancelled.
if (!metadata)
return;
NotifyBrowserTabsUpdated(
/*is_tab_sync_enabled=*/true, *metadata);
}
} // namespace phonehub
} // namespace chromeos