Updated system prefs patches
[webos-internals:imagineer1981s-modifications.git] / advanced / advanced-system-prefs-phone-prefs-vzw.patch
1 --- .orig/etc/palm/db/permissions/com.palm.person.speeddialbackup
2 +++ /etc/palm/db/permissions/com.palm.person.speeddialbackup
3 @@ -31,5 +31,16 @@
4                         "delete": "allow",
5                         "update": "allow"
6                 }
7 -       }
8 +       },
9 +       {
10 +               "type": "db.kind",
11 +               "object": "com.palm.person.speeddialbackup:1",
12 +               "caller": "com.palm.app.phone",
13 +               "operations": {
14 +                       "read": "allow",
15 +                       "create": "allow",
16 +                       "delete": "allow",
17 +                       "update": "allow"
18 +               }
19 +       }       
20  ]
21 --- .orig/usr/palm/applications/com.palm.app.phone/sources.json
22 +++ /usr/palm/applications/com.palm.app.phone/sources.json
23 @@ -141,6 +141,9 @@
24      "source": "app/controllers/pin-assistant.js"
25    },
26    {
27 +    "source": "app/controllers/prefs-assistant.js"
28 +  },
29 +  {
30      "source": "app/models/DBModels.js"
31    },
32    {
33 @@ -172,6 +175,9 @@
34      "source": "app/models/states/Abstract.js"
35    },
36    {
37 +    "source": "app/models/states/Prefs.js"
38 +  },
39 +  {
40      "source": "app/models/states/Start.js"
41    },
42    {
43 --- .orig/usr/palm/applications/com.palm.app.phone/app/controllers/app-assistant.js
44 +++ /usr/palm/applications/com.palm.app.phone/app/controllers/app-assistant.js
45 @@ -2,6 +2,10 @@
46  
47  function AppAssistant(appController) {
48         var libraries;
49 +
50 +       this.phonePrefs = {};
51 +       this.rejectedPrefs = {};
52 +       this.notificationPrefs = {};
53         
54     // Mojo.Log.info( "AppAssistant");
55  
56 @@ -77,6 +81,8 @@
57                 Mojo.Log.error("PHONE APP FAILED TO LOAD BECAUSE AN EXCEPTION WAS THROWN BY A DEPENDENCY. EXCEPTION DETAILS TO FOLLOW.");
58                 throw e;
59         }
60 +
61 +       this.loadPreferences();
62  };
63  
64  AppAssistant.prototype.setup = function() {
65 @@ -108,6 +114,10 @@
66         } else if (event.type == Mojo.Event.command) {
67                 // handle app menu items common to all scenes
68                 switch (event.command) {
69 +                       case MenuController.kPrefsMenuItem.command:
70 +                               UIStateMachine.enter('prefs', this.phonePrefs, this.rejectedPrefs, this.notificationPrefs);
71 +                               break;
72 +
73                         case Mojo.Menu.prefsCmd:
74                                 MenuController.showPrefs();
75                                 break;
76 @@ -134,6 +144,50 @@
77         }
78  };
79  
80 +AppAssistant.prototype.loadPreferences = function() {
81 +       var cookieContainer = new Mojo.Model.Cookie("phone");
82 +
83 +       this.phonePrefs = cookieContainer.get();
84 +       
85 +       if(!this.phonePrefs) {
86 +               this.phonePrefs = {
87 +                       version: 1,
88 +                       closeApp: false,
89 +                       startView: "default",
90 +                       onCallView: "contact",
91 +                       autoDialing: "call",
92 +                       powerButton: "none",
93 +                       sliderOpened: "answer",
94 +                       sliderClosed: "hangup",
95 +                       removedFromTS: "answer",
96 +                       proximityAction: "none"
97 +               };
98 +               
99 +               cookieContainer.put(this.phonePrefs);
100 +       }
101 +
102 +       this.rejectedPrefs = {
103 +               rejectAction: "none",
104 +               rejectTemplate: "Sorry, I am currently busy and will call you back later..."
105 +       };
106 +       
107 +       this.notificationPrefs = {
108 +               notificationBlink: true,
109 +               repeatInterval: 0,
110 +               repeatLimit: 3
111 +       };
112 +
113 +       this.getPreferencesSubscription = new Mojo.Service.Request('palm://com.palm.systemservice/', {
114 +               method: 'getPreferences', parameters: {subscribe: true, keys: ["callRejection", "callNotification"]},
115 +               onSuccess: function(response) {
116 +                       if(response.callRejection)
117 +                               this.rejectedPrefs = response.callRejection;
118 +                       
119 +                       if(response.callNotification)
120 +                               this.notificationPrefs = response.callNotification;
121 +               }.bind(this)});
122 +}
123 +
124  AppAssistant.prototype.loadProperties = function() {
125         var sourcesText = palmGetResource(Mojo.appPath + "properties.json", true);
126         if (sourcesText) {
127 @@ -271,11 +325,17 @@
128                         this.createLockStage();
129                         this.loadSettings();
130                         return;
131 +               } else if (args.closeMissedCall) {
132 +                       Mojo.Controller.getAppController().closeStage("missed");
133 +               } else if (args.playNotificationSound) {
134 +                       // Delay playing to go around WebOS bug (sound not playing).
135 +
136 +                       setTimeout(this.playNotificationSound.bind(this, args.playNotificationSound), 1000);
137                 } else {
138                         // when in first use, always default to doing nothing for invalid args; 
139                         // otherwise default to showing dialpad
140                         if ( ! PalmSystem.isMinimal ) {
141 -                               UIStateMachine.event("launch");
142 +                               UIStateMachine.event("launch", this.phonePrefs.startView);
143                         }
144                 }
145      } else {
146 @@ -283,8 +343,8 @@
147                 if (!(this.telephonyEventListener.isPendingOrActive())) {
148                         if (this.initialLaunch === false) {
149                                 Mojo.Log.info( "handleLaunch", "no args, no calls: focusing stage");
150 -                               
151 -                               UIStateMachine.event("launch");
152 +
153 +                               UIStateMachine.event("launch", this.phonePrefs.startView);
154                         } else {
155                                 Mojo.Log.info( "handleLaunch", "initial launch, so doing nothing");
156                                 this.initialLaunch = false;
157 @@ -297,6 +357,16 @@
158      }
159  };
160  
161 +AppAssistant.prototype.playNotificationSound = function(count) {
162 +       var stageController = Mojo.Controller.getAppController().getStageController("misseddash");
163 +
164 +       if (stageController) {
165 +               stageController.delegateToSceneAssistant("playNotificationSound");
166 +
167 +               stageController.delegateToSceneAssistant("schedulePlayNotificationSoundTask", count);
168 +       }
169 +};
170 +
171  // Public API way of launching the phone app to a number (or opening skypevm)
172  AppAssistant.prototype.launchURI = function(uri) {
173         var uriNoPrefix = uri.replace(/^((tel:)|(wtai:)|(skypevm:\/\/))/,''),
174 @@ -394,7 +464,10 @@
175                                 || contact.addr.charAt(0) === '#'
176                                 || ! this.telephonyEventListener.serviced)) {
177                         
178 -                       UIStateMachine.event("dial", {"action": "dial", "number": contact.addr});
179 +                       if(this.phonePrefs.autoDialing != "none")
180 +                               UIStateMachine.event("dial", {"action": "dial", "number": contact.addr});
181 +                       else
182 +                               UIStateMachine.event("dial", {"action": "fill", "number": contact.addr});
183                 
184                 // CASE: just dial
185                 } else {
186 @@ -407,11 +480,16 @@
187                                 } else {
188                                         this.focusOnActiveCallSceneCreation = true;
189                                 }
190 -                               contact.placeCall(this.dialFailure.bind(this), parseResult);
191 -                       
192 +                               if(this.phonePrefs.autoDialing != "none")
193 +                                       contact.placeCall(this.dialFailure.bind(this), parseResult);
194 +                               else
195 +                                       UIStateMachine.event("dial", {"action": "fill", "number": contact.addr});
196                         // CASE: not immediately dialable. Let dialpad try it
197                         } else {
198 -                               UIStateMachine.event("dial", {"action": "dial", "number": contact.addr});
199 +                               if(this.phonePrefs.autoDialing != "none")
200 +                                       UIStateMachine.event("dial", {"action": "dial", "number": contact.addr});
201 +                               else
202 +                                       UIStateMachine.event("dial", {"action": "fill", "number": contact.addr});
203                         }
204                 }
205                 
206 --- .orig/usr/palm/applications/com.palm.app.phone/app/controllers/activecall-assistant.js
207 +++ /usr/palm/applications/com.palm.app.phone/app/controllers/activecall-assistant.js
208 @@ -29,7 +29,30 @@
209                 this.announcer = this.appAssistant.announcer;
210                 this.contacts = this.appAssistant.contacts; 
211          Mojo.Log.info( "activecall initialize");
212 +
213 +               this.audioPreviousProfile = null;
214 +               this.sliderState = "down";
215 +
216 +      var sliderStateRequest = new Mojo.Service.Request('palm://com.palm.keys/switches/', {
217 +                       method: 'status', parameters: {"get" : "slider"},
218 +                       onSuccess: function(response) {
219 +                               if(response.key === "slider")
220 +                                       this.sliderState = response.state;
221 +                       }.bind(this)});
222 +
223 +               this.sliderSubscription = TelephonyCommands.sliderSubscribe(
224 +                       this.onSliderEventDuringCall.bind(this));
225                 
226 +               if(this.appAssistant.phonePrefs.powerButton == "hangup") {
227 +                       this.powerButtonSubscription = TelephonyCommands.powerButtonSubscribe(
228 +                       true, 'activecall', this.onPowerButtonEventDuringCall.bind(this));
229 +               }
230 +
231 +               if(this.appAssistant.phonePrefs.proximityAction == "change") {
232 +                       this.displayStatusSubscription = TelephonyCommands.displayStatusSubscribe(
233 +                               this.onDisplayEventDuringCall.bind(this));
234 +               }
235 +                               
236                 this.lastLines = [];
237                 this.pauseWaitDigits = [];
238                 this.showWaitButtonOnActive = [];
239 @@ -151,7 +174,7 @@
240                 this.appAssistant.telephonyEventListener.addCallStateListener(this);
241                 this.appAssistant.telephonyEventListener.addAudioStateListener(this);
242                 
243 -               var appMenuModel = {
244 +/*             var appMenuModel = {
245                         visible: true,
246              items: [{
247                  label: $L('Sounds & Ringtones'),
248 @@ -159,6 +182,8 @@
249              }]
250                 }; 
251                 this.controller.setupWidget(Mojo.Menu.appMenu, undefined, appMenuModel);
252 +*/             
253 +               MenuController.setupAppMenu(this.controller);
254                 
255                 if (!this.abridged && this.appAssistant.focusOnActiveCallSceneCreation === true) {
256                         UIStateMachine.event('focus');
257 @@ -558,7 +583,9 @@
258                 if (this.showDTMF === true && lineState.length > 0 && !(lineState.length == 1 && this.lastLines.length == 1 
259                         && (lineState[0].state == TelephonyCallState.ACTIVE || lineState[0].state == TelephonyCallState.DIALPENDING)
260                         && (this.lastLines[0].state == TelephonyCallState.DIALING || this.lastLines[0].state == TelephonyCallState.DIALPENDING))) {
261 -                               this.setDTMFPadVisibility(false);
262 +                                       
263 +                               if(this.appAssistant.phonePrefs.onCallView != "keypad")
264 +                                       this.setDTMFPadVisibility(false);
265                 } 
266         },
267         
268 @@ -1242,6 +1269,9 @@
269                 // clear dial debounce
270                 DialStringParser.clearDebounceTimeout();
271                 this.activated = true;
272 +               
273 +               if(this.appAssistant.phonePrefs.onCallView == "keypad")
274 +                       this.setDTMFPadVisibility(true);
275         },
276      
277         incomingDialogLaunch: function() {
278 @@ -1303,6 +1333,22 @@
279          this.controller.document.removeEventListener('keydown', this.boundStartDTMFHardKey);
280          this.controller.document.removeEventListener('keyup', this.boundEndDTMFHardKey);
281                 
282 +      // remove slider listener
283 +               this.sliderSubscription.cancel();
284 +               delete this.sliderSubscription;
285 +               
286 +                // remove power button listener
287 +               if(this.appAssistant.phonePrefs.powerButton == "hangup") {
288 +                       this.powerButtonSubscription.cancel();
289 +                       delete this.powerButtonSubscription;
290 +               }
291 +
292 +                // remove display status listener
293 +               if(this.appAssistant.phonePrefs.proximityAction == "change") {
294 +                       this.displayStatusSubscription.cancel();
295 +                       delete this.displayStatusSubscription;
296 +               }
297 +       
298                 // drop puck subscription
299                 this.puckSubscription.cancel();
300                 delete this.puckSubscription;
301 @@ -1519,7 +1565,8 @@
302      },
303      
304      enableSpeakerphoneOnPuck: function(){
305 -        if (this.puckConnected === true && this.audioActiveProfile !== "phone_back_speaker") {
306 +        if (this.puckConnected === true && this.audioActiveProfile === "phone_front_speaker")
307 +        {
308              this.onAudioRouteChangeClick("phone_back_speaker");
309          }
310         },
311 @@ -2059,4 +2106,86 @@
312                 }
313         },
314      
315 +       onSliderEventDuringCall: function(response) {
316 +               if((!response) || (!response.key) || (!response.state))
317 +                       return;
318 +
319 +               if(this.appAssistant.phonePrefs.sliderClosed == "none")
320 +                       return;
321 +
322 +               if((response.key == "slider") && (this.audioActiveProfile == "phone_front_speaker")) {
323 +                       if((this.sliderState == "up") && (response.state == "down")) {
324 +                               // First, "tap" each Disconnect Button.
325 +
326 +                               for(i = 0; i < 3; i++) {
327 +                                       if(this.controller.get("disc_button_" + i))
328 +                                               Mojo.Event.send(this.controller.get("disc_button_" + i), Mojo.Event.tap);
329 +                               }
330 +
331 +                               // In case there are calls not disconnected, just call the function to disconnect all calls.
332 +                               // The reason we don't just do this one function is that the screen redraw is not pretty.
333 +
334 +                               this.eventListener.disconnectAllCalls();
335 +                       }
336 +               
337 +                       this.sliderState = response.state;
338 +               } 
339 +       },
340 +
341 +       onPowerButtonEventDuringCall: function(response) {
342 +               if((!response) || (!response.powerKey))
343 +                       return;
344 +
345 +               if(this.appAssistant.phonePrefs.powerButton == "none")
346 +                       return;
347 +
348 +               if((response.powerKey == 'released') && 
349 +                       ((this.audioActiveProfile == "phone_front_speaker") ||
350 +                       (this.appAssistant.phonePrefs.proximityAction == "change")))
351 +               {
352 +                       // First, "tap" each Disconnect Button.
353 +
354 +                       for(i = 0; i < 3; i++) {
355 +                               if(this.controller.get("disc_button_" + i))
356 +                                       Mojo.Event.send(this.controller.get("disc_button_" + i), Mojo.Event.tap);
357 +                       }
358 +
359 +                       // In case there are calls not disconnected, just call the function to disconnect all calls.
360 +                       // The reason we don't just do this one function is that the screen redraw is not pretty.
361 +
362 +                       this.eventListener.disconnectAllCalls();
363 +               }
364 +       },
365 +       
366 +       onDisplayEventDuringCall: function(response) {
367 +               if(this.appAssistant.screenLocked)
368 +                       return;
369 +
370 +               if(this.appAssistant.phonePrefs.proximityAction != "change")
371 +                       return;
372 +
373 +               if(this.eventListener.proxEnabled) {
374 +                       var callStateMessage = this.eventListener.getCallState();
375 +                       var lineState = callStateMessage.lines;
376 +                       
377 +                       var scenarios = this.eventListener.getAvailableAudioScenarios();
378 +                       
379 +                       if(response && (response.event || response.state)) {
380 +                               if(response.event == "displayOn" || response.state == "on") {
381 +                                       if(this.audioActiveProfile !== this.audioPreviousProfile) {
382 +                                               if(this.audioPreviousProfile !== null)
383 +                                                       this.onAudioRouteChangeClick(this.audioPreviousProfile);
384 +                                       }
385 +                               } else if(response.event == "displayOff" || response.state == "off") {
386 +                                       if(this.audioActiveProfile !== "phone_front_speaker") {
387 +                                               this.audioPreviousProfile = this.audioActiveProfile;
388 +                                               
389 +                                               this.onAudioRouteChangeClick("phone_front_speaker");                                            
390 +                                       }
391 +                                       else if(this.audioPreviousProfile === null)
392 +                                               this.audioPreviousProfile = "phone_back_speaker";
393 +                               }
394 +                       }
395 +               }
396 +       }
397  });
398 --- .orig/usr/palm/applications/com.palm.app.phone/app/controllers/announcer-assistant.js
399 +++ /usr/palm/applications/com.palm.app.phone/app/controllers/announcer-assistant.js
400 @@ -47,7 +47,7 @@
401         onAnnounceCreated: function(windowName, single, icon, itemcount, title, message, iconCallback, messageCallback, timestamp, badgeTemplate, stagecontrol) {
402                 Mojo.Log.info( "onAnnounceCreated");
403                 
404 -               stagecontrol.pushScene({"name": "dashannounce"}, windowName, single, icon, itemcount, title, message, iconCallback, messageCallback, timestamp, badgeTemplate);
405 +               stagecontrol.pushScene({"name": "dashannounce"}, windowName, single, icon, itemcount, title, message, iconCallback, messageCallback, timestamp, badgeTemplate, this.appAssistant.notificationPrefs);
406         },
407  
408         announceClear: function(windowName) {
409 @@ -471,6 +471,9 @@
410                         soundClass = "ringtones";
411                 }
412                 
413 +               if(contact.callAlert)
414 +                       soundClass = contact.callAlert;
415 +               
416                 /* TODO if you want to override the ringer switch when a charger connected, 
417                         (puck or USB) comment out the code above and replace it with this.
418                 
419 --- .orig/usr/palm/applications/com.palm.app.phone/app/controllers/dashannounce-assistant.js
420 +++ /usr/palm/applications/com.palm.app.phone/app/controllers/dashannounce-assistant.js
421 @@ -1,7 +1,7 @@
422  /* Copyright 2009 Palm, Inc.  All rights reserved. */
423  
424  var DashannounceAssistant = Class.create({
425 -       initialize: function(windowName, single, icon, itemcount, title, message, iconCallback, messageCallback, timestamp, badgeTemplate) {
426 +       initialize: function(windowName, single, icon, itemcount, title, message, iconCallback, messageCallback, timestamp, badgeTemplate, notificationPrefs) {
427             Mojo.Log.info( "DashannounceAssistant::initialize");
428                 this.windowName = windowName;
429                 this.single = single;
430 @@ -11,6 +11,7 @@
431                 this.message = message;
432                 this.iconCallback = iconCallback;
433                 this.badgeTemplate = badgeTemplate;
434 +               this.notificationPrefs = notificationPrefs;
435                 if (messageCallback) {
436                         this.messageCallback = messageCallback;
437                 } else {
438 @@ -40,7 +41,11 @@
439            this.controller.get('title').innerHTML = this.title;
440            this.controller.get('message').innerHTML = this.message;
441            this.controller.listen(this.controller.document, Mojo.Event.windowActivate, this.onFocus.bindAsEventListener(this));
442 -          this.controller.stageController.indicateNewContent(true);
443 +
444 +               if(this.notificationPrefs.notificationBlink)
445 +                  this.controller.stageController.indicateNewContent(true);
446 +
447 +               this.schedulePlayNotificationSoundTask(0);
448    },
449    onFocus:function() {
450         if (this.missedTimeStamp && this.windowName == 'misseddash') {
451 @@ -57,11 +62,15 @@
452    deactivate:function(){
453         this.controller.stopListening(this.controller.document, Mojo.Event.windowActivate, this.onFocus);
454         
455 +       this.removePlayNotificationSoundTask(); 
456    },
457  
458    // run callback and close this
459    onIconTap: function () {
460         Mojo.Log.info( "DashannounceAssistant::onTap", "windowName:" , this.windowName);
461 +
462 +       this.removePlayNotificationSoundTask(); 
463 +       
464         if (this.iconCallback) {
465                 this.iconCallback();
466         } else {
467 @@ -71,6 +80,9 @@
468    
469    onMessageTap: function () {
470         Mojo.Log.info( "DashannounceAssistant::onTap", "windowName:" , this.windowName);
471 +
472 +       this.removePlayNotificationSoundTask(); 
473 +       
474         if (this.messageCallback) {
475                 this.messageCallback();
476         } else {
477 @@ -91,7 +103,11 @@
478         this.itemcount = itemcount;
479         this.badgeTemplate = badgeTemplate;
480         this.updateBadge();
481 -       this.controller.stageController.indicateNewContent(true);
482 +
483 +       if(this.notificationPrefs.notificationBlink)
484 +               this.controller.stageController.indicateNewContent(true);
485 +
486 +       this.schedulePlayNotificationSoundTask(0);
487    },
488    
489    updateBadge: function() {
490 @@ -115,7 +131,48 @@
491                 this.controller.get('badge').innerHTML = "";
492                 this.controller.get('notification').addClassName("single");
493         }
494 -  }
495 +  },
496    
497 +       schedulePlayNotificationSoundTask: function(count) {
498 +               if((this.notificationPrefs.repeatInterval > 0) && (count++ < this.notificationPrefs.repeatLimit)) {
499 +                       var currentTime = new Date();
500 +               
501 +                       var repeatInterval = this.notificationPrefs.repeatInterval;                             
502 +
503 +                       if(count == 0)                  
504 +                               var playSoundTime = new Date(currentTime.getTime() + (parseInt(repeatInterval) * 1000) - 60000);
505 +                       else
506 +                               var playSoundTime = new Date(currentTime.getTime() + (parseInt(repeatInterval) * 1000));
507 +                               
508 +                       var month = playSoundTime.getUTCMonth()+1;
509 +                       if(month < 10) month = "0" + month;
510 +                       var day = playSoundTime.getUTCDate();
511 +                       if(day < 10) day = "0" + day;
512 +                       var year = playSoundTime.getUTCFullYear();
513 +
514 +                       var hours = playSoundTime.getUTCHours();
515 +                       if(hours < 10) hours = "0" + hours;
516 +                       var minutes = playSoundTime.getUTCMinutes();
517 +                       if(minutes < 10) minutes = "0" + minutes;
518 +                       var seconds = playSoundTime.getUTCSeconds();
519 +                       if(seconds < 10) seconds = "0" + seconds;
520 +
521 +                       var scheduledTimeStr = month + "/" + day + "/" + year + " " + hours + ":" + minutes + ":" + seconds;
522 +                       
523 +                       this.updateTimeoutRequest = new Mojo.Service.Request('palm://com.palm.power/timeout/', {
524 +                               'method': "set", 'parameters': {'key': 'phonePlayNotificationSound',
525 +                               'wakeup': true, 'at': scheduledTimeStr, 'uri': "palm://com.palm.applicationManager/open",
526 +                               'params': {'id': 'com.palm.app.phone', 'params': {'playNotificationSound': count}}} }); 
527 +               }
528 +       },
529 +       
530 +       removePlayNotificationSoundTask: function() {
531 +               this.removeTimeoutRequest = new Mojo.Service.Request("palm://com.palm.power/timeout/", {
532 +                       'method': "clear", 'parameters': {"key": 'phonePlayNotificationSound'} });
533 +       },
534 +
535 +       playNotificationSound: function() {
536 +               Mojo.Controller.getAppController().playSoundNotification("alerts");
537 +       }
538  });
539  
540 --- .orig/usr/palm/applications/com.palm.app.phone/app/controllers/dialpad-assistant.js
541 +++ /usr/palm/applications/com.palm.app.phone/app/controllers/dialpad-assistant.js
542 @@ -258,6 +258,9 @@
543                         Mojo.Log.info( "DialpadAssistant#handleSceneArgs", "fill: " , params.number);
544                         // TODO: can't immediately set it if setup hasn't been finished since
545                         // formatAndUpdateDialString will change visibility only to have it undone by the rest of setup
546 +
547 +                       DialStringParser.clearDebounceTimeout();
548 +               
549                         if (this.setupComplete) {
550                                 this.clear();
551                                 this.hidePicker();
552 --- .orig/usr/palm/applications/com.palm.app.phone/app/controllers/menu-controller.js
553 +++ /usr/palm/applications/com.palm.app.phone/app/controllers/menu-controller.js
554 @@ -8,7 +8,7 @@
555         that = this;
556         originalHandleCommand = controller.handleCommand;
557         
558 -       controller.setupWidget(Mojo.Menu.appMenu, undefined, {
559 +       controller.setupWidget(Mojo.Menu.appMenu, {omitDefaultItems: true}, {
560                 visible: true,
561          items: appMenuItems
562         });
563 @@ -34,7 +34,12 @@
564  };
565  
566  MenuController._getAppMenuItems = function(prefixItems) {
567 -       var items = prefixItems ? prefixItems.slice(0) : []; // always clone array
568 +       var items = [];
569 +       
570 +       items.push(Mojo.Menu.editItem);
571 +
572 +       if(prefixItems)
573 +               items = items.concat(prefixItems);      
574         
575         // add 'Check Skype Balance' if we have a skype account
576         if ( CallSynergy.isSkypeCapable() && CallSynergy.hasSkypeAccount() ) {
577 @@ -42,6 +47,9 @@
578         }
579         
580         items.push(MenuController.kRingtonesMenuItem);
581 +       items.push(MenuController.kServicesMenuItem);
582 +       items.push(MenuController.kPrefsMenuItem);      
583 +       items.push(Mojo.Menu.helpItem);
584         
585         return items;
586  };
587 @@ -86,4 +94,6 @@
588  };
589  
590  MenuController.kSkypeBalanceMenuItem = {label: $L('Check Skype Credit'), command: 'skypebalance'};
591 -MenuController.kRingtonesMenuItem = {label: $L('Sounds & Ringtones'), command: 'ringtones'};
592 \ No newline at end of file
593 +MenuController.kRingtonesMenuItem = {label: $L('Ringtone Settings'), command: 'ringtones'};
594 +MenuController.kServicesMenuItem = {label: $L('Network Services'), command: Mojo.Menu.prefsCmd};
595 +MenuController.kPrefsMenuItem = {label: $L('Preferences'), command: 'phoneprefs'};
596 --- .orig/usr/palm/applications/com.palm.app.phone/app/controllers/missedcall-assistant.js
597 +++ /usr/palm/applications/com.palm.app.phone/app/controllers/missedcall-assistant.js
598 @@ -30,11 +30,37 @@
599                 this.setupScene();
600                 
601                 // stay up for 1 minute
602 -               this.missedTimeout = window.setTimeout(this.closeWindow.bind(this), MissedcallAssistant.kTimeoutMs);
603 +//             this.missedTimeout = window.setTimeout(this.closeWindow.bind(this), MissedcallAssistant.kTimeoutMs);
604                 
605                 this.controller.listen(this.controller.stageController.document, Mojo.Event.windowDeactivate, this.onBlur);
606                 this.telListener.displayStateRegisterCallback(this.onDisplayEvent);
607 -               this.controller.stageController.indicateNewContent(true);
608 +
609 +               if(this.appAssistant.notificationPrefs.notificationBlink)
610 +                       this.controller.stageController.indicateNewContent(true);
611 +
612 +               var missedTimeout = new Date();
613 +               
614 +               missedTimeout = new Date(missedTimeout.getTime() + MissedcallAssistant.kTimeoutMs);
615 +
616 +               var month = missedTimeout.getUTCMonth()+1;
617 +               if(month < 10) month = "0" + month;
618 +               var day = missedTimeout.getUTCDate();
619 +               if(day < 10) day = "0" + day;
620 +               var year = missedTimeout.getUTCFullYear();
621 +
622 +               var hours = missedTimeout.getUTCHours();
623 +               if(hours < 10) hours = "0" + hours;
624 +               var minutes = missedTimeout.getUTCMinutes();
625 +               if(minutes < 10) minutes = "0" + minutes;
626 +               var seconds = missedTimeout.getUTCSeconds();
627 +               if(seconds < 10) seconds = "0" + seconds;
628 +
629 +               var scheduledTimeStr = month + "/" + day + "/" + year + " " + hours + ":" + minutes + ":" + seconds;
630 +
631 +               this.controller.serviceRequest('palm://com.palm.power/timeout/', {'method': "set", 
632 +                       'parameters': {'key': 'phoneMissedTimeout', 'wakeup': true, 'at': scheduledTimeStr, 
633 +                       'uri': "palm://com.palm.applicationManager/open", 'params': {
634 +                               'id': 'com.palm.app.phone', 'params': {'closeMissedCall': true}}} }); 
635      },
636         
637         cleanup: function() {
638 --- .orig/usr/palm/applications/com.palm.app.phone/app/controllers/incomingcall-assistant.js
639 +++ /usr/palm/applications/com.palm.app.phone/app/controllers/incomingcall-assistant.js
640 @@ -69,8 +69,9 @@
641                 }
642                 
643                 try {
644 -                       this.sceneCtrl.get('answer_button').addEventListener(Mojo.Event.tap, this.answerCall.bind(this));
645 -                       this.sceneCtrl.get('reject_button').addEventListener(Mojo.Event.tap, this.rejectCall.bind(this));
646 +                       this.sceneCtrl.get('answer_button').addEventListener(Mojo.Event.tap, this.answerCall.bindAsEventListener(this));
647 +                       this.sceneCtrl.get('reject_button').addEventListener(Mojo.Event.tap, this.rejectCall.bindAsEventListener(this, false));
648 +                       this.sceneCtrl.get('reject_button').addEventListener(Mojo.Event.hold, this.rejectCall.bindAsEventListener(this, true));
649                         
650                 this.exposed = true;
651                         // turn display on and lock it there
652 @@ -333,10 +334,14 @@
653                 
654                 if (response.key === "slider") {
655                         var newSliderOpenState = (response.state === "up");
656 -                       if (this.exposed
657 -                               && this.sliderOpen === false 
658 -                               && newSliderOpenState === true) {
659 -                                       this.answerCall();
660 +                       if((this.sliderOpen === false) && (newSliderOpenState === true)) {
661 +                               if(this.appAssistant.phonePrefs.sliderOpened != "none") {
662 +                                       if(this.exposed)
663 +                  this.answerCall(); 
664 +                                       
665 +                                       if(this.appAssistant.phonePrefs.sliderOpened == "speaker")
666 +                                               TelephonyCommands.setAudioScenario("phone", "phone_back_speaker");
667 +                               }
668                         }
669                         this.sliderOpen = newSliderOpenState;
670                 } 
671 @@ -372,8 +377,10 @@
672                 // answer the call after a delay if we're exposed, set to do so, 
673                 // and we were previously on the puck
674                 if (response && response.type == "inductive") {
675 -                       if (this.appAssistant.puckMode && this.exposed && this.puckConnected === true && response.connected === false) {
676 -                               this.answerIfStillOffPuck.bind(this).delay(0.750);
677 +                       if(this.appAssistant.phonePrefs.removedFromTS == "answer") {
678 +                               if (this.appAssistant.puckMode && this.exposed && this.puckConnected === true && response.connected === false) {
679 +                                       this.answerIfStillOffPuck.bind(this).delay(1.000);
680 +                               }
681                         }
682                         this.puckConnected = response.connected;
683                 }
684 @@ -416,7 +423,9 @@
685      },
686      
687         // hide alert and instruct blur handler to disconnect call & show ignored UI
688 -       rejectCall: function(event){
689 +       rejectCall: function(event, hold){
690 +               event.stop();
691 +               
692          if (this.blockIgnore) {
693                         Mojo.Log.error( "IncomingcallAssistant#rejectCall tapped too soon");
694                         this.unblockIgnore();
695 @@ -426,6 +435,17 @@
696          this.mute();
697                 this.exitStatus = "rejected";
698                 
699 +               if((this.contact.canBeCalled()) && (this.contact.service != CallSynergy.SERVICES.SKYPE)) {
700 +                       if((hold) && (this.appAssistant.rejectedPrefs.rejectAction == "autoreply")) {   
701 +                               this.controller.serviceRequest('palm://com.palm.applicationManager/', {
702 +                                       method: 'launch', parameters: { id: 'com.palm.app.messaging',
703 +                                               params: {composeRecipients: [{address: this.contact.addressFormatted}],
704 +                                               messageText: this.appAssistant.rejectedPrefs.rejectTemplate
705 +                                               }
706 +                               }});
707 +                       }
708 +               }
709 +
710         this.closeWindow();
711      },
712         
713 --- .orig/usr/palm/applications/com.palm.app.phone/stylesheets/phone.css
714 +++ /usr/palm/applications/com.palm.app.phone/stylesheets/phone.css
715 @@ -365,4 +365,13 @@
716  
717  .palm-dark .favorites-list .palm-drag-spacer {
718    -webkit-border-image: url(../images/empty.png) 15 15 15 15 repeat repeat;
719 -}
720 \ No newline at end of file
721 +}
722 +
723 +body.prefs {
724 +       background-image: none;
725 +       background-color: rgba(228,228,228,1.0);
726 +}
727 +
728 +.palm-page-header .icon.phone {
729 +       background-image: url(../images/header-icon-phone.png);
730 +}
731 --- .orig/usr/palm/applications/com.palm.app.phone/app/models/states/ActiveCallCard.js
732 +++ /usr/palm/applications/com.palm.app.phone/app/models/states/ActiveCallCard.js
733 @@ -70,9 +70,13 @@
734                 if ( okToGoBackToStates.indexOf(prevState) < 0 ) {
735                         prevState = this.machine.STATE_DIALPAD_CARD;
736                 }
737 +       
738 +               var cookieContainer = new Mojo.Model.Cookie("phone");
739 +
740 +               var prefs = cookieContainer.get();
741                 
742                 // if stage was hidden when active call started (and not firstuse), hide it
743 -               if ( this.wasHidden && stageController && stageController.fullInit && ! PalmSystem.isMinimal ) {
744 +               if ( ((prefs.closeApp) || (this.wasHidden && stageController && stageController.fullInit)) && ! PalmSystem.isMinimal ) {
745                         stageController.window.PalmSystem.hide();
746                 }
747                 
748 --- .orig/usr/palm/applications/com.palm.app.phone/app/models/states/CallLog.js
749 +++ /usr/palm/applications/com.palm.app.phone/app/models/states/CallLog.js
750 @@ -14,6 +14,14 @@
751         cleanup: function() {
752                 
753         },
754 +       event_launch: function(view) {
755 +               if(view == "calllog")
756 +                       this.machine.enter('calllog');
757 +               else if(view == "favorites")
758 +                       this.machine.enter('favorites');
759 +               else if(view == "dialpad")
760 +                       this.machine.enter('dialpad_card');
761 +       },
762         event_back: function(commandEvent) {
763                 this.machine.enter('dialpad_card');
764         },
765 --- .orig/usr/palm/applications/com.palm.app.phone/app/models/CallSynergyContact.js
766 +++ /usr/palm/applications/com.palm.app.phone/app/models/CallSynergyContact.js
767 @@ -40,7 +40,9 @@
768                 this.locationFormatted = undefined; // for unknown phone numbers only, eg "N. California"
769                 this.personGivenName = undefined; // known person only, for call log
770                 this.personFamilyName = undefined; // known person only, for call log
771 -               this.ringtoneLoc = undefined; // known person only
772 +               this.callAction = undefined; // known person only
773 +               this.callAlert = undefined; // known person only
774 +               this.callRingtonePath = undefined; // known person only
775                 this.pictureLoc = undefined; // known person only
776                 this.pictureObj = undefined; // known person only
777                 this.pictureFormat = undefined; // known person only
778 @@ -394,8 +396,12 @@
779                         this.label = "service_skype";
780                         this.labelFormatted = $L("Skype");
781                 }
782 +
783 +               this.callAction = person.getCallAction().getAction();
784 +       
785 +               this.callAlert = person.getCallAlert().getAlert();
786                 
787 -               this.ringtoneLoc = person.getRingtone().getLocation();
788 +               this.callRingtonePath = person.getRingtone().getLocation();
789                 
790                 // these attributes are NOT displayed but are passed through to
791                 // the call log for the bluetooth service. This shouldn't be needed but
792 --- .orig/usr/palm/applications/com.palm.app.phone/app/models/states/DialpadCard.js
793 +++ /usr/palm/applications/com.palm.app.phone/app/models/states/DialpadCard.js
794 @@ -10,6 +10,14 @@
795                         stageController.delegateToSceneAssistant("resetOnHide");
796                 }
797         },
798 +       event_launch: function(view) {
799 +               if(view == "calllog")
800 +                       this.machine.enter('calllog');
801 +               else if(view == "favorites")
802 +                       this.machine.enter('favorites');
803 +               else if(view == "dialpad")
804 +                       this.machine.enter('dialpad_card');
805 +       },
806         event_back: function(commandEvent) {
807          if ( this.appAssistant.telephonyEventListener.callExists() ) {
808              this.machine.enter("activecall_card");
809 --- .orig/usr/palm/applications/com.palm.app.phone/app/models/states/Favorites.js
810 +++ /usr/palm/applications/com.palm.app.phone/app/models/states/Favorites.js
811 @@ -8,6 +8,14 @@
812         cleanup: function() {
813                 
814         },
815 +       event_launch: function(view) {
816 +               if(view == "calllog")
817 +                       this.machine.enter('calllog');
818 +               else if(view == "favorites")
819 +                       this.machine.enter('favorites');
820 +               else if(view == "dialpad")
821 +                       this.machine.enter('dialpad_card');
822 +       },
823         event_back: function(commandEvent) {
824                 this.machine.enter('dialpad_card');
825         },
826 --- .orig/usr/palm/applications/com.palm.app.phone/app/models/states/FavoritesAdd.js
827 +++ /usr/palm/applications/com.palm.app.phone/app/models/states/FavoritesAdd.js
828 @@ -48,7 +48,8 @@
829                         scenesToPush: [ContactsUI.FavoritePersonWidget.SCENES.PERSON_PICKER, ContactsUI.FavoritePersonWidget.SCENES.CONTACT_POINT_PICKER],
830                         defaultType: this._getDefaultType(),
831                         callback: function() {
832 -                               this.machine.enter("favorites");
833 +//                             this.machine.enter("favorites");        
834 +                               this.machine.currentState = this.machine._states[this.machine.STATE_FAVORITES];
835                         }.bind(this)
836                 }).pushScene();
837         },
838 @@ -62,7 +63,8 @@
839                         listIndexForDefault: lastIndex,
840                         defaultType: this._getDefaultType(),
841                         callback: function() {
842 -                               this.machine.enter("favorites");
843 +//                             this.machine.enter("favorites");        
844 +                               this.machine.currentState = this.machine._states[this.machine.STATE_FAVORITES];
845                         }.bind(this)
846                 }).pushScene();
847         },
848 --- .orig/usr/palm/applications/com.palm.app.phone/app/models/states/Start.js
849 +++ /usr/palm/applications/com.palm.app.phone/app/models/states/Start.js
850 @@ -7,8 +7,13 @@
851                 
852         },
853         // always launch to dialpad first
854 -       event_launch: function() {
855 -               this.machine.enter('dialpad_card');
856 +       event_launch: function(view) {
857 +               if(view == "calllog")
858 +                       this.machine.enter('calllog');
859 +               else if(view == "favorites")
860 +                       this.machine.enter('favorites');
861 +               else
862 +                       this.machine.enter('dialpad_card');
863         },
864         event_emergency: function(isEnabled) {
865                 if ( isEnabled ) {
866 --- .orig/usr/palm/applications/com.palm.app.phone/app/models/TelephonyEventListener.js
867 +++ /usr/palm/applications/com.palm.app.phone/app/models/TelephonyEventListener.js
868 @@ -506,6 +506,10 @@
869                                         && Object.keys(profiles).length == 2                            
870                                         && profiles["phone_front_speaker"] == true) {
871                                         scenario = "phone_front_speaker";
872 +                               } else if (!this.puckConnected && 
873 +                                       Object.keys(profiles).length == 2
874 +                                       && profiles["phone_back_speaker"] == true) {
875 +                                       scenario = "phone_back_speaker";
876                                 } else {
877                                         return;
878                                 }
879 @@ -513,7 +517,7 @@
880                 }
881                 
882                 if (this.isPendingOrActive()) {
883 -                       if (scenario == "phone_front_speaker") {
884 +                       if ((scenario == "phone_front_speaker") || (this.appAssistant.phonePrefs.proximityAction == "change")) {
885                                 this.proxOn();
886                         } else {
887                                 Mojo.Log.info( "TEL#enableProxOnCallAndAudio", "not enabled: " , scenario);
888 @@ -525,8 +529,12 @@
889         },
890         
891         proxOn: function() {
892 +               if(this.appAssistant.screenLocked)
893 +                       return;
894 +
895                 if (!(this.proxSubscription)) {
896                         this.proxSubscription = TelephonyCommands.proxSet(true, this.onProxOn);
897 +                       this.diplayBlockReq = TelephonyCommands.displayDNAST(true, undefined);
898                 } else {
899                         Mojo.Log.info( "TEL#proxOn", "already on");
900                 }
901 @@ -537,6 +545,9 @@
902                 if (this.proxSubscription) {
903                         this.proxSubscription.cancel();
904                         delete this.proxSubscription;
905 +                       this.diplayBlockReq = TelephonyCommands.displayDNAST(false, undefined);
906 +                       this.diplayBlockReq.cancel();
907 +                       delete this.diplayBlockReq;
908                 }
909         },
910         
911 @@ -724,7 +735,32 @@
912                 // wait to show incoming popup until the contact has been decorated
913                 future = this.incomingPending.contact.decorated();
914                 future.then(this, function() {
915 -                       this.announcer.announceIncoming(callState.affectedCallId, future.result, this.isConnected());
916 +                       this.contactPrefs = new window.Contacts.AppPrefs(function(contact) {
917 +                               var blockedNumbers = this.contactPrefs.get(Contacts.AppPrefs.Pref.blockedNumbers);
918 +
919 +                               var unknownNumbers = this.contactPrefs.get(Contacts.AppPrefs.Pref.unknownNumbers);
920 +
921 +                               var unknownPrefs = contact;
922 +
923 +                               if(((blockedNumbers) && (!contact.canBeCalled())) || ((unknownNumbers) && (!contact.personId)))
924 +                                       unknownPrefs = this.contactPrefs.get(Contacts.AppPrefs.Pref.unknownContacts);
925 +                               
926 +                               if((unknownPrefs) && (unknownPrefs.callAction) && (unknownPrefs.callAction == "direct2vm"))
927 +                                       this.flagCallRejected(callState.affectedCallId);
928 +                               else if((unknownPrefs) && (unknownPrefs.callAction) && (unknownPrefs.callAction == "autohangup"))
929 +                                       TelephonyCommands.disconnect(callState.affectedCallId);
930 +                               else {
931 +                                       if((unknownPrefs) && (unknownPrefs.callAlert) && (unknownPrefs.callAlert != "default")) {
932 +                                               contact.callAlert = unknownPrefs.callAlert;
933 +                                       
934 +                                               if((unknownPrefs.callAlert == "ringtone") && (unknownPrefs.callRingtonePath))
935 +                                                       contact.ringtoneLoc = unknownPrefs.callRingtonePath;
936 +                                       }
937 +                               
938 +                                       this.announcer.announceIncoming(callState.affectedCallId, contact, this.isConnected());
939 +                               }
940 +                       }.bind(this, future.result));
941 +
942                         return true; // continue
943                 });
944                 
945 @@ -1210,6 +1246,13 @@
946                 if (response && response.locked !== undefined) {
947                         this.appAssistant.screenLocked = response.locked;
948                         
949 +                       if((this.isPendingOrActive()) && (this.appAssistant.phonePrefs.proximityAction == "change")) {
950 +                               if(response.locked)
951 +                                       this.proxOff();
952 +                               else
953 +                                       this.proxOn();
954 +                       }
955 +                       
956                         // issue unlock event if 
957                         if ( ! response.locked && this.appAssistant.screenLockSecured ) {
958                                 UIStateMachine.event('lock', false); // let the current state know we're locked/unlocked
959 @@ -1264,7 +1307,7 @@
960                 if (response.extended) {
961                         var state = response.extended.state;
962                         switch (state) {
963 -                               case simready:
964 +                               case "simready":
965                                         this.simready = true;
966                                         break;
967                                 default:
968 --- .orig/usr/palm/applications/com.palm.app.phone/app/models/UIStateMachine.js
969 +++ /usr/palm/applications/com.palm.app.phone/app/models/UIStateMachine.js
970 @@ -28,6 +28,8 @@
971         /**
972           * Phone UI states.
973          **/
974 +       STATE_PREFS: 'prefs',
975 +
976         STATE_START: 'start',
977         STATE_PIN: 'pin', // pin scene
978         STATE_PIN_UNLOCKED: 'pin_unlocked',
979 @@ -67,6 +69,8 @@
980         
981      initialize: function() {
982                 this._states = {};
983 +
984 +               this._states[this.STATE_PREFS] = UIStateMachine.STATES.PrefsState;
985                 
986                 this._states[this.STATE_START] = UIStateMachine.STATES.StartState;
987                 this._states[this.STATE_PIN] = UIStateMachine.STATES.PinState;
988 --- .orig/usr/palm/applications/com.palm.app.phone/resources/es/strings.json
989 +++ /usr/palm/applications/com.palm.app.phone/resources/es/strings.json
990 @@ -407,5 +407,48 @@
991         "synchronous circuit data switch": "conmutador de datos de circuito sincrónicos",
992         "via Email": "por correo electrónico",
993         "via Messaging": "por mensajería",
994 -       "voice": "voz"
995 +       "voice": "voz",
996 +       "Phone Services": "",
997 +       "Sound Settings": "",
998 +       "Default View": "",
999 +       "On Call View": "",
1000 +       "No Default View": "",
1001 +       "Slider Opened": "",
1002 +       "Slider Closed": "",
1003 +       "Power Button": "",
1004 +       "On Dial Select": "",
1005 +       "On TS Removal": "",
1006 +       "On Proximity": "",
1007 +       "On Call Reject": "",
1008 +       "Repeat": "",
1009 +       "Limitation": "",
1010 +       "Dialpad": "",
1011 +       "Call Log": "",
1012 +       "Favorites: "",
1013 +       "Contact": "",
1014 +       "Keypad": "",
1015 +       "Do Nothing": "",
1016 +       "Answer Call": "",
1017 +       "Speakerphone": "",
1018 +       "Hangup Call": "",
1019 +       "Start Call": "",
1020 +       "Change Audio": "",
1021 +       "Send SMS Reply": "",
1022 +  "Sorry, I am currently busy and will call you back later...": "",
1023 +       "Disabled": "",
1024 +       "Every 2 minutes": "",
1025 +       "Every 5 minutes": "",
1026 +       "Every 15 minutes": "",
1027 +       "Every 30 minutes": "",
1028 +       "Every 60 minutes": "",
1029 +       "Infinite": "",
1030 +       "Repeat 3 times": "",
1031 +       "Repeat 5 times": "",
1032 +       "Repeat 10 times": "",
1033 +       "Repeat 15 times": "",
1034 +       "Repeat 30 times": "",
1035 +       "Off": "",
1036 +       "On": "",
1037 +       "No": "",
1038 +       "Yes": ""
1039  }