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