wallpaper_private_api.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/extensions/wallpaper_private_api.h"
6
7#include <vector>
8
9#include "ash/shell.h"
10#include "ash/wm/window_cycle_controller.h"
11#include "ash/wm/window_util.h"
12#include "base/file_util.h"
13#include "base/files/file_enumerator.h"
14#include "base/json/json_writer.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/path_service.h"
17#include "base/stringprintf.h"
18#include "base/strings/string_number_conversions.h"
19#include "base/synchronization/cancellation_flag.h"
20#include "base/threading/sequenced_worker_pool.h"
21#include "base/threading/worker_pool.h"
22#include "chrome/browser/browser_process.h"
23#include "chrome/browser/chromeos/login/user.h"
24#include "chrome/browser/chromeos/login/user_image.h"
25#include "chrome/browser/chromeos/login/user_manager.h"
26#include "chrome/browser/chromeos/login/wallpaper_manager.h"
27#include "chrome/browser/extensions/event_router.h"
28#include "chrome/browser/image_decoder.h"
29#include "chrome/common/chrome_paths.h"
30#include "content/public/browser/browser_thread.h"
31#include "net/url_request/url_fetcher.h"
32#include "net/url_request/url_fetcher_delegate.h"
33#include "net/url_request/url_request_status.h"
34#include "googleurl/src/gurl.h"
35#include "grit/app_locale_settings.h"
36#include "grit/generated_resources.h"
37#include "grit/platform_locale_settings.h"
38#include "ui/aura/window_observer.h"
39#include "ui/base/l10n/l10n_util.h"
40#include "ui/webui/web_ui_util.h"
41
42using base::BinaryValue;
43using content::BrowserThread;
44
45namespace {
46
47// Keeps in sync (same order) with WallpaperLayout enum in header file.
48const char* kWallpaperLayoutArrays[] = {
49    "CENTER",
50    "CENTER_CROPPED",
51    "STRETCH",
52    "TILE"
53};
54
55const char kOnlineSource[] = "ONLINE";
56const char kCustomSource[] = "CUSTOM";
57
58#if defined(GOOGLE_CHROME_BUILD)
59const char kWallpaperManifestBaseURL[] = "https://commondatastorage.googleapis."
60    "com/chromeos-wallpaper-public/manifest_";
61#endif
62
63const int kWallpaperLayoutCount = arraysize(kWallpaperLayoutArrays);
64
65ash::WallpaperLayout GetLayoutEnum(const std::string& layout) {
66  for (int i = 0; i < kWallpaperLayoutCount; i++) {
67    if (layout.compare(kWallpaperLayoutArrays[i]) == 0)
68      return static_cast<ash::WallpaperLayout>(i);
69  }
70  // Default to use CENTER layout.
71  return ash::WALLPAPER_LAYOUT_CENTER;
72}
73
74// Saves |data| as |file_name| to directory with |key|. Return false if the
75// directory can not be found/created or failed to write file.
76bool SaveData(int key, const std::string& file_name, const std::string& data) {
77  base::FilePath data_dir;
78  CHECK(PathService::Get(key, &data_dir));
79  if (!file_util::DirectoryExists(data_dir) &&
80      !file_util::CreateDirectory(data_dir)) {
81    return false;
82  }
83  base::FilePath file_path = data_dir.Append(file_name);
84
85  return file_util::PathExists(file_path) ||
86         (file_util::WriteFile(file_path, data.c_str(),
87                               data.size()) != -1);
88}
89
90// Gets |file_name| from directory with |key|. Return false if the directory can
91// not be found or failed to read file to string |data|. Note if the |file_name|
92// can not be found in the directory, return true with empty |data|. It is
93// expected that we may try to access file which did not saved yet.
94bool GetData(const base::FilePath& path, std::string* data) {
95  base::FilePath data_dir = path.DirName();
96  if (!file_util::DirectoryExists(data_dir) &&
97      !file_util::CreateDirectory(data_dir))
98    return false;
99
100  return !file_util::PathExists(path) ||
101         file_util::ReadFileToString(path, data);
102}
103
104class WindowStateManager;
105
106// static
107WindowStateManager* g_window_state_manager = NULL;
108
109// WindowStateManager remembers which windows have been minimized in order to
110// restore them when the wallpaper viewer is hidden.
111class WindowStateManager : public aura::WindowObserver {
112 public:
113
114  // Minimizes all windows except the active window.
115  static void MinimizeInactiveWindows() {
116    if (g_window_state_manager)
117      delete g_window_state_manager;
118    g_window_state_manager = new WindowStateManager();
119    g_window_state_manager->BuildWindowListAndMinimizeInactive(
120        ash::wm::GetActiveWindow());
121  }
122
123  // Activates all minimized windows restoring them to their previous state.
124  // This should only be called after calling MinimizeInactiveWindows.
125  static void RestoreWindows() {
126    DCHECK(g_window_state_manager);
127    g_window_state_manager->RestoreMinimizedWindows();
128    delete g_window_state_manager;
129    g_window_state_manager = NULL;
130  }
131
132 private:
133  WindowStateManager() {}
134
135  virtual ~WindowStateManager() {
136    for (std::vector<aura::Window*>::iterator iter = windows_.begin();
137         iter != windows_.end(); ++iter) {
138      (*iter)->RemoveObserver(this);
139    }
140  }
141
142  void BuildWindowListAndMinimizeInactive(aura::Window* active_window) {
143    windows_ = ash::WindowCycleController::BuildWindowList(NULL, false);
144    // Remove active window.
145    std::vector<aura::Window*>::iterator last =
146        std::remove(windows_.begin(), windows_.end(), active_window);
147    // Removes unfocusable windows.
148    last =
149        std::remove_if(
150            windows_.begin(),
151            last,
152            std::ptr_fun(ash::wm::IsWindowMinimized));
153    windows_.erase(last, windows_.end());
154
155    for (std::vector<aura::Window*>::iterator iter = windows_.begin();
156         iter != windows_.end(); ++iter) {
157      (*iter)->AddObserver(this);
158      ash::wm::MinimizeWindow(*iter);
159    }
160  }
161
162  void RestoreMinimizedWindows() {
163    for (std::vector<aura::Window*>::iterator iter = windows_.begin();
164         iter != windows_.end(); ++iter) {
165      ash::wm::ActivateWindow(*iter);
166    }
167  }
168
169  // aura::WindowObserver overrides.
170  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
171    window->RemoveObserver(this);
172    std::vector<aura::Window*>::iterator i = std::find(windows_.begin(),
173        windows_.end(), window);
174    DCHECK(i != windows_.end());
175    windows_.erase(i);
176  }
177
178  // List of minimized windows.
179  std::vector<aura::Window*> windows_;
180};
181
182}  // namespace
183
184bool WallpaperPrivateGetStringsFunction::RunImpl() {
185  DictionaryValue* dict = new DictionaryValue();
186  SetResult(dict);
187
188#define SET_STRING(id, idr) \
189  dict->SetString(id, l10n_util::GetStringUTF16(idr))
190  SET_STRING("webFontFamily", IDS_WEB_FONT_FAMILY);
191  SET_STRING("webFontSize", IDS_WEB_FONT_SIZE);
192  SET_STRING("allCategoryLabel", IDS_WALLPAPER_MANAGER_ALL_CATEGORY_LABEL);
193  SET_STRING("deleteCommandLabel", IDS_WALLPAPER_MANAGER_DELETE_COMMAND_LABEL);
194  SET_STRING("customCategoryLabel",
195             IDS_WALLPAPER_MANAGER_CUSTOM_CATEGORY_LABEL);
196  SET_STRING("selectCustomLabel",
197             IDS_WALLPAPER_MANAGER_SELECT_CUSTOM_LABEL);
198  SET_STRING("positionLabel", IDS_WALLPAPER_MANAGER_POSITION_LABEL);
199  SET_STRING("colorLabel", IDS_WALLPAPER_MANAGER_COLOR_LABEL);
200  SET_STRING("centerCroppedLayout",
201             IDS_OPTIONS_WALLPAPER_CENTER_CROPPED_LAYOUT);
202  SET_STRING("centerLayout", IDS_OPTIONS_WALLPAPER_CENTER_LAYOUT);
203  SET_STRING("stretchLayout", IDS_OPTIONS_WALLPAPER_STRETCH_LAYOUT);
204  SET_STRING("connectionFailed", IDS_WALLPAPER_MANAGER_ACCESS_FAIL);
205  SET_STRING("downloadFailed", IDS_WALLPAPER_MANAGER_DOWNLOAD_FAIL);
206  SET_STRING("downloadCanceled", IDS_WALLPAPER_MANAGER_DOWNLOAD_CANCEL);
207  SET_STRING("customWallpaperWarning",
208             IDS_WALLPAPER_MANAGER_SHOW_CUSTOM_WALLPAPER_ON_START_WARNING);
209  SET_STRING("accessFileFailure", IDS_WALLPAPER_MANAGER_ACCESS_FILE_FAILURE);
210  SET_STRING("invalidWallpaper", IDS_WALLPAPER_MANAGER_INVALID_WALLPAPER);
211  SET_STRING("surpriseMeLabel", IDS_WALLPAPER_MANAGER_SURPRISE_ME_LABEL);
212  SET_STRING("learnMore", IDS_LEARN_MORE);
213#undef SET_STRING
214
215  webui::SetFontAndTextDirection(dict);
216
217  chromeos::WallpaperManager* wallpaper_manager =
218      chromeos::WallpaperManager::Get();
219  chromeos::WallpaperInfo info;
220
221  if (wallpaper_manager->GetLoggedInUserWallpaperInfo(&info))
222    dict->SetString("currentWallpaper", info.file);
223
224#if defined(GOOGLE_CHROME_BUILD)
225  dict->SetString("manifestBaseURL", kWallpaperManifestBaseURL);
226#endif
227
228  return true;
229}
230
231class WallpaperFunctionBase::WallpaperDecoder : public ImageDecoder::Delegate {
232 public:
233  explicit WallpaperDecoder(scoped_refptr<WallpaperFunctionBase> function)
234      : function_(function) {
235  }
236
237  void Start(const std::string& image_data) {
238    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
239    image_decoder_ = new ImageDecoder(this, image_data,
240                                      ImageDecoder::ROBUST_JPEG_CODEC);
241    scoped_refptr<base::MessageLoopProxy> task_runner =
242        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
243    image_decoder_->Start(task_runner);
244  }
245
246  void Cancel() {
247    cancel_flag_.Set();
248  }
249
250  virtual void OnImageDecoded(const ImageDecoder* decoder,
251                              const SkBitmap& decoded_image) OVERRIDE {
252    // Make the SkBitmap immutable as we won't modify it. This is important
253    // because otherwise it gets duplicated during painting, wasting memory.
254    SkBitmap immutable(decoded_image);
255    immutable.setImmutable();
256    gfx::ImageSkia final_image =
257        gfx::ImageSkia::CreateFrom1xBitmap(immutable);
258    final_image.MakeThreadSafe();
259    if (cancel_flag_.IsSet()) {
260      function_->OnFailureOrCancel("");
261      delete this;
262      return;
263    }
264    function_->OnWallpaperDecoded(final_image);
265    delete this;
266  }
267
268  virtual void OnDecodeImageFailed(const ImageDecoder* decoder) OVERRIDE {
269    function_->OnFailureOrCancel(
270        l10n_util::GetStringUTF8(IDS_WALLPAPER_MANAGER_INVALID_WALLPAPER));
271    delete this;
272  }
273
274 private:
275  scoped_refptr<WallpaperFunctionBase> function_;
276  scoped_refptr<ImageDecoder> image_decoder_;
277  base::CancellationFlag cancel_flag_;
278
279  DISALLOW_COPY_AND_ASSIGN(WallpaperDecoder);
280};
281
282WallpaperFunctionBase::WallpaperDecoder*
283    WallpaperFunctionBase::wallpaper_decoder_;
284
285WallpaperFunctionBase::WallpaperFunctionBase() {
286}
287
288WallpaperFunctionBase::~WallpaperFunctionBase() {
289}
290
291void WallpaperFunctionBase::StartDecode(const std::string& data) {
292  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
293  if (wallpaper_decoder_)
294    wallpaper_decoder_->Cancel();
295  wallpaper_decoder_ = new WallpaperDecoder(this);
296  wallpaper_decoder_->Start(data);
297}
298
299void WallpaperFunctionBase::OnFailureOrCancel(const std::string& error) {
300  wallpaper_decoder_ = NULL;
301  if (!error.empty())
302    SetError(error);
303  SendResponse(false);
304}
305
306WallpaperPrivateSetWallpaperIfExistsFunction::
307    WallpaperPrivateSetWallpaperIfExistsFunction() {}
308
309WallpaperPrivateSetWallpaperIfExistsFunction::
310    ~WallpaperPrivateSetWallpaperIfExistsFunction() {}
311
312bool WallpaperPrivateSetWallpaperIfExistsFunction::RunImpl() {
313  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &urlOrFile_));
314  EXTENSION_FUNCTION_VALIDATE(!urlOrFile_.empty());
315
316  std::string layout_string;
317  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &layout_string));
318  EXTENSION_FUNCTION_VALIDATE(!layout_string.empty());
319  layout_ = GetLayoutEnum(layout_string);
320
321  std::string source;
322  EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &source));
323  EXTENSION_FUNCTION_VALIDATE(!source.empty());
324
325  std::string file_name;
326  std::string email = chromeos::UserManager::Get()->GetLoggedInUser()->email();
327
328  base::FilePath wallpaper_path;
329  base::FilePath fallback_path;
330  ash::WallpaperResolution resolution = ash::Shell::GetInstance()->
331      desktop_background_controller()->GetAppropriateResolution();
332
333  if (source == kOnlineSource) {
334    type_ = chromeos::User::ONLINE;
335    file_name = GURL(urlOrFile_).ExtractFileName();
336    CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS,
337                           &wallpaper_path));
338    fallback_path = wallpaper_path.Append(file_name);
339    if (layout_ != ash::WALLPAPER_LAYOUT_STRETCH &&
340        resolution == ash::WALLPAPER_RESOLUTION_SMALL) {
341      file_name = base::FilePath(file_name).InsertBeforeExtension(
342          chromeos::kSmallWallpaperSuffix).value();
343    }
344    wallpaper_path = wallpaper_path.Append(file_name);
345  } else {
346    type_ = chromeos::User::CUSTOMIZED;
347    file_name = urlOrFile_;
348    const char* sub_dir = (resolution == ash::WALLPAPER_RESOLUTION_SMALL) ?
349        chromeos::kSmallWallpaperSubDir : chromeos::kLargeWallpaperSubDir;
350    wallpaper_path = chromeos::WallpaperManager::Get()->GetCustomWallpaperPath(
351        sub_dir, email, file_name);
352    fallback_path = chromeos::WallpaperManager::Get()->GetCustomWallpaperPath(
353        chromeos::kOriginalWallpaperSubDir, email, file_name);
354  }
355
356  sequence_token_ = BrowserThread::GetBlockingPool()->
357      GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
358  scoped_refptr<base::SequencedTaskRunner> task_runner =
359      BrowserThread::GetBlockingPool()->
360          GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
361              base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
362
363  task_runner->PostTask(FROM_HERE,
364      base::Bind(
365          &WallpaperPrivateSetWallpaperIfExistsFunction::
366              ReadFileAndInitiateStartDecode,
367          this, wallpaper_path, fallback_path));
368  return true;
369}
370
371void WallpaperPrivateSetWallpaperIfExistsFunction::
372    ReadFileAndInitiateStartDecode(const base::FilePath& file_path,
373                                   const base::FilePath& fallback_path) {
374  DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
375      sequence_token_));
376  std::string data;
377  base::FilePath path = file_path;
378
379  if (!file_util::PathExists(file_path))
380    path = fallback_path;
381
382  if (file_util::PathExists(path) &&
383      file_util::ReadFileToString(path, &data)) {
384    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
385        base::Bind(&WallpaperPrivateSetWallpaperIfExistsFunction::StartDecode,
386                   this, data));
387    return;
388  }
389  std::string error = base::StringPrintf(
390        "Failed to set wallpaper %s from file system.",
391        path.BaseName().value().c_str());
392  BrowserThread::PostTask(
393      BrowserThread::UI, FROM_HERE,
394      base::Bind(&WallpaperPrivateSetWallpaperIfExistsFunction::OnFileNotExists,
395                 this, error));
396}
397
398void WallpaperPrivateSetWallpaperIfExistsFunction::OnWallpaperDecoded(
399    const gfx::ImageSkia& wallpaper) {
400  // Set wallpaper_decoder_ to null since the decoding already finished.
401  wallpaper_decoder_ = NULL;
402
403  chromeos::WallpaperManager* wallpaper_manager =
404      chromeos::WallpaperManager::Get();
405  wallpaper_manager->SetWallpaperFromImageSkia(wallpaper, layout_);
406  bool is_persistent =
407      !chromeos::UserManager::Get()->IsCurrentUserNonCryptohomeDataEphemeral();
408  chromeos::WallpaperInfo info = {
409      urlOrFile_,
410      layout_,
411      type_,
412      base::Time::Now().LocalMidnight()
413  };
414  std::string email = chromeos::UserManager::Get()->GetLoggedInUser()->email();
415  wallpaper_manager->SetUserWallpaperInfo(email, info, is_persistent);
416  SetResult(base::Value::CreateBooleanValue(true));
417  SendResponse(true);
418}
419
420void WallpaperPrivateSetWallpaperIfExistsFunction::OnFileNotExists(
421    const std::string& error) {
422  SetResult(base::Value::CreateBooleanValue(false));
423  OnFailureOrCancel(error);
424};
425
426WallpaperPrivateSetWallpaperFunction::WallpaperPrivateSetWallpaperFunction() {
427}
428
429WallpaperPrivateSetWallpaperFunction::~WallpaperPrivateSetWallpaperFunction() {
430}
431
432bool WallpaperPrivateSetWallpaperFunction::RunImpl() {
433  BinaryValue* input = NULL;
434  EXTENSION_FUNCTION_VALIDATE(args_->GetBinary(0, &input));
435
436  std::string layout_string;
437  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &layout_string));
438  EXTENSION_FUNCTION_VALIDATE(!layout_string.empty());
439  layout_ = GetLayoutEnum(layout_string);
440
441  EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &url_));
442  EXTENSION_FUNCTION_VALIDATE(!url_.empty());
443
444  // Gets email address while at UI thread.
445  email_ = chromeos::UserManager::Get()->GetLoggedInUser()->email();
446
447  image_data_.assign(input->GetBuffer(), input->GetSize());
448  StartDecode(image_data_);
449
450  return true;
451}
452
453void WallpaperPrivateSetWallpaperFunction::OnWallpaperDecoded(
454    const gfx::ImageSkia& wallpaper) {
455  wallpaper_ = wallpaper;
456  // Set wallpaper_decoder_ to null since the decoding already finished.
457  wallpaper_decoder_ = NULL;
458
459  sequence_token_ = BrowserThread::GetBlockingPool()->
460      GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
461  scoped_refptr<base::SequencedTaskRunner> task_runner =
462      BrowserThread::GetBlockingPool()->
463          GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
464              base::SequencedWorkerPool::BLOCK_SHUTDOWN);
465
466  task_runner->PostTask(FROM_HERE,
467      base::Bind(&WallpaperPrivateSetWallpaperFunction::SaveToFile, this));
468}
469
470void WallpaperPrivateSetWallpaperFunction::SaveToFile() {
471  DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
472      sequence_token_));
473  std::string file_name = GURL(url_).ExtractFileName();
474  if (SaveData(chrome::DIR_CHROMEOS_WALLPAPERS, file_name, image_data_)) {
475    wallpaper_.EnsureRepsForSupportedScaleFactors();
476    scoped_ptr<gfx::ImageSkia> deep_copy(wallpaper_.DeepCopy());
477    // ImageSkia is not RefCountedThreadSafe. Use a deep copied ImageSkia if
478    // post to another thread.
479    BrowserThread::PostTask(
480        BrowserThread::UI, FROM_HERE,
481        base::Bind(&WallpaperPrivateSetWallpaperFunction::SetDecodedWallpaper,
482                   this, base::Passed(&deep_copy)));
483    chromeos::UserImage wallpaper(wallpaper_);
484
485    base::FilePath wallpaper_dir;
486    CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
487    base::FilePath file_path = wallpaper_dir.Append(
488        file_name).InsertBeforeExtension(chromeos::kSmallWallpaperSuffix);
489    if (file_util::PathExists(file_path))
490      return;
491    // Generates and saves small resolution wallpaper. Uses CENTER_CROPPED to
492    // maintain the aspect ratio after resize.
493    chromeos::WallpaperManager::Get()->ResizeAndSaveWallpaper(
494        wallpaper,
495        file_path,
496        ash::WALLPAPER_LAYOUT_CENTER_CROPPED,
497        ash::kSmallWallpaperMaxWidth,
498        ash::kSmallWallpaperMaxHeight);
499  } else {
500    std::string error = base::StringPrintf(
501        "Failed to create/write wallpaper to %s.", file_name.c_str());
502    BrowserThread::PostTask(
503        BrowserThread::UI, FROM_HERE,
504        base::Bind(&WallpaperPrivateSetWallpaperFunction::OnFailureOrCancel,
505                   this, error));
506  }
507}
508
509void WallpaperPrivateSetWallpaperFunction::SetDecodedWallpaper(
510    scoped_ptr<gfx::ImageSkia> wallpaper) {
511  chromeos::WallpaperManager* wallpaper_manager =
512      chromeos::WallpaperManager::Get();
513  wallpaper_manager->SetWallpaperFromImageSkia(*wallpaper.get(), layout_);
514  bool is_persistent =
515      !chromeos::UserManager::Get()->IsCurrentUserNonCryptohomeDataEphemeral();
516  chromeos::WallpaperInfo info = {
517      url_,
518      layout_,
519      chromeos::User::ONLINE,
520      base::Time::Now().LocalMidnight()
521  };
522  wallpaper_manager->SetUserWallpaperInfo(email_, info, is_persistent);
523  SendResponse(true);
524}
525
526WallpaperPrivateResetWallpaperFunction::
527    WallpaperPrivateResetWallpaperFunction() {}
528
529WallpaperPrivateResetWallpaperFunction::
530    ~WallpaperPrivateResetWallpaperFunction() {}
531
532bool WallpaperPrivateResetWallpaperFunction::RunImpl() {
533  chromeos::WallpaperManager* wallpaper_manager =
534      chromeos::WallpaperManager::Get();
535  chromeos::UserManager* user_manager = chromeos::UserManager::Get();
536
537  std::string email = user_manager->GetLoggedInUser()->email();
538  wallpaper_manager->RemoveUserWallpaperInfo(email);
539
540  chromeos::WallpaperInfo info = {
541      "",
542      ash::WALLPAPER_LAYOUT_CENTER,
543      chromeos::User::DEFAULT,
544      base::Time::Now().LocalMidnight()
545  };
546  bool is_persistent =
547      !user_manager->IsCurrentUserNonCryptohomeDataEphemeral();
548  wallpaper_manager->SetUserWallpaperInfo(email, info, is_persistent);
549  wallpaper_manager->SetDefaultWallpaper();
550  return true;
551}
552
553WallpaperPrivateSetCustomWallpaperFunction::
554    WallpaperPrivateSetCustomWallpaperFunction() {}
555
556WallpaperPrivateSetCustomWallpaperFunction::
557    ~WallpaperPrivateSetCustomWallpaperFunction() {}
558
559bool WallpaperPrivateSetCustomWallpaperFunction::RunImpl() {
560  BinaryValue* input = NULL;
561  EXTENSION_FUNCTION_VALIDATE(args_->GetBinary(0, &input));
562
563  std::string layout_string;
564  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &layout_string));
565  EXTENSION_FUNCTION_VALIDATE(!layout_string.empty());
566  layout_ = GetLayoutEnum(layout_string);
567
568  EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(2, &generate_thumbnail_));
569
570  EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &file_name_));
571  EXTENSION_FUNCTION_VALIDATE(!file_name_.empty());
572
573  // Gets email address while at UI thread.
574  email_ = chromeos::UserManager::Get()->GetLoggedInUser()->email();
575
576  image_data_.assign(input->GetBuffer(), input->GetSize());
577  StartDecode(image_data_);
578
579  return true;
580}
581
582void WallpaperPrivateSetCustomWallpaperFunction::OnWallpaperDecoded(
583    const gfx::ImageSkia& wallpaper) {
584  chromeos::WallpaperManager* wallpaper_manager =
585      chromeos::WallpaperManager::Get();
586  chromeos::UserImage::RawImage raw_image(image_data_.begin(),
587                                          image_data_.end());
588  chromeos::UserImage image(wallpaper, raw_image);
589  base::FilePath thumbnail_path = wallpaper_manager->GetCustomWallpaperPath(
590      chromeos::kThumbnailWallpaperSubDir, email_, file_name_);
591
592  sequence_token_ = BrowserThread::GetBlockingPool()->
593      GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
594  scoped_refptr<base::SequencedTaskRunner> task_runner =
595      BrowserThread::GetBlockingPool()->
596          GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
597              base::SequencedWorkerPool::BLOCK_SHUTDOWN);
598
599  // In the new wallpaper picker UI, we do not depend on WallpaperDelegate
600  // to refresh thumbnail. Uses a null delegate here.
601  wallpaper_manager->SetCustomWallpaper(email_, file_name_, layout_,
602                                        chromeos::User::CUSTOMIZED,
603                                        image);
604  wallpaper_decoder_ = NULL;
605
606  if (generate_thumbnail_) {
607    wallpaper.EnsureRepsForSupportedScaleFactors();
608    scoped_ptr<gfx::ImageSkia> deep_copy(wallpaper.DeepCopy());
609    // Generates thumbnail before call api function callback. We can then
610    // request thumbnail in the javascript callback.
611    task_runner->PostTask(FROM_HERE,
612        base::Bind(
613            &WallpaperPrivateSetCustomWallpaperFunction::GenerateThumbnail,
614            this, thumbnail_path, base::Passed(&deep_copy)));
615  } else {
616    SendResponse(true);
617  }
618}
619
620void WallpaperPrivateSetCustomWallpaperFunction::GenerateThumbnail(
621    const base::FilePath& thumbnail_path, scoped_ptr<gfx::ImageSkia> image) {
622  DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
623      sequence_token_));
624  chromeos::UserImage wallpaper(*image.get());
625  if (!file_util::PathExists(thumbnail_path.DirName()))
626    file_util::CreateDirectory(thumbnail_path.DirName());
627
628  scoped_refptr<base::RefCountedBytes> data;
629  chromeos::WallpaperManager::Get()->ResizeWallpaper(
630      wallpaper,
631      ash::WALLPAPER_LAYOUT_STRETCH,
632      ash::kWallpaperThumbnailWidth,
633      ash::kWallpaperThumbnailHeight,
634      &data);
635  BrowserThread::PostTask(
636        BrowserThread::UI, FROM_HERE,
637        base::Bind(
638            &WallpaperPrivateSetCustomWallpaperFunction::ThumbnailGenerated,
639            this, data));
640}
641
642void WallpaperPrivateSetCustomWallpaperFunction::ThumbnailGenerated(
643    base::RefCountedBytes* data) {
644  BinaryValue* result = BinaryValue::CreateWithCopiedBuffer(
645      reinterpret_cast<const char*>(data->front()), data->size());
646  SetResult(result);
647  SendResponse(true);
648}
649
650WallpaperPrivateSetCustomWallpaperLayoutFunction::
651    WallpaperPrivateSetCustomWallpaperLayoutFunction() {}
652
653WallpaperPrivateSetCustomWallpaperLayoutFunction::
654    ~WallpaperPrivateSetCustomWallpaperLayoutFunction() {}
655
656bool WallpaperPrivateSetCustomWallpaperLayoutFunction::RunImpl() {
657  std::string layout_string;
658  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &layout_string));
659  EXTENSION_FUNCTION_VALIDATE(!layout_string.empty());
660
661  chromeos::WallpaperManager* wallpaper_manager =
662      chromeos::WallpaperManager::Get();
663  chromeos::WallpaperInfo info;
664  wallpaper_manager->GetLoggedInUserWallpaperInfo(&info);
665  if (info.type != chromeos::User::CUSTOMIZED) {
666    SetError("Only custom wallpaper can change layout.");
667    SendResponse(false);
668    return false;
669  }
670  info.layout = GetLayoutEnum(layout_string);
671
672  std::string email = chromeos::UserManager::Get()->GetLoggedInUser()->email();
673  bool is_persistent =
674      !chromeos::UserManager::Get()->IsCurrentUserNonCryptohomeDataEphemeral();
675  wallpaper_manager->SetUserWallpaperInfo(email, info, is_persistent);
676  wallpaper_manager->UpdateWallpaper();
677  SendResponse(true);
678
679  // Gets email address while at UI thread.
680  return true;
681}
682
683WallpaperPrivateMinimizeInactiveWindowsFunction::
684    WallpaperPrivateMinimizeInactiveWindowsFunction() {
685}
686
687WallpaperPrivateMinimizeInactiveWindowsFunction::
688    ~WallpaperPrivateMinimizeInactiveWindowsFunction() {
689}
690
691bool WallpaperPrivateMinimizeInactiveWindowsFunction::RunImpl() {
692  WindowStateManager::MinimizeInactiveWindows();
693  return true;
694}
695
696WallpaperPrivateRestoreMinimizedWindowsFunction::
697    WallpaperPrivateRestoreMinimizedWindowsFunction() {
698}
699
700WallpaperPrivateRestoreMinimizedWindowsFunction::
701    ~WallpaperPrivateRestoreMinimizedWindowsFunction() {
702}
703
704bool WallpaperPrivateRestoreMinimizedWindowsFunction::RunImpl() {
705  WindowStateManager::RestoreWindows();
706  return true;
707}
708
709WallpaperPrivateGetThumbnailFunction::WallpaperPrivateGetThumbnailFunction() {
710}
711
712WallpaperPrivateGetThumbnailFunction::~WallpaperPrivateGetThumbnailFunction() {
713}
714
715bool WallpaperPrivateGetThumbnailFunction::RunImpl() {
716  std::string urlOrFile;
717  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &urlOrFile));
718  EXTENSION_FUNCTION_VALIDATE(!urlOrFile.empty());
719
720  std::string source;
721  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &source));
722  EXTENSION_FUNCTION_VALIDATE(!source.empty());
723
724  std::string file_name;
725  base::FilePath thumbnail_path;
726  std::string email = chromeos::UserManager::Get()->GetLoggedInUser()->email();
727  if (source == kOnlineSource) {
728    file_name = GURL(urlOrFile).ExtractFileName();
729    CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPER_THUMBNAILS,
730                           &thumbnail_path));
731    thumbnail_path = thumbnail_path.Append(file_name);
732  } else {
733    file_name = urlOrFile;
734    thumbnail_path = chromeos::WallpaperManager::Get()->
735        GetCustomWallpaperPath(chromeos::kThumbnailWallpaperSubDir, email,
736                               file_name);
737  }
738
739  sequence_token_ = BrowserThread::GetBlockingPool()->
740      GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
741  scoped_refptr<base::SequencedTaskRunner> task_runner =
742      BrowserThread::GetBlockingPool()->
743          GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
744              base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
745
746  task_runner->PostTask(FROM_HERE,
747      base::Bind(&WallpaperPrivateGetThumbnailFunction::Get, this,
748                 thumbnail_path));
749  return true;
750}
751
752void WallpaperPrivateGetThumbnailFunction::Failure(
753    const std::string& file_name) {
754  SetError(base::StringPrintf("Failed to access wallpaper thumbnails for %s.",
755                              file_name.c_str()));
756  SendResponse(false);
757}
758
759void WallpaperPrivateGetThumbnailFunction::FileNotLoaded() {
760  SendResponse(true);
761}
762
763void WallpaperPrivateGetThumbnailFunction::FileLoaded(
764    const std::string& data) {
765  BinaryValue* thumbnail = BinaryValue::CreateWithCopiedBuffer(data.c_str(),
766                                                               data.size());
767  SetResult(thumbnail);
768  SendResponse(true);
769}
770
771void WallpaperPrivateGetThumbnailFunction::Get(const base::FilePath& path) {
772  DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
773      sequence_token_));
774  std::string data;
775  if (GetData(path, &data)) {
776    if (data.empty()) {
777      BrowserThread::PostTask(
778        BrowserThread::UI, FROM_HERE,
779        base::Bind(&WallpaperPrivateGetThumbnailFunction::FileNotLoaded, this));
780    } else {
781      BrowserThread::PostTask(
782        BrowserThread::UI, FROM_HERE,
783        base::Bind(&WallpaperPrivateGetThumbnailFunction::FileLoaded, this,
784                   data));
785    }
786  } else {
787    BrowserThread::PostTask(
788        BrowserThread::UI, FROM_HERE,
789        base::Bind(&WallpaperPrivateGetThumbnailFunction::Failure, this,
790                   path.BaseName().value()));
791  }
792}
793
794WallpaperPrivateSaveThumbnailFunction::WallpaperPrivateSaveThumbnailFunction() {
795}
796
797WallpaperPrivateSaveThumbnailFunction::
798    ~WallpaperPrivateSaveThumbnailFunction() {}
799
800bool WallpaperPrivateSaveThumbnailFunction::RunImpl() {
801  std::string url;
802  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));
803  EXTENSION_FUNCTION_VALIDATE(!url.empty());
804
805  BinaryValue* input = NULL;
806  EXTENSION_FUNCTION_VALIDATE(args_->GetBinary(1, &input));
807
808  std::string file_name = GURL(url).ExtractFileName();
809  std::string data(input->GetBuffer(), input->GetSize());
810
811  sequence_token_ = BrowserThread::GetBlockingPool()->
812      GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
813  scoped_refptr<base::SequencedTaskRunner> task_runner =
814      BrowserThread::GetBlockingPool()->
815          GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
816              base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
817
818  task_runner->PostTask(FROM_HERE,
819      base::Bind(&WallpaperPrivateSaveThumbnailFunction::Save,
820                 this, data, file_name));
821  return true;
822}
823
824void WallpaperPrivateSaveThumbnailFunction::Failure(
825    const std::string& file_name) {
826  SetError(base::StringPrintf("Failed to create/write thumbnail of %s.",
827                              file_name.c_str()));
828  SendResponse(false);
829}
830
831void WallpaperPrivateSaveThumbnailFunction::Success() {
832  SendResponse(true);
833}
834
835void WallpaperPrivateSaveThumbnailFunction::Save(const std::string& data,
836                                          const std::string& file_name) {
837  DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
838      sequence_token_));
839  if (SaveData(chrome::DIR_CHROMEOS_WALLPAPER_THUMBNAILS, file_name, data)) {
840    BrowserThread::PostTask(
841      BrowserThread::UI, FROM_HERE,
842      base::Bind(&WallpaperPrivateSaveThumbnailFunction::Success, this));
843  } else {
844    BrowserThread::PostTask(
845          BrowserThread::UI, FROM_HERE,
846          base::Bind(&WallpaperPrivateSaveThumbnailFunction::Failure,
847                     this, file_name));
848  }
849}
850
851WallpaperPrivateGetOfflineWallpaperListFunction::
852    WallpaperPrivateGetOfflineWallpaperListFunction() {
853}
854
855WallpaperPrivateGetOfflineWallpaperListFunction::
856    ~WallpaperPrivateGetOfflineWallpaperListFunction() {
857}
858
859bool WallpaperPrivateGetOfflineWallpaperListFunction::RunImpl() {
860  std::string source;
861  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &source));
862  EXTENSION_FUNCTION_VALIDATE(!source.empty());
863
864  std::string email = chromeos::UserManager::Get()->GetLoggedInUser()->email();
865
866  sequence_token_ = BrowserThread::GetBlockingPool()->
867      GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
868  scoped_refptr<base::SequencedTaskRunner> task_runner =
869      BrowserThread::GetBlockingPool()->
870          GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
871              base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
872
873  task_runner->PostTask(FROM_HERE,
874      base::Bind(&WallpaperPrivateGetOfflineWallpaperListFunction::GetList,
875                 this, email, source));
876  return true;
877}
878
879void WallpaperPrivateGetOfflineWallpaperListFunction::GetList(
880    const std::string& email,
881    const std::string& source) {
882  DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
883      sequence_token_));
884  std::vector<std::string> file_list;
885  if (source == kOnlineSource) {
886    base::FilePath wallpaper_dir;
887    CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
888    if (file_util::DirectoryExists(wallpaper_dir)) {
889      base::FileEnumerator files(wallpaper_dir, false,
890                                 base::FileEnumerator::FILES);
891      for (base::FilePath current = files.Next(); !current.empty();
892           current = files.Next()) {
893        std::string file_name = current.BaseName().RemoveExtension().value();
894        // Do not add file name of small resolution wallpaper to the list.
895        if (!EndsWith(file_name, chromeos::kSmallWallpaperSuffix, true))
896          file_list.push_back(current.BaseName().value());
897      }
898    }
899  } else {
900    base::FilePath custom_thumbnails_dir = chromeos::WallpaperManager::Get()->
901        GetCustomWallpaperPath(chromeos::kThumbnailWallpaperSubDir, email, "");
902    if (file_util::DirectoryExists(custom_thumbnails_dir)) {
903      base::FileEnumerator files(custom_thumbnails_dir, false,
904                                 base::FileEnumerator::FILES);
905      std::set<std::string> file_name_set;
906      for (base::FilePath current = files.Next(); !current.empty();
907           current = files.Next()) {
908        file_name_set.insert(current.BaseName().value());
909      }
910      for (std::set<std::string>::reverse_iterator rit = file_name_set.rbegin();
911           rit != file_name_set.rend(); ++rit) {
912        file_list.push_back(*rit);
913      }
914    }
915  }
916  BrowserThread::PostTask(
917      BrowserThread::UI, FROM_HERE,
918      base::Bind(&WallpaperPrivateGetOfflineWallpaperListFunction::OnComplete,
919                 this, file_list));
920}
921
922void WallpaperPrivateGetOfflineWallpaperListFunction::OnComplete(
923    const std::vector<std::string>& file_list) {
924  ListValue* results = new ListValue();
925  results->AppendStrings(file_list);
926  SetResult(results);
927  SendResponse(true);
928}
929