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
.url
!=
287 detail
.fileEntry
.name
.replace(
288 Constants
.CustomWallpaperThumbnailSuffix
, '')) {
289 WallpaperUtil
.storeWallpaperFromSyncFSToLocalFS(
293 } else if (detail
.action
== 'deleted') {
294 var fileName
= detail
.fileEntry
.name
.replace(
295 Constants
.CustomWallpaperThumbnailSuffix
, '');
296 WallpaperUtil
.deleteWallpaperFromLocalFS(fileName
);
298 } else { // detail.direction == 'local_to_remote'
299 if (detail
.action
== 'deleted') {
300 WallpaperUtil
.deleteWallpaperFromSyncFS(detail
.fileEntry
.name
);
301 WallpaperUtil
.deleteWallpaperFromLocalFS(detail
.fileEntry
.name
);
308 chrome
.storage
.onChanged
.addListener(function(changes
, namespace) {
309 WallpaperUtil
.enabledSyncThemesCallback(function(syncEnabled
) {
311 // If sync theme is enabled, use values from chrome.storage.sync to sync
312 // wallpaper changes.
313 WallpaperUtil
.requestSyncFS(function() {});
314 if (changes
[Constants
.AccessSyncSurpriseMeEnabledKey
]) {
315 if (changes
[Constants
.AccessSyncSurpriseMeEnabledKey
].newValue
) {
316 SurpriseWallpaper
.getInstance().next();
318 SurpriseWallpaper
.getInstance().disable();
322 if (changes
[Constants
.AccessSyncWallpaperInfoKey
]) {
323 var syncInfo
= changes
[Constants
.AccessSyncWallpaperInfoKey
].newValue
;
325 Constants
.WallpaperSyncStorage
.get(
326 Constants
.AccessSyncSurpriseMeEnabledKey
, function(enabledItems
) {
327 var syncSurpriseMeEnabled
=
328 enabledItems
[Constants
.AccessSyncSurpriseMeEnabledKey
];
330 Constants
.WallpaperSyncStorage
.get(
331 Constants
.AccessLastSurpriseWallpaperChangedDate
,
333 var syncLastSurpriseMeChangedDate
=
334 items
[Constants
.AccessLastSurpriseWallpaperChangedDate
];
336 var today
= new Date().toDateString();
337 // If SurpriseMe is enabled and surprise wallpaper hasn't been
338 // changed today, we should not sync the change, instead onAlarm()
339 // will be triggered to update a surprise me wallpaper.
340 if (!syncSurpriseMeEnabled
||
341 (syncSurpriseMeEnabled
&&
342 syncLastSurpriseMeChangedDate
== today
)) {
343 Constants
.WallpaperLocalStorage
.get(
344 Constants
.AccessLocalWallpaperInfoKey
, function(infoItems
) {
346 infoItems
[Constants
.AccessLocalWallpaperInfoKey
];
347 // Normally, the wallpaper info saved in local storage and sync
348 // storage are the same. If the synced value changed by sync
349 // service, they may different. In that case, change wallpaper
350 // to the one saved in sync storage and update the local value.
351 if (localInfo
== undefined ||
352 localInfo
.url
!= syncInfo
.url
||
353 localInfo
.layout
!= syncInfo
.layout
||
354 localInfo
.source
!= syncInfo
.source
) {
355 if (syncInfo
.source
== Constants
.WallpaperSourceEnum
.Online
) {
356 // TODO(bshe): Consider schedule an alarm to set online
357 // wallpaper later when failed. Note that we need to cancel
358 // the retry if user set another wallpaper before retry
360 WallpaperUtil
.setOnlineWallpaper(syncInfo
.url
,
361 syncInfo
.layout
, function() {}, function() {});
362 } else if (syncInfo
.source
==
363 Constants
.WallpaperSourceEnum
.Custom
) {
364 WallpaperUtil
.setCustomWallpaperFromSyncFS(syncInfo
.url
,
366 } else if (syncInfo
.source
==
367 Constants
.WallpaperSourceEnum
.Default
) {
368 chrome
.wallpaperPrivate
.resetWallpaper();
370 WallpaperUtil
.saveToLocalStorage(
371 Constants
.AccessLocalWallpaperInfoKey
, syncInfo
);
379 // If sync theme is disabled, use values from chrome.storage.local to
380 // track wallpaper changes.
381 if (changes
[Constants
.AccessLocalSurpriseMeEnabledKey
]) {
382 if (changes
[Constants
.AccessLocalSurpriseMeEnabledKey
].newValue
) {
383 SurpriseWallpaper
.getInstance().next();
385 SurpriseWallpaper
.getInstance().disable();
392 chrome
.alarms
.onAlarm
.addListener(function() {
393 SurpriseWallpaper
.getInstance().next();
396 chrome
.wallpaperPrivate
.onWallpaperChangedBy3rdParty
.addListener(function() {
397 WallpaperUtil
.saveToLocalStorage(
398 Constants
.AccessLocalSurpriseMeEnabledKey
, false, function() {
399 WallpaperUtil
.saveToSyncStorage(Constants
.AccessSyncSurpriseMeEnabledKey
,
402 SurpriseWallpaper
.getInstance().disable();