blob: 7dd128054f43fd5788daa9c4a22d27704d0861c9 [file] [log] [blame]
// Copyright 2017 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/ui/app_list/arc/arc_pai_starter.h"
#include <memory>
#include "chrome/browser/chromeos/arc/arc_optin_uma.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_prefs.h"
#include "components/arc/arc_service_manager.h"
#include "components/arc/arc_util.h"
#include "components/prefs/pref_service.h"
#include "ui/events/event_constants.h"
namespace arc {
namespace {
constexpr int kMinRetryTimeSeconds = 30;
constexpr int kMaxRetryTimeSeconds = 1800;
} // namespace
ArcPaiStarter::ArcPaiStarter(Profile* profile)
: profile_(profile),
pref_service_(profile->GetPrefs()),
retry_interval_seconds_(kMinRetryTimeSeconds),
weak_ptr_factory_(this) {
ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_);
// Prefs may not available in some unit tests.
if (!prefs)
return;
prefs->AddObserver(this);
MaybeStartPai();
}
ArcPaiStarter::~ArcPaiStarter() {
ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_);
if (!prefs)
return;
prefs->RemoveObserver(this);
}
// static
std::unique_ptr<ArcPaiStarter> ArcPaiStarter::CreateIfNeeded(Profile* profile) {
if (profile->GetPrefs()->GetBoolean(prefs::kArcPaiStarted))
return std::unique_ptr<ArcPaiStarter>();
return std::make_unique<ArcPaiStarter>(profile);
}
void ArcPaiStarter::AcquireLock() {
DCHECK(!locked_);
locked_ = true;
}
void ArcPaiStarter::ReleaseLock() {
DCHECK(locked_);
locked_ = false;
MaybeStartPai();
}
void ArcPaiStarter::AddOnStartCallback(base::OnceClosure callback) {
if (started_) {
std::move(callback).Run();
return;
}
onstart_callbacks_.push_back(std::move(callback));
}
void ArcPaiStarter::TriggerRetryForTesting() {
retry_timer_.FireNow();
}
void ArcPaiStarter::MaybeStartPai() {
// Clear retry timer. It is only used to call |MaybeStartPai| in case of PAI
// flow failed and no condition is changed to trigger |MaybeStartPai|.
retry_timer_.Stop();
if (started_ || pending_ || locked_ || IsArcPlayAutoInstallDisabled())
return;
ArcAppListPrefs* const prefs = ArcAppListPrefs::Get(profile_);
DCHECK(prefs);
std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
prefs->GetApp(kPlayStoreAppId);
if (!app_info || !app_info->ready)
return;
arc::mojom::AppInstance* app_instance = ARC_GET_INSTANCE_FOR_METHOD(
arc::ArcServiceManager::Get()->arc_bridge_service()->app(), StartPaiFlow);
if (!app_instance) {
app_instance = ARC_GET_INSTANCE_FOR_METHOD(
arc::ArcServiceManager::Get()->arc_bridge_service()->app(),
StartPaiFlowDeprecated);
// this should always be set because PAI can be started only in case Play
// Store app is ready which means app_instance is connected.
DCHECK(app_instance);
VLOG(1) << "Start deprecated PAI flow";
app_instance->StartPaiFlowDeprecated();
OnPaiDone();
return;
}
VLOG(1) << "Start PAI flow";
pending_ = true;
request_start_time_ = base::Time::Now();
app_instance->StartPaiFlow(base::BindOnce(&ArcPaiStarter::OnPaiRequested,
weak_ptr_factory_.GetWeakPtr()));
}
void ArcPaiStarter::OnPaiDone() {
DCHECK(!pending_);
ArcAppListPrefs* const prefs = ArcAppListPrefs::Get(profile_);
DCHECK(prefs);
started_ = true;
pref_service_->SetBoolean(prefs::kArcPaiStarted, true);
prefs->RemoveObserver(this);
for (auto& callback : onstart_callbacks_)
std::move(callback).Run();
onstart_callbacks_.clear();
}
void ArcPaiStarter::OnPaiRequested(mojom::PaiFlowState state) {
DCHECK(pending_);
pending_ = false;
VLOG(1) << "PAI flow state " << state;
UpdatePlayAutoInstallRequestState(state, profile_);
if (state != mojom::PaiFlowState::SUCCEEDED) {
retry_timer_.Start(
FROM_HERE, base::TimeDelta::FromSeconds(retry_interval_seconds_),
base::BindOnce(&ArcPaiStarter::MaybeStartPai, base::Unretained(this)));
retry_interval_seconds_ =
std::min(retry_interval_seconds_ * 2, kMaxRetryTimeSeconds);
return;
}
arc::UpdatePlayAutoInstallRequestTime(base::Time::Now() - request_start_time_,
profile_);
OnPaiDone();
}
void ArcPaiStarter::OnAppRegistered(const std::string& app_id,
const ArcAppListPrefs::AppInfo& app_info) {
OnAppStatesChanged(app_id, app_info);
}
void ArcPaiStarter::OnAppStatesChanged(
const std::string& app_id,
const ArcAppListPrefs::AppInfo& app_info) {
if (app_id == kPlayStoreAppId && app_info.ready)
MaybeStartPai();
}
} // namespace arc