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.
5 var WALLPAPER_PICKER_WIDTH = 574;
6 var WALLPAPER_PICKER_HEIGHT = 420;
8 var wallpaperPickerWindow;
10 var surpriseWallpaper = null;
12 function SurpriseWallpaper() {
16 * Gets SurpriseWallpaper instance. In case it hasn't been initialized, a new
17 * instance is created.
18 * @return {SurpriseWallpaper} A SurpriseWallpaper instance.
20 SurpriseWallpaper.getInstance = function() {
21 if (!surpriseWallpaper)
22 surpriseWallpaper = new SurpriseWallpaper();
23 return surpriseWallpaper;
27 * Tries to change wallpaper to a new one in the background. May fail due to a
30 SurpriseWallpaper.prototype.tryChangeWallpaper = function() {
32 var onFailure = function(status) {
34 self.fallbackToLocalRss_();
36 self.updateRandomWallpaper_();
38 // Try to fetch newest rss as document from server first. If the requested
39 // URL is not found (404 error), set a random wallpaper displayed in the
40 // wallpaper picker. If any other error occurs, proceed with local copy of
42 WallpaperUtil.fetchURL(Constants.WallpaperRssURL, 'document', function(xhr) {
43 WallpaperUtil.saveToLocalStorage(Constants.AccessLocalRssKey,
44 new XMLSerializer().serializeToString(xhr.responseXML));
45 self.updateSurpriseWallpaper(xhr.responseXML);
50 * Retries changing the wallpaper 1 hour later. This is called when fetching the
51 * rss or wallpaper from server fails.
54 SurpriseWallpaper.prototype.retryLater_ = function() {
55 chrome.alarms.create('RetryAlarm', {delayInMinutes: 60});
59 * Fetches the cached rss feed from local storage in the event of being unable
60 * to download the online feed.
63 SurpriseWallpaper.prototype.fallbackToLocalRss_ = function() {
65 Constants.WallpaperLocalStorage.get(Constants.AccessLocalRssKey,
67 var rssString = items[Constants.AccessLocalRssKey];
69 self.updateSurpriseWallpaper(new DOMParser().parseFromString(rssString,
72 self.updateSurpriseWallpaper();
78 * Starts to change wallpaper. Called after rss is fetched.
79 * @param {Document=} opt_rss The fetched rss document. If opt_rss is null, uses
82 SurpriseWallpaper.prototype.updateSurpriseWallpaper = function(opt_rss) {
84 var items = opt_rss.querySelectorAll('item');
85 var date = new Date(new Date().toDateString()).getTime();
86 for (var i = 0; i < items.length; i++) {
88 var disableDate = new Date(item.getElementsByTagNameNS(
89 Constants.WallpaperNameSpaceURI, 'disableDate')[0].textContent).
91 var enableDate = new Date(item.getElementsByTagNameNS(
92 Constants.WallpaperNameSpaceURI, 'enableDate')[0].textContent).
94 var regionsString = item.getElementsByTagNameNS(
95 Constants.WallpaperNameSpaceURI, 'regions')[0].textContent;
96 var regions = regionsString.split(', ');
97 if (enableDate <= date && disableDate > date &&
98 regions.indexOf(navigator.language) != -1) {
100 this.setWallpaperFromRssItem_(item,
106 self.updateRandomWallpaper_();
112 // No surprise wallpaper for today at current locale or fetching rss feed
113 // fails. Fallback to use a random one from wallpaper server.
114 this.updateRandomWallpaper_();
118 * Sets a new random wallpaper if one has not already been set today.
121 SurpriseWallpaper.prototype.updateRandomWallpaper_ = function() {
123 var onSuccess = function(items) {
124 var dateString = new Date().toDateString();
125 // At most one random wallpaper per day.
126 if (items[Constants.AccessLastSurpriseWallpaperChangedDate] != dateString) {
127 self.setRandomWallpaper_(dateString);
130 WallpaperUtil.enabledSyncThemesCallback(function(syncEnabled) {
132 Constants.WallpaperSyncStorage.get(
133 Constants.AccessLastSurpriseWallpaperChangedDate, onSuccess);
135 Constants.WallpaperLocalStorage.get(
136 Constants.AccessLastSurpriseWallpaperChangedDate, onSuccess);
142 * Sets wallpaper to one of the wallpapers displayed in wallpaper picker. If
143 * the wallpaper download fails, retry one hour later. Wallpapers that are
144 * disabled for surprise me are excluded.
145 * @param {string} dateString String representation of current local date.
148 SurpriseWallpaper.prototype.setRandomWallpaper_ = function(dateString) {
150 Constants.WallpaperLocalStorage.get(Constants.AccessLocalManifestKey,
152 var manifest = items[Constants.AccessLocalManifestKey];
153 if (manifest && manifest.wallpaper_list) {
154 var filtered = manifest.wallpaper_list.filter(function(element) {
155 // Older version manifest do not have available_for_surprise_me field.
156 // In this case, no wallpaper should be filtered out.
157 return element.available_for_surprise_me ||
158 element.available_for_surprise_me == undefined;
160 var index = Math.floor(Math.random() * filtered.length);
161 var wallpaper = filtered[index];
162 var wallpaperURL = wallpaper.base_url + Constants.HighResolutionSuffix;
163 var onSuccess = function() {
164 WallpaperUtil.saveWallpaperInfo(wallpaperURL, wallpaper.default_layout,
165 Constants.WallpaperSourceEnum.Online);
166 WallpaperUtil.saveToLocalStorage(
167 Constants.AccessLastSurpriseWallpaperChangedDate,
168 dateString, function() {
169 WallpaperUtil.saveToSyncStorage(
170 Constants.AccessLastSurpriseWallpaperChangedDate,
174 WallpaperUtil.setOnlineWallpaper(wallpaperURL, wallpaper.default_layout,
175 onSuccess, self.retryLater_.bind(self));
181 * Sets wallpaper to the wallpaper specified by item from rss. If downloading
182 * the wallpaper fails, retry one hour later.
183 * @param {Element} item The wallpaper rss item element.
184 * @param {function} onSuccess Success callback.
185 * @param {function} onFailure Failure callback.
188 SurpriseWallpaper.prototype.setWallpaperFromRssItem_ = function(item,
191 var url = item.querySelector('link').textContent;
192 var layout = item.getElementsByTagNameNS(
193 Constants.WallpaperNameSpaceURI, 'layout')[0].textContent;
195 WallpaperUtil.fetchURL(url, 'arraybuffer', function(xhr) {
196 if (xhr.response != null) {
197 chrome.wallpaperPrivate.setCustomWallpaper(xhr.response, layout, false,
198 'surprise_wallpaper',
200 WallpaperUtil.saveWallpaperInfo(url, layout,
201 Constants.WallpaperSourceEnum.Online);
202 var dateString = new Date().toDateString();
203 WallpaperUtil.saveToLocalStorage(
204 Constants.AccessLastSurpriseWallpaperChangedDate,
205 dateString, function() {
206 WallpaperUtil.saveToSyncStorage(
207 Constants.AccessLastSurpriseWallpaperChangedDate, dataString);
210 self.updateRandomWallpaper_();
216 * Disables the wallpaper surprise me feature. Clear all alarms and states.
218 SurpriseWallpaper.prototype.disable = function() {
219 chrome.alarms.clearAll();
220 // Makes last changed date invalid.
221 WallpaperUtil.saveToLocalStorage(
222 Constants.AccessLastSurpriseWallpaperChangedDate, '', function() {
223 WallpaperUtil.saveToSyncStorage(
224 Constants.AccessLastSurpriseWallpaperChangedDate, '');
229 * Changes current wallpaper and sets up an alarm to schedule next change around
232 SurpriseWallpaper.prototype.next = function() {
233 var nextUpdate = this.nextUpdateTime(new Date());
234 chrome.alarms.create({when: nextUpdate});
235 this.tryChangeWallpaper();
239 * Calculates when the next wallpaper change should be triggered.
240 * @param {Date} now Current time.
241 * @return {number} The time when next wallpaper change should happen.
243 SurpriseWallpaper.prototype.nextUpdateTime = function(now) {
244 var nextUpdate = new Date(now.setDate(now.getDate() + 1)).toDateString();
245 return new Date(nextUpdate).getTime();
248 chrome.app.runtime.onLaunched.addListener(function() {
249 if (wallpaperPickerWindow && !wallpaperPickerWindow.contentWindow.closed) {
250 wallpaperPickerWindow.focus();
251 chrome.wallpaperPrivate.minimizeInactiveWindows();
255 chrome.app.window.create('main.html', {
257 width: WALLPAPER_PICKER_WIDTH,
258 height: WALLPAPER_PICKER_HEIGHT,
262 wallpaperPickerWindow = w;
263 chrome.wallpaperPrivate.minimizeInactiveWindows();
264 w.onClosed.addListener(function() {
265 chrome.wallpaperPrivate.restoreMinimizedWindows();
267 WallpaperUtil.testSendMessage('wallpaper-window-created');
271 chrome.syncFileSystem.onFileStatusChanged.addListener(function(detail) {
272 WallpaperUtil.enabledSyncThemesCallback(function(syncEnabled) {
275 if (detail.status == 'synced') {
276 if (detail.direction == 'remote_to_local') {
277 if (detail.action == 'added') {
278 Constants.WallpaperLocalStorage.get(
279 Constants.AccessLocalWallpaperInfoKey,
281 var localData = items[Constants.AccessLocalWallpaperInfoKey];
282 if (localData && localData.url == detail.fileEntry.name &&
283 localData.source == Constants.WallpaperSourceEnum.Custom) {
284 WallpaperUtil.setCustomWallpaperFromSyncFS(localData.url,
286 } else if (!localData || localData.url !=
287 detail.fileEntry.name.replace(
288 Constants.CustomWallpaperThumbnailSuffix, '')) {
289 // localData might be null on a powerwashed device.
290 WallpaperUtil.storeWallpaperFromSyncFSToLocalFS(
294 } else if (detail.action == 'deleted') {
295 var fileName = detail.fileEntry.name.replace(
296 Constants.CustomWallpaperThumbnailSuffix, '');
297 WallpaperUtil.deleteWallpaperFromLocalFS(fileName);
299 } else { // detail.direction == 'local_to_remote'
300 if (detail.action == 'deleted') {
301 WallpaperUtil.deleteWallpaperFromSyncFS(detail.fileEntry.name);
302 WallpaperUtil.deleteWallpaperFromLocalFS(detail.fileEntry.name);
309 chrome.storage.onChanged.addListener(function(changes, namespace) {
310 WallpaperUtil.enabledSyncThemesCallback(function(syncEnabled) {
312 // If sync theme is enabled, use values from chrome.storage.sync to sync
313 // wallpaper changes.
314 WallpaperUtil.requestSyncFS(function() {});
315 if (changes[Constants.AccessSyncSurpriseMeEnabledKey]) {
316 if (changes[Constants.AccessSyncSurpriseMeEnabledKey].newValue) {
317 SurpriseWallpaper.getInstance().next();
319 SurpriseWallpaper.getInstance().disable();
323 if (changes[Constants.AccessSyncWallpaperInfoKey]) {
324 var syncInfo = changes[Constants.AccessSyncWallpaperInfoKey].newValue;
326 Constants.WallpaperSyncStorage.get(
327 Constants.AccessSyncSurpriseMeEnabledKey, function(enabledItems) {
328 var syncSurpriseMeEnabled =
329 enabledItems[Constants.AccessSyncSurpriseMeEnabledKey];
331 Constants.WallpaperSyncStorage.get(
332 Constants.AccessLastSurpriseWallpaperChangedDate,
334 var syncLastSurpriseMeChangedDate =
335 items[Constants.AccessLastSurpriseWallpaperChangedDate];
337 var today = new Date().toDateString();
338 // If SurpriseMe is enabled and surprise wallpaper hasn't been
339 // changed today, we should not sync the change, instead onAlarm()
340 // will be triggered to update a surprise me wallpaper.
341 if (!syncSurpriseMeEnabled ||
342 (syncSurpriseMeEnabled &&
343 syncLastSurpriseMeChangedDate == today)) {
344 Constants.WallpaperLocalStorage.get(
345 Constants.AccessLocalWallpaperInfoKey, function(infoItems) {
347 infoItems[Constants.AccessLocalWallpaperInfoKey];
348 // Normally, the wallpaper info saved in local storage and sync
349 // storage are the same. If the synced value changed by sync
350 // service, they may different. In that case, change wallpaper
351 // to the one saved in sync storage and update the local value.
352 if (localInfo == undefined ||
353 localInfo.url != syncInfo.url ||
354 localInfo.layout != syncInfo.layout ||
355 localInfo.source != syncInfo.source) {
356 if (syncInfo.source == Constants.WallpaperSourceEnum.Online) {
357 // TODO(bshe): Consider schedule an alarm to set online
358 // wallpaper later when failed. Note that we need to cancel
359 // the retry if user set another wallpaper before retry
361 WallpaperUtil.setOnlineWallpaper(syncInfo.url,
362 syncInfo.layout, function() {}, function() {});
363 } else if (syncInfo.source ==
364 Constants.WallpaperSourceEnum.Custom) {
365 WallpaperUtil.setCustomWallpaperFromSyncFS(syncInfo.url,
367 } else if (syncInfo.source ==
368 Constants.WallpaperSourceEnum.Default) {
369 chrome.wallpaperPrivate.resetWallpaper();
371 WallpaperUtil.saveToLocalStorage(
372 Constants.AccessLocalWallpaperInfoKey, syncInfo);
380 // If sync theme is disabled, use values from chrome.storage.local to
381 // track wallpaper changes.
382 if (changes[Constants.AccessLocalSurpriseMeEnabledKey]) {
383 if (changes[Constants.AccessLocalSurpriseMeEnabledKey].newValue) {
384 SurpriseWallpaper.getInstance().next();
386 SurpriseWallpaper.getInstance().disable();
393 chrome.alarms.onAlarm.addListener(function() {
394 SurpriseWallpaper.getInstance().next();
397 chrome.wallpaperPrivate.onWallpaperChangedBy3rdParty.addListener(function() {
398 WallpaperUtil.saveToLocalStorage(
399 Constants.AccessLocalSurpriseMeEnabledKey, false, function() {
400 WallpaperUtil.saveToSyncStorage(Constants.AccessSyncSurpriseMeEnabledKey,
403 SurpriseWallpaper.getInstance().disable();