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