default_app_order.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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
19namespace chromeos {
20namespace default_app_order {
21
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";
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.
36base::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
57std::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.
84void 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
118ExternalLoader::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
131ExternalLoader::~ExternalLoader() {
132  DCHECK(loaded_.IsSignaled());
133  DCHECK_EQ(loader_instance, this);
134  loader_instance = NULL;
135}
136
137const std::vector<std::string>& ExternalLoader::GetAppIds() {
138  if (!loaded_.IsSignaled())
139    LOG(ERROR) << "GetAppIds() called before loaded.";
140  return app_ids_;
141}
142
143const std::string& ExternalLoader::GetOemAppsFolderName() {
144  if (!loaded_.IsSignaled())
145    LOG(ERROR) << "GetOemAppsFolderName() called before loaded.";
146  return oem_apps_folder_name_;
147}
148
149void 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
181void 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
191std::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