Chromium Code Reviews| 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 791b24f96419f712762339330f2e8525e36dc091..aec6fe89cbf04db47232140441ec1043a4f7a9e7 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 |
| @@ -9,15 +9,19 @@ |
| #include <string> |
| #include <unordered_map> |
| +#include "base/files/file_enumerator.h" |
| #include "base/files/file_util.h" |
| +#include "base/json/json_file_value_serializer.h" |
| #include "base/macros.h" |
| #include "base/metrics/histogram_macros.h" |
| +#include "base/path_service.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/task_runner_util.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h" |
| #include "chrome/browser/ui/app_list/arc/arc_app_utils.h" |
| #include "chrome/browser/ui/app_list/arc/arc_package_syncable_service.h" |
| +#include "chrome/common/chrome_paths.h" |
| #include "chrome/common/pref_names.h" |
| #include "components/arc/arc_bridge_service.h" |
| #include "components/crx_file/id_util.h" |
| @@ -27,26 +31,35 @@ |
| 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 kAppPath[] = "app_path"; |
| 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 kOem[] = "oem"; |
| +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; |
| +// Sub-directory wher Arc apps forward declarations are stored. |
| +const base::FilePath::CharType kArcDefaultDirectory[] = |
| + FILE_PATH_LITERAL("arc"); |
| +const base::FilePath::CharType kArcTestDefaultDirectory[] = |
| + FILE_PATH_LITERAL("arc_default_apps"); |
| + |
| // Provider of write access to a dictionary storing ARC prefs. |
| class ScopedArcPrefUpdate : public DictionaryPrefUpdate { |
| public: |
| @@ -163,38 +176,7 @@ 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()); |
|
khmel
2016/08/25 22:06:08
Moved to class declaration, I have to call class f
xiyuan
2016/08/26 19:32:29
Acknowledged.
|
| - 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); |
| -} |
| +bool use_test_default_apps_directory = false; |
| } // namespace |
| @@ -214,6 +196,11 @@ void ArcAppListPrefs::RegisterProfilePrefs( |
| } |
| // static |
| +void ArcAppListPrefs::UseTestDefaultAppsDirectory() { |
| + use_test_default_apps_directory = true; |
| +} |
| + |
| +// static |
| ArcAppListPrefs* ArcAppListPrefs::Get(content::BrowserContext* context) { |
| return ArcAppListPrefsFactory::GetInstance()->GetForBrowserContext(context); |
| } |
| @@ -225,6 +212,91 @@ std::string ArcAppListPrefs::GetAppId(const std::string& package_name, |
| return crx_file::id_util::GenerateId(input); |
| } |
| +// static |
| +std::unique_ptr<ArcAppListPrefs::DefaultAppInfoMap> |
| +ArcAppListPrefs::ReadDefaultApps() { |
| + DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); |
| + |
| + std::unique_ptr<DefaultAppInfoMap> apps(new DefaultAppInfoMap); |
| + |
| + base::FilePath base_path; |
| + if (!use_test_default_apps_directory) { |
| + if (!base::PathService::Get(chrome::DIR_DEFAULT_APPS, &base_path)) |
| + return apps; |
| + base_path = base_path.Append(kArcDefaultDirectory); |
| + } else { |
| + if (!base::PathService::Get(chrome::DIR_TEST_DATA, &base_path)) |
| + return apps; |
| + base_path = base_path.AppendASCII(kArcTestDefaultDirectory); |
| + } |
| + |
| + base::FilePath::StringType extension(".json"); |
| + base::FileEnumerator json_files( |
| + base_path, |
| + false, // Recursive. |
| + base::FileEnumerator::FILES); |
| + |
| + do { |
| + base::FilePath file = json_files.Next(); |
| + if (file.empty()) |
| + break; |
| + if (file.MatchesExtension(extension)) { |
| + JSONFileValueDeserializer deserializer(file); |
| + std::string error_msg; |
| + std::unique_ptr<base::Value> app_info = |
| + deserializer.Deserialize(nullptr, &error_msg); |
| + if (!app_info) { |
| + VLOG(2) << "Unable to deserialize json data: " << error_msg |
| + << " in file " << file.value() << "."; |
| + continue; |
| + } |
| + |
| + std::unique_ptr<base::DictionaryValue> app_info_dictionary = |
| + base::DictionaryValue::From(std::move(app_info)); |
| + CHECK(app_info_dictionary); |
| + |
| + std::string name; |
| + std::string package_name; |
| + std::string activity; |
| + std::string app_path; |
| + bool oem = false; |
| + |
| + app_info_dictionary->GetString(kName, &name); |
| + app_info_dictionary->GetString(kPackageName, &package_name); |
| + app_info_dictionary->GetString(kActivity, &activity); |
| + app_info_dictionary->GetString(kAppPath, &app_path); |
| + app_info_dictionary->GetBoolean(kOem, &oem); |
| + |
| + if (name.empty() || |
| + package_name.empty() || |
| + activity.empty() || |
| + app_path.empty()) { |
| + VLOG(2) << "Arc app declaration is incomplete in file " |
| + << file.value() << "."; |
| + continue; |
| + } |
| + |
| + const std::string app_id = ArcAppListPrefs::GetAppId( |
| + package_name, activity); |
| + std::unique_ptr<ArcAppListPrefs::DefaultAppInfo> app( |
| + new ArcAppListPrefs::DefaultAppInfo(name, |
| + package_name, |
| + activity, |
| + oem, |
| + base_path.Append(app_path))); |
| + apps.get()->insert( |
| + std::pair<std::string, |
| + std::unique_ptr<ArcAppListPrefs::DefaultAppInfo>>( |
| + app_id, std::move(app))); |
| + } else { |
| + DVLOG(1) << "Not considering: " << file.LossyDisplayName() |
| + << " (does not have a .json extension)"; |
| + } |
| + } while (true); |
| + |
| + return apps; |
| +} |
| + |
| ArcAppListPrefs::ArcAppListPrefs( |
| Profile* profile, |
| arc::InstanceHolder<arc::mojom::AppInstance>* app_instance_holder) |
| @@ -236,6 +308,7 @@ ArcAppListPrefs::ArcAppListPrefs( |
| 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); |
| @@ -243,13 +316,14 @@ 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 ready OnDefaultAppsReady is called. |
| + base::PostTaskAndReplyWithResult( |
| + content::BrowserThread::GetBlockingPool(), FROM_HERE, |
| + base::Bind(&ArcAppListPrefs::ReadDefaultApps), |
| + base::Bind(&ArcAppListPrefs::OnDefaultAppsReady, |
| + weak_ptr_factory_.GetWeakPtr())); |
| } |
| ArcAppListPrefs::~ArcAppListPrefs() { |
| @@ -265,7 +339,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 DefaultAppInfo* default_app = GetDefaultApp(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); |
| } |
| @@ -419,16 +515,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_) { |
| + if (HasDefaultApp(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); |
| + CHECK(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_) { |
| + const std::string& app_id = default_app.first; |
| + const base::DictionaryValue* app = nullptr; |
| + if (HasDefaultApp(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())) |
| @@ -442,13 +558,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 DefaultAppInfo* default_app = GetDefaultApp(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; |
| @@ -497,6 +627,9 @@ std::unique_ptr<ArcAppListPrefs::AppInfo> ArcAppListPrefs::GetApp( |
| } |
| bool ArcAppListPrefs::IsRegistered(const std::string& app_id) const { |
| + if (HasDefaultApp(app_id)) |
| + return true; |
| + |
| if (!IsArcEnabled()) |
| return false; |
| @@ -505,6 +638,11 @@ bool ArcAppListPrefs::IsRegistered(const std::string& app_id) const { |
| return apps && apps->GetDictionaryWithoutPathExpansion(app_id, &app); |
| } |
| +bool ArcAppListPrefs::IsOem(const std::string& app_id) const { |
| + const DefaultAppInfo* app_info = GetDefaultApp(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; |
| @@ -548,6 +686,9 @@ void ArcAppListPrefs::NotifyRegisteredApps() { |
| NOTREACHED(); |
| continue; |
| } |
| + // Default apps are reported earlier. |
| + if (HasDefaultApp(app_id)) |
| + continue; |
| FOR_EACH_OBSERVER(Observer, observer_list_, |
| OnAppRegistered(app_id, *app_info)); |
| } |
| @@ -557,8 +698,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 (!HasDefaultApp(app_id)) |
| + RemoveApp(app_id); |
| + } |
| } |
| void ArcAppListPrefs::OnOptInEnabled(bool enabled) { |
| @@ -568,6 +711,64 @@ void ArcAppListPrefs::OnOptInEnabled(bool enabled) { |
| RemoveAllApps(); |
| } |
| +void ArcAppListPrefs::OnDefaultAppsReady( |
| + std::unique_ptr<DefaultAppInfoMap> apps) { |
| + |
| + default_apps_.swap(*apps.get()); |
| + |
| + // Initially consider packages are installed. |
| + for (const auto& default_app : default_apps_) |
| + default_packages_[default_app.second->package_name] = false; |
| + |
| + // Apply uninstalled packages now. |
| + const std::vector<std::string> uninstalled_package_names = |
| + GetPackagesFromPrefs(false); |
| + for (const auto& uninstalled_package_name : uninstalled_package_names) |
| + MaybeMarkDefaultPackageUninstalled(uninstalled_package_name, true); |
| + |
| + // Report default apps first. |
| + for (const auto& default_app : default_apps_) { |
| + 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_read_ = true; |
| + StartPrefs(); |
| +} |
| + |
| +const ArcAppListPrefs::DefaultAppInfo* ArcAppListPrefs::GetDefaultApp( |
| + const std::string& app_id) const { |
| + const auto it = default_apps_.find(app_id); |
| + if (it == default_apps_.end()) |
| + return nullptr; |
| + // Check if its package was uninstalled. |
| + const auto it_package = default_packages_.find(it->second->package_name); |
| + DCHECK(it_package != default_packages_.end()); |
| + if (it_package->second) |
| + return nullptr; |
| + return it->second.get(); |
| +} |
| + |
| +bool ArcAppListPrefs::HasDefaultApp(const std::string& app_id) const { |
| + return GetDefaultApp(app_id) != nullptr; |
| +} |
| + |
| +bool ArcAppListPrefs::HasDefaultPackage(const std::string& package_name) const { |
| + return default_packages_.count(package_name); |
| +} |
| + |
| +void ArcAppListPrefs::MaybeMarkDefaultPackageUninstalled( |
| + const std::string& package_name, bool uninstalled) { |
| + auto it = default_packages_.find(package_name); |
| + if (it == default_packages_.end()) |
| + return; |
| + it->second = uninstalled; |
| +} |
| + |
| void ArcAppListPrefs::OnInstanceReady() { |
| arc::mojom::AppInstance* app_instance = app_instance_holder_->instance(); |
| if (!app_instance) { |
| @@ -594,9 +795,9 @@ void ArcAppListPrefs::OnInstanceClosed() { |
| } |
| } |
| -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; |
| @@ -619,8 +820,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); |
| @@ -701,13 +902,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)); |
| @@ -716,6 +920,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; |
| + MaybeMarkDefaultPackageUninstalled(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()); |
| + MaybeMarkDefaultPackageUninstalled(package_name, true); |
| + if (!HasDefaultPackage(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()); |
| @@ -740,7 +983,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 (!HasDefaultApp(app_id)) |
| + RemoveApp(app_id); |
| } |
| } |
| @@ -881,7 +1126,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)); |
| } |
| @@ -952,14 +1197,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()); |
| } |
| @@ -1038,6 +1294,19 @@ ArcAppListPrefs::AppInfo::AppInfo(const std::string& name, |
| // Complex class/struct needs an explicit out-of-line destructor |
| ArcAppListPrefs::AppInfo::~AppInfo() {} |
| +ArcAppListPrefs::DefaultAppInfo::DefaultAppInfo(const std::string& name, |
| + const std::string& package_name, |
| + const std::string& activity, |
| + bool oem, |
| + const base::FilePath app_path) |
| + : name(name), |
| + package_name(package_name), |
| + activity(activity), |
| + oem(oem), |
| + app_path(app_path) {} |
| + |
| +ArcAppListPrefs::DefaultAppInfo::~DefaultAppInfo() {} |
| + |
| ArcAppListPrefs::PackageInfo::PackageInfo(const std::string& package_name, |
| int32_t package_version, |
| int64_t last_backup_android_id, |