/* Copyright 2009 Palm, Inc.  All rights reserved. */

var TelephonyEventListener = Class.create({
    initialize: function(appAssistant){
		Mojo.assertDefined(appAssistant, "app assistant passed in as undefined.")
		this.announcer = appAssistant.announcer;
		this.contacts = appAssistant.contacts;
		this.appAssistant = appAssistant;
		this.appControl = Mojo.Controller.getAppController();
		this.systemServiceCallbacks = [];
		this.appAssistant.lookupOnKeyPress = true;
		
        // if mock around, enabled, use it
        if (MockTelephony.useMock == 1) {
            appAssistant.mockTelephony.subscribe(name, this.onMacrocallEvent.bind(this));
            // the mock is GSM by default
            appAssistant.gsm = true;
        } else {
			// otherwise wait for telephony service on luna bus
			this.serviceStatusRequest = TelephonyCommands.subscribeServiceStatus('com.palm.telephony', this.onSvcStatusEvent.bind(this))
			this.serviceStatusSubscription = TelephonyCommands.subscribeSystemServiceStatus(this.onSystemServiceStatus.bind(this));
			this.audioServiceSubscription = TelephonyCommands.subscribeServiceStatus('com.palm.audio', this.onAudiodEvent.bind(this));
        }
        this.lastVoicemail = 0;
		// TODO: maybe move this into the service?  the app shouldn't have to tell the difference
		this.normalDisconnectCodesCDMA = [25, 29, 38];
		this.normalDisconnectCodesGSM = [16, 31, 127];
		this.callState;
		this.abortActiveCall = false;
		
		/** modes we can be in **/
		this.appAssistant.emergencyMode = false;
		this.powered = false;
		this.serviced = false;
		this.limited = false;
		
		this.puckConnected = false;
		this.usbConnected = false;
		
		// default to release build
		this.releaseBuild = true;
		
		/** mock TODO REMOVE **/
		this.mockPicture = false;
		
		this.callStateListeners = [];
		this.audioStateListeners =[];
		this.displayStateListeners = [];
		
		this.subscriptions = [];
		
		this.serviceConnected = false;
		this.voicemailSubscribed = false;
		
		this.onLateLookup = this.onLateLookup.bind(this);
		
		this.dispatchSkippedCallState = this.dispatchSkippedCallState.bind(this);
		
		this.onProxOn = this.onProxOn.bind(this);
		
		this.proxEnabled = false;
		
		this.resetCallAbortState();
		
		this.voicemailNumberEditable = false;
    },
	
	// get build name to determine if this is a release.
	// nova-main is not a release; all else is
	onBuildNameReturn: function(payload) {
		if(!payload) {
			QDLogger.log( "TelephonyEventListener::onBuildNameReturn", "no payload");
			return;
		}
	
		if(payload.returnValue !== undefined && !payload.returnValue) {
			QDLogger.log( "TelephonyEventListener::onBuildNameReturn", "weird payload");
			return;
		}
	
		if ("com.palm.properties.buildName" in payload) {
			var buildName = payload["com.palm.properties.buildName"];	
		
			if(buildName.toLowerCase() === "nova-main") 
				this.releaseBuild = false;	
			else
				this.releaseBuild = true;		
		}
		
	},
	
	// called when luna bus service tells us that the TelephonyService status has changed
    onSvcStatusEvent: function(result){
        QDLogger.log( "TelephonyEventListener::onSvcStatusEvent", "**SUBSCRIBE TELEPHONY** state " , result.connected);
        if (result.connected == true) {
            this.onServiceConnected();
        } else if (result.connected == false) {
     		this.onServiceDisconnected();
        } else {
            QDLogger.log( "TelephonyEventListener::onSvcStatusEvent", "unknown telephony status signal");
        }
        
        QDLogger.log( "TelephonyEventListener::onSvcStatusEvent", "**SUBSCRIBE TELEPHONY ENDED**");
    },
	
	// called when luna bus service tells us that the systemservice status has changed
    onSystemServiceStatus: function(result){
        
		QDLogger.log( "TelephonyEventListener::onSystemStatusService", result.connected);
        if (result.connected == true) {
            
			this.appAssistant.systemServiceStatus = true;
			
			while (this.systemServiceCallbacks.length > 0) {
				var callback = this.systemServiceCallbacks.pop();
				callback();
			}
        } else if (result.connected == false) {
     		this.appAssistant.systemServiceStatus = false;
        } 
    },
	
	// execute callback if system service is connected; if not connected, store in
	// callback queue and execute when it comes available
	whenSystemServiceConnected: function(callback) {
		if (this.appAssistant.systemServiceStatus) {
			callback()
			return;
		}
		
		this.systemServiceCallbacks.push(callback);
	},
	
	// called when the TelephonyService connection succeeds
	// makes subscriptions to service
	onServiceConnected: function() {
		if (!this.serviceConnected) {
			QDLogger.log( "TelephonyEventListener::onServiceConnected");
			this.serviceConnected = true;
			
			TelephonyCommands.buildNameQuery(this.onBuildNameReturn.bind(this));
			TelephonyCommands.subscribePreference("showcontactmatch", this.handlePrefContactLookupOnKey.bind(this));
			TelephonyCommands.subscribe("basebanddebug", this.onBasebandDebug.bind(this));
			
			//query and subscribe to pin1Status
			TelephonyCommands.getPin1Status(true /* subscribe */, this.onPin1Status.bind(this));
			// and other SIM-related events
			//query and subscribe to simlock status
			TelephonyCommands.deviceLockQuery(true /* subscribe */, this.onDeviceLockQuery.bind(this));
			//TelephonyCommands.subscribe("security", this.onSecurityEvent.bind(this));
			TelephonyCommands.subscribe("ussd", this.onUssdEvent.bind(this));
			
			// CDMA-related
			TelephonyCommands.subscribe("infotext", this.onInfotextEvent.bind(this));
			TelephonyCommands.subscribe("otasp", this.onOtaspEvent.bind(this));
			TelephonyCommands.subscribe("emergency", this.onEmergencyEvent.bind(this));

			//Get the PlatformType
			PlatformType.getPhoneType(true);
			
			TelephonyCommands.getPower(true, this.onPowerEvent.bind(this));
			TelephonyCommands.getNetworkStatus(true, this.onNetworkEvent.bind(this));
			this.subscriptions.push(TelephonyCommands.wiredButtonSubscribe(this.onWiredButtonEvent.bind(this)));
			this.subscriptions.push(TelephonyCommands.lockStatusSubscribe(this.onLockStatusEvent.bind(this)));
			this.subscriptions.push(TelephonyCommands.deviceLockModeSubscribe(this.onDeviceLockModeChanged.bind(this)));
			this.subscriptions.push(TelephonyCommands.puckStatusSubscribe(this.onPuckEvent.bind(this)));
			this.subscriptions.push(TelephonyCommands.displayStatusSubscribe(this.displayStateDispatch.bind(this)));
			TelephonyCommands.initOnProvisionStart(this.onProvisioningStatusNotification.bind(this));
			TelephonyCommands.callsGetAll(true, this.onMacrocallEvent.bind(this));
			TelephonyCommands.chargeSignalQuery();
			
			TelephonyCommands.disconnectDelaySet(AppAssistant.properties.DISCONNECT_DELAY);
			
			// prime the call log cache
			this.appAssistant.primeCallLog();
		}
	},
	
	onAudiodEvent: function(result) {
		 if (result.connected == true && !(this.audiodConnected)) {
		 	this.audiodConnected = true;
			TelephonyCommands.subscribeAudioRouting(this.onAudioNotification.bind(this));
		 } else if (result.connected == false) {
		 	this.audiodConnected = false;
		 }
	},
	
	// called when service goes away
	onServiceDisconnected: function() {
		if (this.serviceConnected == true) {
			QDLogger.error( "TelephonyEventListener::onServiceDisconnected", "service crash detected");
			this.onPowerOff();
			this.voicemailSubscribed = false;
			
			// cancel subscriptions we have lying around in the listener
			while (this.subscriptions.length > 0) {
				var subscription = this.subscriptions.pop();
				if (subscription) {
					subscription.cancel();
				}
			}
			
			// cancel TelephonyService-related subscriptions
			TelephonyCommands.cancelSavedRequests();
		}
		
		this.serviceConnected = false;
	},
	
	// called when radio power goes on
	// on CDMA, queries for service settings (like voicemail number)
	onPowerOn: function() {
		QDLogger.log( "TelephonyEventListener::onPowerOn");
		TelephonyCommands.emergencyNumberQuery(this.onEmergencyListReturn.bind(this));
		if (!(PlatformType.isGSM()))
			this.onServiceSettingsReady();
	},
	
	// called when radio power goes off
	// if calls are connected, blows them away
	onPowerOff: function() {
		QDLogger.log( "TelephonyEventListener::onPowerOff");
		if (this.callState && this.callState.lines && this.callExists()) {
			Mojo.Log.error( "TelephonyEventListener::onPowerOff: radio powered off while calls connected");	
			//this.appAssistant.showActiveCall();
			this.handleCallState(this.callState.clearCalls());
		}
		this.clearServiceSettings();
		this.onServiceLoss();
	},
    
	// called on GSM when simready; CDMA when power on
	// gets account-specific server settings (like voicemail number)
	onServiceSettingsReady: function() {
		if (!this.serviceSettingsLoaded) {
			QDLogger.log( "TelephonyEventListener::onServiceSettingsReady");
			this.serviceSettingsLoaded = true;
			// get voicemail number
			this.voicemailSubscription = TelephonyCommands.voicemailNumberQuery(this.onVoicemailNumberReturn.bind(this, false /* not a retry */), true /* subscribe */)
			// query for emergency numbers in case they've changed
			TelephonyCommands.emergencyNumberQuery(this.onEmergencyListReturn.bind(this));
			// attempt to calculate area code
			TelephonyCommands.phoneNumberQuery(this.homeAreaCodeFromPhoneNumber.bind(this));

		}
	},
	
	// called when radio power goes off; clears out account-specific server settings
	clearServiceSettings: function() {
		QDLogger.log( "TelephonyEventListener::clearServiceSettings");
		if (this.serviceSettingsLoaded) {
			if (this.voicemailNumber) {
				// TODO: why is this necessary?
				this.contacts.carrierBook[this.voicemailNumber] = Messages.voicemailContact;
				this.voicemailNumber = undefined;
			}
			
			if (this.carrierDbSubscription) {
				this.carrierDbSubscription.cancel();
				delete this.carrierDbSubscription;
			}
			
			if (this.voicemailSubscription) {
				this.voicemailSubscription.cancel();
				delete this.voicemailSubscription;
			}
			
			this.serviceSettingsLoaded = false;
		}
	},
	
	// called when service comes available
	// gets info we need service for, such as voicemail
	// dials a number if we've queued one up for when we get service
	onServiced: function() {
		if (!(this.serviced)) {
			QDLogger.log( "TelephonyEventListener::onServiced", "got service");
			if (!(this.voicemailSubscribed)) {
				QDLogger.log( "TelephonyEventListener::onServiced", "getting vm count");
				TelephonyCommands.voicemailCountQuery(true, this.onVoicemailEvent.bind(this));
				this.voicemailSubscribed = true;
			}
			
			this.serviced = true;
			this.limited = false;
			this.dialOnService();
		}
	},
	
	// sets a number to be dialed when service is available
	setDialOnService: function(number) {
		this.dialOnServiceNumber = number; 
	},
	
	// if we've queued up a number to dial, do it
	dialOnService: function() {
		if (this.dialOnServiceNumber !== undefined) {
			// don't dial if it's not an emergency number
			if(this.limited && !(PlatformType.isEmergencyNumber(this.dialOnServiceNumber))) {
				return;
			}
			
			this.appAssistant.showDialpad({"action": "dial", "number": this.dialOnServiceNumber});
			this.appAssistant.focusStage();
			this.dialOnServiceNumber = undefined;
		}
	},
	
	// called when service lost; if limited service available, notes it
	onServiceLoss: function() {
		QDLogger.log( "TelephonyEventListener::onServiceLoss");
		this.serviced = false;
		this.limited = false;
		this.incomingPending = undefined;
	},
	
	onLimited: function() {
		QDLogger.log( "TelephonyEventListener::onLimited");
		this.serviced = false;
		this.limited = true;
		this.incomingPending = undefined;
		// attempt to dial if there's an emergency number saved up
		this.dialOnService();
	},
	
    onStkEvent: function(result){
        if (result.eventSTKDT != undefined) {
            /*
			Mojo.Controller.getAppController().assistant.telephonyEventListener.stkWindow = Mojo.Controller.getAppController().assistant.createStage({
                scene: "stk",
                decodedText: result.eventSTKDT.decodedText,
                delayClear: result.eventSTKDT.delayClear,
                highPriority: result.eventSTKDT.highPriority,
                messageId: result.eventSTKDT.messageId
            });
            */
            return;
        }
    },
    
	// receives call events from telephony service, transforms them into TelephonyCallStates
	// passes to handleCallState to act on event
    onMacrocallEvent: function(result){
		
        if (result == undefined || result.macroEventCalls == undefined) {
            QDLogger.log( "TelephonyEventListener#onMacrocallEvent", "macrocall event is null");
			return;
        }
        try {
			// parse out the call state and handle it
			var callState = new TelephonyCallState(result, this.callState);
			this.handleCallState(callState);
		} catch (e) {
			Mojo.Log.error( "PhoneApp: TelephonyEventListener#onMacrocallEvent CAUGHT EXCEPTION: %j" , e);
		}
	},
	
	// processes TelephonyCallStates; dispatches events accordingly (i.e. dial, hold, incoming, 
	// active call handlers)
	handleCallState: function(callState) {
		var prevCallState = this.callState;
		this.callState = callState;
		
		if (callState === null || callState === undefined) {
			Mojo.Log.error( "TelephonyEventListener::handleCallState", "null messages");
			return;
		} else {
			QDLogger.log( "TelephonyEventListener::handleCallState", "action: " , callState.action);
		}
		try {
			// on active or dialing, clear incoming call announcer if it exists and show active call screen
			if (callState.action == TelephonyCallState.ACTIVE) {
				this.handleActive(callState);
			} else if (callState.action == TelephonyCallState.DIALING ||
			callState.action == TelephonyCallState.DIALPENDING) {
				this.handleDialing(callState);
			// incoming call and name updates	
			} else if (callState.action == TelephonyCallState.INCOMING) {
				this.handleIncoming(callState, false /* not update of existing call */);
			} else if (callState.action == TelephonyCallState.INFO &&
			callState.previousAction == TelephonyCallState.INCOMING) {
				this.handleIncoming(callState, true /* update of existing call */);
			// cleanup on disconnect
			} else if (callState.action == TelephonyCallState.DISCONNECTED) {
			
				this.handleDisconnect(callState, prevCallState);
			}
			// send call state to listeners
			this.dispatchCallState(callState);
			
			// reset things if we're out of calls
			// BE CAREFUL: this could fire when there weren't lines before
			// that's safe right now
			if (!callState.lines || callState.lines.length == 0) {
				this.resetCallAbortState();
				this.proxOff();
			} else {
				QDLogger.log("not calling prox off because", (callState.lines ? callState.lines.length : 'still have lines'));
			}
		} catch (e) {
			Mojo.Log.error( "PhoneApp: TelephonyEventListener#handleCallState CAUGHT EXCEPTION: %j" , e);
		}
    },
	
	// makes a fake dialing message and sends it through the message handling code.
	// saves the pauseWaitDigits for later pickup
	// turns proximity sensor on
	conjureDialingMessage: function(number, pauseWaitDigits, contact) {
		QDLogger.log( "TEL#conjureDialingMessage");
		
		this.resetCallAbortState();
		this.pauseWaitDigits = pauseWaitDigits;
		if (!contact) {
			contact = {};
		}
		contact.number = number;
		this.handleCallState(new TelephonyCallState(null, this.callState, contact));
		this.enableProxOnCallAndAudio();
	},

	// grab and clear parameters for after-active pause/wait DTMF sending
	getPauseWaitDigits: function() {
		var payload = this.pauseWaitDigits;
		this.pauseWaitDigits = undefined;
		return payload;
	},
	
	// sends call state to controllers that listen for it
	// will delay and possibly skip states that don't make sense to display
	// (like 2 active calls, 2 held calls)
	dispatchCallState: function(callState, alreadySkipped) {
		QDLogger.log( "dispatchCallState", "action: " , callState.action , " call count: " , callState.lines.length , "listener count: " , this.callStateListeners.length);
		
		// skip this state if this is a skippable state
		// and this is isn't one we already skipped
		if (!alreadySkipped && this.callStateIsSkippable(callState)) {
			QDLogger.log( "dispatchCallState", "skipping state");
			this.skippedCallState = callState;
			// if we've already skipped one, reset the timeout
			if (this.skipCallStateTimeout) {
				clearTimeout(this.skipCallStateTimeout);
			}
			this.skipCallStateTimeout = setTimeout(this.dispatchSkippedCallState, 500);
			return;
		}
		
		// if we've skipped a call state, clear it out
		if (this.skippedCallState) {
			this.skippedCallState = undefined;
			clearTimeout(this.skipCallStateTimeout);
			this.skipCallStateTimeout = undefined;
		}
		
		for (var i = 0; i < this.callStateListeners.length; i++) {
			this.callStateListeners[i].updateCalls(callState);	
		}
	},
	
	// dispatch change in display to listeners
	displayStateDispatch: function(payload) {
		for (var i = 0; i < this.displayStateListeners.length; i++) {
			this.displayStateListeners[i](payload);	
		}
	},
	
	// add a listener for display status
	displayStateRegisterCallback: function(callback) {
		this.displayStateListeners.push(callback);
	},
	
	// remove a display status listener, if it's actually in the list
	displayStateUnregisterCallback: function(callback) {
		for (var i = 0; i < this.displayStateListeners.length; i++) {
			if (this.displayStateListeners[i] == callback) {
				this.displayStateListeners.splice(i, 1);
			}
		}
	},
	
	// called on dialing and when audio scenario changes
	// if we're on a call, and the audio scenario is the front speaker
	// turns proximity sensor on
	enableProxOnCallAndAudio: function(scenario) {
		QDLogger.log( "TEL#enableProxOnCallAndAudio", scenario);
		if (!(scenario)) {
			scenario = this.appAssistant.audioActiveProfile;
			if (!(scenario)) {
				// if we're not on the puck, there are only two profiles available, and one of them is the front speaker,
				// assume that the current profile is phone_front_speaker
				var profiles = this.appAssistant.audioEnabledProfiles;
				
				if (!this.puckConnected
					&& Object.keys(profiles).length == 2 				
					&& profiles["phone_front_speaker"] == true) {
					scenario = "phone_front_speaker";
				} else {
					return;
				}
			}
		}
		
		if (this.isPendingOrActive()) {
			if (scenario == "phone_front_speaker") {
				this.proxOn();
			} else {
				QDLogger.log( "TEL#enableProxOnCallAndAudio", "not enabled: " , scenario);
				this.proxOff();
			}
		} else {
			QDLogger.log( "TEL#enableProxOnCallAndAudio", "no call, doing nothing");	
		}
	},
	
	proxOn: function() {
		if (!(this.proxSubscription)) {
			this.proxSubscription = TelephonyCommands.proxSet(true, this.onProxOn);
		} else {
			QDLogger.log( "TEL#proxOn", "already on");
		}
	},
	
	proxOff: function() {
		QDLogger.log( "TEL#proxOff");
		if (this.proxSubscription) {
			this.proxSubscription.cancel();
			delete this.proxSubscription;
		}
	},
	
	onProxOn: function() {
		QDLogger.log( "TEL#onProxOn");
		this.proxEnabled = true;
	},
	
	// returns true if the call state passed in shouldn't be displayed
	callStateIsSkippable: function(callState) {
		if (callState && callState.lines) {
			if (callState.lines.length == 2) {
				// two calls probably can't be in the same state, except disconnected
				if ( ((callState.lines[0].state == callState.lines[1].state) && callState.lines[0].state !== TelephonyCallState.DISCONNECTED)
					// delay separate conference call disconnect notifications
					|| (callState.action == TelephonyCallState.DISCONNECTED 
						&& callState.lines[0].conferenceMember === true)
					// don't show a disconnected call turning into a dialing call
					|| callState.lines[0].state == TelephonyCallState.DISCONNECTED
						&& (callState.lines[1].state == TelephonyCallState.DIALPENDING || callState.lines[1].state == TelephonyCallState.DIALING)) {
					return true;
				} 
			} else if (callState.lines.length == 1) {
				// it's semi-unusual for a single call to go on hold -- and 
				// you're probably not looking at the screen when it happens
				if (callState.lines[0].state == TelephonyCallState.HOLD 
				// delay separate conference call disconnect notifications
				|| (callState.action == TelephonyCallState.DISCONNECTED &&
					callState.lines[0].conferenceMember === true)) {
					return true;
				}
			}
		}		
		
		return false;
	},
	
	// sends a skipped call state on
	dispatchSkippedCallState: function() {
		QDLogger.log( "dispatchSkippedCallState");
		var callState = this.skippedCallState
		this.skippedCallState = undefined;
		this.skipCallStateTimeout = undefined;
		this.dispatchCallState(callState, true /* already skipped */)
	},
	
	addCallStateListener: function(listener) {
		QDLogger.log( "TEL::addCallStateListener");
		this.callStateListeners.push(listener);
	},
	
	removeCallStateListener: function(listener) {
		for (var i = 0; i < this.callStateListeners.length; i++) {
			if (this.callStateListeners[i] == listener) {
				this.callStateListeners.splice(i, 1);
				QDLogger.log( "TEL::removeCallStateListener", "removed");
			}
		}
		QDLogger.log( "TEL::removeCallStateListener", "len: " , this.callStateListeners.length);
		
		if (this.callStateListeners.length > 2) {
			QDLogger.error( "TEL::removeCallStateListener: HIGH LISTENER COUNT: " , this.callStateListeners.length);
		}
	},
	
	clearCallStateListeners: function() {
		this.callStateListeners = [];
	},
	
	getCallState: function() {
		QDLogger.log( "TelephonyEventListener::getCallState"); //"current call state has lines: " , this.callState.lines.length);
		
		return this.callState;
	},
	
	dispatchAudioState: function(profile) {
		QDLogger.log( "dispatchAudioState",  "listener count: " , this.callStateListeners.length);
		
		for (var i = 0; i < this.audioStateListeners.length; i++) {
			this.audioStateListeners[i].updateActiveAudioRouteButtonImage(profile);	
		}
	},

	addAudioStateListener: function(listener) {
		QDLogger.log( "TEL::addAudioStateListener");
		this.audioStateListeners.push(listener);
	},

	removeAudioStateListener: function(listener) {
		for (var i = 0; i < this.audioStateListeners.length; i++) {
			if (this.audioStateListeners[i] == listener) {
				this.audioStateListeners.splice(i, 1);
				QDLogger.log( "TEL::audioStateListeners", "removed");
			}
		}
		QDLogger.log( "TEL::audioStateListeners", "len: " , this.audioStateListeners.length);
	},

	handleActive: function(callState) {
		if (this.incomingPending && (this.incomingPending == callState.affectedCallId)) {
			this.incomingPending = undefined;
		}
		
		this.enableProxOnCallAndAudio();
		this.announcer.announceIncomingClose(AnnouncerAssistant.kIncomingAnswered);
		if (callState.lines[callState.lines.length-1].contact 
			&& callState.lines[callState.lines.length-1].contact.lookupComplete !== true) {
			this.contacts.reverseLookup(callState.number, callState.lines[callState.lines.length-1].contact,
				this.onActiveLookupComplete.bind(this), this.onLateLookup);
		} else {
			this.onActiveLookupComplete();
		}
		
	},
	
	onActiveLookupComplete: function() {
		Mojo.assertDefined(this.appAssistant, "onActiveLookupComplete: appAssistant is undefined.")
		QDLogger.log( "TelephonyEventListener::onActiveLookupComplete");
		this.appAssistant.showActiveCall();
		// TODO FOR TESTING
		//this.onEmergencyEvent({eventEmergency: {enabled: true}}); 
	},
	
	handleDialing: function(callState) {
		QDLogger.log( "TelephonyEventListener#handleDialing", callState.number , " l:" , callState.lines.length);
		
		// ASSumes that dialing call is the last call in the list.
		
		if(callState.lines.length < 1 || !(callState.lines[callState.lines.length-1])) {
			QDLogger.error( "TelephonyEventListener#handleDialing attempted to handle dialing message after call went away abort:", this.abortActiveCall);
			if (this.abortActiveCall == true) {
				QDLogger.error( "TelephonyEventListener#handleDialing aborting");
				this.abortActiveCall = false;
			} else {
				QDLogger.error( "TelephonyEventListener#handleDialing not aborting but showing dialpad anyway");
			}
			this.appAssistant.showDialpad();
			return;
		}
		
		
		this.contacts.reverseLookup(callState.number, callState.lines[callState.lines.length-1].contact,
				this.onDialingLookupComplete.bind(this), this.onLateLookup);
	},
	
	onDialingLookupComplete: function(contact) {
		if (this.abortActiveCall == true) {
			this.abortActiveCall = false;
			this.appAssistant.showDialpad();
		} else {
			// if lookup hasn't finished, but this message made it through, delay 4 seconds
			// before showing active call 
			if (contact.lookupPending) {
				setTimeout(function(){
					if (this.abortActiveCall || this.callState.lines.length < 1) {
						this.abortActiveCall = false;
						this.appAssistant.showDialpad();
						return;
					} 
					this.appAssistant.showActiveCall()
				}.bind(this), 4000);
			} else {
				if (this.abortActiveCall || this.callState.lines.length < 1) {
					this.abortActiveCall = false;
					this.appAssistant.showDialpad();
					return;
				}
				this.appAssistant.showActiveCall();
			}
		}
	},
	
	// takes a macrocall object, pulls parameters out, and announces incoming call (or updates existing announce)
	handleIncoming: function(callState, update) {
		QDLogger.log( "TelephonyEventListener::handleIncoming", "Incoming call:", 
			callState.affectedCallId, callState.cnapName, callState.number);
		
		this.incomingPending = callState.affectedCallId;
		
		this.contacts.reverseLookup(callState.number, this.contacts.getContact(callState.number, undefined, true /* clear lookupComplete */), // TODO: factor out 'force'
				this.onIncomingLookupComplete.bind(this, callState.affectedCallId, callState.cnapName, callState.number, update), this.onLateLookup);
		
		this.clearDialPending();
	},
	
	// callback after a contact lookup -- announces incoming call or passes on CNAP update
	onIncomingLookupComplete: function(callId, cnapName, number, update, contact) {
		
		contact.cnapName = cnapName;
		
		QDLogger.log( "TelephonyEventListener#onIncomingLookupComplete", "namefromcontacts?:" , !!(contact.name));
		this.announcer.announceIncoming(callId, number, contact, !!(contact.name), this.isConnected(), update);
	},
	
	// called if lookup returns late.  checks for incoming call and updates that if it's up; otherwise
	// updates active call screen
	onLateLookup: function(contact) {
		if (this.incomingCallExists()) {
			this.announcer.announceIncomingUpdateContactLate(contact);
		} else {
			if (this.callCount() > 0 && this.appAssistant.topScene() == "activecall") {
				var stageProxy = this.appControl.getStageProxy("PhoneApp");
				if (stageProxy)
					stageProxy.delegateToSceneAssistant("lateContactInfoUpdate", true /* force */);
			} 
		}
	},
	
	// takes a macrocall object, pulls parameters out, and announces disconnect
	// causes display of drop alert, disconnect banners, missed alert
	// determines if emergency mode alert should be re-raised
	// sets up delayed call to clear disconnect state out of UI
	handleDisconnect: function(callState, prevCallState) {
		
		QDLogger.log( "TelephonyEventListener::handleDisconnect", "previous: " , callState.previousAction);
  
  		if (this.incomingPending && (this.incomingPending == callState.affectedCallId)) {
			this.incomingPending = undefined;
		}
  
  		var disconnectCause = "";
        if (callState.previousAction != TelephonyCallState.INCOMING) { // call was answered
			if (prevCallState && prevCallState.lines && prevCallState.lines.length > 0) {
				if (this.isDisconnectCauseNormal(callState.causeCode)) {
					this.announcer.announceDisconnectNormal(callState);
				} else {
					this.announcer.announceDisconnectAbnormal(callState);
				}
			} else {
				QDLogger.error( "TelephonyEventListener#handleDisconnect", "received disconnect message with no calls present");
				return;	
			}
			
		} else { // call wasn't answered
			if (this.getRejectedCall() === callState.affectedCallId) {
				this.clearRejectedCall();
				disconnectCause = "ignored";
			} else {
				disconnectCause = "missed";
				this.announcer.announceIncomingClose(AnnouncerAssistant.kIncomingMissed, callState.affectedCallId);
				this.announcer.announceMissed(callState.number, this.contacts.getContact(callState.number), new Date().getTime());
			}
		}
		
		this.logDisconnect(callState, prevCallState, disconnectCause);
        
		// remove from contacts hash
		this.contacts.removeCaller(callState.number);
		
		// prepare to clear out the disconnected call state
		this.queueClearDisconnectedCall();
	},
	
	logDisconnect: function(callState, prevCallState, disconnectCause) {
		// this uses the PREVIOUS callstate to get the start time
		if (prevCallState) {
			var startTime = prevCallState.getStartTime(callState.affectedCallId);
			//make sure the call was actually established before 
			//writing it out to the call log as an incoming or outgoing
			//call (instead of missed)
			var duration = 0;
			if (startTime) {
				duration = new Date().getTime() - startTime;
			}
			else if (callState.origin == "dialing") {
				startTime = new Date().getTime();
			}	
			// if there's a starttime, then the call was answered; otherwise not
			if(startTime){
				var type = (callState.origin == "dialing") ? "outgoing" : "incoming";
				CallLogList.addEntry(callState.affectedCallId, callState.number, type, startTime, duration, this.contacts.getContact(callState.number));
			} else {
				CallLogList.addEntry(callState.affectedCallId, callState.number, disconnectCause, new Date().getTime(), 0, this.contacts.getContact(callState.number));
			}
		}
	},
	
	// a call is not aborted if it was started from outside the PhoneApp (like
	// a loopback call or incoming call), or if the card hasn't been flicked off the screen
	callAborted: function() {
		return (this.appInitiatedDialing && !(this.continueCall))
	},
	
	resetCallAbortState: function() {
		QDLogger.log( "TelephonyEventListener#resetCallAbortState");
		// set to true when a dial attempt is made
		this.appInitiatedDialing = false;
		
		// set to false when card is flicked off screen, 
		// or user taps disconnect when 1 call is connected
		this.continueCall = true;
	},
	
	// disconnect a call.
	// passes disconnect on to TelephonyCall
	// queues up removal of disconnect 
	disconnectCall: function(lineNumber) {
		QDLogger.log( "TelephonyEventListener::disconnectCall");
		this.handleCallState(this.callState.disconnectCall(lineNumber));
		
		// TODO does this actually work?
		// if this is the last call, don't continue anymore
		if (this.callState && this.callState.lines 
			&& this.callState.lines.length <= 1) {
				this.continueCall = false;
			}
	},
	
	// this gets called when we're killing all the calls; for example, when the 
	// card is flicked off the screen
	disconnectAllCalls: function() {
		
		if (this.callState && this.callState.lines && this.callState.lines.length > 0) {
			for (i = 0; i < this.callState.lines.length; i++) {
				this.callState.disconnectCall(i);
			}
			this.continueCall = false;
		}
	},
	
	queueClearDisconnectedCall: function() {
		QDLogger.log( "TelephonyEventListener::queueClearDisconnectedCall");
			/* TODO
            if (this.appAssistant.hidden)
            clearDisconnectedCall();
               else
               */
		this.clearDisconnectTimeout = setTimeout(this.clearDisconnectedCall.bind(this), 2500);
	},
	
	clearDisconnectedCall: function() {
		if (this.clearDisconnectTimeout) {
			clearTimeout(this.clearDisconnectTimeout);
			this.clearDisconnectTimeout = null;
			QDLogger.log( "TelephonyEventListener::queueClearDisconnectedCall", "clearing");
			
			if (this.callState && Object.isFunction(this.callState.clearDisconnectedCall)) {
				this.handleCallState(this.callState.clearDisconnectedCall());
			// service went away while we were waiting
			} else {
				var callState = new TelephonyCallState({}, undefined);
				callState.clearCalls(); 
				this.handleCallState(callState);
			}
		}
	},
	
	// indicates that a call was rejected. 
	// used to log a call as ignored instead of missed 
	flagCallRejected: function(callId) {
		this.callLastRejected = callId;
	},

	getRejectedCall: function() {
		return this.callLastRejected;
	},
	
	clearRejectedCall: function() {
		this.callLastRejected = undefined;
	},
	
	
	// removes a call in dialpending and resends through event handling
	// used when dial fails to complete, or incoming call arrives before call completes
	clearDialPending: function() {
		QDLogger.log( "TelephonyEventListener#clearDialPending");
		var oldLength = 0;
		
		if (this.callState) {
			if (this.callState.lines) {
				oldLength = this.callState.lines.length;
			}
			this.callState.clearDialPending();
		} else {
			return;
		}
		
		if (this.callState.lines) {
			if (this.callState.lines.length !== oldLength) {
			this.handleCallState(this.callState);
		}
			if (this.callState.lines.length == 0) {
				this.resetCallAbortState();
			}
		}
		
	},
	
	clearDialPendingDisconnect: function() {
		if (this.callState) {
			this.callState.clearDialPendingDisconnect();
		}
	},
	

	isDialing: function() {
		if (this.callState !== undefined) {
			return this.callState.isDialing();
		}
	},
	
	// this is actually misnamed: it refers to calls that are in a state after dialing
	// but also includes disconnected calls
	isConnected: function() {
		if (this.callState !== undefined) {
			var connected = this.callState.isConnected();
			QDLogger.log( "TelephonyEventListener::isConnected", connected);
			return connected;
		} else {
			return false;
		}
	},
	
	// returns true if there are calls that are not disconnected
	isPendingOrActive: function() {
		if (!(this.callState) || this.callState.length == 0)
			return false;
		else
			return this.callState.isPendingOrActive(); 
	},
	
	callCount: function() {
		
		if (this.callState)
			return this.callState.lines.length;
		else 
			return 0;
	},
	
	
	// returns true if there's any call around, regardless of state 
	callExists: function() {
		if (this.callState)
			return this.callState.callExists();
		else
			return false;
	},
	
	// determines if there's an 'active' incomingcall 
	incomingCallExists: function() {
		return (this.incomingPending !== undefined);
	},
	
    onVoicemailEvent: function(response){
 		var voicemailCount = 0;
        var high = false;
        if (response.extended) {
            voicemailCount = response.extended.line1;
            high = response.extended.high;
        } else if (response.eventVoicemail) {
            voicemailCount = response.eventVoicemail.line1;
            high = response.eventVoicemail.high;
        } else {
            QDLogger.log( "TelephonyEventListener::subscribeVoicemail", "unknown vm message");
        }
        QDLogger.log( "TelephonyEventListener::subscribeVoicemail", voicemailCount  , high);
        if (voicemailCount != this.lastVoicemail) {
			QDLogger.log( "TelephonyEventListener::subscribeVoicemail", "different message count");
			this.lastVoicemail = voicemailCount;
			this.announcer.announceVoicemail(voicemailCount, high);
			
			// update dialpad badge, if it's up
			if (this.voicemailBadgeCallback) {
				this.voicemailBadgeCallback(voicemailCount);
			}
        } 
    },
    
	// saves voicemail number if we got it; otherwise attempts to use device's own phone
	// number as voicemail number
	onVoicemailNumberCarrierDBReturn: function(status, payload) {
		if (status && payload) {
			QDLogger.log( "TelephonyEventListener::onVoicemailNumberCarrierDBReturn", "number: " , payload);
			this.voicemailNumber = payload;
			this.contacts.carrierBook[payload] = Messages.voicemailContact;
			this.callVoicemailOnNumberRetrieved();
		} else {
			QDLogger.log( "TelephonyEventListener::onVoicemailNumberCarrierDBReturn", "didn't get voicemail number from carrierDB; getting device's phone number");
			TelephonyCommands.phoneNumberQuery(this.onPhoneNumberReturn.bind(this));
			}
	},

	onVoicemailNumberReturn: function(retry, status, payload) {
		if (status && payload != "") {
			QDLogger.log( "TelephonyEventListener::onVoicemailNumberReturn", "number: " , payload);
			this.voicemailNumber = payload;
			this.contacts.carrierBook[payload] = Messages.voicemailContact;
			this.callVoicemailOnNumberRetrieved();
		} else {
			if (!retry) {
				QDLogger.log( "TelephonyEventListener::onVoicemailNumberReturn", "didn't get voicemail number; retrying in a second");
				setTimeout(function(){
					TelephonyCommands.voicemailNumberQuery(this.onVoicemailNumberReturn.bind(this, true /* a retry */), false /* don't subscribe */)
				}.bind(this), 1000);
			} else {
				// try one more time in a bit and use carrierdb for now.
				setTimeout(function(){
					TelephonyCommands.voicemailNumberQuery(this.onVoicemailNumberReturn.bind(this, true /* a retry */), false /* don't subscribe */)
				}.bind(this), 35000);
				QDLogger.log( "TelephonyEventListener::onVoicemailNumberReturn", "didn't get voicemail number; querying carrier db");
				this.carrierDbSubscription = TelephonyCommands.voicemailNumberCarrierDBQuery(this.onVoicemailNumberCarrierDBReturn.bind(this));
			}
		}
		TelephonyCommands.subscribePreference("allowEditVoicemail", this.onVoicemailNumberEditableReturn.bind(this));
	},
	
	onVoicemailNumberEditableReturn: function(editable) {
		QDLogger.log( "TelephonyEventListener::onVoicemailNumberEditableReturn", "isEditable :", editable);
		this.voicemailNumberEditable = editable;
	},
	
	// saves own phone number as voicemail number if we got it; otherwise just leaves it undefined
	onPhoneNumberReturn: function(status, payload) {
		if (status) {
			QDLogger.log( "TelephonyEventListener::onPhoneNumberReturn", "got device's number: " , payload);
			this.voicemailNumber = payload;
			this.contacts.carrierBook[payload] = Messages.voicemailContact;
			this.callVoicemailOnNumberRetrieved();
		} else {
			QDLogger.log( "TelephonyEventListener::onPhoneNumberReturn", "failed to get number");
		} 
	},
	
	// calculates home areacode
	homeAreaCodeFromPhoneNumber: function(success, value) {
		if (success) {
			if (value.length == 10) {
				this.appAssistant.homeAreaCode = value.substring(0,3)
			} else if (value.length == 11 && (value.charAt(0) == '1' || value.charAt(0) == '+')) {
				this.appAssistant.homeAreaCode = value.substring(1,4)
			} else if (value.length == 12 && value.substring(0,1) == '+1') {
				this.appAssistant.homeAreaCode = value.substring(2,5)
			}
		}
	},
	
	callVoicemailOnNumberRetrieved: function() {
		if (this.voicemailOnService && this.voicemailNumber) {
			this.voicemailOnService = false;
			this.appAssistant.launchVoicemail();	
		}
	},
	
    onInfotextEvent: function(response){
        if (response.eventInfoText) {
			this.announcer.announceServiceMsg("ID : " 
			+ response.eventInfoText.id + " " + response.eventInfoText.message);
        }
    },
    
    onUssdEvent: function(response){
        if (response && response.eventUssd && response.eventUssd.payload) {
			this.announcer.announceServiceMsg(response.eventUssd.payload);
        } else {
            QDLogger.log( "TelephonyEventListener::subscribeUssd", "unknown message");
        }
    },
	
	onBasebandDebug: function(response){
        if (response && response.eventBasebandDebug && response.eventBasebandDebug.message) {
			if (this.releaseBuild === false) {
				this.announcer.announceBasebandMsg(response.eventBasebandDebug.message);
			}
			
			QDLogger.log( "TelephonyEventListener::onBasebandDebug", response.eventBasebandDebug.message);
        } else {
            QDLogger.log( "TelephonyEventListener::onBasebandDebug", "unknown message");
        }
    },
    
    onOtaspEvent: function(response){
		QDLogger.log( "TelephonyEventListener::onOtaspEvent");
        if (response && response.eventOtasp && response.eventOtasp.status) {
		  this.announcer.announceOtasp(response.eventOtasp.status);
        } else {
            QDLogger.log( "TelephonyEventListener::subscribeOtasp", "unknown message");
        }
    },
    
	onEmergencyListReturn: function(payload) {
		var oldNumbers;
		if (payload != undefined && payload.extended != undefined && payload.extended.value != undefined) {
			oldNumbers = this.appAssistant.emergencyNumbers;
			this.appAssistant.emergencyNumbers = payload.extended.value.match(/[\*\#0-9]+/g);
		}
		
		// clear out entries that were set to the default emergency call number
		if (oldNumbers && oldNumbers.length > 0) {
			oldNumbers.each(function(n){
				if (this.contacts.carrierBook[n] === Messages.emergencyCallContact) {
					this.contacts.carrierBook[n] = undefined;
				}
			}.bind(this));
		}
		
        QDLogger.log( "TelephonyEventListener::onEmergencyListReturn", "Emergency numbers: " , this.appAssistant.emergencyNumbers.toString());
		// add to carrier book if there already isn't an entry
		for (var i = 0; i < this.appAssistant.emergencyNumbers.length; i++) {
			if (!this.contacts.carrierBook[this.appAssistant.emergencyNumbers[i]]) {
				this.contacts.carrierBook[this.appAssistant.emergencyNumbers[i]] = Messages.emergencyCallContact;
			}
		}
    },
	
    onEmergencyEvent: function(response){
        if (response.eventEmergency) {
			if (response.eventEmergency.enabled) {
            	this.appAssistant.emergencyMode = true;
				TelephonyCommands.playEmergencySound();
				this.appAssistant.showEmergencyStage();						
        	} else {
				this.appAssistant.emergencyMode = false;
				// TODO: maybe autoclose on radio reset?
			}
		}
		
    },
	
	
	onPowerEvent: function(response) {
		var state = false;
		if (response.extended) {
			if (response.extended.powerState == "on") {
				state = true;
			} else {
				state = false;
			}
		} else if (response.eventPower == "on") {
			state = true;
		} else {
			state = false;
		}
		
		QDLogger.log( "TelephonyEventListener::onPowerEvent", "powerState: " , state);
		
		if (this.powered !== state) {
			this.powered = state
			// if the radio went off while it was already on, see if we need to 
			// clear calls
			if (this.powered == false) {
				this.onPowerOff();
			} else if (this.powered == true) {
				this.onPowerOn();
			}
		}
		
	},
	
	onNetworkEvent: function(response) {
		var msg = {};
		if (response.extended) {
			msg = response.extended;
		} else if (response.eventNetwork) {
			msg = response.eventNetwork;
		} else {
			QDLogger.log( "TelephonyEventListener::onNetworkEvent", "unknown event");
		}
		
		switch (msg.state) {
			case "service":
				this.onServiced();
				break;
			case "limited":
				this.onLimited(); 
				break;
			default:
				this.onServiceLoss(); 
				break;
		}		
	},
	
	onPuckEvent: function(response) {
		if (response) {
			QDLogger.log( "TelephonyEventListener::onPuckEvent",
				response.type, response.connected);	
		}
		
		if (response && response.type) {
			switch (response.type) {
				case "inductive": 
					this.puckConnected = response.connected;	
					break;
				case "usb":
					this.usbConnected = response.connected;
					break;
					
			}
		}
			
	},
	
	// disconnects call on press of wired button if there's no incoming call
	onWiredButtonEvent: function(response) {
		if (response) {
			QDLogger.log( "TelephonyEventListener::onWiredButtonEvent", response.key, response.state);	
		}

		if (response && response.key == "headset_button") {
			if (response.state == "single_click" 
				&& this.isConnected()
				&& !(this.incomingCallExists())) {
				this.onWiredButtonDisconnect();
			} else if (response.state == "hold") {
				// TODO: voice dial?
			}
		}
	},
	
	// handles wired button disconnect behavior.
	// if there's one call connected, drops it.
	// if there are two, drops the first if it's the active one,
	// otherwise drops the second call
	onWiredButtonDisconnect: function() {
		if (this.callState && this.callState.lines) {
			if (this.callState.lines.length == 1) {
				this.disconnectCall(0);
			} else if (this.callState.lines.length == 2) {
				if (this.callState.lines[0].state == TelephonyCallState.ACTIVE) {
					this.disconnectCall(0);
				} else {
					this.disconnectCall(1);
				}
			}
		}
	},
	
	// detect unlocking to set behavior of other scenes
	onLockStatusEvent: function(response) {
		Mojo.Log.info( "TelephonyEventListener#onLockStatusEvent");// %j", response);
		if (response && response.locked !== undefined) {
			this.appAssistant.screenLocked = response.locked;
		}
	},
	
	// detect screen lock status to set behavior of other scenes
	onDeviceLockModeChanged: function(response) {
		Mojo.Log.info( "TelephonyEventListener#onDeviceLockModeChanged");// %j", response);
		if (response && response.lockMode !== undefined) {
			this.appAssistant.screenLockSecured = response.lockMode !== "none";
		}
	},
	
	onPin1Status:function(response) {
		Mojo.Log.info( "PhoneApp: TelephonyCommands::onPin1Status %j", response);
		if (response.extended) {
			// only raise dialog if we're not in first use
			if (response.extended.pinrequired) {
				this.lock = "pin";
				if (!(PalmSystem.isMinimal) && !(PlatformType.isEmergencyNumber(this.dialOnServiceNumber))) {
					TelephonyCommands.displayPin1Lock();
				}
			} else if (response.extended.pukrequired ){
				this.lock = "puk";
				if (!(PalmSystem.isMinimal) && !(PlatformType.isEmergencyNumber(this.dialOnServiceNumber))) {
					TelephonyCommands.displayPuk1Lock();
				}
			} else if (response.extended.simlocked) {
				this.lock = "sim";
				if (!(PalmSystem.isMinimal) && !(PlatformType.isEmergencyNumber(this.dialOnServiceNumber))) {
					TelephonyCommands.displaySimLock();
				}
			} else {
				this.lock = "";
				// simready, so load settings
				this.onServiceSettingsReady();
			}
		}		
    },
	
	onDeviceLockQuery: function(response){
		Mojo.Log.info( "PhoneApp: TelephonyCommands::onDeviceLockQuery %j", response);
		if (response.extended) {
			var keys = Object.keys(response.extended);
			if (keys.size()>1){
				for (var i =0; i< keys.size(); i++){
					if (response.extended[keys[i]] == true) {
						this.lock = "devicelock";
						this.unblock = true;
						this.locktype = keys[i];
						if (!(PalmSystem.isMinimal)) 
							TelephonyCommands.displayDeviceLock(keys[i], true);
						return;
					}						
				}
			}
			if (keys.size() > 0) {
				this.lock = "devicelock";
				this.unblock = response.extended[keys[0]];
				this.locktype = keys[0];
				if (!(PalmSystem.isMinimal)) 
					TelephonyCommands.displayDeviceLock(keys[0], response.extended[keys[0]]);
			}
			
			// query for emergency numbers, since this event indicates the simcard is ready for reading
			TelephonyCommands.emergencyNumberQuery(this.onEmergencyListReturn.bind(this));
		}		
	},
	
	isDisconnectCauseNormal: function(code) {
		var silentList;
		if (PlatformType.isGSM()) {
			normalDisconnectCodes = this.normalDisconnectCodesGSM;
		} else {
			normalDisconnectCodes = this.normalDisconnectCodesCDMA;
		}
		
		for (i = 0; i < normalDisconnectCodes.length; i++) {
			if (code == normalDisconnectCodes[i])
				return true;
		}
		
		return false;
	},
	
	
	onAudioNotification: function(payload) {
		var prof;
		var audioProfiles = Mojo.Controller.getAppController().assistant.audioEnabledProfiles;
		
		if (!payload)
			return;

		Mojo.Log.info("PhoneApp: TelephonyEventListener::handleAudioNotification %j", payload);
		
		if (payload.scenarios != undefined) {
			while ((prof = payload.scenarios.pop()) != undefined)
				audioProfiles[prof] = true;
			Mojo.Log.info("PhoneApp: TelephonyEventListener::handleAudioNotification Available audio scenarios: %j" , audioProfiles);
			return;
		}
		
		switch (payload.action) {
			case "changed":
				// Update the active scenario
				if (payload.active != undefined) {
					if (payload.active) {
						// Clear the previously active profile (if any)
						if (Mojo.Controller.getAppController().assistant.audioActiveProfile)
							audioProfiles[Mojo.Controller.getAppController().assistant.audioActiveProfile] = true;
						// Mark the new profile as active
						//remove following condition
						//if (audioProfiles[payload.scenario] != undefined)
							audioProfiles[payload.scenario] = "active";
						// Save the active audio profile
						Mojo.Controller.getAppController().assistant.audioActiveProfile = payload.scenario;
						// Notify whoever cares
						var activeCallController = this.appControl.getStageProxy("PhoneApp");
						if (activeCallController !== undefined) {
							//activeCallController.delegateToSceneAssistant("updateActiveAudioRouteButtonImage", payload.scenario);
							this.dispatchAudioState(payload.scenario);
						}
						this.enableProxOnCallAndAudio(payload.scenario);
					} else {
						//add following condition 
						if (payload.scenario == Mojo.Controller.getAppController().assistant.audioActiveProfile)
							Mojo.Controller.getAppController().assistant.audioActiveProfile = null;
						if (audioProfiles[payload.scenario] != undefined)
							audioProfiles[payload.scenario] = true;
					}
				}
				break;
				
			case "enabled":
				audioProfiles[payload.scenario] = true;
				Mojo.Log.info("PhoneApp: TelephonyEventListener::handleAudioNotification: enabled Available audio scenarios: %j" , audioProfiles);
				break;
				
			case "disabled":
				if (audioProfiles[payload.scenario] != undefined)
					delete audioProfiles[payload.scenario];
				this.dispatchAudioState(Mojo.Controller.getAppController().assistant.audioActiveProfile);
				Mojo.Log.info("PhoneApp: TelephonyEventListener::handleAudioNotification: disabled Available audio scenarios: %j" , audioProfiles);
				break;
		}
	},
	
	// TODO: move all the audio stuff into its own model?
	getAvailableAudioScenarios: function() {
		return Mojo.Controller.getAppController().assistant.audioEnabledProfiles;
	},
	
	onProvisioningStatusNotification: function(payload){
		Mojo.Log.info("PhoneApp: TelephonyEventListener::onProvisioningStatusNotification: payload: %j", payload);
		if (payload.status) {
			var showAlert = payload.displayAlert;
			var	msg = payload.status.toLowerCase();
			
			this.announcer.announceProvisioning(payload.trigger ,msg, payload.cancelabel, showAlert, payload.errorCode);
		}	
	},
	
	// prefs
	handlePrefContactLookupOnKey: function(value) {
		this.appAssistant.lookupOnKeyPress = !!value;
		
		if (this.lookupOnKeyPrefChangedCallback) {
			this.lookupOnKeyPrefChangedCallback();
		}
	}
	
});
