Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / extensions / wallpaper_private_api.cc
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/ash_switches.h"
10 #include "ash/desktop_background/desktop_background_controller.h"
11 #include "ash/shell.h"
12 #include "ash/wm/mru_window_tracker.h"
13 #include "ash/wm/window_state.h"
14 #include "ash/wm/window_util.h"
15 #include "base/command_line.h"
16 #include "base/file_util.h"
17 #include "base/files/file_enumerator.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/path_service.h"
20 #include "base/prefs/pref_service.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/threading/worker_pool.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/common/chrome_paths.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/grit/generated_resources.h"
30 #include "chrome/grit/platform_locale_settings.h"
31 #include "components/user_manager/user.h"
32 #include "components/user_manager/user_manager.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "extensions/browser/event_router.h"
35 #include "ui/base/l10n/l10n_util.h"
36 #include "ui/base/webui/web_ui_util.h"
37 #include "ui/strings/grit/app_locale_settings.h"
38 #include "url/gurl.h"
39
40 using base::BinaryValue;
41 using content::BrowserThread;
42 namespace wallpaper_private = extensions::api::wallpaper_private;
43 namespace set_wallpaper_if_exists = wallpaper_private::SetWallpaperIfExists;
44 namespace set_wallpaper = wallpaper_private::SetWallpaper;
45 namespace set_custom_wallpaper = wallpaper_private::SetCustomWallpaper;
46 namespace set_custom_wallpaper_layout =
47     wallpaper_private::SetCustomWallpaperLayout;
48 namespace get_thumbnail = wallpaper_private::GetThumbnail;
49 namespace save_thumbnail = wallpaper_private::SaveThumbnail;
50 namespace get_offline_wallpaper_list =
51     wallpaper_private::GetOfflineWallpaperList;
52
53 namespace {
54
55 #if defined(GOOGLE_CHROME_BUILD)
56 const char kWallpaperManifestBaseURL[] =
57     "https://storage.googleapis.com/chromeos-wallpaper-public/manifest_";
58 #endif
59
60 bool IsOEMDefaultWallpaper() {
61   return CommandLine::ForCurrentProcess()->HasSwitch(
62       ash::switches::kAshDefaultWallpaperIsOem);
63 }
64
65 // Saves |data| as |file_name| to directory with |key|. Return false if the
66 // directory can not be found/created or failed to write file.
67 bool SaveData(int key, const std::string& file_name, const std::string& data) {
68   base::FilePath data_dir;
69   CHECK(PathService::Get(key, &data_dir));
70   if (!base::DirectoryExists(data_dir) &&
71       !base::CreateDirectory(data_dir)) {
72     return false;
73   }
74   base::FilePath file_path = data_dir.Append(file_name);
75
76   return base::PathExists(file_path) ||
77          (base::WriteFile(file_path, data.c_str(), data.size()) != -1);
78 }
79
80 // Gets |file_name| from directory with |key|. Return false if the directory can
81 // not be found or failed to read file to string |data|. Note if the |file_name|
82 // can not be found in the directory, return true with empty |data|. It is
83 // expected that we may try to access file which did not saved yet.
84 bool GetData(const base::FilePath& path, std::string* data) {
85   base::FilePath data_dir = path.DirName();
86   if (!base::DirectoryExists(data_dir) &&
87       !base::CreateDirectory(data_dir))
88     return false;
89
90   return !base::PathExists(path) ||
91          base::ReadFileToString(path, data);
92 }
93
94 // WindowStateManager remembers which windows have been minimized in order to
95 // restore them when the wallpaper viewer is hidden.
96 class WindowStateManager : public aura::WindowObserver {
97  public:
98   typedef std::map<std::string, std::set<aura::Window*> >
99       UserIDHashWindowListMap;
100
101   // Minimizes all windows except the active window.
102   static void MinimizeInactiveWindows(const std::string& user_id_hash);
103
104   // Unminimizes all minimized windows restoring them to their previous state.
105   // This should only be called after calling MinimizeInactiveWindows.
106   static void RestoreWindows(const std::string& user_id_hash);
107
108  private:
109   WindowStateManager();
110
111   virtual ~WindowStateManager();
112
113   // Store all unminimized windows except |active_window| and minimize them.
114   // All the windows are saved in a map and the key value is |user_id_hash|.
115   void BuildWindowListAndMinimizeInactiveForUser(
116       const std::string& user_id_hash, aura::Window* active_window);
117
118   // Unminimize all the stored windows for |user_id_hash|.
119   void RestoreMinimizedWindows(const std::string& user_id_hash);
120
121   // Remove the observer from |window| if |window| is no longer referenced in
122   // user_id_hash_window_list_map_.
123   void RemoveObserverIfUnreferenced(aura::Window* window);
124
125   // aura::WindowObserver overrides.
126   virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
127
128   // Map of user id hash and associated list of minimized windows.
129   UserIDHashWindowListMap user_id_hash_window_list_map_;
130
131   DISALLOW_COPY_AND_ASSIGN(WindowStateManager);
132 };
133
134 // static
135 WindowStateManager* g_window_state_manager = NULL;
136
137 // static
138 void WindowStateManager::MinimizeInactiveWindows(
139     const std::string& user_id_hash) {
140   if (!g_window_state_manager)
141     g_window_state_manager = new WindowStateManager();
142   g_window_state_manager->BuildWindowListAndMinimizeInactiveForUser(
143       user_id_hash, ash::wm::GetActiveWindow());
144 }
145
146 // static
147 void WindowStateManager::RestoreWindows(const std::string& user_id_hash) {
148   if (!g_window_state_manager) {
149     DCHECK(false) << "This should only be called after calling "
150                   << "MinimizeInactiveWindows.";
151     return;
152   }
153
154   g_window_state_manager->RestoreMinimizedWindows(user_id_hash);
155   if (g_window_state_manager->user_id_hash_window_list_map_.empty()) {
156     delete g_window_state_manager;
157     g_window_state_manager = NULL;
158   }
159 }
160
161 WindowStateManager::WindowStateManager() {}
162
163 WindowStateManager::~WindowStateManager() {}
164
165 void WindowStateManager::BuildWindowListAndMinimizeInactiveForUser(
166     const std::string& user_id_hash, aura::Window* active_window) {
167   if (user_id_hash_window_list_map_.find(user_id_hash) ==
168       user_id_hash_window_list_map_.end()) {
169     user_id_hash_window_list_map_[user_id_hash] = std::set<aura::Window*>();
170   }
171   std::set<aura::Window*>* results =
172       &user_id_hash_window_list_map_[user_id_hash];
173
174   std::vector<aura::Window*> windows =
175       ash::MruWindowTracker::BuildWindowList(false);
176
177   for (std::vector<aura::Window*>::iterator iter = windows.begin();
178        iter != windows.end(); ++iter) {
179     // Ignore active window and minimized windows.
180     if (*iter == active_window || ash::wm::GetWindowState(*iter)->IsMinimized())
181       continue;
182
183     // TODO(bshe): Add WindowStateObserver too. http://crbug.com/323252
184     if (!(*iter)->HasObserver(this))
185       (*iter)->AddObserver(this);
186
187     results->insert(*iter);
188     ash::wm::GetWindowState(*iter)->Minimize();
189   }
190 }
191
192 void WindowStateManager::RestoreMinimizedWindows(
193     const std::string& user_id_hash) {
194   UserIDHashWindowListMap::iterator it =
195       user_id_hash_window_list_map_.find(user_id_hash);
196   if (it == user_id_hash_window_list_map_.end()) {
197     DCHECK(false) << "This should only be called after calling "
198                   << "MinimizeInactiveWindows.";
199     return;
200   }
201
202   std::set<aura::Window*> removed_windows;
203   removed_windows.swap(it->second);
204   user_id_hash_window_list_map_.erase(it);
205
206   for (std::set<aura::Window*>::iterator iter = removed_windows.begin();
207        iter != removed_windows.end(); ++iter) {
208     ash::wm::GetWindowState(*iter)->Unminimize();
209     RemoveObserverIfUnreferenced(*iter);
210   }
211 }
212
213 void WindowStateManager::RemoveObserverIfUnreferenced(aura::Window* window) {
214   for (UserIDHashWindowListMap::iterator iter =
215            user_id_hash_window_list_map_.begin();
216        iter != user_id_hash_window_list_map_.end();
217        ++iter) {
218     if (iter->second.find(window) != iter->second.end())
219       return;
220   }
221   // Remove observer if |window| is not observed by any users.
222   window->RemoveObserver(this);
223 }
224
225 void WindowStateManager::OnWindowDestroyed(aura::Window* window) {
226   for (UserIDHashWindowListMap::iterator iter =
227            user_id_hash_window_list_map_.begin();
228        iter != user_id_hash_window_list_map_.end();
229        ++iter) {
230     iter->second.erase(window);
231   }
232 }
233
234 }  // namespace
235
236 bool WallpaperPrivateGetStringsFunction::RunSync() {
237   base::DictionaryValue* dict = new base::DictionaryValue();
238   SetResult(dict);
239
240 #define SET_STRING(id, idr) \
241   dict->SetString(id, l10n_util::GetStringUTF16(idr))
242   SET_STRING("webFontFamily", IDS_WEB_FONT_FAMILY);
243   SET_STRING("webFontSize", IDS_WEB_FONT_SIZE);
244   SET_STRING("allCategoryLabel", IDS_WALLPAPER_MANAGER_ALL_CATEGORY_LABEL);
245   SET_STRING("deleteCommandLabel", IDS_WALLPAPER_MANAGER_DELETE_COMMAND_LABEL);
246   SET_STRING("customCategoryLabel",
247              IDS_WALLPAPER_MANAGER_CUSTOM_CATEGORY_LABEL);
248   SET_STRING("selectCustomLabel",
249              IDS_WALLPAPER_MANAGER_SELECT_CUSTOM_LABEL);
250   SET_STRING("positionLabel", IDS_WALLPAPER_MANAGER_POSITION_LABEL);
251   SET_STRING("colorLabel", IDS_WALLPAPER_MANAGER_COLOR_LABEL);
252   SET_STRING("centerCroppedLayout",
253              IDS_OPTIONS_WALLPAPER_CENTER_CROPPED_LAYOUT);
254   SET_STRING("centerLayout", IDS_OPTIONS_WALLPAPER_CENTER_LAYOUT);
255   SET_STRING("stretchLayout", IDS_OPTIONS_WALLPAPER_STRETCH_LAYOUT);
256   SET_STRING("connectionFailed", IDS_WALLPAPER_MANAGER_ACCESS_FAIL);
257   SET_STRING("downloadFailed", IDS_WALLPAPER_MANAGER_DOWNLOAD_FAIL);
258   SET_STRING("downloadCanceled", IDS_WALLPAPER_MANAGER_DOWNLOAD_CANCEL);
259   SET_STRING("customWallpaperWarning",
260              IDS_WALLPAPER_MANAGER_SHOW_CUSTOM_WALLPAPER_ON_START_WARNING);
261   SET_STRING("accessFileFailure", IDS_WALLPAPER_MANAGER_ACCESS_FILE_FAILURE);
262   SET_STRING("invalidWallpaper", IDS_WALLPAPER_MANAGER_INVALID_WALLPAPER);
263   SET_STRING("surpriseMeLabel", IDS_WALLPAPER_MANAGER_SURPRISE_ME_LABEL);
264   SET_STRING("learnMore", IDS_LEARN_MORE);
265   SET_STRING("currentWallpaperSetByMessage",
266              IDS_CURRENT_WALLPAPER_SET_BY_MESSAGE);
267 #undef SET_STRING
268
269   webui::SetFontAndTextDirection(dict);
270
271   chromeos::WallpaperManager* wallpaper_manager =
272       chromeos::WallpaperManager::Get();
273   chromeos::WallpaperInfo info;
274
275   if (wallpaper_manager->GetLoggedInUserWallpaperInfo(&info))
276     dict->SetString("currentWallpaper", info.location);
277
278 #if defined(GOOGLE_CHROME_BUILD)
279   dict->SetString("manifestBaseURL", kWallpaperManifestBaseURL);
280 #endif
281
282   Profile* profile = Profile::FromBrowserContext(browser_context());
283   std::string app_name(
284       profile->GetPrefs()->GetString(prefs::kCurrentWallpaperAppName));
285   if (!app_name.empty())
286     dict->SetString("wallpaperAppName", app_name);
287
288   dict->SetBoolean("isOEMDefaultWallpaper", IsOEMDefaultWallpaper());
289   dict->SetString("canceledWallpaper",
290                   wallpaper_api_util::kCancelWallpaperMessage);
291   return true;
292 }
293
294 WallpaperPrivateSetWallpaperIfExistsFunction::
295     WallpaperPrivateSetWallpaperIfExistsFunction() {}
296
297 WallpaperPrivateSetWallpaperIfExistsFunction::
298     ~WallpaperPrivateSetWallpaperIfExistsFunction() {}
299
300 bool WallpaperPrivateSetWallpaperIfExistsFunction::RunAsync() {
301   params = set_wallpaper_if_exists::Params::Create(*args_);
302   EXTENSION_FUNCTION_VALIDATE(params);
303
304   user_id_ = user_manager::UserManager::Get()->GetActiveUser()->email();
305
306   base::FilePath wallpaper_path;
307   base::FilePath fallback_path;
308   chromeos::WallpaperManager::WallpaperResolution resolution =
309       chromeos::WallpaperManager::GetAppropriateResolution();
310
311   std::string file_name = GURL(params->url).ExtractFileName();
312   CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS,
313                          &wallpaper_path));
314   fallback_path = wallpaper_path.Append(file_name);
315   if (params->layout != wallpaper_private::WALLPAPER_LAYOUT_STRETCH &&
316       resolution == chromeos::WallpaperManager::WALLPAPER_RESOLUTION_SMALL) {
317     file_name = base::FilePath(file_name).InsertBeforeExtension(
318         chromeos::kSmallWallpaperSuffix).value();
319   }
320   wallpaper_path = wallpaper_path.Append(file_name);
321
322   sequence_token_ = BrowserThread::GetBlockingPool()->
323       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
324   scoped_refptr<base::SequencedTaskRunner> task_runner =
325       BrowserThread::GetBlockingPool()->
326           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
327               base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
328
329   task_runner->PostTask(FROM_HERE,
330       base::Bind(
331           &WallpaperPrivateSetWallpaperIfExistsFunction::
332               ReadFileAndInitiateStartDecode,
333           this, wallpaper_path, fallback_path));
334   return true;
335 }
336
337 void WallpaperPrivateSetWallpaperIfExistsFunction::
338     ReadFileAndInitiateStartDecode(const base::FilePath& file_path,
339                                    const base::FilePath& fallback_path) {
340   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
341       sequence_token_));
342   std::string data;
343   base::FilePath path = file_path;
344
345   if (!base::PathExists(file_path))
346     path = fallback_path;
347
348   if (base::PathExists(path) &&
349       base::ReadFileToString(path, &data)) {
350     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
351         base::Bind(&WallpaperPrivateSetWallpaperIfExistsFunction::StartDecode,
352                    this, data));
353     return;
354   }
355   std::string error = base::StringPrintf(
356         "Failed to set wallpaper %s from file system.",
357         path.BaseName().value().c_str());
358   BrowserThread::PostTask(
359       BrowserThread::UI, FROM_HERE,
360       base::Bind(&WallpaperPrivateSetWallpaperIfExistsFunction::OnFileNotExists,
361                  this, error));
362 }
363
364 void WallpaperPrivateSetWallpaperIfExistsFunction::OnWallpaperDecoded(
365     const gfx::ImageSkia& image) {
366   // Set unsafe_wallpaper_decoder_ to null since the decoding already finished.
367   unsafe_wallpaper_decoder_ = NULL;
368
369   chromeos::WallpaperManager* wallpaper_manager =
370       chromeos::WallpaperManager::Get();
371   ash::WallpaperLayout layout = wallpaper_api_util::GetLayoutEnum(
372       wallpaper_private::ToString(params->layout));
373
374   bool update_wallpaper =
375       user_id_ == user_manager::UserManager::Get()->GetActiveUser()->email();
376   wallpaper_manager->SetWallpaperFromImageSkia(
377       user_id_, image, layout, update_wallpaper);
378   bool is_persistent = !user_manager::UserManager::Get()
379                             ->IsCurrentUserNonCryptohomeDataEphemeral();
380   chromeos::WallpaperInfo info = {params->url, layout,
381                                   user_manager::User::ONLINE,
382                                   base::Time::Now().LocalMidnight()};
383   wallpaper_manager->SetUserWallpaperInfo(user_id_, info, is_persistent);
384   SetResult(new base::FundamentalValue(true));
385   Profile* profile = Profile::FromBrowserContext(browser_context());
386   // This API is only available to the component wallpaper picker. We do not
387   // need to show the app's name if it is the component wallpaper picker. So set
388   // the pref to empty string.
389   profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
390                                  std::string());
391   SendResponse(true);
392 }
393
394 void WallpaperPrivateSetWallpaperIfExistsFunction::OnFileNotExists(
395     const std::string& error) {
396   SetResult(new base::FundamentalValue(false));
397   OnFailure(error);
398 }
399
400 WallpaperPrivateSetWallpaperFunction::WallpaperPrivateSetWallpaperFunction() {
401 }
402
403 WallpaperPrivateSetWallpaperFunction::~WallpaperPrivateSetWallpaperFunction() {
404 }
405
406 bool WallpaperPrivateSetWallpaperFunction::RunAsync() {
407   params = set_wallpaper::Params::Create(*args_);
408   EXTENSION_FUNCTION_VALIDATE(params);
409
410   // Gets email address while at UI thread.
411   user_id_ = user_manager::UserManager::Get()->GetActiveUser()->email();
412
413   StartDecode(params->wallpaper);
414
415   return true;
416 }
417
418 void WallpaperPrivateSetWallpaperFunction::OnWallpaperDecoded(
419     const gfx::ImageSkia& image) {
420   wallpaper_ = image;
421   // Set unsafe_wallpaper_decoder_ to null since the decoding already finished.
422   unsafe_wallpaper_decoder_ = NULL;
423
424   sequence_token_ = BrowserThread::GetBlockingPool()->
425       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
426   scoped_refptr<base::SequencedTaskRunner> task_runner =
427       BrowserThread::GetBlockingPool()->
428           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
429               base::SequencedWorkerPool::BLOCK_SHUTDOWN);
430
431   task_runner->PostTask(FROM_HERE,
432       base::Bind(&WallpaperPrivateSetWallpaperFunction::SaveToFile, this));
433 }
434
435 void WallpaperPrivateSetWallpaperFunction::SaveToFile() {
436   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
437       sequence_token_));
438   std::string file_name = GURL(params->url).ExtractFileName();
439   if (SaveData(chrome::DIR_CHROMEOS_WALLPAPERS, file_name, params->wallpaper)) {
440     wallpaper_.EnsureRepsForSupportedScales();
441     scoped_ptr<gfx::ImageSkia> deep_copy(wallpaper_.DeepCopy());
442     // ImageSkia is not RefCountedThreadSafe. Use a deep copied ImageSkia if
443     // post to another thread.
444     BrowserThread::PostTask(
445         BrowserThread::UI,
446         FROM_HERE,
447         base::Bind(&WallpaperPrivateSetWallpaperFunction::SetDecodedWallpaper,
448                    this,
449                    base::Passed(deep_copy.Pass())));
450
451     base::FilePath wallpaper_dir;
452     CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
453     base::FilePath file_path = wallpaper_dir.Append(
454         file_name).InsertBeforeExtension(chromeos::kSmallWallpaperSuffix);
455     if (base::PathExists(file_path))
456       return;
457     // Generates and saves small resolution wallpaper. Uses CENTER_CROPPED to
458     // maintain the aspect ratio after resize.
459     chromeos::WallpaperManager::Get()->ResizeAndSaveWallpaper(
460         wallpaper_,
461         file_path,
462         ash::WALLPAPER_LAYOUT_CENTER_CROPPED,
463         chromeos::kSmallWallpaperMaxWidth,
464         chromeos::kSmallWallpaperMaxHeight,
465         NULL);
466   } else {
467     std::string error = base::StringPrintf(
468         "Failed to create/write wallpaper to %s.", file_name.c_str());
469     BrowserThread::PostTask(
470         BrowserThread::UI, FROM_HERE,
471         base::Bind(&WallpaperPrivateSetWallpaperFunction::OnFailure,
472                    this, error));
473   }
474 }
475
476 void WallpaperPrivateSetWallpaperFunction::SetDecodedWallpaper(
477     scoped_ptr<gfx::ImageSkia> image) {
478   chromeos::WallpaperManager* wallpaper_manager =
479       chromeos::WallpaperManager::Get();
480
481   ash::WallpaperLayout layout = wallpaper_api_util::GetLayoutEnum(
482       wallpaper_private::ToString(params->layout));
483
484   bool update_wallpaper =
485       user_id_ == user_manager::UserManager::Get()->GetActiveUser()->email();
486   wallpaper_manager->SetWallpaperFromImageSkia(
487       user_id_, *image.get(), layout, update_wallpaper);
488
489   bool is_persistent = !user_manager::UserManager::Get()
490                             ->IsCurrentUserNonCryptohomeDataEphemeral();
491   chromeos::WallpaperInfo info = {params->url, layout,
492                                   user_manager::User::ONLINE,
493                                   base::Time::Now().LocalMidnight()};
494   Profile* profile = Profile::FromBrowserContext(browser_context());
495   // This API is only available to the component wallpaper picker. We do not
496   // need to show the app's name if it is the component wallpaper picker. So set
497   // the pref to empty string.
498   profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
499                                  std::string());
500   wallpaper_manager->SetUserWallpaperInfo(user_id_, info, is_persistent);
501   SendResponse(true);
502 }
503
504 WallpaperPrivateResetWallpaperFunction::
505     WallpaperPrivateResetWallpaperFunction() {}
506
507 WallpaperPrivateResetWallpaperFunction::
508     ~WallpaperPrivateResetWallpaperFunction() {}
509
510 bool WallpaperPrivateResetWallpaperFunction::RunAsync() {
511   chromeos::WallpaperManager* wallpaper_manager =
512       chromeos::WallpaperManager::Get();
513   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
514
515   std::string user_id = user_manager->GetActiveUser()->email();
516   wallpaper_manager->RemoveUserWallpaperInfo(user_id);
517
518   chromeos::WallpaperInfo info = {std::string(),
519                                   ash::WALLPAPER_LAYOUT_CENTER,
520                                   user_manager::User::DEFAULT,
521                                   base::Time::Now().LocalMidnight()};
522   bool is_persistent =
523       !user_manager->IsCurrentUserNonCryptohomeDataEphemeral();
524   wallpaper_manager->SetUserWallpaperInfo(user_id, info, is_persistent);
525
526   wallpaper_manager->SetDefaultWallpaperNow(user_id);
527   Profile* profile = Profile::FromBrowserContext(browser_context());
528   // This API is only available to the component wallpaper picker. We do not
529   // need to show the app's name if it is the component wallpaper picker. So set
530   // the pref to empty string.
531   profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
532                                  std::string());
533   return true;
534 }
535
536 WallpaperPrivateSetCustomWallpaperFunction::
537     WallpaperPrivateSetCustomWallpaperFunction() {}
538
539 WallpaperPrivateSetCustomWallpaperFunction::
540     ~WallpaperPrivateSetCustomWallpaperFunction() {}
541
542 bool WallpaperPrivateSetCustomWallpaperFunction::RunAsync() {
543   params = set_custom_wallpaper::Params::Create(*args_);
544   EXTENSION_FUNCTION_VALIDATE(params);
545
546   // Gets email address and username hash while at UI thread.
547   user_id_ = user_manager::UserManager::Get()->GetActiveUser()->email();
548   user_id_hash_ =
549       user_manager::UserManager::Get()->GetActiveUser()->username_hash();
550
551   StartDecode(params->wallpaper);
552
553   return true;
554 }
555
556 void WallpaperPrivateSetCustomWallpaperFunction::OnWallpaperDecoded(
557     const gfx::ImageSkia& image) {
558   chromeos::WallpaperManager* wallpaper_manager =
559       chromeos::WallpaperManager::Get();
560   base::FilePath thumbnail_path = wallpaper_manager->GetCustomWallpaperPath(
561       chromeos::kThumbnailWallpaperSubDir, user_id_hash_, params->file_name);
562
563   sequence_token_ = BrowserThread::GetBlockingPool()->
564       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
565   scoped_refptr<base::SequencedTaskRunner> task_runner =
566       BrowserThread::GetBlockingPool()->
567           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
568               base::SequencedWorkerPool::BLOCK_SHUTDOWN);
569
570   ash::WallpaperLayout layout = wallpaper_api_util::GetLayoutEnum(
571       wallpaper_private::ToString(params->layout));
572
573   bool update_wallpaper =
574       user_id_ == user_manager::UserManager::Get()->GetActiveUser()->email();
575   wallpaper_manager->SetCustomWallpaper(user_id_,
576                                         user_id_hash_,
577                                         params->file_name,
578                                         layout,
579                                         user_manager::User::CUSTOMIZED,
580                                         image,
581                                         update_wallpaper);
582   unsafe_wallpaper_decoder_ = NULL;
583
584   Profile* profile = Profile::FromBrowserContext(browser_context());
585   // This API is only available to the component wallpaper picker. We do not
586   // need to show the app's name if it is the component wallpaper picker. So set
587   // the pref to empty string.
588   profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName,
589                                  std::string());
590
591   if (params->generate_thumbnail) {
592     image.EnsureRepsForSupportedScales();
593     scoped_ptr<gfx::ImageSkia> deep_copy(image.DeepCopy());
594     // Generates thumbnail before call api function callback. We can then
595     // request thumbnail in the javascript callback.
596     task_runner->PostTask(FROM_HERE,
597         base::Bind(
598             &WallpaperPrivateSetCustomWallpaperFunction::GenerateThumbnail,
599             this, thumbnail_path, base::Passed(&deep_copy)));
600   } else {
601     SendResponse(true);
602   }
603 }
604
605 void WallpaperPrivateSetCustomWallpaperFunction::GenerateThumbnail(
606     const base::FilePath& thumbnail_path, scoped_ptr<gfx::ImageSkia> image) {
607   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
608       sequence_token_));
609   if (!base::PathExists(thumbnail_path.DirName()))
610     base::CreateDirectory(thumbnail_path.DirName());
611
612   scoped_refptr<base::RefCountedBytes> data;
613   chromeos::WallpaperManager::Get()->ResizeImage(
614       *image,
615       ash::WALLPAPER_LAYOUT_STRETCH,
616       chromeos::kWallpaperThumbnailWidth,
617       chromeos::kWallpaperThumbnailHeight,
618       &data,
619       NULL);
620   BrowserThread::PostTask(
621         BrowserThread::UI, FROM_HERE,
622         base::Bind(
623             &WallpaperPrivateSetCustomWallpaperFunction::ThumbnailGenerated,
624             this, data));
625 }
626
627 void WallpaperPrivateSetCustomWallpaperFunction::ThumbnailGenerated(
628     base::RefCountedBytes* data) {
629   BinaryValue* result = BinaryValue::CreateWithCopiedBuffer(
630       reinterpret_cast<const char*>(data->front()), data->size());
631   SetResult(result);
632   SendResponse(true);
633 }
634
635 WallpaperPrivateSetCustomWallpaperLayoutFunction::
636     WallpaperPrivateSetCustomWallpaperLayoutFunction() {}
637
638 WallpaperPrivateSetCustomWallpaperLayoutFunction::
639     ~WallpaperPrivateSetCustomWallpaperLayoutFunction() {}
640
641 bool WallpaperPrivateSetCustomWallpaperLayoutFunction::RunAsync() {
642   scoped_ptr<set_custom_wallpaper_layout::Params> params(
643       set_custom_wallpaper_layout::Params::Create(*args_));
644   EXTENSION_FUNCTION_VALIDATE(params);
645
646   chromeos::WallpaperManager* wallpaper_manager =
647       chromeos::WallpaperManager::Get();
648   chromeos::WallpaperInfo info;
649   wallpaper_manager->GetLoggedInUserWallpaperInfo(&info);
650   if (info.type != user_manager::User::CUSTOMIZED) {
651     SetError("Only custom wallpaper can change layout.");
652     SendResponse(false);
653     return false;
654   }
655   info.layout = wallpaper_api_util::GetLayoutEnum(
656       wallpaper_private::ToString(params->layout));
657
658   std::string email =
659       user_manager::UserManager::Get()->GetActiveUser()->email();
660   bool is_persistent = !user_manager::UserManager::Get()
661                             ->IsCurrentUserNonCryptohomeDataEphemeral();
662   wallpaper_manager->SetUserWallpaperInfo(email, info, is_persistent);
663   wallpaper_manager->UpdateWallpaper(false /* clear_cache */);
664   SendResponse(true);
665
666   // Gets email address while at UI thread.
667   return true;
668 }
669
670 WallpaperPrivateMinimizeInactiveWindowsFunction::
671     WallpaperPrivateMinimizeInactiveWindowsFunction() {
672 }
673
674 WallpaperPrivateMinimizeInactiveWindowsFunction::
675     ~WallpaperPrivateMinimizeInactiveWindowsFunction() {
676 }
677
678 bool WallpaperPrivateMinimizeInactiveWindowsFunction::RunAsync() {
679   WindowStateManager::MinimizeInactiveWindows(
680       user_manager::UserManager::Get()->GetActiveUser()->username_hash());
681   return true;
682 }
683
684 WallpaperPrivateRestoreMinimizedWindowsFunction::
685     WallpaperPrivateRestoreMinimizedWindowsFunction() {
686 }
687
688 WallpaperPrivateRestoreMinimizedWindowsFunction::
689     ~WallpaperPrivateRestoreMinimizedWindowsFunction() {
690 }
691
692 bool WallpaperPrivateRestoreMinimizedWindowsFunction::RunAsync() {
693   WindowStateManager::RestoreWindows(
694       user_manager::UserManager::Get()->GetActiveUser()->username_hash());
695   return true;
696 }
697
698 WallpaperPrivateGetThumbnailFunction::WallpaperPrivateGetThumbnailFunction() {
699 }
700
701 WallpaperPrivateGetThumbnailFunction::~WallpaperPrivateGetThumbnailFunction() {
702 }
703
704 bool WallpaperPrivateGetThumbnailFunction::RunAsync() {
705   scoped_ptr<get_thumbnail::Params> params(
706       get_thumbnail::Params::Create(*args_));
707   EXTENSION_FUNCTION_VALIDATE(params);
708
709   base::FilePath thumbnail_path;
710   std::string email =
711       user_manager::UserManager::Get()->GetActiveUser()->email();
712   if (params->source == get_thumbnail::Params::SOURCE_ONLINE) {
713     std::string file_name = GURL(params->url_or_file).ExtractFileName();
714     CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPER_THUMBNAILS,
715                            &thumbnail_path));
716     thumbnail_path = thumbnail_path.Append(file_name);
717   } else {
718     if (!IsOEMDefaultWallpaper()) {
719       SetError("No OEM wallpaper.");
720       SendResponse(false);
721       return false;
722     }
723
724     // TODO(bshe): Small resolution wallpaper is used here as wallpaper
725     // thumbnail. We should either resize it or include a wallpaper thumbnail in
726     // addition to large and small wallpaper resolutions.
727     thumbnail_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
728         ash::switches::kAshDefaultWallpaperSmall);
729   }
730
731   sequence_token_ = BrowserThread::GetBlockingPool()->
732       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
733   scoped_refptr<base::SequencedTaskRunner> task_runner =
734       BrowserThread::GetBlockingPool()->
735           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
736               base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
737
738   task_runner->PostTask(FROM_HERE,
739       base::Bind(&WallpaperPrivateGetThumbnailFunction::Get, this,
740                  thumbnail_path));
741   return true;
742 }
743
744 void WallpaperPrivateGetThumbnailFunction::Failure(
745     const std::string& file_name) {
746   SetError(base::StringPrintf("Failed to access wallpaper thumbnails for %s.",
747                               file_name.c_str()));
748   SendResponse(false);
749 }
750
751 void WallpaperPrivateGetThumbnailFunction::FileNotLoaded() {
752   SendResponse(true);
753 }
754
755 void WallpaperPrivateGetThumbnailFunction::FileLoaded(
756     const std::string& data) {
757   BinaryValue* thumbnail = BinaryValue::CreateWithCopiedBuffer(data.c_str(),
758                                                                data.size());
759   SetResult(thumbnail);
760   SendResponse(true);
761 }
762
763 void WallpaperPrivateGetThumbnailFunction::Get(const base::FilePath& path) {
764   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
765       sequence_token_));
766   std::string data;
767   if (GetData(path, &data)) {
768     if (data.empty()) {
769       BrowserThread::PostTask(
770         BrowserThread::UI, FROM_HERE,
771         base::Bind(&WallpaperPrivateGetThumbnailFunction::FileNotLoaded, this));
772     } else {
773       BrowserThread::PostTask(
774         BrowserThread::UI, FROM_HERE,
775         base::Bind(&WallpaperPrivateGetThumbnailFunction::FileLoaded, this,
776                    data));
777     }
778   } else {
779     BrowserThread::PostTask(
780         BrowserThread::UI, FROM_HERE,
781         base::Bind(&WallpaperPrivateGetThumbnailFunction::Failure, this,
782                    path.BaseName().value()));
783   }
784 }
785
786 WallpaperPrivateSaveThumbnailFunction::WallpaperPrivateSaveThumbnailFunction() {
787 }
788
789 WallpaperPrivateSaveThumbnailFunction::
790     ~WallpaperPrivateSaveThumbnailFunction() {}
791
792 bool WallpaperPrivateSaveThumbnailFunction::RunAsync() {
793   scoped_ptr<save_thumbnail::Params> params(
794       save_thumbnail::Params::Create(*args_));
795   EXTENSION_FUNCTION_VALIDATE(params);
796
797   sequence_token_ = BrowserThread::GetBlockingPool()->
798       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
799   scoped_refptr<base::SequencedTaskRunner> task_runner =
800       BrowserThread::GetBlockingPool()->
801           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
802               base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
803
804   task_runner->PostTask(FROM_HERE,
805       base::Bind(&WallpaperPrivateSaveThumbnailFunction::Save,
806                  this, params->data, GURL(params->url).ExtractFileName()));
807   return true;
808 }
809
810 void WallpaperPrivateSaveThumbnailFunction::Failure(
811     const std::string& file_name) {
812   SetError(base::StringPrintf("Failed to create/write thumbnail of %s.",
813                               file_name.c_str()));
814   SendResponse(false);
815 }
816
817 void WallpaperPrivateSaveThumbnailFunction::Success() {
818   SendResponse(true);
819 }
820
821 void WallpaperPrivateSaveThumbnailFunction::Save(const std::string& data,
822                                           const std::string& file_name) {
823   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
824       sequence_token_));
825   if (SaveData(chrome::DIR_CHROMEOS_WALLPAPER_THUMBNAILS, file_name, data)) {
826     BrowserThread::PostTask(
827       BrowserThread::UI, FROM_HERE,
828       base::Bind(&WallpaperPrivateSaveThumbnailFunction::Success, this));
829   } else {
830     BrowserThread::PostTask(
831           BrowserThread::UI, FROM_HERE,
832           base::Bind(&WallpaperPrivateSaveThumbnailFunction::Failure,
833                      this, file_name));
834   }
835 }
836
837 WallpaperPrivateGetOfflineWallpaperListFunction::
838     WallpaperPrivateGetOfflineWallpaperListFunction() {
839 }
840
841 WallpaperPrivateGetOfflineWallpaperListFunction::
842     ~WallpaperPrivateGetOfflineWallpaperListFunction() {
843 }
844
845 bool WallpaperPrivateGetOfflineWallpaperListFunction::RunAsync() {
846   sequence_token_ = BrowserThread::GetBlockingPool()->
847       GetNamedSequenceToken(chromeos::kWallpaperSequenceTokenName);
848   scoped_refptr<base::SequencedTaskRunner> task_runner =
849       BrowserThread::GetBlockingPool()->
850           GetSequencedTaskRunnerWithShutdownBehavior(sequence_token_,
851               base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
852
853   task_runner->PostTask(FROM_HERE,
854       base::Bind(&WallpaperPrivateGetOfflineWallpaperListFunction::GetList,
855                  this));
856   return true;
857 }
858
859 void WallpaperPrivateGetOfflineWallpaperListFunction::GetList() {
860   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
861       sequence_token_));
862   std::vector<std::string> file_list;
863   base::FilePath wallpaper_dir;
864   CHECK(PathService::Get(chrome::DIR_CHROMEOS_WALLPAPERS, &wallpaper_dir));
865   if (base::DirectoryExists(wallpaper_dir)) {
866     base::FileEnumerator files(wallpaper_dir, false,
867                                base::FileEnumerator::FILES);
868     for (base::FilePath current = files.Next(); !current.empty();
869          current = files.Next()) {
870       std::string file_name = current.BaseName().RemoveExtension().value();
871       // Do not add file name of small resolution wallpaper to the list.
872       if (!EndsWith(file_name, chromeos::kSmallWallpaperSuffix, true))
873         file_list.push_back(current.BaseName().value());
874     }
875   }
876   BrowserThread::PostTask(
877       BrowserThread::UI, FROM_HERE,
878       base::Bind(&WallpaperPrivateGetOfflineWallpaperListFunction::OnComplete,
879                  this, file_list));
880 }
881
882 void WallpaperPrivateGetOfflineWallpaperListFunction::OnComplete(
883     const std::vector<std::string>& file_list) {
884   base::ListValue* results = new base::ListValue();
885   results->AppendStrings(file_list);
886   SetResult(results);
887   SendResponse(true);
888 }