Commit 8456ca90 authored by Timothy Loh's avatar Timothy Loh Committed by Commit Bot

Add install and last launch time fields to the Crostini registry

This patch adds install_time and last_launch_time fields to the Crostini
registry. These will be used in the app launcher's recently launched
apps list, where currently Crostini apps do not appear.

As we would also like the Terminal to appear in the recents list, this
patch makes the registry support the Terminal, returning it in both
GetRegistration and GetRegisteredAppIds. We don't need to keep track of
Terminal install time as it is just a fallback for apps that haven't
been launched. Internally, we only store the last launched time, so
methods in the registry need to be careful they don't expect all pref
entries will have all the standard fields.

Bug: 821662, 836137
Change-Id: I43f34434afe61bd80c165c3a42047b184f96fcbe
Reviewed-on: https://chromium-review.googlesource.com/1027292
Commit-Queue: Timothy Loh <timloh@chromium.org>
Reviewed-by: default avatarNicholas Verne <nverne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553945}
parent 8a8383af
...@@ -4,7 +4,11 @@ ...@@ -4,7 +4,11 @@
#include "chrome/browser/chromeos/crostini/crostini_registry_service.h" #include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/crostini/crostini_util.h"
...@@ -44,6 +48,8 @@ constexpr char kAppNameKey[] = "name"; ...@@ -44,6 +48,8 @@ constexpr char kAppNameKey[] = "name";
constexpr char kAppNoDisplayKey[] = "no_display"; constexpr char kAppNoDisplayKey[] = "no_display";
constexpr char kAppStartupWMClassKey[] = "startup_wm_class"; constexpr char kAppStartupWMClassKey[] = "startup_wm_class";
constexpr char kAppStartupNotifyKey[] = "startup_notify"; constexpr char kAppStartupNotifyKey[] = "startup_notify";
constexpr char kAppInstallTimeKey[] = "install_time";
constexpr char kAppLastLaunchTimeKey[] = "last_launch_time";
std::string GenerateAppId(const std::string& desktop_file_id, std::string GenerateAppId(const std::string& desktop_file_id,
const std::string& vm_name, const std::string& vm_name,
...@@ -104,6 +110,9 @@ FindAppIdResult FindAppId(const base::DictionaryValue* prefs, ...@@ -104,6 +110,9 @@ FindAppIdResult FindAppId(const base::DictionaryValue* prefs,
bool require_startup_notify = false) { bool require_startup_notify = false) {
result->clear(); result->clear();
for (const auto& item : prefs->DictItems()) { for (const auto& item : prefs->DictItems()) {
if (item.first == kCrostiniTerminalId)
continue;
if (require_startup_notify && if (require_startup_notify &&
!item.second !item.second
.FindKeyOfType(kAppStartupNotifyKey, base::Value::Type::BOOLEAN) .FindKeyOfType(kAppStartupNotifyKey, base::Value::Type::BOOLEAN)
...@@ -126,6 +135,31 @@ FindAppIdResult FindAppId(const base::DictionaryValue* prefs, ...@@ -126,6 +135,31 @@ FindAppIdResult FindAppId(const base::DictionaryValue* prefs,
return FindAppIdResult::NoMatch; return FindAppIdResult::NoMatch;
} }
bool EqualsExcludingTimestamps(const base::Value& left,
const base::Value& right) {
auto left_items = left.DictItems();
auto right_items = right.DictItems();
auto left_iter = left_items.begin();
auto right_iter = right_items.begin();
while (left_iter != left_items.end() && right_iter != right_items.end()) {
if (left_iter->first == kAppInstallTimeKey ||
left_iter->first == kAppLastLaunchTimeKey) {
++left_iter;
continue;
}
if (right_iter->first == kAppInstallTimeKey ||
right_iter->first == kAppLastLaunchTimeKey) {
++right_iter;
continue;
}
if (*left_iter != *right_iter)
return false;
++left_iter;
++right_iter;
}
return left_iter == left_items.end() && right_iter == right_items.end();
}
} // namespace } // namespace
CrostiniRegistryService::Registration::Registration( CrostiniRegistryService::Registration::Registration(
...@@ -137,7 +171,9 @@ CrostiniRegistryService::Registration::Registration( ...@@ -137,7 +171,9 @@ CrostiniRegistryService::Registration::Registration(
const std::vector<std::string>& mime_types, const std::vector<std::string>& mime_types,
bool no_display, bool no_display,
const std::string& startup_wm_class, const std::string& startup_wm_class,
bool startup_notify) bool startup_notify,
base::Time install_time,
base::Time last_launch_time)
: desktop_file_id(desktop_file_id), : desktop_file_id(desktop_file_id),
vm_name(vm_name), vm_name(vm_name),
container_name(container_name), container_name(container_name),
...@@ -146,7 +182,9 @@ CrostiniRegistryService::Registration::Registration( ...@@ -146,7 +182,9 @@ CrostiniRegistryService::Registration::Registration(
mime_types(mime_types), mime_types(mime_types),
no_display(no_display), no_display(no_display),
startup_wm_class(startup_wm_class), startup_wm_class(startup_wm_class),
startup_notify(startup_notify) { startup_notify(startup_notify),
install_time(install_time),
last_launch_time(last_launch_time) {
DCHECK(name.find(std::string()) != name.end()); DCHECK(name.find(std::string()) != name.end());
} }
...@@ -169,7 +207,7 @@ const std::string& CrostiniRegistryService::Registration::Localize( ...@@ -169,7 +207,7 @@ const std::string& CrostiniRegistryService::Registration::Localize(
} }
CrostiniRegistryService::CrostiniRegistryService(Profile* profile) CrostiniRegistryService::CrostiniRegistryService(Profile* profile)
: prefs_(profile->GetPrefs()) {} : prefs_(profile->GetPrefs()), clock_(base::DefaultClock::GetInstance()) {}
CrostiniRegistryService::~CrostiniRegistryService() = default; CrostiniRegistryService::~CrostiniRegistryService() = default;
...@@ -257,7 +295,8 @@ std::vector<std::string> CrostiniRegistryService::GetRegisteredAppIds() const { ...@@ -257,7 +295,8 @@ std::vector<std::string> CrostiniRegistryService::GetRegisteredAppIds() const {
std::vector<std::string> result; std::vector<std::string> result;
for (const auto& item : apps->DictItems()) for (const auto& item : apps->DictItems())
result.push_back(item.first); result.push_back(item.first);
if (!apps->FindKey(kCrostiniTerminalId))
result.push_back(kCrostiniTerminalId);
return result; return result;
} }
...@@ -267,6 +306,18 @@ CrostiniRegistryService::GetRegistration(const std::string& app_id) const { ...@@ -267,6 +306,18 @@ CrostiniRegistryService::GetRegistration(const std::string& app_id) const {
prefs_->GetDictionary(kCrostiniRegistryPref); prefs_->GetDictionary(kCrostiniRegistryPref);
const base::Value* pref_registration = const base::Value* pref_registration =
apps->FindKeyOfType(app_id, base::Value::Type::DICTIONARY); apps->FindKeyOfType(app_id, base::Value::Type::DICTIONARY);
if (app_id == kCrostiniTerminalId) {
std::map<std::string, std::string> name = {
{std::string(), kCrostiniTerminalAppName}};
return std::make_unique<Registration>(
"", kCrostiniDefaultVmName, kCrostiniDefaultContainerName, name,
Registration::LocaleString(), std::vector<std::string>(), false, "",
false, base::Time(),
pref_registration ? GetTime(*pref_registration, kAppLastLaunchTimeKey)
: base::Time());
}
if (!pref_registration) if (!pref_registration)
return nullptr; return nullptr;
...@@ -296,7 +347,9 @@ CrostiniRegistryService::GetRegistration(const std::string& app_id) const { ...@@ -296,7 +347,9 @@ CrostiniRegistryService::GetRegistration(const std::string& app_id) const {
DictionaryToStringMap(comment), ListToStringVector(mime_types), DictionaryToStringMap(comment), ListToStringVector(mime_types),
no_display->GetBool(), no_display->GetBool(),
startup_wm_class ? startup_wm_class->GetString() : "", startup_wm_class ? startup_wm_class->GetString() : "",
startup_notify && startup_notify->GetBool()); startup_notify && startup_notify->GetBool(),
GetTime(*pref_registration, kAppInstallTimeKey),
GetTime(*pref_registration, kAppLastLaunchTimeKey));
} }
void CrostiniRegistryService::UpdateApplicationList( void CrostiniRegistryService::UpdateApplicationList(
...@@ -356,18 +409,35 @@ void CrostiniRegistryService::UpdateApplicationList( ...@@ -356,18 +409,35 @@ void CrostiniRegistryService::UpdateApplicationList(
base::Value(app.startup_notify())); base::Value(app.startup_notify()));
base::Value* old_app = apps->FindKey(app_id); base::Value* old_app = apps->FindKey(app_id);
if (old_app && pref_registration == *old_app) if (old_app && EqualsExcludingTimestamps(pref_registration, *old_app))
continue; continue;
if (old_app) base::Value* old_install_time = nullptr;
base::Value* old_last_launch_time = nullptr;
if (old_app) {
updated_apps.push_back(app_id); updated_apps.push_back(app_id);
else old_install_time = old_app->FindKey(kAppInstallTimeKey);
old_last_launch_time = old_app->FindKey(kAppLastLaunchTimeKey);
} else {
inserted_apps.push_back(app_id); inserted_apps.push_back(app_id);
}
if (old_install_time)
pref_registration.SetKey(kAppInstallTimeKey, old_install_time->Clone());
else
SetCurrentTime(&pref_registration, kAppInstallTimeKey);
if (old_last_launch_time) {
pref_registration.SetKey(kAppLastLaunchTimeKey,
old_last_launch_time->Clone());
}
apps->SetKey(app_id, std::move(pref_registration)); apps->SetKey(app_id, std::move(pref_registration));
} }
for (const auto& item : apps->DictItems()) { for (const auto& item : apps->DictItems()) {
if (item.first == kCrostiniTerminalId)
continue;
if (item.second.FindKey(kAppVmNameKey)->GetString() == if (item.second.FindKey(kAppVmNameKey)->GetString() ==
app_list.vm_name() && app_list.vm_name() &&
item.second.FindKey(kAppContainerNameKey)->GetString() == item.second.FindKey(kAppContainerNameKey)->GetString() ==
...@@ -381,8 +451,11 @@ void CrostiniRegistryService::UpdateApplicationList( ...@@ -381,8 +451,11 @@ void CrostiniRegistryService::UpdateApplicationList(
apps->RemoveKey(removed_app); apps->RemoveKey(removed_app);
} }
for (Observer& obs : observers_) if (!updated_apps.empty() || !removed_apps.empty() ||
obs.OnRegistryUpdated(this, updated_apps, removed_apps, inserted_apps); !inserted_apps.empty()) {
for (Observer& obs : observers_)
obs.OnRegistryUpdated(this, updated_apps, removed_apps, inserted_apps);
}
} }
void CrostiniRegistryService::AddObserver(Observer* observer) { void CrostiniRegistryService::AddObserver(Observer* observer) {
...@@ -393,6 +466,40 @@ void CrostiniRegistryService::RemoveObserver(Observer* observer) { ...@@ -393,6 +466,40 @@ void CrostiniRegistryService::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer); observers_.RemoveObserver(observer);
} }
void CrostiniRegistryService::AppLaunched(const std::string& app_id) {
DictionaryPrefUpdate update(prefs_, kCrostiniRegistryPref);
base::DictionaryValue* apps = update.Get();
base::Value* app = apps->FindKey(app_id);
if (!app) {
DCHECK_EQ(app_id, kCrostiniTerminalId);
base::Value pref(base::Value::Type::DICTIONARY);
SetCurrentTime(&pref, kAppLastLaunchTimeKey);
apps->SetKey(app_id, std::move(pref));
return;
}
SetCurrentTime(app, kAppLastLaunchTimeKey);
}
void CrostiniRegistryService::SetCurrentTime(base::Value* dictionary,
const char* key) const {
DCHECK(dictionary);
int64_t time = clock_->Now().ToDeltaSinceWindowsEpoch().InMicroseconds();
dictionary->SetKey(key, base::Value(base::Int64ToString(time)));
}
base::Time CrostiniRegistryService::GetTime(const base::Value& dictionary,
const char* key) const {
const base::Value* value =
dictionary.FindKeyOfType(key, base::Value::Type::STRING);
int64_t time;
if (!value || !base::StringToInt64(value->GetString(), &time))
return base::Time();
return base::Time::FromDeltaSinceWindowsEpoch(
base::TimeDelta::FromMicroseconds(time));
}
// static // static
void CrostiniRegistryService::RegisterProfilePrefs( void CrostiniRegistryService::RegisterProfilePrefs(
PrefRegistrySimple* registry) { PrefRegistrySimple* registry) {
......
...@@ -18,6 +18,12 @@ class Profile; ...@@ -18,6 +18,12 @@ class Profile;
class PrefRegistrySimple; class PrefRegistrySimple;
class PrefService; class PrefService;
namespace base {
class Clock;
class Time;
class Value;
} // namespace base
namespace vm_tools { namespace vm_tools {
namespace apps { namespace apps {
class ApplicationList; class ApplicationList;
...@@ -38,8 +44,7 @@ namespace crostini { ...@@ -38,8 +44,7 @@ namespace crostini {
// 2) Crostini App List Ids (app_id): // 2) Crostini App List Ids (app_id):
// - Valid extensions ids for apps stored in the registry, derived from the // - Valid extensions ids for apps stored in the registry, derived from the
// desktop file id, vm name, and container name. // desktop file id, vm name, and container name.
// - The default Terminal app is a special case app list item, without an // - The Terminal is a special case, using kCrostiniTerminalId (see below).
// entry in the registry.
// 3) Exo Window App Ids (window_app_id): // 3) Exo Window App Ids (window_app_id):
// - Retrieved from exo::ShellSurface::GetApplicationId() // - Retrieved from exo::ShellSurface::GetApplicationId()
// - For Wayland apps, this is the surface class of the app // - For Wayland apps, this is the surface class of the app
...@@ -50,6 +55,11 @@ namespace crostini { ...@@ -50,6 +55,11 @@ namespace crostini {
// - Used in ash::ShelfID::app_id // - Used in ash::ShelfID::app_id
// - Either a Window App Id prefixed by "crostini:" or a Crostini App Id. // - Either a Window App Id prefixed by "crostini:" or a Crostini App Id.
// - For pinned apps, this is a Crostini App Id. // - For pinned apps, this is a Crostini App Id.
// The default Terminal app does not correspond to a desktop file, but users
// of the registry can treat it as a regular app that is always installed.
// Internal to the registry, the pref entry only contains the last launch time
// so some care is required.
class CrostiniRegistryService : public KeyedService { class CrostiniRegistryService : public KeyedService {
public: public:
struct Registration { struct Registration {
...@@ -66,7 +76,9 @@ class CrostiniRegistryService : public KeyedService { ...@@ -66,7 +76,9 @@ class CrostiniRegistryService : public KeyedService {
const std::vector<std::string>& mime_types, const std::vector<std::string>& mime_types,
bool no_display, bool no_display,
const std::string& startup_wm_class, const std::string& startup_wm_class,
bool startup_notify); bool startup_notify,
base::Time install_time,
base::Time last_launch_time);
~Registration(); ~Registration();
static const std::string& Localize(const LocaleString& locale_string); static const std::string& Localize(const LocaleString& locale_string);
...@@ -83,13 +95,17 @@ class CrostiniRegistryService : public KeyedService { ...@@ -83,13 +95,17 @@ class CrostiniRegistryService : public KeyedService {
std::string startup_wm_class; std::string startup_wm_class;
bool startup_notify; bool startup_notify;
base::Time install_time;
base::Time last_launch_time;
DISALLOW_COPY_AND_ASSIGN(Registration); DISALLOW_COPY_AND_ASSIGN(Registration);
}; };
class Observer { class Observer {
public: public:
// Called at the end of UpdateApplicationList() with lists of app_ids for // Called at the end of UpdateApplicationList() with lists of app_ids for
// apps which have been updated, removed, and inserted. // apps which have been updated, removed, and inserted. Not called when the
// last_launch_time field is updated.
virtual void OnRegistryUpdated( virtual void OnRegistryUpdated(
CrostiniRegistryService* registry_service, CrostiniRegistryService* registry_service,
const std::vector<std::string>& updated_apps, const std::vector<std::string>& updated_apps,
...@@ -117,10 +133,10 @@ class CrostiniRegistryService : public KeyedService { ...@@ -117,10 +133,10 @@ class CrostiniRegistryService : public KeyedService {
// Returns whether the app_id is a Crostini app id. // Returns whether the app_id is a Crostini app id.
bool IsCrostiniShelfAppId(const std::string& shelf_app_id); bool IsCrostiniShelfAppId(const std::string& shelf_app_id);
// Return all installed apps. This always includes the Terminal app.
std::vector<std::string> GetRegisteredAppIds() const; std::vector<std::string> GetRegisteredAppIds() const;
// Return null if |app_id| is not found in the registry. // Return null if |app_id| is not found in the registry.
// TODO(timloh): We should probably have an entry for the Terminal app.
std::unique_ptr<CrostiniRegistryService::Registration> GetRegistration( std::unique_ptr<CrostiniRegistryService::Registration> GetRegistration(
const std::string& app_id) const; const std::string& app_id) const;
...@@ -130,6 +146,15 @@ class CrostiniRegistryService : public KeyedService { ...@@ -130,6 +146,15 @@ class CrostiniRegistryService : public KeyedService {
void AddObserver(Observer* observer); void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer); void RemoveObserver(Observer* observer);
// Notify the registry to update the last_launched field.
void AppLaunched(const std::string& app_id);
// Serializes the current time and stores it in |dictionary|.
void SetCurrentTime(base::Value* dictionary, const char* key) const;
// Deserializes a time from |dictionary|.
base::Time GetTime(const base::Value& dictionary, const char* key) const;
void SetClockForTesting(base::Clock* clock) { clock_ = clock; }
static void RegisterProfilePrefs(PrefRegistrySimple* registry); static void RegisterProfilePrefs(PrefRegistrySimple* registry);
private: private:
...@@ -138,6 +163,8 @@ class CrostiniRegistryService : public KeyedService { ...@@ -138,6 +163,8 @@ class CrostiniRegistryService : public KeyedService {
base::ObserverList<Observer> observers_; base::ObserverList<Observer> observers_;
const base::Clock* clock_;
DISALLOW_COPY_AND_ASSIGN(CrostiniRegistryService); DISALLOW_COPY_AND_ASSIGN(CrostiniRegistryService);
}; };
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include <stddef.h> #include <stddef.h>
#include "base/macros.h" #include "base/macros.h"
#include "base/test/simple_test_clock.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "chromeos/dbus/vm_applications/apps.pb.h" #include "chromeos/dbus/vm_applications/apps.pb.h"
#include "components/crx_file/id_util.h" #include "components/crx_file/id_util.h"
...@@ -14,6 +16,7 @@ ...@@ -14,6 +16,7 @@
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using vm_tools::apps::App; using vm_tools::apps::App;
using vm_tools::apps::ApplicationList; using vm_tools::apps::ApplicationList;
...@@ -26,6 +29,7 @@ class CrostiniRegistryServiceTest : public testing::Test { ...@@ -26,6 +29,7 @@ class CrostiniRegistryServiceTest : public testing::Test {
// testing::Test: // testing::Test:
void SetUp() override { void SetUp() override {
service_ = std::make_unique<CrostiniRegistryService>(&profile_); service_ = std::make_unique<CrostiniRegistryService>(&profile_);
service_->SetClockForTesting(&test_clock_);
} }
protected: protected:
...@@ -71,6 +75,9 @@ class CrostiniRegistryServiceTest : public testing::Test { ...@@ -71,6 +75,9 @@ class CrostiniRegistryServiceTest : public testing::Test {
CrostiniRegistryService* service() { return service_.get(); } CrostiniRegistryService* service() { return service_.get(); }
protected:
base::SimpleTestClock test_clock_;
private: private:
content::TestBrowserThreadBundle thread_bundle_; content::TestBrowserThreadBundle thread_bundle_;
TestingProfile profile_; TestingProfile profile_;
...@@ -159,6 +166,53 @@ TEST_F(CrostiniRegistryServiceTest, Observer) { ...@@ -159,6 +166,53 @@ TEST_F(CrostiniRegistryServiceTest, Observer) {
service()->UpdateApplicationList(app_list); service()->UpdateApplicationList(app_list);
} }
TEST_F(CrostiniRegistryServiceTest, InstallAndLaunchTime) {
ApplicationList app_list = BasicAppList("app", "vm", "container");
std::string app_id = GenerateAppId("app", "vm", "container");
test_clock_.Advance(base::TimeDelta::FromHours(1));
Observer observer;
service()->AddObserver(&observer);
EXPECT_CALL(observer, OnRegistryUpdated(service(), testing::IsEmpty(),
testing::IsEmpty(),
testing::ElementsAre(app_id)));
service()->UpdateApplicationList(app_list);
auto result = service()->GetRegistration(app_id);
base::Time install_time = test_clock_.Now();
EXPECT_EQ(result->install_time, install_time);
EXPECT_EQ(result->last_launch_time, base::Time());
// UpdateApplicationList with nothing changed. Times shouldn't be updated and
// the observer shouldn't fire.
test_clock_.Advance(base::TimeDelta::FromHours(1));
EXPECT_CALL(observer, OnRegistryUpdated(_, _, _, _)).Times(0);
service()->UpdateApplicationList(app_list);
result = service()->GetRegistration(app_id);
EXPECT_EQ(result->install_time, install_time);
EXPECT_EQ(result->last_launch_time, base::Time());
// Launch the app
test_clock_.Advance(base::TimeDelta::FromHours(1));
service()->AppLaunched(app_id);
result = service()->GetRegistration(app_id);
EXPECT_EQ(result->install_time, install_time);
EXPECT_EQ(result->last_launch_time,
base::Time() + base::TimeDelta::FromHours(3));
// The install time shouldn't change if fields change.
test_clock_.Advance(base::TimeDelta::FromHours(1));
app_list.mutable_apps(0)->set_no_display(true);
EXPECT_CALL(observer,
OnRegistryUpdated(service(), testing::ElementsAre(app_id),
testing::IsEmpty(), testing::IsEmpty()));
service()->UpdateApplicationList(app_list);
result = service()->GetRegistration(app_id);
EXPECT_EQ(result->install_time, install_time);
EXPECT_EQ(result->last_launch_time,
base::Time() + base::TimeDelta::FromHours(3));
}
// Test that UpdateApplicationList doesn't clobber apps from different VMs or // Test that UpdateApplicationList doesn't clobber apps from different VMs or
// containers. // containers.
TEST_F(CrostiniRegistryServiceTest, MultipleContainers) { TEST_F(CrostiniRegistryServiceTest, MultipleContainers) {
...@@ -170,7 +224,8 @@ TEST_F(CrostiniRegistryServiceTest, MultipleContainers) { ...@@ -170,7 +224,8 @@ TEST_F(CrostiniRegistryServiceTest, MultipleContainers) {
std::string app_id_3 = GenerateAppId("app", "vm 2", "container 1"); std::string app_id_3 = GenerateAppId("app", "vm 2", "container 1");
EXPECT_THAT(service()->GetRegisteredAppIds(), EXPECT_THAT(service()->GetRegisteredAppIds(),
testing::UnorderedElementsAre(app_id_1, app_id_2, app_id_3)); testing::UnorderedElementsAre(app_id_1, app_id_2, app_id_3,
kCrostiniTerminalId));
// Clobber app_id_2 // Clobber app_id_2
service()->UpdateApplicationList( service()->UpdateApplicationList(
...@@ -178,7 +233,8 @@ TEST_F(CrostiniRegistryServiceTest, MultipleContainers) { ...@@ -178,7 +233,8 @@ TEST_F(CrostiniRegistryServiceTest, MultipleContainers) {
std::string new_app_id = GenerateAppId("app 2", "vm 1", "container 2"); std::string new_app_id = GenerateAppId("app 2", "vm 1", "container 2");
EXPECT_THAT(service()->GetRegisteredAppIds(), EXPECT_THAT(service()->GetRegisteredAppIds(),
testing::UnorderedElementsAre(app_id_1, app_id_3, new_app_id)); testing::UnorderedElementsAre(app_id_1, app_id_3, new_app_id,
kCrostiniTerminalId));
} }
TEST_F(CrostiniRegistryServiceTest, GetCrostiniAppIdNoStartupID) { TEST_F(CrostiniRegistryServiceTest, GetCrostiniAppIdNoStartupID) {
...@@ -189,7 +245,7 @@ TEST_F(CrostiniRegistryServiceTest, GetCrostiniAppIdNoStartupID) { ...@@ -189,7 +245,7 @@ TEST_F(CrostiniRegistryServiceTest, GetCrostiniAppIdNoStartupID) {
service()->UpdateApplicationList(BasicAppList("super", "vm 2", "container")); service()->UpdateApplicationList(BasicAppList("super", "vm 2", "container"));
EXPECT_THAT(service()->GetRegisteredAppIds(), testing::SizeIs(4)); EXPECT_THAT(service()->GetRegisteredAppIds(), testing::SizeIs(5));
EXPECT_EQ( EXPECT_EQ(
service()->GetCrostiniShelfAppId(WindowIdForWMClass("App"), nullptr), service()->GetCrostiniShelfAppId(WindowIdForWMClass("App"), nullptr),
...@@ -226,7 +282,7 @@ TEST_F(CrostiniRegistryServiceTest, GetCrostiniAppIdStartupWMClass) { ...@@ -226,7 +282,7 @@ TEST_F(CrostiniRegistryServiceTest, GetCrostiniAppIdStartupWMClass) {
app_list.mutable_apps(2)->set_startup_wm_class("app2"); app_list.mutable_apps(2)->set_startup_wm_class("app2");
service()->UpdateApplicationList(app_list); service()->UpdateApplicationList(app_list);
EXPECT_THAT(service()->GetRegisteredAppIds(), testing::SizeIs(3)); EXPECT_THAT(service()->GetRegisteredAppIds(), testing::SizeIs(4));
EXPECT_EQ(service()->GetCrostiniShelfAppId(WindowIdForWMClass("app_start"), EXPECT_EQ(service()->GetCrostiniShelfAppId(WindowIdForWMClass("app_start"),
nullptr), nullptr),
......
...@@ -75,6 +75,8 @@ bool IsExperimentalCrostiniUIAvailable() { ...@@ -75,6 +75,8 @@ bool IsExperimentalCrostiniUIAvailable() {
void LaunchCrostiniApp(Profile* profile, const std::string& app_id) { void LaunchCrostiniApp(Profile* profile, const std::string& app_id) {
auto* crostini_manager = crostini::CrostiniManager::GetInstance(); auto* crostini_manager = crostini::CrostiniManager::GetInstance();
crostini::CrostiniRegistryService* registry_service =
crostini::CrostiniRegistryServiceFactory::GetForProfile(profile);
if (app_id == kCrostiniTerminalId) { if (app_id == kCrostiniTerminalId) {
RecordAppLaunchHistogram(CrostiniAppLaunchAppType::kTerminal); RecordAppLaunchHistogram(CrostiniAppLaunchAppType::kTerminal);
...@@ -87,11 +89,10 @@ void LaunchCrostiniApp(Profile* profile, const std::string& app_id) { ...@@ -87,11 +89,10 @@ void LaunchCrostiniApp(Profile* profile, const std::string& app_id) {
profile, kCrostiniDefaultVmName, kCrostiniDefaultContainerName, profile, kCrostiniDefaultVmName, kCrostiniDefaultContainerName,
base::BindOnce(&MaybeLaunchTerminal, profile)); base::BindOnce(&MaybeLaunchTerminal, profile));
} }
registry_service->AppLaunched(app_id);
return; return;
} }
crostini::CrostiniRegistryService* registry_service =
crostini::CrostiniRegistryServiceFactory::GetForProfile(profile);
std::unique_ptr<crostini::CrostiniRegistryService::Registration> std::unique_ptr<crostini::CrostiniRegistryService::Registration>
registration = registry_service->GetRegistration(app_id); registration = registry_service->GetRegistration(app_id);
if (!registration) { if (!registration) {
...@@ -105,4 +106,5 @@ void LaunchCrostiniApp(Profile* profile, const std::string& app_id) { ...@@ -105,4 +106,5 @@ void LaunchCrostiniApp(Profile* profile, const std::string& app_id) {
profile, registration->vm_name, registration->container_name, profile, registration->vm_name, registration->container_name,
base::BindOnce(&MaybeLaunchContainerAppplication, base::BindOnce(&MaybeLaunchContainerAppplication,
std::move(registration))); std::move(registration)));
registry_service->AppLaunched(app_id);
} }
...@@ -24,12 +24,6 @@ CrostiniAppModelBuilder::~CrostiniAppModelBuilder() { ...@@ -24,12 +24,6 @@ CrostiniAppModelBuilder::~CrostiniAppModelBuilder() {
} }
void CrostiniAppModelBuilder::BuildModel() { void CrostiniAppModelBuilder::BuildModel() {
InsertApp(std::make_unique<CrostiniAppItem>(
profile(), GetSyncItem(kCrostiniTerminalId), kCrostiniTerminalId,
kCrostiniTerminalAppName,
ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_LOGO_CROSTINI_TERMINAL)));
crostini::CrostiniRegistryService* registry_service = crostini::CrostiniRegistryService* registry_service =
crostini::CrostiniRegistryServiceFactory::GetForProfile(profile()); crostini::CrostiniRegistryServiceFactory::GetForProfile(profile());
for (const std::string& app_id : registry_service->GetRegisteredAppIds()) { for (const std::string& app_id : registry_service->GetRegisteredAppIds()) {
...@@ -54,7 +48,8 @@ void CrostiniAppModelBuilder::InsertCrostiniAppItem( ...@@ -54,7 +48,8 @@ void CrostiniAppModelBuilder::InsertCrostiniAppItem(
InsertApp(std::make_unique<CrostiniAppItem>( InsertApp(std::make_unique<CrostiniAppItem>(
profile(), GetSyncItem(app_id), app_id, localized_name, profile(), GetSyncItem(app_id), app_id, localized_name,
ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_LOGO_CROSTINI_DEFAULT))); app_id == kCrostiniTerminalId ? IDR_LOGO_CROSTINI_TERMINAL
: IDR_LOGO_CROSTINI_DEFAULT)));
} }
void CrostiniAppModelBuilder::OnRegistryUpdated( void CrostiniAppModelBuilder::OnRegistryUpdated(
......
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