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 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. 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. 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 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 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 162 WindowStateManager::WindowStateManager() {} 163 164 WindowStateManager::~WindowStateManager() {} 165 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 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 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 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 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:: 296 WallpaperPrivateSetWallpaperIfExistsFunction() {} 297 298 WallpaperPrivateSetWallpaperIfExistsFunction:: 299 ~WallpaperPrivateSetWallpaperIfExistsFunction() {} 300 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:: 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 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 398 void WallpaperPrivateSetWallpaperIfExistsFunction::OnFileNotExists( 399 const std::string& error) { 400 SetResult(base::Value::CreateBooleanValue(false)); 401 OnFailure(error); 402 } 403 404 WallpaperPrivateSetWallpaperFunction::WallpaperPrivateSetWallpaperFunction() { 405 } 406 407 WallpaperPrivateSetWallpaperFunction::~WallpaperPrivateSetWallpaperFunction() { 408 } 409 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 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 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 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:: 512 WallpaperPrivateResetWallpaperFunction() {} 513 514 WallpaperPrivateResetWallpaperFunction:: 515 ~WallpaperPrivateResetWallpaperFunction() {} 516 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:: 546 WallpaperPrivateSetCustomWallpaperFunction() {} 547 548 WallpaperPrivateSetCustomWallpaperFunction:: 549 ~WallpaperPrivateSetCustomWallpaperFunction() {} 550 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 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 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 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:: 645 WallpaperPrivateSetCustomWallpaperLayoutFunction() {} 646 647 WallpaperPrivateSetCustomWallpaperLayoutFunction:: 648 ~WallpaperPrivateSetCustomWallpaperLayoutFunction() {} 649 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:: 679 WallpaperPrivateMinimizeInactiveWindowsFunction() { 680 } 681 682 WallpaperPrivateMinimizeInactiveWindowsFunction:: 683 ~WallpaperPrivateMinimizeInactiveWindowsFunction() { 684 } 685 686 bool WallpaperPrivateMinimizeInactiveWindowsFunction::RunAsync() { 687 WindowStateManager::MinimizeInactiveWindows( 688 chromeos::UserManager::Get()->GetActiveUser()->username_hash()); 689 return true; 690 } 691 692 WallpaperPrivateRestoreMinimizedWindowsFunction:: 693 WallpaperPrivateRestoreMinimizedWindowsFunction() { 694 } 695 696 WallpaperPrivateRestoreMinimizedWindowsFunction:: 697 ~WallpaperPrivateRestoreMinimizedWindowsFunction() { 698 } 699 700 bool WallpaperPrivateRestoreMinimizedWindowsFunction::RunAsync() { 701 WindowStateManager::RestoreWindows( 702 chromeos::UserManager::Get()->GetActiveUser()->username_hash()); 703 return true; 704 } 705 706 WallpaperPrivateGetThumbnailFunction::WallpaperPrivateGetThumbnailFunction() { 707 } 708 709 WallpaperPrivateGetThumbnailFunction::~WallpaperPrivateGetThumbnailFunction() { 710 } 711 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 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 758 void WallpaperPrivateGetThumbnailFunction::FileNotLoaded() { 759 SendResponse(true); 760 } 761 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 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 793 WallpaperPrivateSaveThumbnailFunction::WallpaperPrivateSaveThumbnailFunction() { 794 } 795 796 WallpaperPrivateSaveThumbnailFunction:: 797 ~WallpaperPrivateSaveThumbnailFunction() {} 798 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 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 824 void WallpaperPrivateSaveThumbnailFunction::Success() { 825 SendResponse(true); 826 } 827 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:: 845 WallpaperPrivateGetOfflineWallpaperListFunction() { 846 } 847 848 WallpaperPrivateGetOfflineWallpaperListFunction:: 849 ~WallpaperPrivateGetOfflineWallpaperListFunction() { 850 } 851 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 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 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