Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / test / data / extensions / api_test / notifications / galore / app / controller.js
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 var STOPPED = "Stopped";
6 var RECORDING = "Recording";
7 var PAUSED_RECORDING = "Recording Paused";
8 var PAUSED_PLAYING = "Playing Paused";
9 var PLAYING = "Playing";
10
11 var recordingState = STOPPED;
12
13 // Timestamp when current segment started.
14 var segmentStart;
15 // Segment duration accumulated before pause button was hit.
16 var pausedDuration;
17 // The array of segments, with delay and action.
18 var recordingList;
19 // When this timer fires, the next segment from recordingList should be played.
20 var playingTimer;
21 var currentSegmentIndex;
22 // A set of web Notifications - used to delete them during playback by id.
23 var webNotifications = {};
24
25 var recorderButtons = [ "play", "record", "pause", "stop"];
26 var recorderButtonStates = [
27   { state: STOPPED, enabled: "play record" },
28   { state: RECORDING, enabled: "pause stop" },
29   { state: PAUSED_RECORDING, enabled: "record stop" },
30   { state: PAUSED_PLAYING, enabled: "play stop" },
31   { state: PLAYING, enabled: "pause stop" }
32 ];
33
34 // This function forms 2 selector lists - one that includes enabled buttons
35 // and one that includes disabled ones. Then it applies "disabled" attribute to
36 // corresponding sets of buttons.
37 function updateButtonsState() {
38   recorderButtonStates.map(function(entry) {
39     if (entry.state != recordingState)
40       return;
41     // Found entry with current recorder state. Now compute the sets
42     // of enabled/disabled buttons.
43     // Copy a list of all buttons.
44     var disabled = recorderButtons.slice(0);
45     // Get an array of enabled buttons for the state.
46     var enabled = entry.enabled.split(" ");
47     // Remove enabled buttons from disabled list, prefix them with "#" so they
48     // form proper id selectors.
49     for (var i = 0; i < enabled.length; i++) {
50       disabled.splice(disabled.indexOf(enabled[i]), 1);
51       enabled[i] = "#" + enabled[i];
52     }
53     // Prefix remaining disabled ids to form proper id selectors.
54     for (var i = 0; i < disabled.length; i++) {
55       disabled[i] = "#" + disabled[i];
56     }
57     getElements(disabled.join(", ")).forEach(function(element) {
58       element.setAttribute("disabled", "true")
59     })
60     getElements(enabled.join(", ")).forEach(function(element) {
61       element.removeAttribute("disabled")
62     })
63   })
64 }
65
66
67 function setRecordingState(newState) {
68   setRecorderStatusText(newState);
69   recordingState = newState;
70   updateButtonsState();
71 }
72
73 function updateRecordingStats(context) {
74   var length = 0;
75   var segmentCnt = 0;
76   recordingList.slice(currentSegmentIndex).forEach(function(segment) {
77     length += segment.delay || 0;
78     segmentCnt++;
79   })
80   updateRecordingStatsDisplay(context + ": " + (segmentCnt-1) + " segments, " +
81                               Math.floor(length/1000) + " seconds.");
82 }
83
84 function loadRecording() {
85   chrome.storage.local.get("recording", function(items) {
86     recordingList = JSON.parse(items["recording"] || "[]");
87     setRecordingState(STOPPED);
88     updateRecordingStats("Loaded record");
89   })
90 }
91
92 function finalizeRecording() {
93   chrome.storage.local.set({"recording": JSON.stringify(recordingList)});
94   updateRecordingStats("Recorded");
95 }
96
97 function setPreviousSegmentDuration() {
98   var now  = new Date().getTime();
99   var delay = now - segmentStart;
100   segmentStart = now;
101   recordingList[recordingList.length - 1].delay = delay;
102 }
103
104 function cloneOptions(obj){
105   if(obj == null || typeof(obj) != 'object')
106     return obj;
107
108   var temp = {};
109   for(var key in obj)
110     temp[key] = cloneOptions(obj[key]);
111   return temp;
112 }
113
114 function recordCreate(kind, id, options) {
115   if (recordingState != RECORDING)
116     return;
117   setPreviousSegmentDuration();
118   recordingList.push(
119     { type: "create", kind: kind, id: id, options: cloneOptions(options) });
120   updateRecordingStats("Recording");
121 }
122
123 function recordUpdate(kind, id, options) {
124   if (recordingState != RECORDING)
125     return;
126   setPreviousSegmentDuration();
127   recordingList.push(
128     { type: "update", kind: kind, id: id, options: cloneOptions(options) });
129   updateRecordingStats("Recording");
130 }
131
132 function recordDelete(kind, id) {
133   if (recordingState != RECORDING)
134     return;
135   setPreviousSegmentDuration();
136   recordingList.push({ type: "delete", kind: kind, id: id });
137   updateRecordingStats("Recording");
138 }
139
140 function startPlaying() {
141   if (recordingList.length < 2)
142     return false;
143
144   setRecordingState(PLAYING);
145
146   if (playingTimer)
147     clearTimeout(playingTimer);
148
149   webNotifications = {};
150   currentSegmentIndex = 0;
151   playingTimer = setTimeout(playNextSegment,
152                             recordingList[currentSegmentIndex].delay);
153   updateRecordingStats("Playing");
154 }
155
156 function playNextSegment() {
157   currentSegmentIndex++;
158   var segment = recordingList[currentSegmentIndex];
159   if (!segment) {
160     stopPlaying();
161     return;
162   }
163
164   if (segment.type == "create") {
165     createNotificationForPlay(segment.kind, segment.id, segment.options);
166   } else if (segment.type == "update") {
167     updateNotificationForPlay(segment.kind, segment.id, segment.options);
168   } else { // type == "delete"
169     deleteNotificationForPlay(segment.kind, segment.id);
170   }
171   playingTimer = setTimeout(playNextSegment,
172                             recordingList[currentSegmentIndex].delay);
173   segmentStart = new Date().getTime();
174   updateRecordingStats("Playing");
175 }
176
177 function deleteNotificationForPlay(kind, id) {
178   if (kind == 'web') {
179     webNotifications[id].close();
180   } else {
181     chrome.notifications.clear(id, function(wasClosed) {
182       // nothing to do
183     });
184   }
185 }
186
187 function createNotificationForPlay(kind, id, options) {
188   if (kind == 'web') {
189     webNotifications[id] = createWebNotification(id, options);
190   } else {
191     var type = options.type;
192     var priority = options.priority;
193     createRichNotification(id, type, priority, options);
194   }
195 }
196
197 function updateNotificationForPlay(kind, id, options) {
198   if (kind == 'web') {
199     // TODO: implement update.
200   } else {
201     var type = options.type;
202     var priority = options.priority;
203     updateRichNotification(id, type, priority, options);
204   }
205 }
206
207 function stopPlaying() {
208   currentSegmentIndex = 0;
209   clearTimeout(playingTimer);
210   updateRecordingStats("Record");
211   setRecordingState(STOPPED);
212 }
213
214 function pausePlaying() {
215   clearTimeout(playingTimer);
216   pausedDuration = new Date().getTime() - segmentStart;
217   setRecordingState(PAUSED_PLAYING);
218 }
219
220 function unpausePlaying() {
221   var remainingInSegment =
222       recordingList[currentSegmentIndex].delay - pausedDuration;
223   if (remainingInSegment < 0)
224     remainingInSegment = 0;
225   playingTimer = setTimeout(playNextSegment, remainingInSegment);
226   segmentStart = new Date().getTime() - pausedDuration;
227 }
228
229 function onRecord() {
230   if (recordingState == STOPPED) {
231     segmentStart = new Date().getTime();
232     pausedDuration = 0;
233     // This item is only needed to keep a duration of the delay between start
234     // and first action.
235     recordingList = [ { type:"start" } ];
236   } else if (recordingState == PAUSED_RECORDING) {
237     segmentStart = new Date().getTime() - pausedDuration;
238     pausedDuration = 0;
239   } else {
240     return;
241   }
242   updateRecordingStats("Recording");
243   setRecordingState(RECORDING);
244 }
245
246 function pauseRecording() {
247   pausedDuration = new Date().getTime() - segmentStart;
248   segmentStart = 0;
249   setRecordingState(PAUSED_RECORDING);
250 }
251
252 function onPause() {
253   if (recordingState == RECORDING) {
254     pauseRecording();
255   } else if (recordingState == PLAYING) {
256     pausePlaying();
257   } else {
258     return;
259   }
260 }
261
262 function onStop() {
263   switch (recordingState) {
264     case PAUSED_RECORDING:
265       segmentStart = new Date().getTime() - pausedDuration;
266       // fall through
267     case RECORDING:
268       finalizeRecording();
269       break;
270     case PLAYING:
271     case PAUSED_PLAYING:
272       stopPlaying();
273       break;
274   }
275   setRecordingState(STOPPED);
276 }
277
278 function onPlay() {
279   if (recordingState == STOPPED) {
280     if (!startPlaying())
281       return;
282   } else if (recordingState == PAUSED_PLAYING) {
283     unpausePlaying();
284   }
285   setRecordingState(PLAYING);
286 }
287
288 function createWindow() {
289   chrome.storage.local.get('settings', onSettingsFetched);
290 }
291
292 function onSettingsFetched(items) {
293   settings = items.settings || settings;
294   var request = new XMLHttpRequest();
295   var source = '/data/data.json';
296   request.open('GET', source, true);
297   request.responseType = 'text';
298   request.onload = onDataFetched;
299   request.send();
300 }
301
302 function onDataFetched() {
303   var data = JSON.parse(this.response);
304   createAppWindow(function() {
305     // Create notification buttons.
306     data.forEach(function(section) {
307       var type = section.notificationType;
308       if (type == "progress") {
309         addProgressControl(section.sectionName);
310       }
311       (section.notificationOptions || []).forEach(function(options) {
312         addNotificationButton(section.sectionName,
313                               options.title,
314                               options.iconUrl,
315                               function() { createNotification(type, options) });
316       });
317     });
318     loadRecording();
319     addListeners();
320     showWindow();
321   });
322 }
323
324 function onSettingsChange(settings) {
325   chrome.storage.local.set({settings: settings});
326 }
327
328 function scheduleNextProgress(id, priority, options, progress, step, timeout) {
329   var new_progress = progress + step;
330   if (new_progress > 100)
331     new_progress = 100;
332   setTimeout(nextProgress(id, priority, options, new_progress, step, timeout),
333     timeout);
334 }
335
336 function nextProgress(id, priority, options, progress, step, timeout) {
337   return (function() {
338     options["progress"] = progress;
339     updateRichNotification(id, "progress", priority, options);
340     if (progress >= 100)
341       return;
342     scheduleNextProgress(id, priority, options, progress, step, timeout)
343   })
344 }
345
346 function createNotification(type, options) {
347   var id = getNextId();
348   var priority = Number(settings.priority || 0);
349   if (type == 'web')
350     createWebNotification(id, options);
351   else {
352     if (type == "progress") {
353       if (getElement('#progress-oneshot').checked) {
354         options["progress"] = Number(getElement('#progress').value);
355       } else {
356         var step = Number(getElement('#progress-step').value);
357         options["progress"] = step;
358         if (options["progress"] < 100) {
359           scheduleNextProgress(id, priority, options, options["progress"], step,
360             Number(getElement('#progress-sec').value) * 1000);
361         }
362       }
363     }
364     createRichNotification(id, type, priority, options);
365   }
366 }
367
368 function createWebNotification(id, options) {
369   var iconUrl = options.iconUrl;
370   var title = options.title;
371   var message = options.message;
372   var n = new Notification(title, {
373     body: message,
374     icon: iconUrl,
375     tag: id
376   });
377   n.onshow = function() { logEvent('WebNotification #' + id + ': onshow'); }
378   n.onclick = function() { logEvent('WebNotification #' + id + ': onclick'); }
379   n.onclose = function() {
380     logEvent('WebNotification #' + id + ': onclose');
381     recordDelete('web', id);
382   }
383   logMethodCall('created', 'Web', id, 'title: "' + title + '"');
384   recordCreate('web', id, options);
385   return n;
386 }
387
388 function createRichNotification(id, type, priority, options) {
389   options["type"] = type;
390   options["priority"] = priority;
391   chrome.notifications.create(id, options, function() {
392     var argument1 = 'type: "' + type + '"';
393     var argument2 = 'priority: ' + priority;
394     var argument3 = 'title: "' + options.title + '"';
395     logMethodCall('created', 'Rich', id, argument1, argument2, argument3);
396   });
397   recordCreate('rich', id, options);
398 }
399
400 function updateRichNotification(id, type, priority, options) {
401   options["type"] = type;
402   options["priority"] = priority;
403   chrome.notifications.update(id, options, function() {
404     var argument1 = 'type: "' + type + '"';
405     var argument2 = 'priority: ' + priority;
406     var argument3 = 'title: "' + options.title + '"';
407     logMethodCall('updated', 'Rich', id, argument1, argument2, argument3);
408   });
409   recordUpdate('rich', id, options);
410 }
411
412 var counter = 0;
413 function getNextId() {
414     return String(counter++);
415 }
416
417 function addListeners() {
418   chrome.notifications.onClosed.addListener(onClosed);
419   chrome.notifications.onClicked.addListener(onClicked);
420   chrome.notifications.onButtonClicked.addListener(onButtonClicked);
421 }
422
423 function logMethodCall(method, kind, id, var_args) {
424   logEvent(kind + ' Notification #' + id + ': ' + method + ' (' +
425   Array.prototype.slice.call(arguments, 2).join(', ') + ')');
426 }
427
428 function onClosed(id) {
429   logEvent('Notification #' + id + ': onClosed');
430   recordDelete('rich', id);
431 }
432
433 function onClicked(id) {
434   logEvent('Notification #' + id + ': onClicked');
435 }
436
437 function onButtonClicked(id, index) {
438   logEvent('Notification #' + id + ': onButtonClicked, btn: ' + index);
439 }