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"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/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"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/extensions/extension_util.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/webstore_data_fetcher.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/webstore_install_helper.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/image_decoder.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/browser/image_loader.h"
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/constants.h"
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/extension_urls.h"
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest.h"
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest_constants.h"
33c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/manifest_handlers/icons_handler.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/codec/png_codec.h"
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/image/image.h"
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Keys for local state data. See sample layout in KioskAppManager.
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kKeyName[] = "name";
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kKeyIcon[] = "icon";
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Icon file extension.
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kIconFileExtension[] = ".png";
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Save |raw_icon| for given |app_id|.
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SaveIconToLocalOnBlockingPool(
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& icon_path,
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<base::RefCountedString> raw_icon) {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath dir = icon_path.DirName();
597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::PathExists(dir))
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    CHECK(base::CreateDirectory(dir));
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK_EQ(static_cast<int>(raw_icon->size()),
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)           base::WriteFile(icon_path,
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           raw_icon->data().c_str(), raw_icon->size()));
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns true for valid kiosk app manifest.
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool IsValidKioskAppManifest(const extensions::Manifest& manifest) {
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool kiosk_enabled;
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (manifest.GetBoolean(extensions::manifest_keys::kKioskEnabled,
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          &kiosk_enabled)) {
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return kiosk_enabled;
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return false;
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string ValueToString(const base::Value* value) {
7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::string json;
8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  base::JSONWriter::Write(value, &json);
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return json;
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// KioskAppData::IconLoader
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Loads locally stored icon data and decode it.
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class KioskAppData::IconLoader : public ImageDecoder::Delegate {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enum LoadResult {
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SUCCESS,
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FAILED_TO_LOAD,
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    FAILED_TO_DECODE,
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  IconLoader(const base::WeakPtr<KioskAppData>& client,
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             const base::FilePath& icon_path)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : client_(client),
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        icon_path_(icon_path),
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        load_result_(SUCCESS) {}
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Start() {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::SequencedWorkerPool::SequenceToken token = pool->GetSequenceToken();
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior(
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        token,
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    task_runner_->PostTask(FROM_HERE,
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           base::Bind(&IconLoader::LoadOnBlockingPool,
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      base::Unretained(this)));
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  friend class base::RefCountedThreadSafe<IconLoader>;
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~IconLoader() {}
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Loads the icon from locally stored |icon_path_| on the blocking pool
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void LoadOnBlockingPool() {
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(task_runner_->RunsTasksOnCurrentThread());
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string data;
12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!base::ReadFileToString(base::FilePath(icon_path_), &data)) {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ReportResultOnBlockingPool(FAILED_TO_LOAD);
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    raw_icon_ = base::RefCountedString::TakeString(&data);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<ImageDecoder> image_decoder = new ImageDecoder(
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        this, raw_icon_->data(), ImageDecoder::DEFAULT_CODEC);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    image_decoder->Start(task_runner_);
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void ReportResultOnBlockingPool(LoadResult result) {
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(task_runner_->RunsTasksOnCurrentThread());
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    load_result_ = result;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI,
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&IconLoader::ReportResultOnUIThread,
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Unretained(this)));
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void NotifyClient() {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!client_)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (load_result_ == SUCCESS)
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client_->OnIconLoadSuccess(raw_icon_, icon_);
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client_->OnIconLoadFailure();
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void ReportResultOnUIThread() {
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotifyClient();
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete this;
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ImageDecoder::Delegate overrides:
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnImageDecoded(const ImageDecoder* decoder,
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              const SkBitmap& decoded_image) OVERRIDE {
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    icon_.MakeThreadSafe();
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportResultOnBlockingPool(SUCCESS);
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnDecodeImageFailed(const ImageDecoder* decoder) OVERRIDE {
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReportResultOnBlockingPool(FAILED_TO_DECODE);
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WeakPtr<KioskAppData> client_;
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath icon_path_;
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadResult load_result_;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::SequencedTaskRunner> task_runner_;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::ImageSkia icon_;
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<base::RefCountedString> raw_icon_;
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(IconLoader);
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// KioskAppData::WebstoreDataParser
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use WebstoreInstallHelper to parse the manifest and decode the icon.
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class KioskAppData::WebstoreDataParser
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : public extensions::WebstoreInstallHelper::Delegate {
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  explicit WebstoreDataParser(const base::WeakPtr<KioskAppData>& client)
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : client_(client) {}
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Start(const std::string& app_id,
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             const std::string& manifest,
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             const GURL& icon_url,
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             net::URLRequestContextGetter* context_getter) {
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_refptr<extensions::WebstoreInstallHelper> webstore_helper =
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        new extensions::WebstoreInstallHelper(this,
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              app_id,
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              manifest,
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              "",  // No icon data.
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              icon_url,
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              context_getter);
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    webstore_helper->Start();
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  friend class base::RefCounted<WebstoreDataParser>;
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~WebstoreDataParser() {}
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void ReportFailure() {
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (client_)
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      client_->OnWebstoreParseFailure();
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delete this;
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // WebstoreInstallHelper::Delegate overrides:
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnWebstoreParseSuccess(
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& id,
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const SkBitmap& icon,
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::DictionaryValue* parsed_manifest) OVERRIDE {
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Takes ownership of |parsed_manifest|.
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    extensions::Manifest manifest(
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        extensions::Manifest::INVALID_LOCATION,
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        scoped_ptr<base::DictionaryValue>(parsed_manifest));
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!IsValidKioskAppManifest(manifest)) {
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReportFailure();
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (client_)
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      client_->OnWebstoreParseSuccess(icon);
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete this;
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void OnWebstoreParseFailure(
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& id,
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      InstallHelperResultCode result_code,
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::string& error_message) OVERRIDE {
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ReportFailure();
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::WeakPtr<KioskAppData> client_;
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(WebstoreDataParser);
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)////////////////////////////////////////////////////////////////////////////////
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// KioskAppData
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)KioskAppData::KioskAppData(KioskAppDataDelegate* delegate,
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           const std::string& app_id,
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                           const std::string& user_id)
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : delegate_(delegate),
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      status_(STATUS_INIT),
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      app_id_(app_id),
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      user_id_(user_id) {
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)KioskAppData::~KioskAppData() {}
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::Load() {
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStatus(STATUS_LOADING);
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (LoadFromCache())
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StartFetch();
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::ClearCache() {
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryPrefUpdate dict_update(local_state,
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   KioskAppManager::kKioskDictionaryName);
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string app_key = std::string(KioskAppManager::kKeyApps) + '.' + app_id_;
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict_update->Remove(app_key, NULL);
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!icon_path_.empty()) {
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostBlockingPoolTask(
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
2907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        base::Bind(base::IgnoreResult(&base::DeleteFile), icon_path_, false));
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void KioskAppData::LoadFromInstalledApp(Profile* profile,
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                        const extensions::Extension* app) {
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetStatus(STATUS_LOADING);
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!app) {
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    app = extensions::ExtensionSystem::Get(profile)
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              ->extension_service()
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              ->GetInstalledExtension(app_id_);
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(app_id_, app->id());
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  name_ = app->name();
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const int kIconSize = extension_misc::EXTENSION_ICON_LARGE;
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource(
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app, kIconSize, ExtensionIconSet::MATCH_BIGGER);
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  extensions::ImageLoader::Get(profile)->LoadImageAsync(
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app, image, gfx::Size(kIconSize, kIconSize),
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&KioskAppData::OnExtensionIconLoaded, AsWeakPtr()));
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool KioskAppData::IsLoading() const {
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return status_ == STATUS_LOADING;
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::SetStatus(Status status) {
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (status_ == status)
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  status_ = status;
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!delegate_)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (status_) {
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATUS_INIT:
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATUS_LOADING:
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATUS_LOADED:
33490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      delegate_->OnKioskAppDataChanged(app_id_);
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATUS_ERROR:
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      delegate_->OnKioskAppDataLoadFailure(app_id_);
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)net::URLRequestContextGetter* KioskAppData::GetRequestContextGetter() {
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return g_browser_process->system_request_context();
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool KioskAppData::LoadFromCache() {
34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string app_key = std::string(KioskAppManager::kKeyApps) + '.' + app_id_;
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string name_key = app_key + '.' + kKeyName;
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string icon_path_key = app_key + '.' + kKeyIcon;
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::DictionaryValue* dict =
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      local_state->GetDictionary(KioskAppManager::kKioskDictionaryName);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_path_.clear();
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string icon_path_string;
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!dict->GetString(name_key, &name_) ||
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !dict->GetString(icon_path_key, &icon_path_string)) {
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_path_ = base::FilePath(icon_path_string);
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // IconLoader deletes itself when done.
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  (new IconLoader(AsWeakPtr(), icon_path_))->Start();
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::SetCache(const std::string& name,
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            const base::FilePath& icon_path) {
37090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string app_key = std::string(KioskAppManager::kKeyApps) + '.' + app_id_;
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string name_key = app_key + '.' + kKeyName;
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string icon_path_key = app_key + '.' + kKeyIcon;
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DictionaryPrefUpdate dict_update(local_state,
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   KioskAppManager::kKioskDictionaryName);
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict_update->SetString(name_key, name);
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dict_update->SetString(icon_path_key, icon_path.value());
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_path_ = icon_path;
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void KioskAppData::SetCache(const std::string& name, const SkBitmap& icon) {
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_ = gfx::ImageSkia::CreateFrom1xBitmap(icon);
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  icon_.MakeThreadSafe();
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<unsigned char> image_data;
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CHECK(gfx::PNGCodec::EncodeBGRASkBitmap(icon, false, &image_data));
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  raw_icon_ = new base::RefCountedString;
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  raw_icon_->data().assign(image_data.begin(), image_data.end());
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath cache_dir;
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (delegate_)
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delegate_->GetKioskAppIconCacheDir(&cache_dir);
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath icon_path =
39690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      cache_dir.AppendASCII(app_id_).AddExtension(kIconFileExtension);
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::GetBlockingPool()->PostTask(
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SaveIconToLocalOnBlockingPool, icon_path, raw_icon_));
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetCache(name, icon_path);
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void KioskAppData::OnExtensionIconLoaded(const gfx::Image& icon) {
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (icon.IsEmpty()) {
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(WARNING) << "Failed to load icon from installed app"
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << ", id=" << app_id_;
4085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    SetCache(name_, *extensions::util::GetDefaultAppIcon().bitmap());
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else {
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetCache(name_, icon.AsBitmap());
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetStatus(STATUS_LOADED);
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void KioskAppData::OnIconLoadSuccess(
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const scoped_refptr<base::RefCountedString>& raw_icon,
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const gfx::ImageSkia& icon) {
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  raw_icon_ = raw_icon;
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  icon_ = icon;
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetStatus(STATUS_LOADED);
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void KioskAppData::OnIconLoadFailure() {
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Re-fetch data from web store when failed to load cached data.
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  StartFetch();
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void KioskAppData::OnWebstoreParseSuccess(const SkBitmap& icon) {
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetCache(name_, icon);
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStatus(STATUS_LOADED);
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::OnWebstoreParseFailure() {
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStatus(STATUS_ERROR);
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::StartFetch() {
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  webstore_fetcher_.reset(new extensions::WebstoreDataFetcher(
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this,
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetRequestContextGetter(),
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GURL(),
44490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      app_id_));
445116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  webstore_fetcher_->set_max_auto_retries(3);
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  webstore_fetcher_->Start();
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::OnWebstoreRequestFailure() {
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStatus(STATUS_ERROR);
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::OnWebstoreResponseParseSuccess(
454f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      scoped_ptr<base::DictionaryValue> webstore_data) {
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Takes ownership of |webstore_data|.
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  webstore_fetcher_.reset();
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string manifest;
459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!CheckResponseKeyValue(webstore_data.get(), kManifestKey, &manifest))
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
462f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!CheckResponseKeyValue(webstore_data.get(), kLocalizedNameKey, &name_))
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string icon_url_string;
466f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!CheckResponseKeyValue(webstore_data.get(), kIconUrlKey,
467f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                             &icon_url_string))
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
46958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GURL icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      icon_url_string);
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!icon_url.is_valid()) {
47358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    LOG(ERROR) << "Webstore response error (icon url): "
474f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)               << ValueToString(webstore_data.get());
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OnWebstoreResponseParseFailure(kInvalidWebstoreResponseError);
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // WebstoreDataParser deletes itself when done.
48090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  (new WebstoreDataParser(AsWeakPtr()))->Start(app_id_,
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               manifest,
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               icon_url,
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               GetRequestContextGetter());
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void KioskAppData::OnWebstoreResponseParseFailure(const std::string& error) {
48758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  LOG(ERROR) << "Webstore failed for kiosk app " << app_id_
48858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)             << ", " << error;
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  webstore_fetcher_.reset();
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetStatus(STATUS_ERROR);
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
49358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool KioskAppData::CheckResponseKeyValue(const base::DictionaryValue* response,
49458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                         const char* key,
49558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                         std::string* value) {
49658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!response->GetString(key, value)) {
49758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    LOG(ERROR) << "Webstore response error (" << key
49858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)               << "): " << ValueToString(response);
49958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    OnWebstoreResponseParseFailure(kInvalidWebstoreResponseError);
50058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return false;
50158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
50258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return true;
50358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
50458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chromeos
506