1 // Copyright 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 cr.define('login', function() { 6 7 /** 8 * Minimum wallpaper load delay in milliseconds. 9 * @type {number} 10 * @const 11 */ 12 var WALLPAPER_LOAD_MIN_DELAY_MS = 100; 13 14 /** 15 * If last walpaper load time cannot be calculated, assume this value. 16 * @type {number} 17 * @const 18 */ 19 var WALLPAPER_DEFAULT_LOAD_TIME_MS = 200; 20 21 /** 22 * Min and Max average wallpaper load time. 23 * Delay to next wallpaper load is 2 * <average load time>. 24 * @type {number} 25 * @const 26 */ 27 var WALLPAPER_MIN_LOAD_TIME_MS = 50; 28 var WALLPAPER_MAX_LOAD_TIME_MS = 2000; 29 30 /** 31 * Number last wallpaper load times to remember. 32 * @type {number} 33 * @const 34 */ 35 var WALLPAPER_LOAD_STATS_MAX_LENGTH = 4; 36 37 38 /** 39 * Creates a new pod row element. 40 * @constructor 41 * @extends {HTMLDivElement} 42 */ 43 var WallpaperLoader = function() { 44 this.wallpaperLoadInProgress_ = { 45 name: '', 46 date: undefined 47 }; 48 this.loadStats_ = []; 49 }; 50 51 WallpaperLoader.prototype = { 52 // When moving through users quickly at login screen, set a timeout to 53 // prevent loading intermediate wallpapers. 54 beforeLoadTimeout_: null, 55 56 // If we do not receive notification on WallpaperLoaded within timeout, 57 // probably an error happened and the wallpaper is just bad. Skip it 58 // and unblock loader. 59 loadTimeout_: null, 60 61 // When waiting for wallpaper load, remember load start time. 62 // wallpaperLoadInProgress_: { name: '', date: undefined } 63 wallpaperLoadInProgress_: undefined, 64 65 // Wait a delay and then load this wallpaper. Value = username. 66 wallpaperLoadPending_: undefined, 67 68 // Wait untill this Date before loading next wallpaper. 69 wallpaperLoadTryNextAfter_: undefined, 70 71 // Username, owner of current wallpaper. 72 currentWallpaper_: '', 73 74 // Array of times (in milliseconds) of last wallpaper load attempts. 75 // Length is limited by WALLPAPER_LOAD_STATS_MAX_LENGTH. 76 loadStats_: undefined, 77 78 // Force next load request even if requested wallpaper is already loaded. 79 forceLoad_: false, 80 81 /** 82 * Stop load timer. Clear pending record. 83 */ 84 reset: function() { 85 delete this.wallpaperLoadPending_; 86 87 if (this.beforeLoadTimeout_ != null) 88 window.clearTimeout(this.beforeLoadTimeout_); 89 this.beforeLoadTimeout_ = null; 90 91 if (this.loadTimeout_ != null) 92 window.clearTimeout(this.loadTimeout_); 93 this.loadTimeout_ = null; 94 95 this.wallpaperLoadInProgress_.name = ''; 96 }, 97 98 /** 99 * Schedules wallpaper load. 100 */ 101 scheduleLoad: function(email, force) { 102 if (force || this.forceLoad_) { 103 this.forceLoad_ = true; 104 } else { 105 if (this.wallpaperLoadPending_ && this.wallpaperLoadPending_ == email) 106 return; 107 if ((this.wallpaperLoadInProgress_.name == '') && 108 (this.currentWallpaper_ == email)) 109 return; 110 } 111 this.reset(); 112 113 this.wallpaperLoadPending_ = email; 114 var now = new Date(); 115 var timeout = WALLPAPER_LOAD_MIN_DELAY_MS; 116 if (this.wallpaperLoadTryNextAfter_) 117 timeout = Math.max(timeout, this.wallpaperLoadTryNextAfter_ - now); 118 119 this.beforeLoadTimeout_ = window.setTimeout( 120 this.loadWallpaper_.bind(this), timeout); 121 }, 122 123 124 /** 125 * Loads pending wallpaper, if any. 126 * @private 127 */ 128 loadWallpaper_: function() { 129 this.beforeLoadTimeout_ = null; 130 if (!this.wallpaperLoadPending_) 131 return; 132 if (!this.forceLoad_ && this.wallpaperLoadInProgress_.name != '') 133 return; 134 var email = this.wallpaperLoadPending_; 135 delete this.wallpaperLoadPending_; 136 if (!this.forceLoad_ && email == this.currentWallpaper_) 137 return; 138 this.wallpaperLoadInProgress_.name = email; 139 this.wallpaperLoadInProgress_.date = new Date(); 140 this.forceLoad_ = false; 141 chrome.send('loadWallpaper', [email]); 142 143 var timeout = 3 * this.getWallpaperLoadTime_(); 144 this.loadTimeout_ = window.setTimeout( 145 this.loadTimeoutFired_.bind(this), timeout); 146 }, 147 148 /** 149 * Calculates average wallpaper load time. 150 */ 151 calcLoadStatsAvg: function() { 152 return this.loadStats_.reduce( 153 function(previousValue, currentValue) { 154 return previousValue + currentValue; 155 }) / this.loadStats_.length; 156 }, 157 158 /** 159 * Calculates average next wallpaper load delay time. 160 */ 161 getWallpaperLoadTime_: function() { 162 var avg = WALLPAPER_DEFAULT_LOAD_TIME_MS; 163 164 if (this.loadStats_.length == 0) 165 return avg; 166 167 avg = this.calcLoadStatsAvg(); 168 if (avg < WALLPAPER_MIN_LOAD_TIME_MS) 169 avg = WALLPAPER_MIN_LOAD_TIME_MS; 170 171 if (avg > WALLPAPER_MAX_LOAD_TIME_MS) 172 avg = WALLPAPER_MAX_LOAD_TIME_MS; 173 174 return avg; 175 }, 176 177 /** 178 * Handles 'onWallpaperLoaded' event. Recalculates statistics and 179 * [re]schedules next wallpaper load. 180 */ 181 onWallpaperLoaded: function(email) { 182 this.currentWallpaper_ = email; 183 if (email != this.wallpaperLoadInProgress_.name) 184 return; 185 186 window.clearTimeout(this.loadTimeout_); 187 this.loadTimeout_ = null; 188 189 this.wallpaperLoadInProgress_.name = ''; 190 var started = this.wallpaperLoadInProgress_.date; 191 var finished = new Date(); 192 var elapsed = started ? finished - started : 193 WALLPAPER_DEFAULT_LOAD_TIME_MS; 194 this.loadStats_.push(elapsed); 195 if (this.loadStats_.length > WALLPAPER_LOAD_STATS_MAX_LENGTH) 196 this.loadStats_.shift(); 197 198 this.wallpaperLoadTryNextAfter_ = new Date(Date.now() + 2 * 199 this.getWallpaperLoadTime_()); 200 if (this.wallpaperLoadPending_) { 201 var newWallpaperEmail = this.wallpaperLoadPending_; 202 this.reset(); 203 this.scheduleLoad(newWallpaperEmail, this.forceLoad_); 204 } 205 }, 206 207 /** 208 * Handles timeout of wallpaper load. Pretends load is completed to unblock 209 * loader. 210 */ 211 loadTimeoutFired_: function() { 212 var email = this.wallpaperLoadInProgress_.name; 213 this.loadTimeout_ = null; 214 if (email == '') 215 return; 216 this.onWallpaperLoaded(email); 217 } 218 }; 219 220 return { 221 WallpaperLoader: WallpaperLoader 222 }; 223 }); 224