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