| OLD | NEW |
| (Empty) |
| 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 | |
| 5 'use strict'; | |
| 6 | |
| 7 /** | |
| 8 * SuggestAppsDialog contains a list box to select an app to be opened the file | |
| 9 * with. This dialog should be used as action picker for file operations. | |
| 10 */ | |
| 11 | |
| 12 /** | |
| 13 * The width of the widget (in pixel). | |
| 14 * @type {number} | |
| 15 * @const | |
| 16 */ | |
| 17 var WEBVIEW_WIDTH = 735; | |
| 18 /** | |
| 19 * The height of the widget (in pixel). | |
| 20 * @type {number} | |
| 21 * @const | |
| 22 */ | |
| 23 var WEBVIEW_HEIGHT = 480; | |
| 24 | |
| 25 /** | |
| 26 * The URL of the widget. | |
| 27 * @type {string} | |
| 28 * @const | |
| 29 */ | |
| 30 var CWS_WIDGET_URL = | |
| 31 'https://clients5.google.com/webstore/wall/cros-widget-container'; | |
| 32 /** | |
| 33 * The origin of the widget. | |
| 34 * @type {string} | |
| 35 * @const | |
| 36 */ | |
| 37 var CWS_WIDGET_ORIGIN = 'https://clients5.google.com'; | |
| 38 | |
| 39 /** | |
| 40 * Creates dialog in DOM tree. | |
| 41 * | |
| 42 * @param {HTMLElement} parentNode Node to be parent for this dialog. | |
| 43 * @param {Object} state Static state of suggest app dialog. | |
| 44 * @constructor | |
| 45 * @extends {FileManagerDialogBase} | |
| 46 */ | |
| 47 function SuggestAppsDialog(parentNode, state) { | |
| 48 FileManagerDialogBase.call(this, parentNode); | |
| 49 | |
| 50 this.frame_.id = 'suggest-app-dialog'; | |
| 51 | |
| 52 this.webviewContainer_ = this.document_.createElement('div'); | |
| 53 this.webviewContainer_.id = 'webview-container'; | |
| 54 this.webviewContainer_.style.width = WEBVIEW_WIDTH + 'px'; | |
| 55 this.webviewContainer_.style.height = WEBVIEW_HEIGHT + 'px'; | |
| 56 this.frame_.insertBefore(this.webviewContainer_, this.text_.nextSibling); | |
| 57 | |
| 58 var spinnerLayer = this.document_.createElement('div'); | |
| 59 spinnerLayer.className = 'spinner-layer'; | |
| 60 this.webviewContainer_.appendChild(spinnerLayer); | |
| 61 | |
| 62 this.buttons_ = this.document_.createElement('div'); | |
| 63 this.buttons_.id = 'buttons'; | |
| 64 this.frame_.appendChild(this.buttons_); | |
| 65 | |
| 66 this.webstoreButton_ = this.document_.createElement('div'); | |
| 67 this.webstoreButton_.id = 'webstore-button'; | |
| 68 this.webstoreButton_.innerHTML = str('SUGGEST_DIALOG_LINK_TO_WEBSTORE'); | |
| 69 this.webstoreButton_.addEventListener( | |
| 70 'click', this.onWebstoreLinkClicked_.bind(this)); | |
| 71 this.buttons_.appendChild(this.webstoreButton_); | |
| 72 | |
| 73 this.initialFocusElement_ = this.webviewContainer_; | |
| 74 | |
| 75 this.webview_ = null; | |
| 76 this.accessToken_ = null; | |
| 77 this.widgetUrl_ = | |
| 78 state.overrideCwsContainerUrlForTest || CWS_WIDGET_URL; | |
| 79 this.widgetOrigin_ = | |
| 80 state.overrideCwsContainerOriginForTest || CWS_WIDGET_ORIGIN; | |
| 81 | |
| 82 this.extension_ = null; | |
| 83 this.mime_ = null; | |
| 84 this.installingItemId_ = null; | |
| 85 this.state_ = SuggestAppsDialog.State.UNINITIALIZED; | |
| 86 | |
| 87 this.initializationTask_ = new AsyncUtil.Group(); | |
| 88 this.initializationTask_.add(this.retrieveAuthorizeToken_.bind(this)); | |
| 89 this.initializationTask_.run(); | |
| 90 } | |
| 91 | |
| 92 SuggestAppsDialog.prototype = { | |
| 93 __proto__: FileManagerDialogBase.prototype | |
| 94 }; | |
| 95 | |
| 96 /** | |
| 97 * @enum {string} | |
| 98 * @const | |
| 99 */ | |
| 100 SuggestAppsDialog.State = { | |
| 101 UNINITIALIZED: 'SuggestAppsDialog.State.UNINITIALIZED', | |
| 102 INITIALIZING: 'SuggestAppsDialog.State.INITIALIZING', | |
| 103 INITIALIZE_FAILED_CLOSING: | |
| 104 'SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING', | |
| 105 INITIALIZED: 'SuggestAppsDialog.State.INITIALIZED', | |
| 106 INSTALLING: 'SuggestAppsDialog.State.INSTALLING', | |
| 107 INSTALLED_CLOSING: 'SuggestAppsDialog.State.INSTALLED_CLOSING', | |
| 108 OPENING_WEBSTORE_CLOSING: 'SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING', | |
| 109 CANCELED_CLOSING: 'SuggestAppsDialog.State.CANCELED_CLOSING' | |
| 110 }; | |
| 111 Object.freeze(SuggestAppsDialog.State); | |
| 112 | |
| 113 /** | |
| 114 * @enum {string} | |
| 115 * @const | |
| 116 */ | |
| 117 SuggestAppsDialog.Result = { | |
| 118 // Install is done. The install app should be opened. | |
| 119 INSTALL_SUCCESSFUL: 'SuggestAppsDialog.Result.INSTALL_SUCCESSFUL', | |
| 120 // User cancelled the suggest app dialog. No message should be shown. | |
| 121 USER_CANCELL: 'SuggestAppsDialog.Result.USER_CANCELL', | |
| 122 // User clicked the link to web store so the dialog is closed. | |
| 123 WEBSTORE_LINK_OPENED: 'SuggestAppsDialog.Result.WEBSTORE_LINK_OPENED', | |
| 124 // Failed to load the widget. Error message should be shown. | |
| 125 FAILED: 'SuggestAppsDialog.Result.FAILED' | |
| 126 }; | |
| 127 Object.freeze(SuggestAppsDialog.Result); | |
| 128 | |
| 129 /** | |
| 130 * @override | |
| 131 */ | |
| 132 SuggestAppsDialog.prototype.onInputFocus = function() { | |
| 133 this.webviewContainer_.select(); | |
| 134 }; | |
| 135 | |
| 136 /** | |
| 137 * Injects headers into the passed request. | |
| 138 * | |
| 139 * @param {Event} e Request event. | |
| 140 * @return {{requestHeaders: HttpHeaders}} Modified headers. | |
| 141 * @private | |
| 142 */ | |
| 143 SuggestAppsDialog.prototype.authorizeRequest_ = function(e) { | |
| 144 e.requestHeaders.push({ | |
| 145 name: 'Authorization', | |
| 146 value: 'Bearer ' + this.accessToken_ | |
| 147 }); | |
| 148 return {requestHeaders: e.requestHeaders}; | |
| 149 }; | |
| 150 | |
| 151 /** | |
| 152 * Retrieves the authorize token. This method should be called in | |
| 153 * initialization of the dialog. | |
| 154 * | |
| 155 * @param {function()} callback Called when the token is retrieved. | |
| 156 * @private | |
| 157 */ | |
| 158 SuggestAppsDialog.prototype.retrieveAuthorizeToken_ = function(callback) { | |
| 159 if (window.IN_TEST) { | |
| 160 // In test, use a dummy string as token. This must be a non-empty string. | |
| 161 this.accessToken_ = 'DUMMY_ACCESS_TOKEN_FOR_TEST'; | |
| 162 } | |
| 163 | |
| 164 if (this.accessToken_) { | |
| 165 callback(); | |
| 166 return; | |
| 167 } | |
| 168 | |
| 169 // Fetch or update the access token. | |
| 170 chrome.fileBrowserPrivate.requestWebStoreAccessToken( | |
| 171 function(accessToken) { | |
| 172 // In case of error, this.accessToken_ will be set to null. | |
| 173 this.accessToken_ = accessToken; | |
| 174 callback(); | |
| 175 }.bind(this)); | |
| 176 }; | |
| 177 | |
| 178 /** | |
| 179 * Dummy function for SuggestAppsDialog.show() not to be called unintentionally. | |
| 180 */ | |
| 181 SuggestAppsDialog.prototype.show = function() { | |
| 182 console.error('SuggestAppsDialog.show() shouldn\'t be called directly.'); | |
| 183 }; | |
| 184 | |
| 185 /** | |
| 186 * Shows suggest-apps dialog by file extension and mime. | |
| 187 * | |
| 188 * @param {string} extension Extension of the file. | |
| 189 * @param {string} mime Mime of the file. | |
| 190 * @param {function(boolean)} onDialogClosed Called when the dialog is closed. | |
| 191 * The argument is the result of installation: true if an app is installed, | |
| 192 * false otherwise. | |
| 193 */ | |
| 194 SuggestAppsDialog.prototype.showByExtensionAndMime = | |
| 195 function(extension, mime, onDialogClosed) { | |
| 196 this.text_.hidden = true; | |
| 197 this.dialogText_ = ''; | |
| 198 this.showInternal_(null, extension, mime, onDialogClosed); | |
| 199 }; | |
| 200 | |
| 201 /** | |
| 202 * Shows suggest-apps dialog by the filename. | |
| 203 * | |
| 204 * @param {string} filename Filename (without extension) of the file. | |
| 205 * @param {function(boolean)} onDialogClosed Called when the dialog is closed. | |
| 206 * The argument is the result of installation: true if an app is installed, | |
| 207 * false otherwise. | |
| 208 */ | |
| 209 SuggestAppsDialog.prototype.showByFilename = | |
| 210 function(filename, onDialogClosed) { | |
| 211 this.text_.hidden = false; | |
| 212 this.dialogText_ = str('SUGGEST_DIALOG_MESSAGE_FOR_EXECUTABLE'); | |
| 213 this.showInternal_(filename, null, null, onDialogClosed); | |
| 214 }; | |
| 215 | |
| 216 /** | |
| 217 * Internal method to show a dialog. This should be called only from 'Suggest. | |
| 218 * appDialog.showXxxx()' functions. | |
| 219 * | |
| 220 * @param {string} filename Filename (without extension) of the file. | |
| 221 * @param {string} extension Extension of the file. | |
| 222 * @param {string} mime Mime of the file. | |
| 223 * @param {function(boolean)} onDialogClosed Called when the dialog is closed. | |
| 224 * The argument is the result of installation: true if an app is installed, | |
| 225 * false otherwise. | |
| 226 * @private | |
| 227 */ | |
| 228 SuggestAppsDialog.prototype.showInternal_ = | |
| 229 function(filename, extension, mime, onDialogClosed) { | |
| 230 if (this.state_ != SuggestAppsDialog.State.UNINITIALIZED) { | |
| 231 console.error('Invalid state.'); | |
| 232 return; | |
| 233 } | |
| 234 | |
| 235 this.extension_ = extension; | |
| 236 this.mimeType_ = mime; | |
| 237 this.onDialogClosed_ = onDialogClosed; | |
| 238 this.state_ = SuggestAppsDialog.State.INITIALIZING; | |
| 239 | |
| 240 SuggestAppsDialog.Metrics.recordShowDialog(); | |
| 241 SuggestAppsDialog.Metrics.startLoad(); | |
| 242 | |
| 243 // Makes it sure that the initialization is completed. | |
| 244 this.initializationTask_.run(function() { | |
| 245 if (!this.accessToken_) { | |
| 246 this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING; | |
| 247 this.onHide_(); | |
| 248 return; | |
| 249 } | |
| 250 | |
| 251 var title = str('SUGGEST_DIALOG_TITLE'); | |
| 252 var show = this.dialogText_ ? | |
| 253 FileManagerDialogBase.prototype.showTitleAndTextDialog.call( | |
| 254 this, title, this.dialogText_) : | |
| 255 FileManagerDialogBase.prototype.showTitleOnlyDialog.call( | |
| 256 this, title); | |
| 257 if (!show) { | |
| 258 console.error('SuggestAppsDialog can\'t be shown'); | |
| 259 this.state_ = SuggestAppsDialog.State.UNINITIALIZED; | |
| 260 this.onHide(); | |
| 261 return; | |
| 262 } | |
| 263 | |
| 264 this.webview_ = this.document_.createElement('webview'); | |
| 265 this.webview_.id = 'cws-widget'; | |
| 266 this.webview_.partition = 'persist:cwswidgets'; | |
| 267 this.webview_.style.width = WEBVIEW_WIDTH + 'px'; | |
| 268 this.webview_.style.height = WEBVIEW_HEIGHT + 'px'; | |
| 269 this.webview_.request.onBeforeSendHeaders.addListener( | |
| 270 this.authorizeRequest_.bind(this), | |
| 271 {urls: [this.widgetOrigin_ + '/*']}, | |
| 272 ['blocking', 'requestHeaders']); | |
| 273 this.webview_.addEventListener('newwindow', function(event) { | |
| 274 // Discard the window object and reopen in an external window. | |
| 275 event.window.discard(); | |
| 276 util.visitURL(event.targetUrl); | |
| 277 event.preventDefault(); | |
| 278 }); | |
| 279 this.webviewContainer_.appendChild(this.webview_); | |
| 280 | |
| 281 this.frame_.classList.add('show-spinner'); | |
| 282 | |
| 283 this.webviewClient_ = new CWSContainerClient( | |
| 284 this.webview_, | |
| 285 extension, mime, filename, | |
| 286 WEBVIEW_WIDTH, WEBVIEW_HEIGHT, | |
| 287 this.widgetUrl_, this.widgetOrigin_); | |
| 288 this.webviewClient_.addEventListener(CWSContainerClient.Events.LOADED, | |
| 289 this.onWidgetLoaded_.bind(this)); | |
| 290 this.webviewClient_.addEventListener(CWSContainerClient.Events.LOAD_FAILED, | |
| 291 this.onWidgetLoadFailed_.bind(this)); | |
| 292 this.webviewClient_.addEventListener( | |
| 293 CWSContainerClient.Events.REQUEST_INSTALL, | |
| 294 this.onInstallRequest_.bind(this)); | |
| 295 this.webviewClient_.load(); | |
| 296 }.bind(this)); | |
| 297 }; | |
| 298 | |
| 299 /** | |
| 300 * Called when the 'See more...' link is clicked to be navigated to Webstore. | |
| 301 * @param {Event} e Event. | |
| 302 * @private | |
| 303 */ | |
| 304 SuggestAppsDialog.prototype.onWebstoreLinkClicked_ = function(e) { | |
| 305 var webStoreUrl = | |
| 306 FileTasks.createWebStoreLink(this.extension_, this.mimeType_); | |
| 307 util.visitURL(webStoreUrl); | |
| 308 this.state_ = SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING; | |
| 309 this.hide(); | |
| 310 }; | |
| 311 | |
| 312 /** | |
| 313 * Called when the widget is loaded successfully. | |
| 314 * @param {Event} event Event. | |
| 315 * @private | |
| 316 */ | |
| 317 SuggestAppsDialog.prototype.onWidgetLoaded_ = function(event) { | |
| 318 SuggestAppsDialog.Metrics.finishLoad(); | |
| 319 SuggestAppsDialog.Metrics.recordLoad( | |
| 320 SuggestAppsDialog.Metrics.LOAD.SUCCEEDED); | |
| 321 | |
| 322 this.frame_.classList.remove('show-spinner'); | |
| 323 this.state_ = SuggestAppsDialog.State.INITIALIZED; | |
| 324 | |
| 325 this.webview_.focus(); | |
| 326 }; | |
| 327 | |
| 328 /** | |
| 329 * Called when the widget is failed to load. | |
| 330 * @param {Event} event Event. | |
| 331 * @private | |
| 332 */ | |
| 333 SuggestAppsDialog.prototype.onWidgetLoadFailed_ = function(event) { | |
| 334 SuggestAppsDialog.Metrics.recordLoad(SuggestAppsDialog.Metrics.LOAD.FAILURE); | |
| 335 | |
| 336 this.frame_.classList.remove('show-spinner'); | |
| 337 this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING; | |
| 338 | |
| 339 this.hide(); | |
| 340 }; | |
| 341 | |
| 342 /** | |
| 343 * Called when the connection status is changed. | |
| 344 * @param {util.DriveConnectionType} connectionType Current connection type. | |
| 345 */ | |
| 346 SuggestAppsDialog.prototype.onDriveConnectionChanged = | |
| 347 function(connectionType) { | |
| 348 if (this.state_ !== SuggestAppsDialog.State.UNINITIALIZED && | |
| 349 connectionType === util.DriveConnectionType.OFFLINE) { | |
| 350 this.state_ = SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING; | |
| 351 this.hide(); | |
| 352 } | |
| 353 }; | |
| 354 | |
| 355 /** | |
| 356 * Called when receiving the install request from the webview client. | |
| 357 * @param {Event} e Event. | |
| 358 * @private | |
| 359 */ | |
| 360 SuggestAppsDialog.prototype.onInstallRequest_ = function(e) { | |
| 361 var itemId = e.itemId; | |
| 362 this.installingItemId_ = itemId; | |
| 363 | |
| 364 this.appInstaller_ = new AppInstaller(itemId); | |
| 365 this.appInstaller_.install(this.onInstallCompleted_.bind(this)); | |
| 366 | |
| 367 this.frame_.classList.add('show-spinner'); | |
| 368 this.state_ = SuggestAppsDialog.State.INSTALLING; | |
| 369 }; | |
| 370 | |
| 371 /** | |
| 372 * Called when the installation is completed from the app installer. | |
| 373 * @param {AppInstaller.Result} result Result of the installation. | |
| 374 * @param {string} error Detail of the error. | |
| 375 * @private | |
| 376 */ | |
| 377 SuggestAppsDialog.prototype.onInstallCompleted_ = function(result, error) { | |
| 378 var success = (result === AppInstaller.Result.SUCCESS); | |
| 379 | |
| 380 this.frame_.classList.remove('show-spinner'); | |
| 381 this.state_ = success ? | |
| 382 SuggestAppsDialog.State.INSTALLED_CLOSING : | |
| 383 SuggestAppsDialog.State.INITIALIZED; // Back to normal state. | |
| 384 this.webviewClient_.onInstallCompleted(success, this.installingItemId_); | |
| 385 this.installingItemId_ = null; | |
| 386 | |
| 387 switch (result) { | |
| 388 case AppInstaller.Result.SUCCESS: | |
| 389 SuggestAppsDialog.Metrics.recordInstall( | |
| 390 SuggestAppsDialog.Metrics.INSTALL.SUCCESS); | |
| 391 this.hide(); | |
| 392 break; | |
| 393 case AppInstaller.Result.CANCELLED: | |
| 394 SuggestAppsDialog.Metrics.recordInstall( | |
| 395 SuggestAppsDialog.Metrics.INSTALL.CANCELLED); | |
| 396 // User cancelled the installation. Do nothing. | |
| 397 break; | |
| 398 case AppInstaller.Result.ERROR: | |
| 399 SuggestAppsDialog.Metrics.recordInstall( | |
| 400 SuggestAppsDialog.Metrics.INSTALL.FAILED); | |
| 401 fileManager.error.show(str('SUGGEST_DIALOG_INSTALLATION_FAILED')); | |
| 402 break; | |
| 403 } | |
| 404 }; | |
| 405 | |
| 406 /** | |
| 407 * @override | |
| 408 */ | |
| 409 SuggestAppsDialog.prototype.hide = function(opt_originalOnHide) { | |
| 410 switch (this.state_) { | |
| 411 case SuggestAppsDialog.State.INSTALLING: | |
| 412 // Install is being aborted. Send the failure result. | |
| 413 // Cancels the install. | |
| 414 if (this.webviewClient_) | |
| 415 this.webviewClient_.onInstallCompleted(false, this.installingItemId_); | |
| 416 this.installingItemId_ = null; | |
| 417 | |
| 418 // Assumes closing the dialog as canceling the install. | |
| 419 this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING; | |
| 420 break; | |
| 421 case SuggestAppsDialog.State.INITIALIZING: | |
| 422 SuggestAppsDialog.Metrics.recordLoad( | |
| 423 SuggestAppsDialog.Metrics.LOAD.CANCELLED); | |
| 424 this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING; | |
| 425 break; | |
| 426 case SuggestAppsDialog.State.INSTALLED_CLOSING: | |
| 427 case SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING: | |
| 428 case SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING: | |
| 429 // Do nothing. | |
| 430 break; | |
| 431 case SuggestAppsDialog.State.INITIALIZED: | |
| 432 this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING; | |
| 433 break; | |
| 434 default: | |
| 435 this.state_ = SuggestAppsDialog.State.CANCELED_CLOSING; | |
| 436 console.error('Invalid state.'); | |
| 437 } | |
| 438 | |
| 439 if (this.webviewClient_) { | |
| 440 this.webviewClient_.dispose(); | |
| 441 this.webviewClient_ = null; | |
| 442 } | |
| 443 | |
| 444 this.webviewContainer_.removeChild(this.webview_); | |
| 445 this.webview_ = null; | |
| 446 this.extension_ = null; | |
| 447 this.mime_ = null; | |
| 448 | |
| 449 FileManagerDialogBase.prototype.hide.call( | |
| 450 this, | |
| 451 this.onHide_.bind(this, opt_originalOnHide)); | |
| 452 }; | |
| 453 | |
| 454 /** | |
| 455 * @param {function()=} opt_originalOnHide Original onHide function passed to | |
| 456 * SuggestAppsDialog.hide(). | |
| 457 * @private | |
| 458 */ | |
| 459 SuggestAppsDialog.prototype.onHide_ = function(opt_originalOnHide) { | |
| 460 // Calls the callback after the dialog hides. | |
| 461 if (opt_originalOnHide) | |
| 462 opt_originalOnHide(); | |
| 463 | |
| 464 var result; | |
| 465 switch (this.state_) { | |
| 466 case SuggestAppsDialog.State.INSTALLED_CLOSING: | |
| 467 result = SuggestAppsDialog.Result.INSTALL_SUCCESSFUL; | |
| 468 SuggestAppsDialog.Metrics.recordCloseDialog( | |
| 469 SuggestAppsDialog.Metrics.CLOSE_DIALOG.ITEM_INSTALLED); | |
| 470 break; | |
| 471 case SuggestAppsDialog.State.INITIALIZE_FAILED_CLOSING: | |
| 472 result = SuggestAppsDialog.Result.FAILED; | |
| 473 break; | |
| 474 case SuggestAppsDialog.State.CANCELED_CLOSING: | |
| 475 result = SuggestAppsDialog.Result.USER_CANCELL; | |
| 476 SuggestAppsDialog.Metrics.recordCloseDialog( | |
| 477 SuggestAppsDialog.Metrics.CLOSE_DIALOG.USER_CANCELL); | |
| 478 break; | |
| 479 case SuggestAppsDialog.State.OPENING_WEBSTORE_CLOSING: | |
| 480 result = SuggestAppsDialog.Result.WEBSTORE_LINK_OPENED; | |
| 481 SuggestAppsDialog.Metrics.recordCloseDialog( | |
| 482 SuggestAppsDialog.Metrics.CLOSE_DIALOG.WEB_STORE_LINK); | |
| 483 break; | |
| 484 default: | |
| 485 result = SuggestAppsDialog.Result.USER_CANCELL; | |
| 486 SuggestAppsDialog.Metrics.recordCloseDialog( | |
| 487 SuggestAppsDialog.Metrics.CLOSE_DIALOG.UNKNOWN_ERROR); | |
| 488 console.error('Invalid state.'); | |
| 489 } | |
| 490 this.state_ = SuggestAppsDialog.State.UNINITIALIZED; | |
| 491 | |
| 492 this.onDialogClosed_(result); | |
| 493 }; | |
| 494 | |
| 495 /** | |
| 496 * Utility methods and constants to record histograms. | |
| 497 */ | |
| 498 SuggestAppsDialog.Metrics = Object.freeze({ | |
| 499 LOAD: Object.freeze({ | |
| 500 SUCCEEDED: 0, | |
| 501 CANCELLED: 1, | |
| 502 FAILED: 2, | |
| 503 }), | |
| 504 | |
| 505 /** | |
| 506 * @param {SuggestAppsDialog.Metrics.LOAD} result Result of load. | |
| 507 */ | |
| 508 recordLoad: function(result) { | |
| 509 if (0 <= result && result < 3) | |
| 510 metrics.recordEnum('SuggestApps.Load', result, 3); | |
| 511 }, | |
| 512 | |
| 513 CLOSE_DIALOG: Object.freeze({ | |
| 514 UNKOWN_ERROR: 0, | |
| 515 ITEM_INSTALLED: 1, | |
| 516 USER_CANCELLED: 2, | |
| 517 WEBSTORE_LINK_OPENED: 3, | |
| 518 }), | |
| 519 | |
| 520 /** | |
| 521 * @param {SuggestAppsDialog.Metrics.CLOSE_DIALOG} reason Reason of closing | |
| 522 * dialog. | |
| 523 */ | |
| 524 recordCloseDialog: function(reason) { | |
| 525 if (0 <= reason && reason < 4) | |
| 526 metrics.recordEnum('SuggestApps.CloseDialog', reason, 4); | |
| 527 }, | |
| 528 | |
| 529 INSTALL: Object.freeze({ | |
| 530 SUCCEEDED: 0, | |
| 531 CANCELLED: 1, | |
| 532 FAILED: 2, | |
| 533 }), | |
| 534 | |
| 535 /** | |
| 536 * @param {SuggestAppsDialog.Metrics.INSTALL} result Result of installation. | |
| 537 */ | |
| 538 recordInstall: function(result) { | |
| 539 if (0 <= result && result < 3) | |
| 540 metrics.recordEnum('SuggestApps.Install', result, 3); | |
| 541 }, | |
| 542 | |
| 543 recordShowDialog: function() { | |
| 544 metrics.recordUserAction('SuggestApps.ShowDialog'); | |
| 545 }, | |
| 546 | |
| 547 startLoad: function() { | |
| 548 metrics.startInterval('SuggestApps.LoadTime'); | |
| 549 }, | |
| 550 | |
| 551 finishLoad: function() { | |
| 552 metrics.recordInterval('SuggestApps.LoadTime'); | |
| 553 }, | |
| 554 }); | |
| OLD | NEW |