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