Index: chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc |
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc |
index aae7f03f610248441ab7d551b853897deaccff90..460d66ceabfab914ee8b9bcb777b41be4a6c0228 100644 |
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc |
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc |
@@ -7,10 +7,8 @@ |
#include <stddef.h> |
#include <string> |
-#include <unordered_map> |
#include "base/files/file_util.h" |
-#include "base/macros.h" |
#include "base/metrics/histogram_macros.h" |
#include "base/strings/string_number_conversions.h" |
#include "base/task_runner_util.h" |
@@ -28,23 +26,24 @@ |
namespace { |
-const char kName[] = "name"; |
-const char kPackageName[] = "package_name"; |
-const char kPackageVersion[] = "package_version"; |
const char kActivity[] = "activity"; |
-const char kShortcut[] = "shortcut"; |
-const char kIntentUri[] = "intent_uri"; |
const char kIconResourceId[] = "icon_resource_id"; |
-const char kSticky[] = "sticky"; |
-const char kNotificationsEnabled[] = "notifications_enabled"; |
+const char kInstallTime[] = "install_time"; |
+const char kIntentUri[] = "intent_uri"; |
const char kLastBackupAndroidId[] = "last_backup_android_id"; |
const char kLastBackupTime[] = "last_backup_time"; |
const char kLastLaunchTime[] = "lastlaunchtime"; |
const char kLaunchable[] = "launchable"; |
+const char kName[] = "name"; |
+const char kNotificationsEnabled[] = "notifications_enabled"; |
+const char kOrientationLock[] = "orientation_lock"; |
+const char kPackageName[] = "package_name"; |
+const char kPackageVersion[] = "package_version"; |
+const char kSticky[] = "sticky"; |
+const char kShortcut[] = "shortcut"; |
const char kShouldSync[] = "should_sync"; |
const char kSystem[] = "system"; |
-const char kOrientationLock[] = "orientation_lock"; |
-const char kInstallTime[] = "install_time"; |
+const char kUninstalled[] = "uninstalled"; |
constexpr int kSetNotificationsEnabledMinVersion = 6; |
@@ -164,39 +163,6 @@ bool GetInt64FromPref(const base::DictionaryValue* dict, |
return true; |
} |
-// Add or update local pref for given package. |
-void AddOrUpdatePackagePrefs(PrefService* prefs, |
- const arc::mojom::ArcPackageInfo& package) { |
- DCHECK(IsArcEnabled()); |
- const std::string& package_name = package.package_name; |
- if (package_name.empty()) { |
- VLOG(2) << "Package name cannot be empty."; |
- return; |
- } |
- ScopedArcPrefUpdate update(prefs, package_name, prefs::kArcPackages); |
- base::DictionaryValue* package_dict = update.Get(); |
- const std::string id_str = |
- base::Int64ToString(package.last_backup_android_id); |
- const std::string time_str = base::Int64ToString(package.last_backup_time); |
- |
- package_dict->SetBoolean(kShouldSync, package.sync); |
- package_dict->SetInteger(kPackageVersion, package.package_version); |
- package_dict->SetString(kLastBackupAndroidId, id_str); |
- package_dict->SetString(kLastBackupTime, time_str); |
- package_dict->SetBoolean(kSystem, package.system); |
-} |
- |
-// Remove given package from local pref. |
-void RemovePackageFromPrefs(PrefService* prefs, |
- const std::string& package_name) { |
- DCHECK(IsArcEnabled()); |
- DictionaryPrefUpdate update(prefs, prefs::kArcPackages); |
- base::DictionaryValue* packages = update.Get(); |
- const bool removed = packages->RemoveWithoutPathExpansion(package_name, |
- nullptr); |
- DCHECK(removed); |
-} |
- |
} // namespace |
// static |
@@ -234,9 +200,11 @@ ArcAppListPrefs::ArcAppListPrefs( |
app_instance_holder_(app_instance_holder), |
sync_service_(nullptr), |
binding_(this), |
+ default_apps_(this), |
weak_ptr_factory_(this) { |
DCHECK(profile); |
DCHECK(app_instance_holder); |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
const base::FilePath& base_path = profile->GetPath(); |
base_path_ = base_path.AppendASCII(prefs::kArcApps); |
@@ -244,13 +212,9 @@ ArcAppListPrefs::ArcAppListPrefs( |
if (!auth_service) |
return; |
- if (auth_service->state() != arc::ArcAuthService::State::NOT_INITIALIZED) |
- OnOptInEnabled(auth_service->IsArcEnabled()); |
- auth_service->AddObserver(this); |
+ DCHECK(arc::ArcAuthService::IsAllowedForProfile(profile)); |
- app_instance_holder_->AddObserver(this); |
- if (!app_instance_holder_->instance()) |
- OnInstanceClosed(); |
+ // Once default apps are ready OnDefaultAppsReady is called. |
} |
ArcAppListPrefs::~ArcAppListPrefs() { |
@@ -266,7 +230,29 @@ ArcAppListPrefs::~ArcAppListPrefs() { |
auth_service->RemoveObserver(this); |
} |
+void ArcAppListPrefs::StartPrefs() { |
+ arc::ArcAuthService* auth_service = arc::ArcAuthService::Get(); |
+ CHECK(auth_service); |
+ |
+ if (auth_service->state() != arc::ArcAuthService::State::NOT_INITIALIZED) |
+ OnOptInEnabled(auth_service->IsArcEnabled()); |
+ auth_service->AddObserver(this); |
+ |
+ app_instance_holder_->AddObserver(this); |
+ if (!app_instance_holder_->instance()) |
+ OnInstanceClosed(); |
+} |
+ |
base::FilePath ArcAppListPrefs::GetAppPath(const std::string& app_id) const { |
+ const ArcDefaultAppList::AppInfo* default_app = default_apps_.GetApp(app_id); |
+ if (default_app) { |
+ const base::DictionaryValue* app = nullptr; |
+ const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps); |
+ // If app is not ready yet, use resources from pre-build. |
+ if (!apps || !apps->GetDictionaryWithoutPathExpansion(app_id, &app)) |
+ return default_app->app_path; |
+ } |
+ |
return base_path_.AppendASCII(app_id); |
} |
@@ -420,16 +406,36 @@ std::unique_ptr<ArcAppListPrefs::PackageInfo> ArcAppListPrefs::GetPackage( |
} |
std::vector<std::string> ArcAppListPrefs::GetAppIds() const { |
- if (!IsArcEnabled()) |
- return std::vector<std::string>(); |
+ if (!IsArcEnabled()) { |
+ // Default Arc apps available before OptIn. |
+ std::vector<std::string> ids; |
+ for (const auto& default_app : default_apps_.app_map()) { |
+ if (default_apps_.HasApp(default_app.first)) |
+ ids.push_back(default_app.first); |
+ } |
+ return ids; |
+ } |
return GetAppIdsNoArcEnabledCheck(); |
} |
std::vector<std::string> ArcAppListPrefs::GetAppIdsNoArcEnabledCheck() const { |
std::vector<std::string> ids; |
- // crx_file::id_util is de-facto utility for id generation. |
const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps); |
+ DCHECK(apps); |
+ |
+ // Include default app ids into the list. In order not to list app twice, |
+ // at first step include default apps that do not exist yet. |
+ for (const auto& default_app : default_apps_.app_map()) { |
+ const std::string& app_id = default_app.first; |
+ const base::DictionaryValue* app = nullptr; |
+ if (default_apps_.HasApp(default_app.first) && |
+ !apps->GetDictionaryWithoutPathExpansion(app_id, &app)) { |
+ ids.push_back(app_id); |
+ } |
+ } |
+ |
+ // crx_file::id_util is de-facto utility for id generation. |
for (base::DictionaryValue::Iterator app_id(*apps); !app_id.IsAtEnd(); |
app_id.Advance()) { |
if (!crx_file::id_util::IdIsValid(app_id.key())) |
@@ -443,13 +449,27 @@ std::vector<std::string> ArcAppListPrefs::GetAppIdsNoArcEnabledCheck() const { |
std::unique_ptr<ArcAppListPrefs::AppInfo> ArcAppListPrefs::GetApp( |
const std::string& app_id) const { |
- if (!IsArcEnabled()) |
+ // Information for default app is available before Arc enabled. |
+ const ArcDefaultAppList::AppInfo* default_app = default_apps_.GetApp(app_id); |
+ if (!IsArcEnabled() && !default_app) |
return std::unique_ptr<AppInfo>(); |
const base::DictionaryValue* app = nullptr; |
const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps); |
- if (!apps || !apps->GetDictionaryWithoutPathExpansion(app_id, &app)) |
+ if (!apps || !apps->GetDictionaryWithoutPathExpansion(app_id, &app)) { |
+ // Default app may not be available at this point so create app info based |
+ // on its forward declaration. |
+ if (default_app) { |
+ return base::MakeUnique<AppInfo>( |
+ default_app->name, default_app->package_name, default_app->activity, |
+ std::string() /* intent_uri */, std::string() /* icon_resource_id */, |
+ base::Time() /* last_launch_time */, base::Time() /* install_time */, |
+ false /* sticky */, false /* notifications_enabled */, |
+ false /* ready */, true /* showInLauncher */, false /* shortcut */, |
+ true /* launchable */, arc::mojom::OrientationLock::NONE); |
+ } |
return std::unique_ptr<AppInfo>(); |
+ } |
std::string name; |
std::string package_name; |
@@ -498,6 +518,9 @@ std::unique_ptr<ArcAppListPrefs::AppInfo> ArcAppListPrefs::GetApp( |
} |
bool ArcAppListPrefs::IsRegistered(const std::string& app_id) const { |
+ if (default_apps_.HasApp(app_id)) |
+ return true; |
+ |
if (!IsArcEnabled()) |
return false; |
@@ -506,6 +529,15 @@ bool ArcAppListPrefs::IsRegistered(const std::string& app_id) const { |
return apps && apps->GetDictionaryWithoutPathExpansion(app_id, &app); |
} |
+bool ArcAppListPrefs::IsDefault(const std::string& app_id) const { |
+ return default_apps_.HasApp(app_id); |
+} |
+ |
+bool ArcAppListPrefs::IsOem(const std::string& app_id) const { |
+ const ArcDefaultAppList::AppInfo* app_info = default_apps_.GetApp(app_id); |
+ return app_info && app_info->oem; |
+} |
+ |
bool ArcAppListPrefs::IsShortcut(const std::string& app_id) const { |
std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = GetApp(app_id); |
return app_info && app_info->shortcut; |
@@ -549,6 +581,9 @@ void ArcAppListPrefs::NotifyRegisteredApps() { |
NOTREACHED(); |
continue; |
} |
+ // Default apps are reported earlier. |
+ if (default_apps_.HasApp(app_id)) |
+ continue; |
FOR_EACH_OBSERVER(Observer, observer_list_, |
OnAppRegistered(app_id, *app_info)); |
} |
@@ -558,8 +593,10 @@ void ArcAppListPrefs::NotifyRegisteredApps() { |
void ArcAppListPrefs::RemoveAllApps() { |
std::vector<std::string> app_ids = GetAppIdsNoArcEnabledCheck(); |
- for (const auto& app_id : app_ids) |
- RemoveApp(app_id); |
+ for (const auto& app_id : app_ids) { |
+ if (!default_apps_.HasApp(app_id)) |
+ RemoveApp(app_id); |
+ } |
} |
void ArcAppListPrefs::OnOptInEnabled(bool enabled) { |
@@ -569,6 +606,38 @@ void ArcAppListPrefs::OnOptInEnabled(bool enabled) { |
RemoveAllApps(); |
} |
+void ArcAppListPrefs::OnDefaultAppsReady() { |
+ // Apply uninstalled packages now. |
+ const std::vector<std::string> uninstalled_package_names = |
+ GetPackagesFromPrefs(false); |
+ for (const auto& uninstalled_package_name : uninstalled_package_names) |
+ default_apps_.MaybeMarkPackageUninstalled(uninstalled_package_name, true); |
+ |
+ // Report default apps first. |
+ for (const auto& default_app : default_apps_.app_map()) { |
+ const std::string& app_id = default_app.first; |
+ std::unique_ptr<AppInfo> app_info = GetApp(app_id); |
+ if (app_info) { |
+ FOR_EACH_OBSERVER(Observer, observer_list_, |
+ OnAppRegistered(app_id, *app_info)); |
+ } |
+ } |
+ |
+ default_apps_ready_ = true; |
+ if (!default_apps_ready_callback_.is_null()) |
+ default_apps_ready_callback_.Run(); |
+ |
+ StartPrefs(); |
+} |
+ |
+void ArcAppListPrefs::SetDefaltAppsReadyCallback(base::Closure callback) { |
+ DCHECK(!callback.is_null()); |
+ DCHECK(default_apps_ready_callback_.is_null()); |
+ default_apps_ready_callback_ = callback; |
+ if (default_apps_ready_) |
+ default_apps_ready_callback_.Run(); |
+} |
+ |
void ArcAppListPrefs::OnInstanceReady() { |
arc::mojom::AppInstance* app_instance = app_instance_holder_->instance(); |
@@ -599,9 +668,9 @@ void ArcAppListPrefs::OnInstanceClosed() { |
is_initialized_ = false; |
} |
-void ArcAppListPrefs::MayAddNonLaunchableApp(const std::string& name, |
- const std::string& package_name, |
- const std::string& activity) { |
+void ArcAppListPrefs::MaybeAddNonLaunchableApp(const std::string& name, |
+ const std::string& package_name, |
+ const std::string& activity) { |
DCHECK(IsArcEnabled()); |
if (IsRegistered(GetAppId(package_name, activity))) |
return; |
@@ -624,8 +693,8 @@ void ArcAppListPrefs::AddAppAndShortcut( |
const bool shortcut, |
const bool launchable, |
const arc::mojom::OrientationLock orientation_lock) { |
- std::string app_id = shortcut ? GetAppId(package_name, intent_uri) |
- : GetAppId(package_name, activity); |
+ const std::string app_id = shortcut ? GetAppId(package_name, intent_uri) |
+ : GetAppId(package_name, activity); |
const bool was_registered = IsRegistered(app_id); |
if (was_registered) { |
std::unique_ptr<ArcAppListPrefs::AppInfo> app_old_info = GetApp(app_id); |
@@ -706,13 +775,16 @@ void ArcAppListPrefs::RemoveApp(const std::string& app_id) { |
// From now, app is not available. |
ready_apps_.erase(app_id); |
+ // app_id may be released by observers, get the path first. It should be done |
+ // before removing prefs entry in order not to mix with pre-build default apps |
+ // files. |
+ const base::FilePath app_path = GetAppPath(app_id); |
+ |
// Remove from prefs. |
DictionaryPrefUpdate update(prefs_, prefs::kArcApps); |
base::DictionaryValue* apps = update.Get(); |
const bool removed = apps->Remove(app_id, nullptr); |
DCHECK(removed); |
- // app_id may be released by observers, get the path first. |
- const base::FilePath app_path = GetAppPath(app_id); |
FOR_EACH_OBSERVER(Observer, observer_list_, OnAppRemoved(app_id)); |
@@ -721,6 +793,45 @@ void ArcAppListPrefs::RemoveApp(const std::string& app_id) { |
FROM_HERE, base::Bind(&DeleteAppFolderFromFileThread, app_path)); |
} |
+void ArcAppListPrefs::AddOrUpdatePackagePrefs( |
+ PrefService* prefs, const arc::mojom::ArcPackageInfo& package) { |
+ DCHECK(IsArcEnabled()); |
+ const std::string& package_name = package.package_name; |
+ default_apps_.MaybeMarkPackageUninstalled(package_name, false); |
+ if (package_name.empty()) { |
+ VLOG(2) << "Package name cannot be empty."; |
+ return; |
+ } |
+ ScopedArcPrefUpdate update(prefs, package_name, prefs::kArcPackages); |
+ base::DictionaryValue* package_dict = update.Get(); |
+ const std::string id_str = |
+ base::Int64ToString(package.last_backup_android_id); |
+ const std::string time_str = base::Int64ToString(package.last_backup_time); |
+ |
+ package_dict->SetBoolean(kShouldSync, package.sync); |
+ package_dict->SetInteger(kPackageVersion, package.package_version); |
+ package_dict->SetString(kLastBackupAndroidId, id_str); |
+ package_dict->SetString(kLastBackupTime, time_str); |
+ package_dict->SetBoolean(kSystem, package.system); |
+} |
+ |
+void ArcAppListPrefs::RemovePackageFromPrefs(PrefService* prefs, |
+ const std::string& package_name) { |
+ DCHECK(IsArcEnabled()); |
+ default_apps_.MaybeMarkPackageUninstalled(package_name, true); |
+ if (!default_apps_.HasPackage(package_name)) { |
+ DictionaryPrefUpdate update(prefs, prefs::kArcPackages); |
+ base::DictionaryValue* packages = update.Get(); |
+ const bool removed = packages->RemoveWithoutPathExpansion(package_name, |
+ nullptr); |
+ DCHECK(removed); |
+ } else { |
+ ScopedArcPrefUpdate update(prefs, package_name, prefs::kArcPackages); |
+ base::DictionaryValue* package_dict = update.Get(); |
+ package_dict->SetBoolean(kUninstalled, true); |
+ } |
+} |
+ |
void ArcAppListPrefs::OnAppListRefreshed( |
mojo::Array<arc::mojom::AppInfoPtr> apps) { |
DCHECK(IsArcEnabled()); |
@@ -745,7 +856,9 @@ void ArcAppListPrefs::OnAppListRefreshed( |
// If this is a shortcut, we just mark it as ready. |
ready_apps_.insert(app_id); |
} else { |
- RemoveApp(app_id); |
+ // Default apps may not be installed yet at this moment. |
+ if (!default_apps_.HasApp(app_id)) |
+ RemoveApp(app_id); |
} |
} |
@@ -886,7 +999,7 @@ void ArcAppListPrefs::OnTaskCreated(int32_t task_id, |
const mojo::String& package_name, |
const mojo::String& activity, |
const mojo::String& name) { |
- MayAddNonLaunchableApp(name, package_name, activity); |
+ MaybeAddNonLaunchableApp(name, package_name, activity); |
FOR_EACH_OBSERVER(Observer, observer_list_, |
OnTaskCreated(task_id, package_name, activity)); |
} |
@@ -996,14 +1109,25 @@ void ArcAppListPrefs::OnPackageListRefreshed( |
} |
std::vector<std::string> ArcAppListPrefs::GetPackagesFromPrefs() const { |
+ return GetPackagesFromPrefs(true); |
+} |
+ |
+std::vector<std::string> ArcAppListPrefs::GetPackagesFromPrefs( |
+ bool installed) const { |
std::vector<std::string> packages; |
- if (!IsArcEnabled()) |
+ if (!IsArcEnabled() && installed) |
return packages; |
const base::DictionaryValue* package_prefs = |
prefs_->GetDictionary(prefs::kArcPackages); |
for (base::DictionaryValue::Iterator package(*package_prefs); |
!package.IsAtEnd(); package.Advance()) { |
+ |
+ bool uninstalled = false; |
+ package_prefs->GetBoolean(kSystem, &uninstalled); |
+ if (installed != !uninstalled) |
+ continue; |
+ |
packages.push_back(package.key()); |
} |