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