1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/chromeos/extensions/default_app_order.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/files/file_path.h" 10#include "base/files/file_util.h" 11#include "base/json/json_file_value_serializer.h" 12#include "base/path_service.h" 13#include "base/time/time.h" 14#include "chrome/browser/browser_process.h" 15#include "chrome/common/extensions/extension_constants.h" 16#include "chromeos/chromeos_paths.h" 17#include "content/public/browser/browser_thread.h" 18#include "extensions/common/constants.h" 19 20namespace chromeos { 21namespace default_app_order { 22namespace { 23 24// The single ExternalLoader instance. 25ExternalLoader* loader_instance = NULL; 26 27// Names used in JSON file. 28const char kOemAppsFolderAttr[] = "oem_apps_folder"; 29const char kLocalizedContentAttr[] = "localized_content"; 30const char kDefaultAttr[] = "default"; 31const char kNameAttr[] = "name"; 32const char kImportDefaultOrderAttr[] = "import_default_order"; 33 34const char* kDefaultAppOrder[] = { 35 extension_misc::kChromeAppId, 36 extensions::kWebStoreAppId, 37 extension_misc::kGoogleSearchAppId, 38 extension_misc::kYoutubeAppId, 39 extension_misc::kGmailAppId, 40 "ejjicmeblgpmajnghnpcppodonldlgfn", // Calendar 41 "kjebfhglflhjjjiceimfkgicifkhjlnm", // Scratchpad 42 "lneaknkopdijkpnocmklfnjbeapigfbh", // Google Maps 43 "apdfllckaahabafndbhieahigkjlhalf", // Drive 44 extension_misc::kGoogleDocAppId, 45 extension_misc::kGoogleSheetsAppId, 46 extension_misc::kGoogleSlidesAppId, 47 "dlppkpafhbajpcmmoheippocdidnckmm", // Google+ 48 "kbpgddbgniojgndnhlkjbkpknjhppkbk", // Google+ Hangouts 49 "hhaomjibdihmijegdhdafkllkbggdgoj", // Files 50 extension_misc::kGooglePlayMusicAppId, 51 "mmimngoggfoobjdlefbcabngfnmieonb", // Play Books 52 "gdijeikdkaembjbdobgfkoidjkpbmlkd", // Play Movies & TV 53 "fobcpibfeplaikcclojfdhfdmbbeofai", // Games 54 "joodangkbfjnajiiifokapkpmhfnpleo", // Calculator 55 "hfhhnacclhffhdffklopdkcgdhifgngh", // Camera 56 "gbchcmhmhahfdphkhkmpfmihenigjmpp", // Chrome Remote Desktop 57}; 58 59// Reads external ordinal json file and returned the parsed value. Returns NULL 60// if the file does not exist or could not be parsed properly. Caller takes 61// ownership of the returned value. 62base::ListValue* ReadExternalOrdinalFile(const base::FilePath& path) { 63 if (!base::PathExists(path)) 64 return NULL; 65 66 JSONFileValueSerializer serializer(path); 67 std::string error_msg; 68 base::Value* value = serializer.Deserialize(NULL, &error_msg); 69 if (!value) { 70 LOG(WARNING) << "Unable to deserialize default app ordinals json data:" 71 << error_msg << ", file=" << path.value(); 72 return NULL; 73 } 74 75 base::ListValue* ordinal_list_value = NULL; 76 if (value->GetAsList(&ordinal_list_value)) 77 return ordinal_list_value; 78 79 LOG(WARNING) << "Expect a JSON list in file " << path.value(); 80 return NULL; 81} 82 83std::string GetLocaleSpecificStringImpl( 84 const base::DictionaryValue* root, 85 const std::string& locale, 86 const std::string& dictionary_name, 87 const std::string& entry_name) { 88 const base::DictionaryValue* dictionary_content = NULL; 89 if (!root || !root->GetDictionary(dictionary_name, &dictionary_content)) 90 return std::string(); 91 92 const base::DictionaryValue* locale_dictionary = NULL; 93 if (dictionary_content->GetDictionary(locale, &locale_dictionary)) { 94 std::string result; 95 if (locale_dictionary->GetString(entry_name, &result)) 96 return result; 97 } 98 99 const base::DictionaryValue* default_dictionary = NULL; 100 if (dictionary_content->GetDictionary(kDefaultAttr, &default_dictionary)) { 101 std::string result; 102 if (default_dictionary->GetString(entry_name, &result)) 103 return result; 104 } 105 106 return std::string(); 107} 108 109// Gets built-in default app order. 110void GetDefault(std::vector<std::string>* app_ids) { 111 for (size_t i = 0; i < arraysize(kDefaultAppOrder); ++i) 112 app_ids->push_back(std::string(kDefaultAppOrder[i])); 113} 114 115} // namespace 116 117const size_t kDefaultAppOrderCount = arraysize(kDefaultAppOrder); 118 119ExternalLoader::ExternalLoader(bool async) 120 : loaded_(true /* manual_rest */, false /* initially_signaled */) { 121 DCHECK(!loader_instance); 122 loader_instance = this; 123 124 if (async) { 125 content::BrowserThread::PostBlockingPoolTask(FROM_HERE, 126 base::Bind(&ExternalLoader::Load, base::Unretained(this))); 127 } else { 128 Load(); 129 } 130} 131 132ExternalLoader::~ExternalLoader() { 133 DCHECK(loaded_.IsSignaled()); 134 DCHECK_EQ(loader_instance, this); 135 loader_instance = NULL; 136} 137 138const std::vector<std::string>& ExternalLoader::GetAppIds() { 139 if (!loaded_.IsSignaled()) 140 LOG(ERROR) << "GetAppIds() called before loaded."; 141 return app_ids_; 142} 143 144const std::string& ExternalLoader::GetOemAppsFolderName() { 145 if (!loaded_.IsSignaled()) 146 LOG(ERROR) << "GetOemAppsFolderName() called before loaded."; 147 return oem_apps_folder_name_; 148} 149 150void ExternalLoader::Load() { 151 base::FilePath ordinals_file; 152 CHECK(PathService::Get(chromeos::FILE_DEFAULT_APP_ORDER, &ordinals_file)); 153 154 scoped_ptr<base::ListValue> ordinals_value( 155 ReadExternalOrdinalFile(ordinals_file)); 156 if (ordinals_value) { 157 std::string locale = g_browser_process->GetApplicationLocale(); 158 for (size_t i = 0; i < ordinals_value->GetSize(); ++i) { 159 std::string app_id; 160 base::DictionaryValue* dict = NULL; 161 if (ordinals_value->GetString(i, &app_id)) { 162 app_ids_.push_back(app_id); 163 } else if (ordinals_value->GetDictionary(i, &dict)) { 164 bool flag = false; 165 if (dict->GetBoolean(kOemAppsFolderAttr, &flag) && flag) { 166 oem_apps_folder_name_ = GetLocaleSpecificStringImpl( 167 dict, locale, kLocalizedContentAttr, kNameAttr); 168 } else if (dict->GetBoolean(kImportDefaultOrderAttr, &flag) && flag) { 169 GetDefault(&app_ids_); 170 } else { 171 LOG(ERROR) << "Invalid syntax in default_app_order.json"; 172 } 173 } else { 174 LOG(ERROR) << "Invalid entry in default_app_order.json"; 175 } 176 } 177 } else { 178 GetDefault(&app_ids_); 179 } 180 181 loaded_.Signal(); 182} 183 184void Get(std::vector<std::string>* app_ids) { 185 // |loader_instance| could be NULL for test. 186 if (!loader_instance) { 187 GetDefault(app_ids); 188 return; 189 } 190 191 *app_ids = loader_instance->GetAppIds(); 192} 193 194std::string GetOemAppsFolderName() { 195 // |loader_instance| could be NULL for test. 196 if (!loader_instance) 197 return std::string(); 198 else 199 return loader_instance->GetOemAppsFolderName(); 200} 201 202} // namespace default_app_order 203} // namespace chromeos 204