12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/app_mode/kiosk_app_data.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <vector>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/file_util.h"
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/json/json_writer.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/ref_counted_memory.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/browser_process.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/app_mode/kiosk_app_data_delegate.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
2081843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
2181843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
2281843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)#include "chrome/browser/extensions/image_loader.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/webstore_data_fetcher.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/webstore_install_helper.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/image_decoder.h"
2681843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
2881843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest.h"
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest_constants.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/codec/png_codec.h"
3381843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)#include "ui/gfx/image/image.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Keys for local state data. See sample layout in KioskAppManager.
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kKeyName[] = "name";
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kKeyIcon[] = "icon";
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Web store data keys.
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kManifestKey[] = "manifest";
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kIconUrlKey[] = "icon_url";
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kLocalizedNameKey[] = "localized_name";
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Icon file extension.
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kIconFileExtension[] = ".png";
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Save |raw_icon| for given |app_id|.
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SaveIconToLocalOnBlockingPool(
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& icon_path,
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<base::RefCountedString> raw_icon) {
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath dir = icon_path.DirName();
627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::PathExists(dir))
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    CHECK(base::CreateDirectory(dir));
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK_EQ(static_cast<int>(raw_icon->size()),
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           file_util::WriteFile(icon_path,
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                raw_icon->data().c_str(), raw_icon->size()));
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns true for valid kiosk app manifest.
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool IsValidKioskAppManifest(const extensions::Manifest& manifest) {
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool kiosk_enabled;
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (manifest.GetBoolean(extensions::manifest_keys::kKioskEnabled,
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &kiosk_enabled)) {
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return kiosk_enabled;
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return false;
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string ValueToString(const base::Value* value) {
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string json;
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::JSONWriter::Write(value, &json);
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return json;
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// KioskAppData::IconLoader
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Loads locally stored icon data and decode it.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class KioskAppData::IconLoader : public ImageDecoder::Delegate {
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enum LoadResult {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SUCCESS,
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FAILED_TO_LOAD,
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FAILED_TO_DECODE,
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  IconLoader(const base::WeakPtr<KioskAppData>& client,
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             const base::FilePath& icon_path)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : client_(client),
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        icon_path_(icon_path),
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        load_result_(SUCCESS) {}
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Start() {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::SequencedWorkerPool::SequenceToken token = pool->GetSequenceToken();
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior(
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        token,
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    task_runner_->PostTask(FROM_HERE,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           base::Bind(&IconLoader::LoadOnBlockingPool,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      base::Unretained(this)));
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  friend class base::RefCountedThreadSafe<IconLoader>;
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~IconLoader() {}
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Loads the icon from locally stored |icon_path_| on the blocking pool
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void LoadOnBlockingPool() {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(task_runner_->RunsTasksOnCurrentThread());
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string data;
12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!base::ReadFileToString(base::FilePath(icon_path_), &data)) {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ReportResultOnBlockingPool(FAILED_TO_LOAD);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    raw_icon_ = base::RefCountedString::TakeString(&data);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<ImageDecoder> image_decoder = new ImageDecoder(
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        this, raw_icon_->data(), ImageDecoder::DEFAULT_CODEC);
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    image_decoder->Start(task_runner_);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void ReportResultOnBlockingPool(LoadResult result) {
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(task_runner_->RunsTasksOnCurrentThread());
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    load_result_ = result;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&IconLoader::ReportResultOnUIThread,
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Unretained(this)));
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void NotifyClient() {
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!client_)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (load_result_ == SUCCESS)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client_->OnIconLoadSuccess(raw_icon_, icon_);
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client_->OnIconLoadFailure();
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void ReportResultOnUIThread() {
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotifyClient();
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete this;
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ImageDecoder::Delegate overrides:
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnImageDecoded(const ImageDecoder* decoder,
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              const SkBitmap& decoded_image) OVERRIDE {
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_.MakeThreadSafe();
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportResultOnBlockingPool(SUCCESS);
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnDecodeImageFailed(const ImageDecoder* decoder) OVERRIDE {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportResultOnBlockingPool(FAILED_TO_DECODE);
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WeakPtr<KioskAppData> client_;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath icon_path_;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadResult load_result_;
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::SequencedTaskRunner> task_runner_;
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::ImageSkia icon_;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::RefCountedString> raw_icon_;
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(IconLoader);
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// KioskAppData::WebstoreDataParser
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use WebstoreInstallHelper to parse the manifest and decode the icon.
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class KioskAppData::WebstoreDataParser
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public extensions::WebstoreInstallHelper::Delegate {
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit WebstoreDataParser(const base::WeakPtr<KioskAppData>& client)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : client_(client) {}
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Start(const std::string& app_id,
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             const std::string& manifest,
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             const GURL& icon_url,
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             net::URLRequestContextGetter* context_getter) {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<extensions::WebstoreInstallHelper> webstore_helper =
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new extensions::WebstoreInstallHelper(this,
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              app_id,
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              manifest,
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              "",  // No icon data.
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              icon_url,
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              context_getter);
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    webstore_helper->Start();
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  friend class base::RefCounted<WebstoreDataParser>;
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~WebstoreDataParser() {}
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void ReportFailure() {
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (client_)
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      client_->OnWebstoreParseFailure();
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delete this;
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // WebstoreInstallHelper::Delegate overrides:
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnWebstoreParseSuccess(
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& id,
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const SkBitmap& icon,
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* parsed_manifest) OVERRIDE {
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Takes ownership of |parsed_manifest|.
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    extensions::Manifest manifest(
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        extensions::Manifest::INVALID_LOCATION,
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        scoped_ptr<base::DictionaryValue>(parsed_manifest));
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!IsValidKioskAppManifest(manifest)) {
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReportFailure();
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (client_)
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      client_->OnWebstoreParseSuccess(icon);
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete this;
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnWebstoreParseFailure(
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& id,
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      InstallHelperResultCode result_code,
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& error_message) OVERRIDE {
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ReportFailure();
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WeakPtr<KioskAppData> client_;
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(WebstoreDataParser);
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// KioskAppData
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)KioskAppData::KioskAppData(KioskAppDataDelegate* delegate,
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           const std::string& app_id,
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           const std::string& user_id)
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : delegate_(delegate),
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      status_(STATUS_INIT),
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      app_id_(app_id),
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      user_id_(user_id) {
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)KioskAppData::~KioskAppData() {}
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::Load() {
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStatus(STATUS_LOADING);
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (LoadFromCache())
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StartFetch();
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::ClearCache() {
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryPrefUpdate dict_update(local_state,
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   KioskAppManager::kKioskDictionaryName);
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string app_key = std::string(KioskAppManager::kKeyApps) + '.' + app_id_;
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict_update->Remove(app_key, NULL);
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!icon_path_.empty()) {
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostBlockingPoolTask(
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
2937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        base::Bind(base::IgnoreResult(&base::DeleteFile), icon_path_, false));
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29781843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)void KioskAppData::LoadFromInstalledApp(Profile* profile,
29881843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)                                        const extensions::Extension* app) {
29981843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  SetStatus(STATUS_LOADING);
30081843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)
30181843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  if (!app) {
30281843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)    app = extensions::ExtensionSystem::Get(profile)
30381843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)              ->extension_service()
30481843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)              ->GetInstalledExtension(app_id_);
30581843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  }
30681843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)
30781843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  DCHECK_EQ(app_id_, app->id());
30881843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)
30981843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  name_ = app->name();
31081843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)
31181843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  const int kIconSize = extension_misc::EXTENSION_ICON_LARGE;
31281843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
31381843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)      app, kIconSize, ExtensionIconSet::MATCH_BIGGER);
31481843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  extensions::ImageLoader::Get(profile)->LoadImageAsync(
31581843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)      app, image, gfx::Size(kIconSize, kIconSize),
31681843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)      base::Bind(&KioskAppData::OnExtensionIconLoaded, AsWeakPtr()));
31781843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)}
31881843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool KioskAppData::IsLoading() const {
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return status_ == STATUS_LOADING;
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::SetStatus(Status status) {
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status_ == status)
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  status_ = status;
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!delegate_)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (status_) {
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATUS_INIT:
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATUS_LOADING:
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATUS_LOADED:
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      delegate_->OnKioskAppDataChanged(app_id_);
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATUS_ERROR:
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      delegate_->OnKioskAppDataLoadFailure(app_id_);
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)net::URLRequestContextGetter* KioskAppData::GetRequestContextGetter() {
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return g_browser_process->system_request_context();
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool KioskAppData::LoadFromCache() {
35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string app_key = std::string(KioskAppManager::kKeyApps) + '.' + app_id_;
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string name_key = app_key + '.' + kKeyName;
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string icon_path_key = app_key + '.' + kKeyIcon;
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::DictionaryValue* dict =
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      local_state->GetDictionary(KioskAppManager::kKioskDictionaryName);
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_path_.clear();
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string icon_path_string;
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!dict->GetString(name_key, &name_) ||
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !dict->GetString(icon_path_key, &icon_path_string)) {
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_path_ = base::FilePath(icon_path_string);
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // IconLoader deletes itself when done.
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  (new IconLoader(AsWeakPtr(), icon_path_))->Start();
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::SetCache(const std::string& name,
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            const base::FilePath& icon_path) {
37390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string app_key = std::string(KioskAppManager::kKeyApps) + '.' + app_id_;
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string name_key = app_key + '.' + kKeyName;
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string icon_path_key = app_key + '.' + kKeyIcon;
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryPrefUpdate dict_update(local_state,
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   KioskAppManager::kKioskDictionaryName);
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict_update->SetString(name_key, name);
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict_update->SetString(icon_path_key, icon_path.value());
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_path_ = icon_path;
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
38581843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)void KioskAppData::SetCache(const std::string& name, const SkBitmap& icon) {
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_ = gfx::ImageSkia::CreateFrom1xBitmap(icon);
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_.MakeThreadSafe();
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<unsigned char> image_data;
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(gfx::PNGCodec::EncodeBGRASkBitmap(icon, false, &image_data));
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  raw_icon_ = new base::RefCountedString;
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  raw_icon_->data().assign(image_data.begin(), image_data.end());
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath cache_dir;
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (delegate_)
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delegate_->GetKioskAppIconCacheDir(&cache_dir);
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath icon_path =
39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      cache_dir.AppendASCII(app_id_).AddExtension(kIconFileExtension);
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::GetBlockingPool()->PostTask(
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SaveIconToLocalOnBlockingPool, icon_path, raw_icon_));
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
40481843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  SetCache(name, icon_path);
40581843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)}
40681843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)
40781843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)void KioskAppData::OnExtensionIconLoaded(const gfx::Image& icon) {
40881843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  if (icon.IsEmpty()) {
40981843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)    LOG(WARNING) << "Failed to load icon from installed app"
41081843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)                 << ", id=" << app_id_;
41181843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)    SetCache(name_, *extensions::IconsInfo::GetDefaultAppIcon().bitmap());
41281843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  } else {
41381843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)    SetCache(name_, icon.AsBitmap());
41481843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  }
41581843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)
41681843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  SetStatus(STATUS_LOADED);
41781843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)}
41881843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)
41981843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)void KioskAppData::OnIconLoadSuccess(
42081843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)    const scoped_refptr<base::RefCountedString>& raw_icon,
42181843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)    const gfx::ImageSkia& icon) {
42281843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
42381843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  raw_icon_ = raw_icon;
42481843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  icon_ = icon;
42581843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  SetStatus(STATUS_LOADED);
42681843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)}
42781843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)
42881843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)void KioskAppData::OnIconLoadFailure() {
42981843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  // Re-fetch data from web store when failed to load cached data.
43081843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  StartFetch();
43181843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)}
43281843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)
43381843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)void KioskAppData::OnWebstoreParseSuccess(const SkBitmap& icon) {
43481843c7b1423e241009db79d34acf2450330fcc5Torne (Richard Coles)  SetCache(name_, icon);
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStatus(STATUS_LOADED);
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::OnWebstoreParseFailure() {
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStatus(STATUS_ERROR);
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::StartFetch() {
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  webstore_fetcher_.reset(new extensions::WebstoreDataFetcher(
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this,
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetRequestContextGetter(),
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GURL(),
44790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      app_id_));
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  webstore_fetcher_->Start();
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::OnWebstoreRequestFailure() {
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStatus(STATUS_ERROR);
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::OnWebstoreResponseParseSuccess(
456f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      scoped_ptr<base::DictionaryValue> webstore_data) {
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Takes ownership of |webstore_data|.
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  webstore_fetcher_.reset();
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string manifest;
461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!CheckResponseKeyValue(webstore_data.get(), kManifestKey, &manifest))
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
464f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!CheckResponseKeyValue(webstore_data.get(), kLocalizedNameKey, &name_))
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string icon_url_string;
468f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!CheckResponseKeyValue(webstore_data.get(), kIconUrlKey,
469f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                             &icon_url_string))
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
47158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GURL icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      icon_url_string);
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!icon_url.is_valid()) {
47558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    LOG(ERROR) << "Webstore response error (icon url): "
476f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)               << ValueToString(webstore_data.get());
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OnWebstoreResponseParseFailure(kInvalidWebstoreResponseError);
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // WebstoreDataParser deletes itself when done.
48290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  (new WebstoreDataParser(AsWeakPtr()))->Start(app_id_,
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               manifest,
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               icon_url,
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               GetRequestContextGetter());
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::OnWebstoreResponseParseFailure(const std::string& error) {
48958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  LOG(ERROR) << "Webstore failed for kiosk app " << app_id_
49058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)             << ", " << error;
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  webstore_fetcher_.reset();
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStatus(STATUS_ERROR);
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
49558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool KioskAppData::CheckResponseKeyValue(const base::DictionaryValue* response,
49658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                         const char* key,
49758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                         std::string* value) {
49858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!response->GetString(key, value)) {
49958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    LOG(ERROR) << "Webstore response error (" << key
50058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)               << "): " << ValueToString(response);
50158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    OnWebstoreResponseParseFailure(kInvalidWebstoreResponseError);
50258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
50358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
50458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
50558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
50658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chromeos
508