blob: d3286b16a0347ca3ec00edf67f8ec305257bbf8f [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_ASH_SHELF_CHROME_SHELF_PREFS_H_
#define CHROME_BROWSER_UI_ASH_SHELF_CHROME_SHELF_PREFS_H_
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ash/app_list/app_list_syncable_service.h"
#include "components/services/app_service/public/cpp/app_types.h"
class ShelfControllerHelper;
class PrefService;
class Profile;
namespace ash {
struct ShelfID;
} // namespace ash
namespace user_prefs {
class PrefRegistrySyncable;
} // namespace user_prefs
// This class is responsible for briding between sync/pref-store and the ash
// shelf.
class ChromeShelfPrefs : public app_list::AppListSyncableService::Observer {
public:
explicit ChromeShelfPrefs(Profile* profile);
ChromeShelfPrefs(const ChromeShelfPrefs&) = delete;
ChromeShelfPrefs& operator=(const ChromeShelfPrefs&) = delete;
~ChromeShelfPrefs() override;
// Key for the dictionary entries in the prefs::kPinnedLauncherApps list
// specifying the extension ID of the app to be pinned by that entry.
static const char kPinnedAppsPrefAppIDKey[];
// All prefs must be registered early in the process lifecycle.
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
// Init a local pref from a synced pref, if the local pref has no user
// setting. This is used to init shelf alignment and auto-hide on the first
// user sync. The goal is to apply the last elected shelf alignment and
// auto-hide values when a user signs in to a new device for the first time.
// Otherwise, shelf properties are persisted per-display/device. The local
// prefs are initialized with synced (or default) values when when syncing
// begins, to avoid syncing shelf prefs across devices after the very start of
// the user's first session.
void InitLocalPref(PrefService* prefs, const char* local, const char* synced);
// Gets the ordered list of pinned apps that exist on device from the app sync
// service. This returns apps that are known to the app service with one
// exceptions: app_constants::kChromeAppId (ash-chrome) can be returned and is
// not known to the app service.
std::vector<ash::ShelfID> GetPinnedAppsFromSync(
ShelfControllerHelper* helper);
// Gets the ordered list of apps that have been pinned by policy. May contain
// duplicates.
std::vector<std::string> GetAppsPinnedByPolicy(ShelfControllerHelper* helper);
// Removes information about pin position from sync model for the app.
// Note, |shelf_id| with non-empty launch_id is not supported.
void RemovePinPosition(Profile* profile, const ash::ShelfID& shelf_id);
// Updates information about pin position in sync model for the app
// |shelf_id|. |shelf_id_before| optionally specifies an app that exists right
// before the target app. |shelf_ids_after| optionally specifies sorted by
// position apps that exist right after the target app. Note, |shelf_id| with
// non-empty launch_id is not supported.
void SetPinPosition(const ash::ShelfID& shelf_id,
const ash::ShelfID& shelf_id_before,
const std::vector<ash::ShelfID>& shelf_ids_after);
// Makes GetPinnedAppsFromSync() return an empty list. Avoids test failures
// due to an untitled Play Store icon in the shelf.
// https://crbug.com/1085597
static void SkipPinnedAppsFromSyncForTest();
// Ensure the Files Chrome app pinned positions are appropriately migrated to
// the Files System Web App.
void MigrateFilesChromeAppToSWA(
app_list::AppListSyncableService* syncable_service);
// This is run each time ash launches and each time new data is obtained from
// sync. It ensures that both ash-chrome and lacros-chrome are properly
// pinned or unpinned.
void EnsureChromePinned(app_list::AppListSyncableService* syncable_service);
// Whether the default apps have already been added for this device form
// factor.
bool DidAddDefaultApps(PrefService* pref_service);
// Virtual for testing.
// Whether it's safe to add the default apps. We will refrain from adding the
// default apps if there are policies that modify the pinned apps, or if app
// sync has not yet started.
virtual bool ShouldAddDefaultApps(PrefService* pref_service);
// This migration is run once per device form factor and the result is stored
// in prefs. It is never run again if that pref is present. It causes several
// default apps to be shown in the shelf.
void AddDefaultApps(PrefService* pref_service,
app_list::AppListSyncableService* syncable_service);
// In multi-user login, it's possible for the profile to change during a
// session. This requires resetting all migrations. This method is also called
// shorty after initialization.
void AttachProfile(Profile* profile);
// Sync is the source of truth. However, the data from sync can be
// nonsensical, either because the user nuked all sync data, corruption, or
// otherwise. The purpose of the consistency migrations are two fold:
// (1) To perform what should logically be 1-time migrations.
// (2) In case of data loss or corruption, to bring the user back to a
// safe/consistent state.
// By necessity, all consistency migrations must be idempotent. Otherwise the
// logic will trigger on every call to GetPinnedAppsFromSync().
//
// This method returns whether the consistency migrations need to be run
// again.
bool ShouldPerformConsistencyMigrations() const;
// During Lacros development, there is a period of time when we wish to deploy
// a transparent migration to Lacros, while still allowing users to fall back
// to Ash. This requires us to be very careful about how we store data in
// sync, which will be used by potentially both Lacros and Ash. We use the
// following scheme:
// (1) If the app is either an ash extension platform app or a lacros
// extension platform app, we store the ash extension app id in sync.
// (2) If the app is part of a small keep-list that continues to run in ash,
// we expose the ash extension app id to the shelf.
// (3) If Lacros chrome apps is enabled, we expose the lacros extension app id
// to the shelf.
// (4) If ash chrome apps is enabled, we expose the ash extension app id to
// the shelf.
//
// These methods are public as there are some places that need to translate
// from the ShelfId to SyncId to match up with policy, which uses SyncId.
//
// In order to ensure that the chrome icon in the shelf is consistent across
// devices, we must apply the following rules:
// (1) If ash is the only web-browser, transform [sync id] kChromeAppId <->
// [shelf id] kChromeAppId
// (2) If lacros is the only web-browser, transform [sync id] kChromeAppId <->
// [shelf id] kLacrosAppId
// (3) If lacros and ash are both web browsers, do not use any transformation.
std::string GetShelfId(const std::string& sync_id);
std::string GetSyncId(const std::string& shelf_id);
protected:
// Virtual for testing. Returns the syncable service associated with the
// current profile.
virtual app_list::AppListSyncableService* GetSyncableService();
// Virtual for testing. Returns the pref service associated with the current
// profile.
virtual PrefService* GetPrefs();
// Starts observing the sync service if not already doing so.
virtual void ObserveSyncService();
// Virtual for testing. The migration to use a standalone browser (lacros) to
// publish chrome apps is incomplete. In the interim, this class uses some
// workarounds to ensure that sync does not end up in an inconsistent state.
virtual bool IsStandaloneBrowserPublishingChromeApps();
// Virtual for testing. Returns the app type associated with an app id.
virtual apps::AppType GetAppType(const std::string& app_id);
// Virtual for testing. Returns whether this app_id corresponds to an ash
// extension-based platform app.
virtual bool IsAshExtensionApp(const std::string& app_id);
// Virtual for testing. There's a small set of apps that always run in Ash.
virtual bool IsAshKeepListApp(const std::string& app_id);
private:
// app_list::AppListSyncableService::Observer:
void OnSyncModelUpdated() override;
// Stops observing the current sync service.
void StopObservingSyncService();
// Migrations are performed in several situations:
// (1) On first launch
// (2) Any time there's a sync update
// (3) On profile change.
// In order to prevent an endless cycle of sync updates, all migrations must
// be idempotent.
bool needs_consistency_migrations_ = true;
// The sync service instance that is currently being observed. If nullptr then
// nothing is being observed.
raw_ptr<app_list::AppListSyncableService, ExperimentalAsh>
observed_sync_service_ = nullptr;
// The owner of this class is responsible for ensuring the validity of this
// pointer.
raw_ptr<Profile, ExperimentalAsh> profile_ = nullptr;
};
#endif // CHROME_BROWSER_UI_ASH_SHELF_CHROME_SHELF_PREFS_H_