Commit daccddc2 authored by Yue Cen's avatar Yue Cen Committed by Commit Bot

Start Fast App Reinstall flow.

If the user clicks the Install button after ARC++ is provisioned, we should
start the flow right away. If not, we delay the flow until Play Store is ready.

ARC++ changes: ag/4174872

Bug: 835029
Change-Id: I36037df522addd9aec3f525157e2e5478c9d4836
Reviewed-on: https://chromium-review.googlesource.com/1080012Reviewed-by: default avatarLuis Hector Chavez <lhchavez@chromium.org>
Reviewed-by: default avatarGreg Kerr <kerrnel@chromium.org>
Reviewed-by: default avatarYusuke Sato <yusukes@chromium.org>
Reviewed-by: default avatarYury Khmel <khmel@chromium.org>
Reviewed-by: default avatarAlexander Alekseev <alemate@chromium.org>
Commit-Queue: Yue Cen <rsgingerrs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567420}
parent 148a481a
......@@ -31,6 +31,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/arc/arc_app_launcher.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "chrome/browser/ui/app_list/arc/arc_fast_app_reinstall_starter.h"
#include "chrome/browser/ui/app_list/arc/arc_pai_starter.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
#include "chrome/browser/ui/browser_commands.h"
......@@ -497,6 +498,7 @@ void ArcSessionManager::Shutdown() {
}
context_.reset();
pai_starter_.reset();
fast_app_reinstall_starter_.reset();
profile_ = nullptr;
state_ = State::NOT_INITIALIZED;
if (scoped_opt_in_tracker_) {
......@@ -686,6 +688,11 @@ bool ArcSessionManager::RequestEnableImpl() {
ArcPaiStarter::CreateIfNeeded(profile_, profile_->GetPrefs());
}
if (!fast_app_reinstall_starter_ && IsPlayStoreAvailable()) {
fast_app_reinstall_starter_ = ArcFastAppReinstallStarter::CreateIfNeeded(
profile_, profile_->GetPrefs());
}
if (start_arc_directly) {
StartArc();
// When in ARC kiosk mode, there's no Chrome tabs to restore. Remove the
......@@ -724,6 +731,7 @@ void ArcSessionManager::RequestDisable() {
enable_requested_ = false;
scoped_opt_in_tracker_.reset();
pai_starter_.reset();
fast_app_reinstall_starter_.reset();
// Reset any pending request to re-enable ARC.
reenable_arc_ = false;
......@@ -988,6 +996,7 @@ void ArcSessionManager::StopArc() {
profile_->GetPrefs()->SetBoolean(prefs::kArcSignedIn, false);
profile_->GetPrefs()->SetBoolean(prefs::kArcPaiStarted, false);
profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, false);
profile_->GetPrefs()->SetBoolean(prefs::kArcFastAppReinstallStarted, false);
}
ShutdownSession();
if (support_host_)
......
......@@ -27,6 +27,7 @@ namespace arc {
class ArcAndroidManagementChecker;
class ArcAuthContext;
class ArcDataRemover;
class ArcFastAppReinstallStarter;
class ArcPaiStarter;
class ArcTermsOfServiceNegotiator;
enum class ProvisioningResult : int;
......@@ -242,6 +243,12 @@ class ArcSessionManager : public ArcSessionRunner::Observer,
// available only on initial start.
ArcPaiStarter* pai_starter() { return pai_starter_.get(); }
// Returns Fast App Reinstall starter that is used to start Play Fast App
// Reinstall flow. It is available only on initial start.
ArcFastAppReinstallStarter* fast_app_resintall_starter() {
return fast_app_reinstall_starter_.get();
}
// Returns true if the current ARC run has started with skipping user ToS
// negotiation, because the user had accepted already or policy does not
// require ToS acceptance. Returns false in other cases, including one when
......@@ -384,6 +391,7 @@ class ArcSessionManager : public ArcSessionRunner::Observer,
std::unique_ptr<ScopedOptInFlowTracker> scoped_opt_in_tracker_;
std::unique_ptr<ArcPaiStarter> pai_starter_;
std::unique_ptr<ArcFastAppReinstallStarter> fast_app_reinstall_starter_;
// The time when the sign in process started.
base::Time sign_in_start_time_;
......
......@@ -3629,6 +3629,8 @@ split_static_library("ui") {
"app_list/arc/arc_app_utils.h",
"app_list/arc/arc_default_app_list.cc",
"app_list/arc/arc_default_app_list.h",
"app_list/arc/arc_fast_app_reinstall_starter.cc",
"app_list/arc/arc_fast_app_reinstall_starter.h",
"app_list/arc/arc_package_sync_data_type_controller.cc",
"app_list/arc/arc_package_sync_data_type_controller.h",
"app_list/arc/arc_package_syncable_service.cc",
......
......@@ -39,6 +39,7 @@
#include "chrome/browser/ui/app_list/arc/arc_app_test.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "chrome/browser/ui/app_list/arc/arc_default_app_list.h"
#include "chrome/browser/ui/app_list/arc/arc_fast_app_reinstall_starter.h"
#include "chrome/browser/ui/app_list/arc/arc_package_syncable_service_factory.h"
#include "chrome/browser/ui/app_list/arc/arc_pai_starter.h"
#include "chrome/browser/ui/app_list/chrome_app_list_item.h"
......@@ -1408,6 +1409,100 @@ TEST_P(ArcVoiceInteractionTest, PaiStarterVoiceInteractionWizardNotComplete) {
WaitForPaiStarted();
}
TEST_P(ArcPlayStoreAppTest,
FastAppReinstallStarterUserFinishesSelectionBeforePlayStore) {
ASSERT_TRUE(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get());
ASSERT_TRUE(prefs);
arc::ArcFastAppReinstallStarter starter1(profile_.get(),
profile_->GetPrefs());
EXPECT_FALSE(starter1.started());
EXPECT_EQ(0, app_instance()->start_fast_app_reinstall_request_count());
arc::ArcSessionManager* session_manager = arc::ArcSessionManager::Get();
ASSERT_TRUE(session_manager);
// Fast App Reinstall starter is not expected for ARC without the Play Store.
if (GetParam() == ArcState::ARC_PERSISTENT_WITHOUT_PLAY_STORE) {
EXPECT_FALSE(session_manager->fast_app_resintall_starter());
return;
}
ASSERT_TRUE(session_manager->fast_app_resintall_starter());
EXPECT_FALSE(session_manager->fast_app_resintall_starter()->started());
// Fast App Reinstall is not expected to start when the user finishes
// selection without the Play Store.
base::ListValue* package_list = new base::ListValue();
package_list->Set(0, std::make_unique<base::Value>("fake_package_name"));
const base::ListValue* selected_packages(package_list);
profile_.get()->GetTestingPrefService()->Set(
arc::prefs::kArcFastAppReinstallPackages, *selected_packages);
starter1.OnAppsSelectionFinished();
EXPECT_FALSE(starter1.started());
EXPECT_EQ(0, app_instance()->start_fast_app_reinstall_request_count());
SendPlayStoreApp();
EXPECT_TRUE(starter1.started());
EXPECT_EQ(2, app_instance()->start_fast_app_reinstall_request_count());
arc::ArcFastAppReinstallStarter starter2(profile_.get(),
profile_->GetPrefs());
EXPECT_TRUE(starter2.started());
EXPECT_EQ(3, app_instance()->start_fast_app_reinstall_request_count());
}
TEST_P(ArcPlayStoreAppTest,
FastAppReinstallStarterUserFinishesSelectionAfterPlayStore) {
ASSERT_TRUE(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
ArcAppListPrefs* prefs = ArcAppListPrefs::Get(profile_.get());
ASSERT_TRUE(prefs);
arc::ArcFastAppReinstallStarter starter1(profile_.get(),
profile_->GetPrefs());
EXPECT_FALSE(starter1.started());
EXPECT_EQ(0, app_instance()->start_fast_app_reinstall_request_count());
arc::ArcSessionManager* session_manager = arc::ArcSessionManager::Get();
ASSERT_TRUE(session_manager);
// Fast App Reinstall starter is not expected for ARC without the Play Store.
if (GetParam() == ArcState::ARC_PERSISTENT_WITHOUT_PLAY_STORE) {
EXPECT_FALSE(session_manager->fast_app_resintall_starter());
return;
}
ASSERT_TRUE(session_manager->fast_app_resintall_starter());
EXPECT_FALSE(session_manager->fast_app_resintall_starter()->started());
SendPlayStoreApp();
// Fast App Reinstall is not expected to start when the user has not finished
// selection.
EXPECT_FALSE(starter1.started());
EXPECT_EQ(0, app_instance()->start_fast_app_reinstall_request_count());
base::ListValue* package_list = new base::ListValue();
package_list->Set(0, std::make_unique<base::Value>("fake_package_name"));
const base::ListValue* selected_packages(package_list);
profile_.get()->GetTestingPrefService()->Set(
arc::prefs::kArcFastAppReinstallPackages, *selected_packages);
starter1.OnAppsSelectionFinished();
// Fast App Reinstall is expected to start right after user finishes selection
// after Play Store is ready.
EXPECT_TRUE(starter1.started());
EXPECT_EQ(1, app_instance()->start_fast_app_reinstall_request_count());
arc::ArcFastAppReinstallStarter starter2(profile_.get(),
profile_->GetPrefs());
EXPECT_TRUE(starter2.started());
EXPECT_EQ(2, app_instance()->start_fast_app_reinstall_request_count());
}
// Test that icon is correctly extracted for shelf group.
TEST_P(ArcAppModelBuilderTest, IconLoaderForShelfGroup) {
const arc::mojom::AppInfo& app = fake_apps()[0];
......
......@@ -28,6 +28,7 @@
#include "chrome/browser/ui/ash/launcher/shelf_spinner_controller.h"
#include "chrome/common/pref_names.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/arc/common/intent_helper.mojom.h"
......@@ -372,6 +373,34 @@ void StartPaiFlow() {
app_instance->StartPaiFlow();
}
std::vector<std::string> GetSelectedPackagesFromPrefs(
content::BrowserContext* context) {
std::vector<std::string> packages;
const Profile* const profile = Profile::FromBrowserContext(context);
const PrefService* prefs = profile->GetPrefs();
const base::ListValue* selected_package_prefs =
prefs->GetList(arc::prefs::kArcFastAppReinstallPackages);
for (const base::Value& item : selected_package_prefs->GetList()) {
std::string item_str;
item.GetAsString(&item_str);
packages.push_back(std::move(item_str));
}
return packages;
}
void StartFastAppReinstallFlow(const std::vector<std::string>& package_names) {
arc::mojom::AppInstance* app_instance =
GET_APP_INSTANCE(StartFastAppReinstallFlow);
if (!app_instance) {
LOG(ERROR) << "Failed to start Fast App Reinstall flow because app "
"instance is not connected.";
return;
}
app_instance->StartFastAppReinstallFlow(package_names);
}
void UninstallPackage(const std::string& package_name) {
VLOG(2) << "Uninstalling " << package_name;
......
......@@ -129,6 +129,13 @@ void ShowTalkBackSettings();
// Starts Play Auto Install flow.
void StartPaiFlow();
// Gets user selected package names.
std::vector<std::string> GetSelectedPackagesFromPrefs(
content::BrowserContext* context);
// Starts Play Fast App Reinstall flow.
void StartFastAppReinstallFlow(const std::vector<std::string>& package_names);
// Uninstalls the package in ARC.
void UninstallPackage(const std::string& package_name);
......
// Copyright 2018 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_fast_app_reinstall_starter.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "components/arc/arc_prefs.h"
#include "components/arc/arc_util.h"
#include "components/prefs/pref_service.h"
namespace arc {
// TODO(rsgingerrs): This shares a lot of functionality with ArcPaiStarter.
// Should create a base class and put common code there.
ArcFastAppReinstallStarter::ArcFastAppReinstallStarter(
content::BrowserContext* context,
PrefService* pref_service)
: context_(context), pref_service_(pref_service) {
ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
// Prefs may not available in some unit tests.
if (!prefs)
return;
prefs->AddObserver(this);
MaybeStartFastAppReinstall();
}
ArcFastAppReinstallStarter::~ArcFastAppReinstallStarter() {
ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
if (!prefs)
return;
prefs->RemoveObserver(this);
}
// static
std::unique_ptr<ArcFastAppReinstallStarter>
ArcFastAppReinstallStarter::CreateIfNeeded(content::BrowserContext* context,
PrefService* pref_service) {
if (pref_service->GetBoolean(prefs::kArcFastAppReinstallStarted))
return nullptr;
return std::make_unique<ArcFastAppReinstallStarter>(context, pref_service);
}
void ArcFastAppReinstallStarter::OnAppsSelectionFinished() {
MaybeStartFastAppReinstall();
}
void ArcFastAppReinstallStarter::MaybeStartFastAppReinstall() {
if (started_) {
VLOG(2) << "Fast App Reinstall has already started.";
return;
}
ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
DCHECK(prefs);
std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
prefs->GetApp(kPlayStoreAppId);
if (!app_info || !app_info->ready) {
VLOG(2) << "Play Store is not ready. Will not start Fast App Reinstall.";
return;
}
const std::vector<std::string> selected_packages =
GetSelectedPackagesFromPrefs(context_);
if (selected_packages.size() <= 0) {
VLOG(2) << "No selected packages. Will not start Fast App Reinstall.";
return;
}
VLOG(2) << "Fast App Reinstall started...";
started_ = true;
StartFastAppReinstallFlow(selected_packages);
pref_service_->SetBoolean(prefs::kArcFastAppReinstallStarted, true);
}
void ArcFastAppReinstallStarter::OnAppRegistered(
const std::string& app_id,
const ArcAppListPrefs::AppInfo& app_info) {
OnAppReadyChanged(app_id, app_info.ready);
}
void ArcFastAppReinstallStarter::OnAppReadyChanged(const std::string& app_id,
bool ready) {
if (app_id == kPlayStoreAppId && ready)
MaybeStartFastAppReinstall();
}
} // namespace arc
// Copyright 2018 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 CHROME_BROWSER_UI_APP_LIST_ARC_ARC_FAST_APP_REINSTALL_STARTER_H_
#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_FAST_APP_REINSTALL_STARTER_H_
#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
class PrefService;
namespace content {
class BrowserContext;
}
namespace arc {
// Helper class that starts Play Fast App Reinstall flow when the Play Store app
// is ready.
class ArcFastAppReinstallStarter : public ArcAppListPrefs::Observer {
public:
ArcFastAppReinstallStarter(content::BrowserContext* context,
PrefService* pref_service);
~ArcFastAppReinstallStarter() override;
// Creating Fast App Reinstall starter will call MaybeStartFastAppReinstall().
// If the flow has already started, there is no need to create a new starter.
static std::unique_ptr<ArcFastAppReinstallStarter> CreateIfNeeded(
content::BrowserContext* context,
PrefService* pref_service);
bool started() const { return started_; }
void OnAppsSelectionFinished();
private:
void MaybeStartFastAppReinstall();
// ArcAppListPrefs::Observer:
void OnAppRegistered(const std::string& app_id,
const ArcAppListPrefs::AppInfo& app_info) override;
void OnAppReadyChanged(const std::string& app_id, bool ready) override;
content::BrowserContext* const context_;
PrefService* const pref_service_;
bool started_ = false;
DISALLOW_COPY_AND_ASSIGN(ArcFastAppReinstallStarter);
};
} // namespace arc
#endif // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_FAST_APP_REINSTALL_STARTER_H_
......@@ -4,10 +4,13 @@
#include "chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h"
#include "chrome/browser/chromeos/arc/arc_session_manager.h"
#include "chrome/browser/chromeos/login/screens/recommend_apps_screen.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/app_list/arc/arc_fast_app_reinstall_starter.h"
#include "chrome/grit/generated_resources.h"
#include "components/arc/arc_prefs.h"
#include "components/login/localized_values_builder.h"
namespace {
......@@ -106,7 +109,16 @@ void RecommendAppsScreenHandler::HandleRetry() {
}
void RecommendAppsScreenHandler::HandleInstall(const base::ListValue* args) {
pref_service_->Set("userSelectedAppList", *args);
pref_service_->Set(arc::prefs::kArcFastAppReinstallPackages, *args);
arc::ArcFastAppReinstallStarter* fast_app_reinstall_starter =
arc::ArcSessionManager::Get()->fast_app_resintall_starter();
if (fast_app_reinstall_starter) {
fast_app_reinstall_starter->OnAppsSelectionFinished();
} else {
LOG(ERROR)
<< "Cannot complete Fast App Reinstall flow. Starter is not available.";
}
for (auto& observer : observer_list_)
observer.OnInstall();
......
......@@ -54,6 +54,11 @@ const char kArcLocationServiceEnabled[] = "arc.location_service.enabled";
const char kArcPackages[] = "arc.packages";
// A preference that indicates that Play Auto Install flow was already started.
const char kArcPaiStarted[] = "arc.pai.started";
// A preference that indicates that Play Fast App Reinstall flow was already
// started.
const char kArcFastAppReinstallStarted[] = "arc.fast.app.reinstall.started";
// A preference to keep list of Play Fast App Reinstall packages.
const char kArcFastAppReinstallPackages[] = "arc.fast.app.reinstall.packages";
// A preference that holds the list of apps that the admin requested to be
// push-installed.
const char kArcPushInstallAppsRequested[] = "arc.push_install.requested";
......@@ -112,6 +117,8 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kArcEnabled, false);
registry->RegisterBooleanPref(kArcInitialSettingsPending, false);
registry->RegisterBooleanPref(kArcPaiStarted, false);
registry->RegisterBooleanPref(kArcFastAppReinstallStarted, false);
registry->RegisterListPref(kArcFastAppReinstallPackages);
registry->RegisterBooleanPref(kArcPolicyComplianceReported, false);
registry->RegisterBooleanPref(kArcSignedIn, false);
registry->RegisterBooleanPref(kArcTermsAccepted, false);
......
......@@ -18,6 +18,8 @@ ARC_EXPORT extern const char kArcApps[];
ARC_EXPORT extern const char kArcBackupRestoreEnabled[];
ARC_EXPORT extern const char kArcDataRemoveRequested[];
ARC_EXPORT extern const char kArcEnabled[];
ARC_EXPORT extern const char kArcFastAppReinstallPackages[];
ARC_EXPORT extern const char kArcFastAppReinstallStarted[];
ARC_EXPORT extern const char kArcInitialSettingsPending[];
ARC_EXPORT extern const char kArcPolicyComplianceReported[];
ARC_EXPORT extern const char kArcTermsAccepted[];
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Next MinVersion: 33
// Next MinVersion: 34
module arc.mojom;
......@@ -272,7 +272,7 @@ interface AppHost {
};
// TODO(lhchavez): Migrate all request/response messages to Mojo.
// Next method ID: 25
// Next method ID: 26
interface AppInstance {
// DEPRECATED: Please use Init@21 instead.
InitDeprecated@0(AppHost host_ptr);
......@@ -357,6 +357,9 @@ interface AppInstance {
// Sends a request to ARC to start PAI flow.
[MinVersion=21] StartPaiFlow@17();
// Sends a request to ARC to start FastAppReinstall flow.
[MinVersion=33] StartFastAppReinstallFlow@25(array<string> arc_package_names);
// Sends a request to ARC to uninstall the given package. Error (if ever
// happens) is ignored, and uninstall option should appear in the UI.
[MinVersion=2] UninstallPackage@5(string package_name);
......
......@@ -415,6 +415,11 @@ void FakeAppInstance::StartPaiFlow() {
++start_pai_request_count_;
}
void FakeAppInstance::StartFastAppReinstallFlow(
const std::vector<std::string>& package_names) {
++start_fast_app_reinstall_request_count_;
}
void FakeAppInstance::LaunchIntentDeprecated(
const std::string& intent_uri,
const base::Optional<gfx::Rect>& dimension_on_screen) {
......
......@@ -134,6 +134,8 @@ class FakeAppInstance : public mojom::AppInstance {
void GetAppShortcutItems(const std::string& package_name,
GetAppShortcutItemsCallback callback) override;
void StartPaiFlow() override;
void StartFastAppReinstallFlow(
const std::vector<std::string>& package_names) override;
// Methods to reply messages.
void SendRefreshAppList(const std::vector<mojom::AppInfo>& apps);
......@@ -173,6 +175,10 @@ class FakeAppInstance : public mojom::AppInstance {
int start_pai_request_count() const { return start_pai_request_count_; }
int start_fast_app_reinstall_request_count() const {
return start_fast_app_reinstall_request_count_;
}
int launch_app_shortcut_item_count() const {
return launch_app_shortcut_item_count_;
}
......@@ -202,6 +208,8 @@ class FakeAppInstance : public mojom::AppInstance {
int refresh_app_list_count_ = 0;
// Number of requests to start PAI flows.
int start_pai_request_count_ = 0;
// Number of requests to start Fast App Reinstall flows.
int start_fast_app_reinstall_request_count_ = 0;
// Keeps information about launch app shortcut requests.
int launch_app_shortcut_item_count_ = 0;
// Keeps information about launch requests.
......
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