Don't preload rarely seen large images
[chromium-blink-merge.git] / third_party / google_input_tools / src / chrome / os / statistics.js
blob693e18979b7f27ea428e316dfc06a1a89831619f
1 // Copyright 2014 The ChromeOS IME Authors. All Rights Reserved.
2 // limitations under the License.
3 // See the License for the specific language governing permissions and
4 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5 // distributed under the License is distributed on an "AS-IS" BASIS,
6 // Unless required by applicable law or agreed to in writing, software
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // You may obtain a copy of the License at
11 // you may not use this file except in compliance with the License.
12 // Licensed under the Apache License, Version 2.0 (the "License");
14 goog.provide('i18n.input.chrome.Statistics');
16 goog.require('i18n.input.chrome.TriggerType');
18 goog.scope(function() {
19 var TriggerType = i18n.input.chrome.TriggerType;
23 /**
24 * The statistics util class for IME of ChromeOS.
26 * @constructor
28 i18n.input.chrome.Statistics = function() {
30 goog.addSingletonGetter(i18n.input.chrome.Statistics);
31 var Statistics = i18n.input.chrome.Statistics;
34 /**
35 * The layout types for stats.
37 * @enum {number}
39 Statistics.LayoutTypes = {
40 COMPACT: 0,
41 COMPACT_SYMBOL: 1,
42 COMPACT_MORE: 2,
43 FULL: 3,
44 A11Y: 4,
45 HANDWRITING: 5,
46 EMOJI: 6,
47 MAX: 7
51 /**
52 * The commit type for stats.
53 * Keep this in sync with the enum IMECommitType2 in histograms.xml file in
54 * chromium.
55 * For adding new items, please append it at the end.
57 * @enum {number}
59 Statistics.CommitTypes = {
60 X_X0: 0, // User types X, and chooses X as top suggestion.
61 X_Y0: 1, // User types X, and chooses Y as top suggestion.
62 X_X1: 2, // User types X, and chooses X as 2nd suggestion.
63 X_Y1: 3, // User types X, and chooses Y as 2nd suggestion.
64 X_X2: 4, // User types X, and chooses X as 3rd/other suggestion.
65 X_Y2: 5, // User types X, and chooses Y as 3rd/other suggestion.
66 PREDICTION: 6,
67 REVERT: 7,
68 VOICE: 8,
69 MAX: 9
73 /**
74 * The current input method id.
76 * @private {string}
78 Statistics.prototype.inputMethodId_ = '';
81 /**
82 * The current auto correct level.
84 * @private {number}
86 Statistics.prototype.autoCorrectLevel_ = 0;
89 /**
90 * Number of characters entered between each backspace.
92 * @private {number}
94 Statistics.prototype.charactersBetweenBackspaces_ = 0;
97 /**
98 * Maximum pause duration in milliseconds.
100 * @private {number}
101 * @const
103 Statistics.prototype.MAX_PAUSE_DURATION_ = 3000;
107 * Minimum words typed before committing the WPM statistic.
109 * @private {number}
110 * @const
112 Statistics.prototype.MIN_WORDS_FOR_WPM_ = 10;
116 * Timestamp of last activity.
118 * @private {number}
120 Statistics.prototype.lastActivityTimeStamp_ = 0;
124 * Time spent typing.
126 * @private {number}
128 Statistics.prototype.typingDuration_ = 0;
132 * Whether recording for physical keyboard specially.
134 * @private {boolean}
136 Statistics.prototype.isPhysicalKeyboard_ = false;
140 * The length of the last text commit.
142 * @private {number}
144 Statistics.prototype.lastCommitLength_ = 0;
148 * The number of characters typed in this session.
150 * @private {number}
152 Statistics.prototype.charactersCommitted_ = 0;
156 * The number of characters to ignore when calculating WPM.
158 * @private {number}
160 Statistics.prototype.droppedKeys_ = 0;
164 * Sets whether recording for physical keyboard.
166 * @param {boolean} isPhysicalKeyboard .
168 Statistics.prototype.setPhysicalKeyboard = function(isPhysicalKeyboard) {
169 this.isPhysicalKeyboard_ = isPhysicalKeyboard;
174 * Sets the current input method id.
176 * @param {string} inputMethodId .
178 Statistics.prototype.setInputMethodId = function(
179 inputMethodId) {
180 this.inputMethodId_ = inputMethodId;
185 * Sets the current auto-correct level.
187 * @param {number} level .
189 Statistics.prototype.setAutoCorrectLevel = function(
190 level) {
191 this.autoCorrectLevel_ = level;
192 this.recordEnum('InputMethod.AutoCorrectLevel', level, 3);
197 * Records that the controller session ended.
199 Statistics.prototype.recordSessionEnd = function() {
200 // Do not record cases where we gain and immediately lose focus. This also
201 // excudes the focus loss-gain on the new tab page from being counted.
202 if (this.charactersCommitted_ > 0) {
203 this.recordValue('InputMethod.VirtualKeyboard.CharactersCommitted',
204 this.charactersCommitted_, 16384, 50);
205 var words = (this.charactersCommitted_ - this.droppedKeys_) / 5;
206 if (this.typingDuration_ > 0 && words > this.MIN_WORDS_FOR_WPM_) {
207 // Milliseconds to minutes.
208 var minutes = this.typingDuration_ / 60000;
209 this.recordValue('InputMethod.VirtualKeyboard.WordsPerMinute',
210 Math.round(words / minutes), 100, 100);
213 this.droppedKeys_ = 0;
214 this.charactersCommitted_ = 0;
215 this.lastCommitLength_ = 0;
216 this.typingDuration_ = 0;
217 this.lastActivityTimeStamp_ = 0;
222 * Records the metrics for each commit.
224 * @param {string} source .
225 * @param {string} target .
226 * @param {number} targetIndex The target index.
227 * @param {!TriggerType} triggerType The trigger type.
229 Statistics.prototype.recordCommit = function(
230 source, target, targetIndex, triggerType) {
231 if (!this.inputMethodId_) {
232 return;
234 var length = target.length;
235 // Increment to include space.
236 if (triggerType == TriggerType.RESET) {
237 length++;
238 } else if (triggerType == TriggerType.REVERT) {
239 length -= this.lastCommitLength_;
241 this.lastCommitLength_ = length;
242 this.charactersCommitted_ += length;
244 var CommitTypes = Statistics.CommitTypes;
245 var commitType = -1;
246 if (targetIndex == 0 && source == target) {
247 commitType = CommitTypes.X_X0;
248 } else if (targetIndex == 0 && source != target) {
249 commitType = CommitTypes.X_Y0;
250 } else if (targetIndex == 1 && source == target) {
251 commitType = CommitTypes.X_X1;
252 } else if (targetIndex == 1 && source != target) {
253 commitType = CommitTypes.X_Y1;
254 } else if (targetIndex > 1 && source == target) {
255 commitType = CommitTypes.X_X2;
256 } else if (targetIndex > 1 && source != target) {
257 commitType = CommitTypes.X_Y2;
258 } else if (!source && source != target) {
259 commitType = CommitTypes.PREDICTION;
260 } else if (triggerType == TriggerType.REVERT) {
261 commitType = CommitTypes.REVERT;
262 } else if (triggerType == TriggerType.VOICE) {
263 commitType = CommitTypes.VOICE;
265 if (commitType < 0) {
266 return;
269 // For latin transliteration, record the logs under the name with 'Pk' which
270 // means Physical Keyboard.
271 var name = this.isPhysicalKeyboard_ ?
272 'InputMethod.PkCommit.' : 'InputMethod.Commit.';
273 var type = this.isPhysicalKeyboard_ ? 'Type' : 'Type2';
275 var self = this;
276 var record = function(suffix) {
277 self.recordEnum(name + 'Index' + suffix, targetIndex + 1, 20);
278 self.recordEnum(name + type + suffix, commitType, CommitTypes.MAX);
281 record('');
283 if (/^pinyin/.test(this.inputMethodId_)) {
284 record('.Pinyin');
285 } else if (/^xkb:us/.test(this.inputMethodId_)) {
286 record('.US');
287 record('.US.AC' + this.autoCorrectLevel_);
288 } else if (/^xkb:fr/.test(this.inputMethodId_)) {
289 record('.FR');
290 record('.FR.AC' + this.autoCorrectLevel_);
296 * Records the latency value for stats.
298 * @param {string} name .
299 * @param {number} timeInMs .
301 Statistics.prototype.recordLatency = function(
302 name, timeInMs) {
303 this.recordValue(name, timeInMs, 1000, 50);
308 * Gets the layout type for stats.
310 * @param {string} layoutCode .
311 * @param {boolean} isA11yMode .
312 * @return {Statistics.LayoutTypes}
314 Statistics.prototype.getLayoutType = function(layoutCode, isA11yMode) {
315 var LayoutTypes = Statistics.LayoutTypes;
316 var layoutType = LayoutTypes.MAX;
317 if (isA11yMode) {
318 layoutType = LayoutTypes.A11Y;
319 } else if (/compact/.test(layoutCode)) {
320 if (/symbol/.test(layoutCode)) {
321 layoutType = LayoutTypes.COMPACT_SYMBOL;
322 } else if (/more/.test(layoutCode)) {
323 layoutType = LayoutTypes.COMPACT_MORE;
324 } else {
325 layoutType = LayoutTypes.COMPACT;
327 } else if (/^hwt/.test(layoutCode)) {
328 layoutType = LayoutTypes.HANDWRITING;
329 } else if (/^emoji/.test(layoutCode)) {
330 layoutType = LayoutTypes.EMOJI;
332 return layoutType;
337 * Records the layout usage.
339 * @param {string} layoutCode The layout code to be switched to.
340 * @param {boolean} isA11yMode .
342 Statistics.prototype.recordLayout = function(
343 layoutCode, isA11yMode) {
344 this.recordEnum('InputMethod.VirtualKeyboard.Layout',
345 this.getLayoutType(layoutCode, isA11yMode), Statistics.LayoutTypes.MAX);
350 * Records the layout switching action.
352 Statistics.prototype.recordLayoutSwitch = function() {
353 this.recordValue('InputMethod.VirtualKeyboard.LayoutSwitch', 1, 1, 1);
358 * Records enum value.
360 * @param {string} name .
361 * @param {number} enumVal .
362 * @param {number} enumCount .
364 Statistics.prototype.recordEnum = function(
365 name, enumVal, enumCount) {
366 if (chrome.metricsPrivate && chrome.metricsPrivate.recordValue) {
367 chrome.metricsPrivate.recordValue({
368 'metricName': name,
369 'type': 'histogram-linear',
370 'min': 0,
371 'max': enumCount - 1,
372 'buckets': enumCount
373 }, enumVal);
379 * Records count value.
381 * @param {string} name .
382 * @param {number} count .
383 * @param {number} max .
384 * @param {number} bucketCount .
386 Statistics.prototype.recordValue = function(
387 name, count, max, bucketCount) {
388 if (chrome.metricsPrivate && chrome.metricsPrivate.recordValue) {
389 chrome.metricsPrivate.recordValue({
390 'metricName': name,
391 'type': 'histogram-log',
392 'min': 0,
393 'max': max,
394 'buckets': bucketCount
395 }, count);
401 * Records a key down.
403 Statistics.prototype.recordCharacterKey = function() {
404 var now = Date.now();
405 if (this.lastActivityTimeStamp_) {
406 if (now < (this.lastActivityTimeStamp_ + this.MAX_PAUSE_DURATION_)) {
407 this.typingDuration_ += (now - this.lastActivityTimeStamp_);
408 } else {
409 // Exceeded pause duration. Ignore this character.
410 this.droppedKeys_++;
412 } else {
413 // Ignore the first character in the new session.
414 this.droppedKeys_++;
416 this.lastActivityTimeStamp_ = now;
417 this.charactersBetweenBackspaces_++;
422 * Records a backspace.
424 Statistics.prototype.recordBackspace = function() {
425 // Ignore multiple backspaces typed in succession.
426 if (this.charactersBetweenBackspaces_ > 0) {
427 this.recordValue(
428 'InputMethod.VirtualKeyboard.CharactersBetweenBackspaces',
429 this.charactersBetweenBackspaces_, 4096, 50);
431 this.charactersBetweenBackspaces_ = 0;
433 }); // goog.scope