OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "ash/common/wallpaper/wallpaper_controller.h" | |
6 | |
7 #include <string> | |
8 #include <utility> | |
9 | |
10 #include "ash/common/ash_switches.h" | |
11 #include "ash/common/wallpaper/wallpaper_controller_observer.h" | |
12 #include "ash/common/wallpaper/wallpaper_delegate.h" | |
13 #include "ash/common/wallpaper/wallpaper_view.h" | |
14 #include "ash/common/wallpaper/wallpaper_widget_controller.h" | |
15 #include "ash/common/wm_shell.h" | |
16 #include "ash/common/wm_window.h" | |
17 #include "ash/public/cpp/shell_window_ids.h" | |
18 #include "ash/root_window_controller.h" | |
19 #include "base/bind.h" | |
20 #include "base/command_line.h" | |
21 #include "base/logging.h" | |
22 #include "base/task_runner.h" | |
23 #include "components/wallpaper/wallpaper_color_calculator.h" | |
24 #include "components/wallpaper/wallpaper_resizer.h" | |
25 #include "ui/display/manager/managed_display_info.h" | |
26 #include "ui/display/screen.h" | |
27 #include "ui/gfx/color_analysis.h" | |
28 #include "ui/views/widget/widget.h" | |
29 | |
30 namespace ash { | |
31 | |
32 namespace { | |
33 | |
34 // How long to wait reloading the wallpaper after the display size has changed. | |
35 const int kWallpaperReloadDelayMs = 100; | |
36 | |
37 } // namespace | |
38 | |
39 // static | |
40 bool WallpaperController::GetProminentColorProfile( | |
41 color_utils::LumaRange* luma, | |
42 color_utils::SaturationRange* saturation) { | |
43 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | |
44 switches::kAshShelfColor)) { | |
45 return false; | |
46 } | |
47 | |
48 *luma = color_utils::LumaRange::NORMAL; | |
49 *saturation = color_utils::SaturationRange::VIBRANT; | |
50 | |
51 const std::string switch_value = | |
52 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
53 switches::kAshShelfColor); | |
54 if (switch_value.find("light") != std::string::npos) | |
55 *luma = color_utils::LumaRange::LIGHT; | |
56 else if (switch_value.find("normal") != std::string::npos) | |
57 *luma = color_utils::LumaRange::NORMAL; | |
58 else if (switch_value.find("dark") != std::string::npos) | |
59 *luma = color_utils::LumaRange::DARK; | |
60 | |
61 if (switch_value.find("vibrant") != std::string::npos) | |
62 *saturation = color_utils::SaturationRange::VIBRANT; | |
63 else if (switch_value.find("muted") != std::string::npos) | |
64 *saturation = color_utils::SaturationRange::MUTED; | |
65 | |
66 return true; | |
67 } | |
68 | |
69 WallpaperController::WallpaperController( | |
70 const scoped_refptr<base::TaskRunner>& task_runner) | |
71 : locked_(false), | |
72 wallpaper_mode_(WALLPAPER_NONE), | |
73 prominent_color_(SK_ColorTRANSPARENT), | |
74 wallpaper_reload_delay_(kWallpaperReloadDelayMs), | |
75 task_runner_(task_runner) { | |
76 WmShell::Get()->AddDisplayObserver(this); | |
77 WmShell::Get()->AddShellObserver(this); | |
78 } | |
79 | |
80 WallpaperController::~WallpaperController() { | |
81 if (current_wallpaper_) | |
82 current_wallpaper_->RemoveObserver(this); | |
83 if (color_calculator_) | |
84 color_calculator_->RemoveObserver(this); | |
85 WmShell::Get()->RemoveDisplayObserver(this); | |
86 WmShell::Get()->RemoveShellObserver(this); | |
87 } | |
88 | |
89 void WallpaperController::BindRequest( | |
90 mojom::WallpaperControllerRequest request) { | |
91 bindings_.AddBinding(this, std::move(request)); | |
92 } | |
93 | |
94 gfx::ImageSkia WallpaperController::GetWallpaper() const { | |
95 if (current_wallpaper_) | |
96 return current_wallpaper_->image(); | |
97 return gfx::ImageSkia(); | |
98 } | |
99 | |
100 void WallpaperController::AddObserver(WallpaperControllerObserver* observer) { | |
101 observers_.AddObserver(observer); | |
102 } | |
103 | |
104 void WallpaperController::RemoveObserver( | |
105 WallpaperControllerObserver* observer) { | |
106 observers_.RemoveObserver(observer); | |
107 } | |
108 | |
109 wallpaper::WallpaperLayout WallpaperController::GetWallpaperLayout() const { | |
110 if (current_wallpaper_) | |
111 return current_wallpaper_->layout(); | |
112 return wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED; | |
113 } | |
114 | |
115 void WallpaperController::SetWallpaperImage(const gfx::ImageSkia& image, | |
116 wallpaper::WallpaperLayout layout) { | |
117 VLOG(1) << "SetWallpaper: image_id=" | |
118 << wallpaper::WallpaperResizer::GetImageId(image) | |
119 << " layout=" << layout; | |
120 | |
121 if (WallpaperIsAlreadyLoaded(image, true /* compare_layouts */, layout)) { | |
122 VLOG(1) << "Wallpaper is already loaded"; | |
123 return; | |
124 } | |
125 | |
126 current_wallpaper_.reset(new wallpaper::WallpaperResizer( | |
127 image, GetMaxDisplaySizeInNative(), layout, task_runner_)); | |
128 current_wallpaper_->AddObserver(this); | |
129 current_wallpaper_->StartResize(); | |
130 | |
131 for (auto& observer : observers_) | |
132 observer.OnWallpaperDataChanged(); | |
133 wallpaper_mode_ = WALLPAPER_IMAGE; | |
134 InstallDesktopControllerForAllWindows(); | |
135 } | |
136 | |
137 void WallpaperController::CreateEmptyWallpaper() { | |
138 SetProminentColor(SK_ColorTRANSPARENT); | |
139 current_wallpaper_.reset(); | |
140 wallpaper_mode_ = WALLPAPER_IMAGE; | |
141 InstallDesktopControllerForAllWindows(); | |
142 } | |
143 | |
144 bool WallpaperController::MoveToLockedContainer() { | |
145 if (locked_) | |
146 return false; | |
147 locked_ = true; | |
148 return ReparentWallpaper(GetWallpaperContainerId(true)); | |
149 } | |
150 | |
151 bool WallpaperController::MoveToUnlockedContainer() { | |
152 if (!locked_) | |
153 return false; | |
154 locked_ = false; | |
155 return ReparentWallpaper(GetWallpaperContainerId(false)); | |
156 } | |
157 | |
158 void WallpaperController::OnDisplayConfigurationChanged() { | |
159 gfx::Size max_display_size = GetMaxDisplaySizeInNative(); | |
160 if (current_max_display_size_ != max_display_size) { | |
161 current_max_display_size_ = max_display_size; | |
162 if (wallpaper_mode_ == WALLPAPER_IMAGE && current_wallpaper_) { | |
163 timer_.Stop(); | |
164 timer_.Start(FROM_HERE, | |
165 base::TimeDelta::FromMilliseconds(wallpaper_reload_delay_), | |
166 base::Bind(&WallpaperController::UpdateWallpaper, | |
167 base::Unretained(this), false /* clear cache */)); | |
168 } | |
169 } | |
170 } | |
171 | |
172 void WallpaperController::OnRootWindowAdded(WmWindow* root_window) { | |
173 // The wallpaper hasn't been set yet. | |
174 if (wallpaper_mode_ == WALLPAPER_NONE) | |
175 return; | |
176 | |
177 // Handle resolution change for "built-in" images. | |
178 gfx::Size max_display_size = GetMaxDisplaySizeInNative(); | |
179 if (current_max_display_size_ != max_display_size) { | |
180 current_max_display_size_ = max_display_size; | |
181 if (wallpaper_mode_ == WALLPAPER_IMAGE && current_wallpaper_) | |
182 UpdateWallpaper(true /* clear cache */); | |
183 } | |
184 | |
185 InstallDesktopController(root_window); | |
186 } | |
187 | |
188 // static | |
189 gfx::Size WallpaperController::GetMaxDisplaySizeInNative() { | |
190 // Return an empty size for test environments where the screen is null. | |
191 if (!display::Screen::GetScreen()) | |
192 return gfx::Size(); | |
193 | |
194 // Note that |shell| is null when this is called from Chrome running in Mash. | |
195 WmShell* shell = WmShell::Get(); | |
196 | |
197 gfx::Size max; | |
198 for (const auto& display : display::Screen::GetScreen()->GetAllDisplays()) { | |
199 // Use the native size, not ManagedDisplayInfo::size_in_pixel or | |
200 // Display::size. | |
201 // TODO(msw): Avoid using Display::size here; see http://crbug.com/613657. | |
202 gfx::Size size = display.size(); | |
203 if (shell) { | |
204 display::ManagedDisplayInfo info = shell->GetDisplayInfo(display.id()); | |
205 // TODO(mash): Mash returns a fake ManagedDisplayInfo. crbug.com/622480 | |
206 if (info.id() == display.id()) | |
207 size = info.bounds_in_native().size(); | |
208 } | |
209 if (display.rotation() == display::Display::ROTATE_90 || | |
210 display.rotation() == display::Display::ROTATE_270) { | |
211 size = gfx::Size(size.height(), size.width()); | |
212 } | |
213 max.SetToMax(size); | |
214 } | |
215 | |
216 return max; | |
217 } | |
218 | |
219 bool WallpaperController::WallpaperIsAlreadyLoaded( | |
220 const gfx::ImageSkia& image, | |
221 bool compare_layouts, | |
222 wallpaper::WallpaperLayout layout) const { | |
223 if (!current_wallpaper_) | |
224 return false; | |
225 | |
226 // Compare layouts only if necessary. | |
227 if (compare_layouts && layout != current_wallpaper_->layout()) | |
228 return false; | |
229 | |
230 return wallpaper::WallpaperResizer::GetImageId(image) == | |
231 current_wallpaper_->original_image_id(); | |
232 } | |
233 | |
234 void WallpaperController::OpenSetWallpaperPage() { | |
235 if (wallpaper_picker_ && | |
236 WmShell::Get()->wallpaper_delegate()->CanOpenSetWallpaperPage()) { | |
237 wallpaper_picker_->Open(); | |
238 } | |
239 } | |
240 | |
241 void WallpaperController::SetWallpaperPicker(mojom::WallpaperPickerPtr picker) { | |
242 wallpaper_picker_ = std::move(picker); | |
243 } | |
244 | |
245 void WallpaperController::SetWallpaper(const SkBitmap& wallpaper, | |
246 wallpaper::WallpaperLayout layout) { | |
247 if (wallpaper.isNull()) | |
248 return; | |
249 | |
250 SetWallpaperImage(gfx::ImageSkia::CreateFrom1xBitmap(wallpaper), layout); | |
251 } | |
252 | |
253 void WallpaperController::OnWallpaperResized() { | |
254 CalculateWallpaperColors(); | |
255 } | |
256 | |
257 void WallpaperController::OnColorCalculationComplete() { | |
258 const SkColor color = color_calculator_->prominent_color(); | |
259 color_calculator_.reset(); | |
260 SetProminentColor(color); | |
261 } | |
262 | |
263 void WallpaperController::InstallDesktopController(WmWindow* root_window) { | |
264 WallpaperWidgetController* component = nullptr; | |
265 int container_id = GetWallpaperContainerId(locked_); | |
266 | |
267 switch (wallpaper_mode_) { | |
268 case WALLPAPER_IMAGE: { | |
269 component = new WallpaperWidgetController( | |
270 CreateWallpaper(root_window, container_id)); | |
271 break; | |
272 } | |
273 case WALLPAPER_NONE: | |
274 NOTREACHED(); | |
275 return; | |
276 } | |
277 | |
278 RootWindowController* controller = root_window->GetRootWindowController(); | |
279 controller->SetAnimatingWallpaperWidgetController( | |
280 new AnimatingWallpaperWidgetController(component)); | |
281 component->StartAnimating(controller); | |
282 } | |
283 | |
284 void WallpaperController::InstallDesktopControllerForAllWindows() { | |
285 for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) | |
286 InstallDesktopController(root); | |
287 current_max_display_size_ = GetMaxDisplaySizeInNative(); | |
288 } | |
289 | |
290 bool WallpaperController::ReparentWallpaper(int container) { | |
291 bool moved = false; | |
292 for (WmWindow* root_window : WmShell::Get()->GetAllRootWindows()) { | |
293 RootWindowController* root_window_controller = | |
294 root_window->GetRootWindowController(); | |
295 // In the steady state (no animation playing) the wallpaper widget | |
296 // controller exists in the RootWindowController. | |
297 WallpaperWidgetController* wallpaper_widget_controller = | |
298 root_window_controller->wallpaper_widget_controller(); | |
299 if (wallpaper_widget_controller) { | |
300 moved |= wallpaper_widget_controller->Reparent( | |
301 root_window_controller->GetWindow(), container); | |
302 } | |
303 // During wallpaper show animations the controller lives in | |
304 // AnimatingWallpaperWidgetController owned by RootWindowController. | |
305 // NOTE: If an image load happens during a wallpaper show animation there | |
306 // can temporarily be two wallpaper widgets. We must reparent both of them, | |
307 // one above and one here. | |
308 WallpaperWidgetController* animating_controller = | |
309 root_window_controller->animating_wallpaper_widget_controller() | |
310 ? root_window_controller->animating_wallpaper_widget_controller() | |
311 ->GetController(false) | |
312 : nullptr; | |
313 if (animating_controller) { | |
314 moved |= animating_controller->Reparent( | |
315 root_window_controller->GetWindow(), container); | |
316 } | |
317 } | |
318 return moved; | |
319 } | |
320 | |
321 int WallpaperController::GetWallpaperContainerId(bool locked) { | |
322 return locked ? kShellWindowId_LockScreenWallpaperContainer | |
323 : kShellWindowId_WallpaperContainer; | |
324 } | |
325 | |
326 void WallpaperController::UpdateWallpaper(bool clear_cache) { | |
327 current_wallpaper_.reset(); | |
328 WmShell::Get()->wallpaper_delegate()->UpdateWallpaper(clear_cache); | |
329 } | |
330 | |
331 void WallpaperController::SetProminentColor(SkColor color) { | |
332 if (prominent_color_ == color) | |
333 return; | |
334 | |
335 prominent_color_ = color; | |
336 for (auto& observer : observers_) | |
337 observer.OnWallpaperColorsChanged(); | |
338 } | |
339 | |
340 void WallpaperController::CalculateWallpaperColors() { | |
341 color_utils::LumaRange luma; | |
342 color_utils::SaturationRange saturation; | |
343 if (!GetProminentColorProfile(&luma, &saturation)) | |
344 return; | |
345 | |
346 if (color_calculator_) | |
347 color_calculator_->RemoveObserver(this); | |
348 | |
349 color_calculator_ = base::MakeUnique<wallpaper::WallpaperColorCalculator>( | |
350 GetWallpaper(), luma, saturation, task_runner_); | |
351 color_calculator_->AddObserver(this); | |
352 if (!color_calculator_->StartCalculation()) | |
353 SetProminentColor(SK_ColorTRANSPARENT); | |
354 } | |
355 | |
356 } // namespace ash | |
OLD | NEW |