blob: 9b0b5460b331ee850f3f4c4ac0ceb9e6a8fb5a00 [file] [log] [blame]
// 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 <set>
#include <string>
#include <vector>
#include "ash/app_list/model/app_list_item.h"
#include "ash/app_list/model/app_list_model.h"
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/accelerators.h"
#include "ash/public/cpp/pagination/pagination_model.h"
#include "ash/public/cpp/shelf_model.h"
#include "ash/public/cpp/test/app_list_test_api.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/ash/login/login_manager_test.h"
#include "chrome/browser/ash/login/test/login_manager_mixin.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/app_list/app_list_client_impl.h"
#include "chrome/browser/ui/app_list/app_list_model_updater.h"
#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
#include "chrome/browser/ui/app_list/chrome_app_list_item.h"
#include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/browser/web_applications/web_app_id_constants.h"
#include "chrome/browser/web_applications/web_app_install_info.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "components/account_id/account_id.h"
#include "components/app_constants/constants.h"
#include "components/session_manager/core/session_manager.h"
#include "components/sync/model/string_ordinal.h"
#include "components/sync/test/model/fake_sync_change_processor.h"
#include "components/sync/test/model/sync_error_factory_mock.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/extension_system.h"
namespace {
constexpr char kOemAppId[] = "emfkafnhnpcmabnnkckkchdilgeoekbo";
// Gets list of item app IDs in order they appear in shelf model. Only items
// contained in `filter` will be included.
std::vector<std::string> GetOrderedShelfItems(
const std::set<std::string>& filter) {
std::vector<std::string> result;
for (const auto& item : ash::ShelfModel::Get()->items()) {
if (base::Contains(filter, item.id.app_id))
result.push_back(item.id.app_id);
}
return result;
}
} // namespace
class OemAppPositionTest : public ash::LoginManagerTest {
public:
OemAppPositionTest() { login_mixin_.AppendRegularUsers(1); }
OemAppPositionTest(const OemAppPositionTest&) = delete;
OemAppPositionTest& operator=(const OemAppPositionTest&) = delete;
~OemAppPositionTest() override = default;
// LoginManagerTest:
bool SetUpUserDataDirectory() override {
// Create test user profile directory and copy extensions and preferences
// from the test data directory to it.
base::FilePath user_data_dir;
base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
const std::string& email =
login_mixin_.users()[0].account_id.GetUserEmail();
const std::string user_id_hash =
ash::ProfileHelper::GetUserIdHashByUserIdForTesting(email);
const base::FilePath user_profile_path = user_data_dir.Append(
ash::ProfileHelper::GetUserProfileDir(user_id_hash));
base::CreateDirectory(user_profile_path);
base::FilePath src_dir;
base::PathService::Get(chrome::DIR_TEST_DATA, &src_dir);
src_dir = src_dir.AppendASCII("extensions").AppendASCII("app_list_oem");
base::CopyFile(src_dir.Append(chrome::kPreferencesFilename),
user_profile_path.Append(chrome::kPreferencesFilename));
base::CopyDirectory(src_dir.AppendASCII("Extensions"), user_profile_path,
true);
return true;
}
ash::LoginManagerMixin login_mixin_{&mixin_host_};
};
class ChromeAppListModelUpdaterTestBase
: public extensions::ExtensionBrowserTest {
public:
explicit ChromeAppListModelUpdaterTestBase(
bool enable_productivity_launcher) {
feature_list_.InitWithFeatureState(ash::features::kProductivityLauncher,
enable_productivity_launcher);
}
~ChromeAppListModelUpdaterTestBase() override = default;
ChromeAppListModelUpdaterTestBase(
const ChromeAppListModelUpdaterTestBase& other) = delete;
ChromeAppListModelUpdaterTestBase& operator=(
const ChromeAppListModelUpdaterTestBase& other) = delete;
protected:
void SetUpOnMainThread() override {
ExtensionBrowserTest::SetUpOnMainThread();
AppListClientImpl* client = AppListClientImpl::GetInstance();
ASSERT_TRUE(client);
client->UpdateProfile();
// Ensure async callbacks are run.
base::RunLoop().RunUntilIdle();
}
void ShowAppList() {
ash::AcceleratorController::Get()->PerformActionIfEnabled(
ash::TOGGLE_APP_LIST_FULLSCREEN, {});
if (ash::features::IsProductivityLauncherEnabled()) {
app_list_test_api_.WaitForBubbleWindow(
/*wait_for_opening_animation=*/false);
}
}
ash::AppListTestApi app_list_test_api_;
private:
base::test::ScopedFeatureList feature_list_;
};
// Parameterized by whether productivity launcher is enabled,
class ChromeAppListModelUpdaterTest
: public ChromeAppListModelUpdaterTestBase,
public ::testing::WithParamInterface<bool> {
public:
ChromeAppListModelUpdaterTest()
: ChromeAppListModelUpdaterTestBase(
/*enable_productivity_launcher=*/GetParam()) {}
~ChromeAppListModelUpdaterTest() override = default;
};
INSTANTIATE_TEST_SUITE_P(ProductivityLauncher,
ChromeAppListModelUpdaterTest,
::testing::Bool());
// Test cases with productivity launcher enabled.
class ChromeAppListModelUpdaterLegacyLauncherTest
: public ChromeAppListModelUpdaterTestBase {
public:
ChromeAppListModelUpdaterLegacyLauncherTest()
: ChromeAppListModelUpdaterTestBase(
/*enable_productivity_launcher=*/false) {}
~ChromeAppListModelUpdaterLegacyLauncherTest() override = default;
};
class ChromeAppListModelUpdaterProductivityLauncherTest
: public ChromeAppListModelUpdaterTestBase {
public:
ChromeAppListModelUpdaterProductivityLauncherTest()
: ChromeAppListModelUpdaterTestBase(
/*enable_productivity_launcher=*/true) {}
};
// Tests that an Oem app and its folder are created with valid positions after
// sign-in.
IN_PROC_BROWSER_TEST_F(OemAppPositionTest, ValidOemAppPosition) {
LoginUser(login_mixin_.users()[0].account_id);
// Ensure apps that are installed upon sign-in are registered with the App
// Service, resolving any pending messages as a result of running async
// callbacks.
Profile* profile = ProfileManager::GetActiveUserProfile();
auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile);
proxy->FlushMojoCallsForTesting();
AppListClientImpl* client = AppListClientImpl::GetInstance();
ASSERT_TRUE(client);
client->UpdateProfile();
AppListModelUpdater* model_updater = test::GetModelUpdater(client);
// Ensure async callbacks are run.
base::RunLoop().RunUntilIdle();
const ChromeAppListItem* oem_app = model_updater->FindItem(kOemAppId);
ASSERT_TRUE(oem_app);
EXPECT_TRUE(oem_app->position().IsValid());
const ChromeAppListItem* oem_folder =
model_updater->FindItem(ash::kOemFolderId);
ASSERT_TRUE(oem_folder);
EXPECT_TRUE(oem_folder->position().IsValid());
}
IN_PROC_BROWSER_TEST_P(ChromeAppListModelUpdaterTest,
GetPositionBeforeFirstItemTest) {
AppListClientImpl* client = AppListClientImpl::GetInstance();
ASSERT_TRUE(client);
AppListModelUpdater* model_updater = test::GetModelUpdater(client);
// Default apps will be present but we add an app to guarantee there will be
// at least 1 app.
const std::string app1_id =
LoadExtension(test_data_dir_.AppendASCII("app1"))->id();
ASSERT_FALSE(app1_id.empty());
// Create the app list view and show the apps grid.
ShowAppList();
std::vector<std::string> top_level_id_list =
app_list_test_api_.GetTopLevelViewIdList();
syncer::StringOrdinal position_before_first_item =
model_updater->GetPositionBeforeFirstItem();
// Check that position is before all items in the list.
for (const auto& id : top_level_id_list) {
ChromeAppListItem* item = model_updater->FindItem(id);
ASSERT_TRUE(position_before_first_item.LessThan(item->position()));
}
// Move app to the front.
app_list_test_api_.MoveItemToPosition(app1_id, 0);
std::vector<std::string> reordered_top_level_id_list =
app_list_test_api_.GetTopLevelViewIdList();
syncer::StringOrdinal new_position_before_first_item =
model_updater->GetPositionBeforeFirstItem();
// Re-check that position is before all items in the list.
for (const auto& id : reordered_top_level_id_list) {
ChromeAppListItem* item = model_updater->FindItem(id);
ASSERT_TRUE(new_position_before_first_item.LessThan(item->position()));
}
}
IN_PROC_BROWSER_TEST_P(ChromeAppListModelUpdaterTest,
PRE_ReorderAppPositionInTopLevelAppList) {
const std::string app1_id =
LoadExtension(test_data_dir_.AppendASCII("app1"))->id();
ASSERT_FALSE(app1_id.empty());
const std::string app2_id =
LoadExtension(test_data_dir_.AppendASCII("app2"))->id();
ASSERT_FALSE(app2_id.empty());
// App3 is the same app as app1 in |test_data_dir_|. Take app4 as the third
// app in this test.
const std::string app3_id =
LoadExtension(test_data_dir_.AppendASCII("app4"))->id();
ASSERT_FALSE(app3_id.empty());
// Create the app list view and show the apps grid.
ShowAppList();
std::vector<std::string> top_level_id_list =
app_list_test_api_.GetTopLevelViewIdList();
size_t top_level_id_list_size = top_level_id_list.size();
// This test ignores the default apps and we don't test the exact
// |top_level_id_list| size here.
ASSERT_GE(top_level_id_list_size, 3u);
if (ash::features::IsProductivityLauncherEnabled()) {
ASSERT_EQ(top_level_id_list[2], app1_id);
ASSERT_EQ(top_level_id_list[1], app2_id);
ASSERT_EQ(top_level_id_list[0], app3_id);
} else {
ASSERT_EQ(top_level_id_list[top_level_id_list_size - 3], app1_id);
ASSERT_EQ(top_level_id_list[top_level_id_list_size - 2], app2_id);
ASSERT_EQ(top_level_id_list[top_level_id_list_size - 1], app3_id);
}
// After the move operation, app3 should be at index 0 and app1 should be at
// index 1. App2 stays at the last position in the item list.
app_list_test_api_.MoveItemToPosition(app1_id, 0);
app_list_test_api_.MoveItemToPosition(app3_id, 0);
std::vector<std::string> reordered_top_level_id_list =
app_list_test_api_.GetTopLevelViewIdList();
EXPECT_EQ(top_level_id_list_size, reordered_top_level_id_list.size());
EXPECT_EQ(reordered_top_level_id_list[0], app3_id);
EXPECT_EQ(reordered_top_level_id_list[1], app1_id);
if (ash::features::IsProductivityLauncherEnabled()) {
EXPECT_EQ(reordered_top_level_id_list[2], app2_id);
} else {
EXPECT_EQ(reordered_top_level_id_list.back(), app2_id);
}
}
// Tests if the app position changed in the top level persist after the system
// restarts.
IN_PROC_BROWSER_TEST_P(ChromeAppListModelUpdaterTest,
ReorderAppPositionInTopLevelAppList) {
// Create the app list view and show the apps grid.
ShowAppList();
const std::string app1_id =
GetExtensionByPath(extension_registry()->enabled_extensions(),
test_data_dir_.AppendASCII("app1"))
->id();
const std::string app2_id =
GetExtensionByPath(extension_registry()->enabled_extensions(),
test_data_dir_.AppendASCII("app2"))
->id();
const std::string app3_id =
GetExtensionByPath(extension_registry()->enabled_extensions(),
test_data_dir_.AppendASCII("app4"))
->id();
std::vector<std::string> reordered_top_level_id_list =
app_list_test_api_.GetTopLevelViewIdList();
// This test ignores the default apps and we don't test the exact
// |reordered_top_level_id_list| size here.
ASSERT_GE(reordered_top_level_id_list.size(), 3u);
EXPECT_EQ(reordered_top_level_id_list[0], app3_id);
EXPECT_EQ(reordered_top_level_id_list[1], app1_id);
if (ash::features::IsProductivityLauncherEnabled()) {
ASSERT_EQ(reordered_top_level_id_list[2], app2_id);
} else {
EXPECT_EQ(reordered_top_level_id_list.back(), app2_id);
}
}
IN_PROC_BROWSER_TEST_P(ChromeAppListModelUpdaterTest,
PRE_ReorderAppPositionInFolder) {
const std::string app1_id =
LoadExtension(test_data_dir_.AppendASCII("app1"))->id();
ASSERT_FALSE(app1_id.empty());
const std::string app2_id =
LoadExtension(test_data_dir_.AppendASCII("app2"))->id();
ASSERT_FALSE(app2_id.empty());
// App3 is the same app as app1 in |test_data_dir_|. Take app4 as the third
// app in this test.
const std::string app3_id =
LoadExtension(test_data_dir_.AppendASCII("app4"))->id();
ASSERT_FALSE(app3_id.empty());
// Create the app list view and show the apps grid.
ShowAppList();
// Create a folder with app1, app2 and app3 in order.
const std::string folder_id =
app_list_test_api_.CreateFolderWithApps({app1_id, app2_id, app3_id});
std::vector<std::string> original_id_list{app1_id, app2_id, app3_id};
ASSERT_EQ(app_list_test_api_.GetAppIdsInFolder(folder_id), original_id_list);
// Change an app position in the folder.
app_list_test_api_.MoveItemToPosition(app1_id, 2);
std::vector<std::string> reordered_id_list{app2_id, app3_id, app1_id};
EXPECT_EQ(app_list_test_api_.GetAppIdsInFolder(folder_id), reordered_id_list);
}
// Tests if the app position changed in a folder persist after the system
// restarts.
IN_PROC_BROWSER_TEST_P(ChromeAppListModelUpdaterTest,
ReorderAppPositionInFolder) {
const std::string app1_id =
GetExtensionByPath(extension_registry()->enabled_extensions(),
test_data_dir_.AppendASCII("app1"))
->id();
const std::string app2_id =
GetExtensionByPath(extension_registry()->enabled_extensions(),
test_data_dir_.AppendASCII("app2"))
->id();
const std::string app3_id =
GetExtensionByPath(extension_registry()->enabled_extensions(),
test_data_dir_.AppendASCII("app4"))
->id();
std::string folder_id = app_list_test_api_.GetFolderId(app1_id);
// Check if the three apps are still in the same folder.
ASSERT_FALSE(folder_id.empty());
ASSERT_EQ(app_list_test_api_.GetFolderId(app2_id), folder_id);
ASSERT_EQ(app_list_test_api_.GetFolderId(app3_id), folder_id);
std::vector<std::string> reordered_id_list{app2_id, app3_id, app1_id};
EXPECT_EQ(app_list_test_api_.GetAppIdsInFolder(folder_id), reordered_id_list);
}
IN_PROC_BROWSER_TEST_P(ChromeAppListModelUpdaterTest,
PRE_UnmergeTwoItemFolder) {
const std::string app1_id =
LoadExtension(test_data_dir_.AppendASCII("app1"))->id();
ASSERT_FALSE(app1_id.empty());
const std::string app2_id =
LoadExtension(test_data_dir_.AppendASCII("app2"))->id();
ASSERT_FALSE(app2_id.empty());
// App3 is the same app as app1 in |test_data_dir_|. Take app4 as the third
// app in this test.
const std::string app3_id =
LoadExtension(test_data_dir_.AppendASCII("app4"))->id();
ASSERT_FALSE(app3_id.empty());
// Create the app list view and show the apps grid.
ShowAppList();
// Create a folder with app1, app2 and app3 in order.
const std::string folder_id =
app_list_test_api_.CreateFolderWithApps({app1_id, app2_id});
ash::AppListModel* model = app_list_test_api_.GetAppListModel();
ash::AppListItem* app1_item = model->FindItem(app1_id);
ASSERT_TRUE(app1_item);
ash::AppListItem* app2_item = model->FindItem(app2_id);
ASSERT_TRUE(app2_item);
ash::AppListItem* app3_item = model->FindItem(app3_id);
ASSERT_TRUE(app3_item);
if (ash::features::IsProductivityLauncherEnabled()) {
model->MoveItemToRootAt(app2_item, app3_item->position().CreateBefore());
} else {
model->MoveItemToRootAt(app2_item, app3_item->position().CreateAfter());
}
// Get last 3 items (the grid may have default items, in addition to the ones
// installed by the test).
std::vector<std::string> top_level_id_list =
app_list_test_api_.GetTopLevelViewIdList();
ASSERT_GT(top_level_id_list.size(), 2u);
if (ash::features::IsProductivityLauncherEnabled()) {
EXPECT_TRUE(base::Contains(top_level_id_list, folder_id));
model->MoveItemToRootAt(app1_item, app2_item->position().CreateBefore());
top_level_id_list = app_list_test_api_.GetTopLevelViewIdList();
EXPECT_FALSE(base::Contains(top_level_id_list, folder_id));
} else {
EXPECT_FALSE(base::Contains(top_level_id_list, folder_id));
}
if (ash::features::IsProductivityLauncherEnabled()) {
std::vector<std::string> leading_items = {
top_level_id_list[0],
top_level_id_list[1],
top_level_id_list[2],
};
EXPECT_EQ(std::vector<std::string>({app1_id, app2_id, app3_id}),
leading_items);
} else {
std::vector<std::string> trailing_items = {
top_level_id_list[top_level_id_list.size() - 3],
top_level_id_list[top_level_id_list.size() - 2],
top_level_id_list[top_level_id_list.size() - 1],
};
EXPECT_EQ(std::vector<std::string>({app1_id, app3_id, app2_id}),
trailing_items);
}
}
IN_PROC_BROWSER_TEST_P(ChromeAppListModelUpdaterTest, UnmergeTwoItemFolder) {
const std::string app1_id =
GetExtensionByPath(extension_registry()->enabled_extensions(),
test_data_dir_.AppendASCII("app1"))
->id();
const std::string app2_id =
GetExtensionByPath(extension_registry()->enabled_extensions(),
test_data_dir_.AppendASCII("app2"))
->id();
const std::string app3_id =
GetExtensionByPath(extension_registry()->enabled_extensions(),
test_data_dir_.AppendASCII("app4"))
->id();
// Create the app list view and show the apps grid.
ShowAppList();
// Get last 3 items (the grid may have default items, in addition to the ones
// installed by the test).
std::vector<std::string> top_level_id_list =
app_list_test_api_.GetTopLevelViewIdList();
ASSERT_GT(top_level_id_list.size(), 2u);
if (ash::features::IsProductivityLauncherEnabled()) {
std::vector<std::string> leading_items = {
top_level_id_list[0],
top_level_id_list[1],
top_level_id_list[2],
};
EXPECT_EQ(std::vector<std::string>({app1_id, app2_id, app3_id}),
leading_items);
} else {
std::vector<std::string> trailing_items = {
top_level_id_list[top_level_id_list.size() - 3],
top_level_id_list[top_level_id_list.size() - 2],
top_level_id_list[top_level_id_list.size() - 1],
};
EXPECT_EQ(std::vector<std::string>({app1_id, app3_id, app2_id}),
trailing_items);
}
}
// Tests that session restart before a default pinned preinstalled app is
// correctly positioned in the app list if the session restarts before the app
// installation completes.
IN_PROC_BROWSER_TEST_P(ChromeAppListModelUpdaterTest,
PRE_SessionRestartDoesntOverrideDefaultAppListPosition) {
// Simluate installation of an app pinned to shelf by default:
// App with web_app::kGmailAppId ID.
auto gmail_info = std::make_unique<WebAppInstallInfo>();
gmail_info->start_url =
GURL("https://mail.google.com/mail/?usp=installed_webapp");
gmail_info->display_mode = blink::mojom::DisplayMode::kMinimalUi;
web_app::test::InstallWebApp(profile(), std::move(gmail_info));
// Flush app service so app installation gets handled.
apps::AppServiceProxyFactory::GetForProfile(profile())
->FlushMojoCallsForTesting();
std::set<std::string> app_filter({app_constants::kChromeAppId,
web_app::kGmailAppId,
web_app::kMessagesAppId});
EXPECT_EQ(std::vector<std::string>(
{app_constants::kChromeAppId, web_app::kGmailAppId}),
GetOrderedShelfItems(app_filter));
}
IN_PROC_BROWSER_TEST_P(ChromeAppListModelUpdaterTest,
SessionRestartDoesntOverrideDefaultAppListPosition) {
app_list::AppListSyncableService* app_list_syncable_service =
app_list::AppListSyncableServiceFactory::GetForProfile(profile());
AppListModelUpdater* app_list_model_updater =
app_list_syncable_service->GetModelUpdater();
app_list_model_updater->SetActive(true);
app_list_syncable_service->MergeDataAndStartSyncing(
syncer::APP_LIST, syncer::SyncDataList(),
std::make_unique<syncer::FakeSyncChangeProcessor>(),
std::make_unique<syncer::SyncErrorFactoryMock>());
// Simluate installation of an app pinned to shelf by default after initial
// sync data is merged: app with web_app::kMessagesAppId ID.
auto messages_info = std::make_unique<WebAppInstallInfo>();
messages_info->start_url = GURL("https://messages.google.com/web/");
messages_info->display_mode = blink::mojom::DisplayMode::kMinimalUi;
web_app::test::InstallWebApp(profile(), std::move(messages_info));
// Flush app service so app installation gets handled.
apps::AppServiceProxyFactory::GetForProfile(profile())
->FlushMojoCallsForTesting();
std::set<std::string> app_filter({app_constants::kChromeAppId,
web_app::kGmailAppId,
web_app::kMessagesAppId});
EXPECT_EQ(
std::vector<std::string>({app_constants::kChromeAppId,
web_app::kGmailAppId, web_app::kMessagesAppId}),
GetOrderedShelfItems(app_filter));
// Verify that order of apps in the app list respects default app ordinals
// (for test apps that have default app list ordinal set).
ShowAppList();
std::vector<std::string> top_level_id_list =
app_list_test_api_.GetTopLevelViewIdList();
std::vector<std::string> filtered_top_level_id_list;
for (const auto& item : top_level_id_list) {
if (base::Contains(app_filter, item))
filtered_top_level_id_list.push_back(item);
}
EXPECT_EQ(
std::vector<std::string>({app_constants::kChromeAppId,
web_app::kGmailAppId, web_app::kMessagesAppId}),
filtered_top_level_id_list);
}
IN_PROC_BROWSER_TEST_F(ChromeAppListModelUpdaterProductivityLauncherTest,
IsNewInstall) {
AppListClientImpl* client = AppListClientImpl::GetInstance();
ASSERT_TRUE(client);
AppListModelUpdater* model_updater = test::GetModelUpdater(client);
ASSERT_TRUE(model_updater);
// The built-in "Web Store" app is not a new install.
ChromeAppListItem* web_store_item =
model_updater->FindItem(extensions::kWebStoreAppId);
ASSERT_TRUE(web_store_item);
EXPECT_FALSE(web_store_item->CloneMetadata()->is_new_install);
// Install 2 apps.
const std::string app1_id =
LoadExtension(test_data_dir_.AppendASCII("app1"))->id();
ASSERT_FALSE(app1_id.empty());
const std::string app2_id =
LoadExtension(test_data_dir_.AppendASCII("app2"))->id();
ASSERT_FALSE(app2_id.empty());
// Both apps are new installs.
ChromeAppListItem* item1 = model_updater->FindItem(app1_id);
ASSERT_TRUE(item1);
EXPECT_TRUE(item1->CloneMetadata()->is_new_install);
ChromeAppListItem* item2 = model_updater->FindItem(app2_id);
ASSERT_TRUE(item2);
EXPECT_TRUE(item2->CloneMetadata()->is_new_install);
// Launch the first app.
item1->Activate(ui::EF_NONE);
// First app is no longer a new install.
EXPECT_FALSE(item1->CloneMetadata()->is_new_install);
// Second app is still a new install.
EXPECT_TRUE(item2->CloneMetadata()->is_new_install);
}
IN_PROC_BROWSER_TEST_F(ChromeAppListModelUpdaterProductivityLauncherTest,
IsNewInstallInFolder) {
AppListClientImpl* client = AppListClientImpl::GetInstance();
ASSERT_TRUE(client);
AppListModelUpdater* model_updater = test::GetModelUpdater(client);
ASSERT_TRUE(model_updater);
// Install 2 apps.
const std::string app1_id =
LoadExtension(test_data_dir_.AppendASCII("app1"))->id();
ASSERT_FALSE(app1_id.empty());
const std::string app2_id =
LoadExtension(test_data_dir_.AppendASCII("app2"))->id();
ASSERT_FALSE(app2_id.empty());
ShowAppList();
// Put the apps in a folder.
const std::string folder_id =
app_list_test_api_.CreateFolderWithApps({app1_id, app2_id});
// Both apps are new installs.
ash::AppListModel* model = app_list_test_api_.GetAppListModel();
ash::AppListItem* app1_item = model->FindItem(app1_id);
ASSERT_TRUE(app1_item);
EXPECT_TRUE(app1_item->is_new_install());
ash::AppListItem* app2_item = model->FindItem(app2_id);
ASSERT_TRUE(app2_item);
EXPECT_TRUE(app2_item->is_new_install());
// The folder is considered a "new install" because it contains an item that
// is a new install.
ash::AppListItem* folder_item = model->FindItem(folder_id);
ASSERT_TRUE(folder_item);
EXPECT_TRUE(folder_item->is_new_install());
// Launching one item clears its new install status, but the folder still
// contains a new install.
model_updater->FindItem(app1_id)->Activate(ui::EF_NONE);
EXPECT_FALSE(app1_item->is_new_install());
EXPECT_TRUE(app2_item->is_new_install());
EXPECT_TRUE(folder_item->is_new_install());
// Launching them other item clears its new install status, and the folder
// no longer contains a new install.
model_updater->FindItem(app2_id)->Activate(ui::EF_NONE);
EXPECT_FALSE(app1_item->is_new_install());
EXPECT_FALSE(app2_item->is_new_install());
EXPECT_FALSE(folder_item->is_new_install());
}
IN_PROC_BROWSER_TEST_F(ChromeAppListModelUpdaterLegacyLauncherTest,
PRE_PersistTrailingUserCreatedPage) {
const std::string app1_id =
LoadExtension(test_data_dir_.AppendASCII("app1"))->id();
ASSERT_FALSE(app1_id.empty());
const std::string app2_id =
LoadExtension(test_data_dir_.AppendASCII("app2"))->id();
ASSERT_FALSE(app2_id.empty());
// Create the app list view and show the apps grid.
ash::AcceleratorController::Get()->PerformActionIfEnabled(
ash::TOGGLE_APP_LIST_FULLSCREEN, {});
ASSERT_EQ(1, app_list_test_api_.GetPaginationModel()->total_pages());
app_list_test_api_.GetLastItemInAppsGridView()->RequestFocus();
ASSERT_TRUE(ui_test_utils::SendKeyPressToWindowSync(
nullptr, ui::VKEY_DOWN, /*control=*/true, /*shift=*/false,
/*alt=*/false, /*command=*/false));
EXPECT_EQ(2, app_list_test_api_.GetPaginationModel()->total_pages());
}
IN_PROC_BROWSER_TEST_F(ChromeAppListModelUpdaterLegacyLauncherTest,
PersistTrailingUserCreatedPage) {
const std::string app1_id =
LoadExtension(test_data_dir_.AppendASCII("app1"))->id();
ASSERT_FALSE(app1_id.empty());
const std::string app2_id =
LoadExtension(test_data_dir_.AppendASCII("app2"))->id();
ASSERT_FALSE(app2_id.empty());
// Verify that the app list still has 2 pages after session restart.
ash::AcceleratorController::Get()->PerformActionIfEnabled(
ash::TOGGLE_APP_LIST_FULLSCREEN, {});
EXPECT_EQ(2, app_list_test_api_.GetPaginationModel()->total_pages());
}