event_page.js revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 5var WALLPAPER_PICKER_WIDTH = 574; 6var WALLPAPER_PICKER_HEIGHT = 420; 7 8var wallpaperPickerWindow; 9 10var surpriseWallpaper = null; 11 12function SurpriseWallpaper() { 13} 14 15/** 16 * Gets SurpriseWallpaper instance. In case it hasn't been initialized, a new 17 * instance is created. 18 * @return {SurpriseWallpaper} A SurpriseWallpaper instance. 19 */ 20SurpriseWallpaper.getInstance = function() { 21 if (!surpriseWallpaper) 22 surpriseWallpaper = new SurpriseWallpaper(); 23 return surpriseWallpaper; 24}; 25 26/** 27 * Tries to change wallpaper to a new one in the background. May fail due to a 28 * network issue. 29 */ 30SurpriseWallpaper.prototype.tryChangeWallpaper = function() { 31 var self = this; 32 var onFailure = function() { 33 self.retryLater_(); 34 self.fallbackToLocalRss_(); 35 }; 36 // Try to fetch newest rss as document from server first. If any error occurs, 37 // proceed with local copy of rss. 38 WallpaperUtil.fetchURL(Constants.WallpaperRssURL, 'document', function(xhr) { 39 WallpaperUtil.saveToStorage(Constants.AccessRssKey, 40 new XMLSerializer().serializeToString(xhr.responseXML), false); 41 self.updateSurpriseWallpaper(xhr.responseXML); 42 }, onFailure); 43}; 44 45/** 46 * Retries changing the wallpaper 1 hour later. This is called when fetching the 47 * rss or wallpaper from server fails. 48 * @private 49 */ 50SurpriseWallpaper.prototype.retryLater_ = function() { 51 chrome.alarms.create('RetryAlarm', {delayInMinutes: 60}); 52}; 53 54/** 55 * Fetches the cached rss feed from local storage in the event of being unable 56 * to download the online feed. 57 * @private 58 */ 59SurpriseWallpaper.prototype.fallbackToLocalRss_ = function() { 60 var self = this; 61 Constants.WallpaperLocalStorage.get(Constants.AccessRssKey, function(items) { 62 var rssString = items[Constants.AccessRssKey]; 63 if (rssString) { 64 self.updateSurpriseWallpaper(new DOMParser().parseFromString(rssString, 65 'text/xml')); 66 } else { 67 self.updateSurpriseWallpaper(); 68 } 69 }); 70}; 71 72/** 73 * Starts to change wallpaper. Called after rss is fetched. 74 * @param {Document=} opt_rss The fetched rss document. If opt_rss is null, uses 75 * a random wallpaper. 76 */ 77SurpriseWallpaper.prototype.updateSurpriseWallpaper = function(opt_rss) { 78 if (opt_rss) { 79 var items = opt_rss.querySelectorAll('item'); 80 var date = new Date(new Date().toDateString()).getTime(); 81 for (var i = 0; i < items.length; i++) { 82 item = items[i]; 83 var disableDate = new Date(item.getElementsByTagNameNS( 84 Constants.WallpaperNameSpaceURI, 'disableDate')[0].textContent). 85 getTime(); 86 var enableDate = new Date(item.getElementsByTagNameNS( 87 Constants.WallpaperNameSpaceURI, 'enableDate')[0].textContent). 88 getTime(); 89 var regionsString = item.getElementsByTagNameNS( 90 Constants.WallpaperNameSpaceURI, 'regions')[0].textContent; 91 var regions = regionsString.split(', '); 92 if (enableDate <= date && disableDate > date && 93 regions.indexOf(navigator.language) != -1) { 94 var self = this; 95 this.setWallpaperFromRssItem_(item, 96 function() {}, 97 function() { 98 self.retryLater_(); 99 self.updateRandomWallpaper_(); 100 }); 101 return; 102 } 103 } 104 } 105 // No surprise wallpaper for today at current locale or fetching rss feed 106 // fails. Fallback to use a random one from wallpaper server. 107 this.updateRandomWallpaper_(); 108}; 109 110/** 111 * Sets a new random wallpaper if one has not already been set today. 112 * @private 113 */ 114SurpriseWallpaper.prototype.updateRandomWallpaper_ = function() { 115 var self = this; 116 Constants.WallpaperSyncStorage.get( 117 Constants.AccessLastSurpriseWallpaperChangedDate, function(items) { 118 var dateString = new Date().toDateString(); 119 // At most one random wallpaper per day. 120 if (items[Constants.AccessLastSurpriseWallpaperChangedDate] != dateString) { 121 self.setRandomWallpaper_(dateString); 122 } 123 }); 124}; 125 126/** 127 * Sets wallpaper to one of the wallpapers displayed in wallpaper picker. If 128 * the wallpaper download fails, retry one hour later. Wallpapers that are 129 * disabled for surprise me are excluded. 130 * @param {string} dateString String representation of current local date. 131 * @private 132 */ 133SurpriseWallpaper.prototype.setRandomWallpaper_ = function(dateString) { 134 var self = this; 135 Constants.WallpaperLocalStorage.get(Constants.AccessManifestKey, 136 function(items) { 137 var manifest = items[Constants.AccessManifestKey]; 138 if (manifest && manifest.wallpaper_list) { 139 var filtered = manifest.wallpaper_list.filter(function(element) { 140 // Older version manifest do not have available_for_surprise_me field. 141 // In this case, no wallpaper should be filtered out. 142 return element.available_for_surprise_me || 143 element.available_for_surprise_me == undefined; 144 }); 145 var index = Math.floor(Math.random() * filtered.length); 146 var wallpaper = filtered[index]; 147 var wallpaperURL = wallpaper.base_url + Constants.HighResolutionSuffix; 148 var onSuccess = function() { 149 WallpaperUtil.saveToStorage( 150 Constants.AccessLastSurpriseWallpaperChangedDate, 151 dateString, 152 true); 153 }; 154 WallpaperUtil.setOnlineWallpaper(wallpaperURL, wallpaper.default_layout, 155 onSuccess, self.retryLater_.bind(self)); 156 } 157 }); 158}; 159 160/** 161 * Sets wallpaper to the wallpaper specified by item from rss. If downloading 162 * the wallpaper fails, retry one hour later. 163 * @param {Element} item The wallpaper rss item element. 164 * @param {function} onSuccess Success callback. 165 * @param {function} onFailure Failure callback. 166 * @private 167 */ 168SurpriseWallpaper.prototype.setWallpaperFromRssItem_ = function(item, 169 onSuccess, 170 onFailure) { 171 var url = item.querySelector('link').textContent; 172 var layout = item.getElementsByTagNameNS( 173 Constants.WallpaperNameSpaceURI, 'layout')[0].textContent; 174 var self = this; 175 WallpaperUtil.fetchURL(url, 'arraybuffer', function(xhr) { 176 if (xhr.response != null) { 177 chrome.wallpaperPrivate.setCustomWallpaper(xhr.response, layout, false, 178 'surprise_wallpaper', 179 onSuccess); 180 } else { 181 onFailure(); 182 } 183 }, onFailure); 184}; 185 186/** 187 * Disables the wallpaper surprise me feature. Clear all alarms and states. 188 */ 189SurpriseWallpaper.prototype.disable = function() { 190 chrome.alarms.clearAll(); 191 // Makes last changed date invalid. 192 WallpaperUtil.saveToStorage(Constants.AccessLastSurpriseWallpaperChangedDate, 193 '', true); 194}; 195 196/** 197 * Changes current wallpaper and sets up an alarm to schedule next change around 198 * midnight. 199 */ 200SurpriseWallpaper.prototype.next = function() { 201 var nextUpdate = this.nextUpdateTime(new Date()); 202 chrome.alarms.create({when: nextUpdate}); 203 this.tryChangeWallpaper(); 204}; 205 206/** 207 * Calculates when the next wallpaper change should be triggered. 208 * @param {Date} now Current time. 209 * @return {number} The time when next wallpaper change should happen. 210 */ 211SurpriseWallpaper.prototype.nextUpdateTime = function(now) { 212 var nextUpdate = new Date(now.setDate(now.getDate() + 1)).toDateString(); 213 return new Date(nextUpdate).getTime(); 214}; 215 216chrome.app.runtime.onLaunched.addListener(function() { 217 if (wallpaperPickerWindow && !wallpaperPickerWindow.contentWindow.closed) { 218 wallpaperPickerWindow.focus(); 219 chrome.wallpaperPrivate.minimizeInactiveWindows(); 220 return; 221 } 222 223 chrome.app.window.create('main.html', { 224 frame: 'none', 225 width: WALLPAPER_PICKER_WIDTH, 226 height: WALLPAPER_PICKER_HEIGHT, 227 resizable: false, 228 alphaEnabled: true 229 }, function(w) { 230 wallpaperPickerWindow = w; 231 chrome.wallpaperPrivate.minimizeInactiveWindows(); 232 w.onClosed.addListener(function() { 233 chrome.wallpaperPrivate.restoreMinimizedWindows(); 234 }); 235 WallpaperUtil.testSendMessage('wallpaper-window-created'); 236 }); 237}); 238 239chrome.storage.onChanged.addListener(function(changes, namespace) { 240 if (changes[Constants.AccessSurpriseMeEnabledKey]) { 241 if (changes[Constants.AccessSurpriseMeEnabledKey].newValue) { 242 SurpriseWallpaper.getInstance().next(); 243 } else { 244 SurpriseWallpaper.getInstance().disable(); 245 } 246 } 247 248 if (changes[Constants.AccessSyncWallpaperInfoKey]) { 249 var newValue = changes[Constants.AccessSyncWallpaperInfoKey].newValue; 250 Constants.WallpaperLocalStorage.get(Constants.AccessLocalWallpaperInfoKey, 251 function(items) { 252 // Normally, the wallpaper info saved in local storage and sync storage 253 // are the same. If the synced value changed by sync service, they may 254 // different. In that case, change wallpaper to the one saved in sync 255 // storage and update the local value. 256 var localValue = items[Constants.AccessLocalWallpaperInfoKey]; 257 if (localValue == undefined || 258 localValue.url != newValue.url || 259 localValue.layout != newValue.layout || 260 localValue.source != newValue.source) { 261 if (newValue.source == Constants.WallpaperSourceEnum.Online) { 262 // TODO(bshe): Consider schedule an alarm to set online wallpaper 263 // later when failed. Note that we need to cancel the retry if user 264 // set another wallpaper before retry alarm invoked. 265 WallpaperUtil.setOnlineWallpaper(newValue.url, newValue.layout, 266 function() {}, function() {}); 267 } 268 WallpaperUtil.saveToStorage(Constants.AccessLocalWallpaperInfoKey, 269 newValue, false); 270 } 271 }); 272 } 273}); 274 275chrome.alarms.onAlarm.addListener(function() { 276 SurpriseWallpaper.getInstance().next(); 277}); 278