/*
 * Copyright (C) 2013 AVM GmbH <info@avm.de>
 * Copyright (C) 2009 The Sipdroid Open Source Project
 * 
 * This file is part of Sipdroid (http://www.sipdroid.org)
 * 
 * Sipdroid is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This source code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this source code; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package de.avm.android.fritzapp.sipua.ui;

import org.sipdroid.media.RtpStreamReceiver;

import android.annotation.SuppressLint;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.widget.RemoteViews;
import de.avm.android.fritzapp.R;
import de.avm.android.fritzapp.com.ComSettingsChecker;
import de.avm.android.fritzapp.gui.FRITZApp;
import de.avm.android.fritzapp.gui.SettingsExtendedActivity;
import de.avm.android.fritzapp.service.SipExpiredAlarm;
import de.avm.android.fritzapp.sipua.SipdroidEngine;
import de.avm.android.fritzapp.sipua.UserAgent;
import de.avm.android.fritzapp.sipua.phone.Call;
import de.avm.android.fritzapp.sipua.phone.Connection;
import de.avm.android.fritzapp.util.BuildHelper;
import de.avm.android.fritzapp.util.ResourceHelper;

	public class Receiver extends BroadcastReceiver {

		final static String TAG = "Receiver";
		
		public final static String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
		final static String ACTION_SIGNAL_STRENGTH_CHANGED = "android.intent.action.SIG_STR";
		public final static String ACTION_DATA_STATE_CHANGED = "android.intent.action.ANY_DATA_STATE";
		public final static String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT";
		final static String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
		final static String PAUSE_ACTION = "com.android.music.musicservicecommand.pause";
		final static String TOGGLEPAUSE_ACTION = "com.android.music.musicservicecommand.togglepause";
		
		public final static int CALL_NOTIFICATION = 2;
		public final static int MISSED_CALL_NOTIFICATION = 3;
		public final static int AUTO_ANSWER_NOTIFICATION = 4;
		public final static int MWI_NOTIFICATION = 5;
		
		public static int docked = -1;
		public static int headset = -1;
		public static SipdroidEngine mSipdroidEngine;
		
		public static Context mContext;
		public static Call ccCall;
		public static Connection ccConn;
		public static int call_state;
		
		public static String pstn_state;
		public static long pstn_time;
		public static String MWI_account;
		public static String call_end_reason = null;
		private static String laststate,lastnumber;	
		public static Runnable mPlugHeadsetListener = null;
		private static boolean mMuteNotification = false;
		
		public static MediaPlayer ringbackPlayer;

		public static SipdroidEngine engine(Context context) {
			mContext = context;
			if (mSipdroidEngine == null) {
				mSipdroidEngine = new SipdroidEngine();
				mSipdroidEngine.StartEngine();
			} /*else
				mSipdroidEngine.CheckEngine();
				*/
			return mSipdroidEngine;
		}
		
		static PowerManager.WakeLock mBrightWakeLock = null;
		static WifiManager.WifiLock mWifiLock = null;

		private static Thread ringer_thread = null;
		private static Thread vibrator_thread = null;
		
		private static void startRinging() {
			if(ringer_thread != null) return;			
			ringer_thread = new Thread(new Runnable() {
				public void run() {
					String ringtoneUri = PreferenceManager.getDefaultSharedPreferences(mContext)
							.getString(Sipdroid.PREF_RINGTONE,
									Settings.System.DEFAULT_RINGTONE_URI.toString());
					Ringtone ringtone = null;
					if (!TextUtils.isEmpty(ringtoneUri))
					{
						Uri uri = null;
						try { uri = Uri.parse(ringtoneUri); }
						catch(Exception e)
						{
							Log.e(TAG, "Invalid ringtone Uri: " + ringtoneUri);
							uri = Settings.System.DEFAULT_RINGTONE_URI;
						}
						ringtone = RingtoneManager.getRingtone(mContext, uri);
					}
					// empty ringtoneUri is for silence

					if (ringtone != null)
					{
						try {
							while(true) {
								ringtone.play();
								while(ringtone.isPlaying()) {
									Thread.sleep(200);
								}
							}
						}
						catch (InterruptedException ex) {
							Log.d(TAG, "Ringer thread interrupted");
						}
						finally {
							ringtone.stop();
						}
					}
					Log.d(TAG, "Ringer thread exiting");
				}
			});
			ringer_thread.start();
		}
		
		private static void stopRinging() {
			if(ringer_thread != null) {
				ringer_thread.interrupt();
				try {
					ringer_thread.join(250);
				}
				catch (InterruptedException ex) {}
				ringer_thread = null;
			}
		}
		
		public static void stopRingtone() {
			stopRinging();
			stopVibration();
		}
		
		private static void startVibration() {
			if(vibrator_thread != null) return;
			vibrator_thread = new Thread(new Runnable() {
				public void run() {
					android.os.Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
					try {
						while(true) {
							v.vibrate(1000);
							Thread.sleep(2000);
						}
					}
					catch (InterruptedException ex) {
						Log.d(TAG, "Vibrator thread interrupted");
					}
					finally {
						v.cancel();
					}
					Log.d(TAG, "Vibrator thread exiting");					
				}
			});
			vibrator_thread.start();
		}
		
		private static void stopVibration() {
			if(vibrator_thread != null) {
				vibrator_thread.interrupt();
				try {
					vibrator_thread.join(250);
				}
				catch (InterruptedException ex) {}
				vibrator_thread = null;
			}
		}
		
		@SuppressLint("InlinedApi")
		public static void onState(int state,String caller) {
			if (ccCall == null) {
		        ccCall = new Call();
		        ccConn = new Connection();
		        ccCall.setConn(ccConn);
		        ccConn.setCall(ccCall);
			}
			if (call_state != state) {
				call_state = state;
				switch(call_state)
				{
				case UserAgent.UA_STATE_INCOMING_CALL:
					BuildHelper.dump();
					lock(true);
					RtpStreamReceiver.good = RtpStreamReceiver.lost = RtpStreamReceiver.loss = RtpStreamReceiver.late = 0;
					String text = null, text2 = null;
					// number in SIP address
					int begin = caller.indexOf("<sip:");
					if (begin >= 0)
					{
						begin += 5;
						int end = caller.indexOf("@", begin);
						if (end > begin) text = caller.substring(begin, end);
					}
					// name string in brackets (e.g additional to SIP address)
					begin = caller.indexOf("\"");
					if (begin >= 0)
					{
						int end = caller.indexOf("\"", ++begin);
						if (end > begin) text2 = caller.substring(begin, end);
					}
					broadcastCallStateChanged("RINGING", caller);
			        mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
					ccCall.setState(Call.State.INCOMING);
					ccConn.setUserData(null);
					ccConn.setAddress((text == null) ? caller : text,
							(text2 == null) ? caller : text2);
					ccConn.setIncoming(true);
					ccConn.date = System.currentTimeMillis();
					ccCall.base = 0;
					AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
					int rm = am.getRingerMode();
					int vs = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
			        KeyguardManager keyguardManager = (KeyguardManager)mContext.
			        		getSystemService(Context.KEYGUARD_SERVICE);
					if (PreferenceManager.getDefaultSharedPreferences(mContext)
							.getBoolean(Sipdroid.PREF_AUTOON, false) &&
							!keyguardManager.inKeyguardRestrictedInputMode())
					{
				        startVibration();
					}
					else {
						if ((pstn_state == null || pstn_state.equals("IDLE")) &&
								(rm == AudioManager.RINGER_MODE_VIBRATE ||
								(rm == AudioManager.RINGER_MODE_NORMAL && vs == AudioManager.VIBRATE_SETTING_ON))) {
							startVibration();
						}
						if (am.getStreamVolume(AudioManager.STREAM_RING) > 0) {
							startRinging();
						}
					}
					moveTop();
					if (mBrightWakeLock == null) {
						PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
						mBrightWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK |
								PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE,
								Receiver.class.getName());
					}
					mBrightWakeLock.acquire();
					break;
				case UserAgent.UA_STATE_OUTGOING_CALL:
					BuildHelper.dump();
					lock(true);
					RtpStreamReceiver.good = RtpStreamReceiver.lost = RtpStreamReceiver.loss = RtpStreamReceiver.late = 0;
					onText(MISSED_CALL_NOTIFICATION, null, 0,0);
					if(!engine(mContext).isRegistered()) // Fix NB
						engine(mContext).register();
	        		updateProximity();
					broadcastCallStateChanged("OFFHOOK", caller);
					ccCall.setState(Call.State.DIALING);
					ccConn.setUserData(null);
					ccConn.setAddress(caller,caller);
					ccConn.setIncoming(false);
					ccConn.date = System.currentTimeMillis();
					ccCall.base = 0;
					moveTop();
					break;
				case UserAgent.UA_STATE_IDLE:
					lock(false);
					broadcastCallStateChanged("IDLE", null);
					onText(CALL_NOTIFICATION, null, 0,0);
					ccCall.setState(Call.State.DISCONNECTED);
					stopRingtone();
					if ((mBrightWakeLock != null) && mBrightWakeLock.isHeld())
						mBrightWakeLock.release();
					if ((mWifiLock != null) && mWifiLock.isHeld())
						mWifiLock.release();
	        		updateProximity();
			        mContext.startActivity(createIntent(InCallScreen.class));
					ccConn.log(ccCall.base, call_end_reason);
					call_end_reason = null;
					ccConn.date = 0;
					engine(mContext).listen();
					break;
				case UserAgent.UA_STATE_INCALL:
					lock(true);
					broadcastCallStateChanged("OFFHOOK", null);
					if (ccCall.base == 0) {
						ccCall.base = SystemClock.elapsedRealtime();
					}
					onText(CALL_NOTIFICATION, mContext.getString(R.string.card_title_in_progress), android.R.drawable.stat_sys_phone_call,ccCall.base);
					ccCall.setState(Call.State.ACTIVE);
					stopRingtone();
					if (mWifiLock == null)
					{
						WifiManager wm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
						int flag = (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) ?
								WifiManager.WIFI_MODE_FULL : WifiManager.WIFI_MODE_FULL_HIGH_PERF;
						mWifiLock = wm.createWifiLock(flag, Receiver.class.getName());
					}
					mWifiLock.acquire();
					if ((mBrightWakeLock != null) && mBrightWakeLock.isHeld())
						mBrightWakeLock.release();

	        		updateProximity();
					
					mContext.startActivity(createIntent(InCallScreen.class));
		       		if (docked > 0)
	    				engine(mContext).speaker(AudioManager.MODE_NORMAL);
					break;
				case UserAgent.UA_STATE_HOLD:
					lock(false);
					onText(CALL_NOTIFICATION, mContext.getString(R.string.card_title_on_hold), android.R.drawable.stat_sys_phone_call_on_hold,ccCall.base);
					ccCall.setState(Call.State.HOLDING);
			        mContext.startActivity(createIntent(InCallScreen.class));
					break;
				}
				if (ringbackPlayer != null && ringbackPlayer.isPlaying()) {
					ringbackPlayer.stop();
				}
			}
		}
		
		public static void onText(int type, String text, int iconResId, long base)
		{
	        NotificationManager notificationMgr = (NotificationManager)mContext
	        		.getSystemService(Context.NOTIFICATION_SERVICE);
	        if (text != null)
	        {
		        Notification notification = new Notification();
		        notification.icon = iconResId;

		        if (type == MISSED_CALL_NOTIFICATION)
				{
		        	notification.tickerText = String.format(
							mContext.getString(R.string.notify_missed_call_ticker),
							text);
					String caller = String.format(
							mContext.getString(R.string.notify_missed_call_fmt),
							text);
					
		        	notification.flags |= Notification.FLAG_AUTO_CANCEL;
		        	notification.setLatestEventInfo(mContext,
		        			mContext.getString(R.string.notify_missed_call_label),
		        			caller,
		        			PendingIntent.getActivity(mContext, 0, createCallLogIntent(), 0));
	        		// blue LED flashing
		        	notification.flags |= Notification.FLAG_SHOW_LIGHTS;
		        	notification.ledARGB = 0xff0000ff; /* blue */
		        	notification.ledOnMS = 125;
		        	notification.ledOffMS = 2875;
	        	}
				else
				{
			        switch (type)
	        		{
			        	case MWI_NOTIFICATION:
				        	notification.flags |= Notification.FLAG_AUTO_CANCEL;
							notification.contentIntent = PendingIntent.getActivity(mContext, 0, 
									createMWIIntent(), 0);	
				        	notification.flags |= Notification.FLAG_SHOW_LIGHTS;
				        	notification.ledARGB = 0xff00ff00; /* green */
				        	notification.ledOnMS = 125;
				        	notification.ledOffMS = 2875;
							break;
			        	case AUTO_ANSWER_NOTIFICATION:
							notification.contentIntent = PendingIntent.getActivity(mContext, 0,
					                createIntent(AutoAnswer.class), 0);
							break;
			        	case CALL_NOTIFICATION:
			        		if ((call_state == UserAgent.UA_STATE_OUTGOING_CALL) ||
			        			 (call_state == UserAgent.UA_STATE_INCALL))
			        		{
			        			if (mMuteNotification)
			        			{
				        			// muted
			        				notification.icon = android.R.drawable.stat_notify_call_mute;
			        				text = mContext.getString(R.string.menu_mute);
			        			}
			        			else if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL)
			        			{
				        			// speaker on
		        					notification.icon = android.R.drawable.stat_sys_speakerphone;
			        			}
			        		}
							notification.contentIntent = PendingIntent.getActivity(mContext, 0,
						            createIntent(FRITZApp.class), 0);
			        		break;
			        	default:
							notification.contentIntent = PendingIntent.getActivity(mContext, 0,
						            createIntent(FRITZApp.class), 0);
			        		break;
		        	}			
		        	notification.flags |= Notification.FLAG_ONGOING_EVENT;
			        RemoteViews contentView = new RemoteViews(mContext.getPackageName(),
	                        R.layout.ongoing_call_notification);
			        contentView.setImageViewResource(R.id.icon, notification.icon);
					if (base != 0)
						contentView.setChronometer(R.id.text1, base, text+" (%s)", true);
					else
						contentView.setTextViewText(R.id.text1, text);
			        contentView.setTextViewText(R.id.text2,
			        		ResourceHelper.getApplicationName(mContext));
					notification.contentView = contentView;
		        }
		        notificationMgr.notify(type,notification);
	        }
	        else
	        {
	        	if (type == CALL_NOTIFICATION) mMuteNotification = false;
	        	notificationMgr.cancel(type);
	        }

	        if (type != AUTO_ANSWER_NOTIFICATION) updateAutoAnswer();
		}
		
		public static void onMuteChanged(boolean enable)
		{
			if (mMuteNotification != enable)
			{
				mMuteNotification = enable;
				if (call_state == UserAgent.UA_STATE_INCALL)
					onSpeakerChanged(); // kick update notification
			}
		}
		
		public static void onSpeakerChanged()
		{
			if ((mContext != null) && (ccCall != null))
			{
				switch(call_state)
				{
					case UserAgent.UA_STATE_OUTGOING_CALL:
					case UserAgent.UA_STATE_INCALL:
						// update notification
						onText(CALL_NOTIFICATION, mContext.
								getString(R.string.card_title_in_progress),
								android.R.drawable.stat_sys_phone_call, ccCall.base);
						break;
				}
			}
		}

		static void updateAutoAnswer() {
			if (PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean(Sipdroid.PREF_AUTOONDEMAND, false) &&
				Sipdroid.on(mContext)) {
				if (PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean(Sipdroid.PREF_AUTOONDEMAND, false))
					updateAutoAnswer(1);
				else
					updateAutoAnswer(0);
			} else
				updateAutoAnswer(-1);
		}

		// no notification for auto answer setting
//		private static int autoAnswerState = -1;
		
		static void updateAutoAnswer(int status) {
//			if (status != autoAnswerState) {
//				switch (autoAnswerState = status) {
//				case 0:
//					Receiver.onText(Receiver.AUTO_ANSWER_NOTIFICATION,mContext.getString(R.string.auto_disabled),R.drawable.auto_answer_disabled,0);
//					break;
//				case 1:
//					Receiver.onText(Receiver.AUTO_ANSWER_NOTIFICATION,mContext.getString(R.string.auto_enabled),R.drawable.auto_answer,0);
//					break;
//				case -1:
//					Receiver.onText(Receiver.AUTO_ANSWER_NOTIFICATION, null, 0, 0);
//					break;
//				}
//			}
		}

		/**
		 * Updates usage of proximity lock for current
		 * acquired only in  UserAgent.UA_STATE_INCALL if not
		 * docked and no headset plugged in an speaker is off
		 */
		public static void updateProximity()
		{
			if (mNoProximity) return; // failed previously
			
			boolean acquire = false;
			if ((headset <= 0) && (docked <= 0))
			{
				switch(call_state)
				{
					case UserAgent.UA_STATE_OUTGOING_CALL:
						// FIXME why is it MODE_CURRENT initially,
						// but after Speaker ON+OFF MODE_IN_CALL??
						acquire = (RtpStreamReceiver.speakermode ==
								AudioManager.MODE_CURRENT) ||
								(RtpStreamReceiver.speakermode ==
								AudioManager.MODE_IN_CALL);
						break;
						
					case UserAgent.UA_STATE_INCALL:
						acquire = (RtpStreamReceiver.speakermode ==
								AudioManager.MODE_IN_CALL);
						break;
						
					default:
						acquire = false;
						break;
				}
			}

			// workaround for broken audio output while SCREEN_OFF
			// possibly a bug on some devices -> don't use proximity
			boolean isDimOnly = SettingsExtendedActivity.isDimOnly(mContext);
			
			if (!isDimOnly && acquire &&
					(mProximityWakeLock == null))
			{
				try
				{
					mProximityWakeLock = ((PowerManager)mContext
							.getSystemService(Context.POWER_SERVICE))
							.newWakeLock( PROXIMITY_SCREEN_OFF_WAKE_LOCK,
									Receiver.class.getName());
				}
				catch(IllegalArgumentException exp)
				{
					mNoProximity = true;
				}
			}
			
			if ((mProximityWakeLock != null) &&
					((acquire && !mNoProximity && !isDimOnly) !=
					mProximityWakeLock.isHeld()))
			{
				if (acquire && !mNoProximity && !isDimOnly)
					mProximityWakeLock.acquire();
				else
					mProximityWakeLock.release();
			}
		}
		
		public static void registered() {
		}
	    
		private static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32; // not documented in SDK!
		private static boolean mNoProximity = false;
		private static PowerManager.WakeLock mPartialWakeLock = null;
		private static PowerManager.WakeLock mDimWakeLock = null;
		private static PowerManager.WakeLock mProximityWakeLock = null;

		static void lock(boolean lock)
		{
//			Log.d(TAG, String.format("lock(%s) - currently %s",
//					Boolean.toString(lock), (mPartialWakeLock == null) ?
//					"uninitialized" : Boolean.toString(mPartialWakeLock.isHeld())));
		
			if (lock)
			{
				// workaround for broken audio output while SCREEN_OFF
				// possibly a bug on some devices -> prevent SCREEN_OFF, dim instead
				boolean isDimOnly = SettingsExtendedActivity.isDimOnly(mContext);
				
				PowerManager pm = null;
				if (mPartialWakeLock == null)
				{
					pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
					mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
							Receiver.class.getName());
				}
				if (isDimOnly && (mDimWakeLock == null))
				{
					Log.d(TAG, "Don't switch off Display in phone call, but dim.");
					if (pm == null)
						pm = (PowerManager)mContext.getSystemService(
								Context.POWER_SERVICE);
					mDimWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK |
							PowerManager.ON_AFTER_RELEASE, Receiver.class.getName());
				}
				if (!mPartialWakeLock.isHeld()) mPartialWakeLock.acquire();
				if (isDimOnly && !mDimWakeLock.isHeld()) mDimWakeLock.acquire();
			}
			else
			{
				if ((mPartialWakeLock != null) && mPartialWakeLock.isHeld())
					mPartialWakeLock.release();
				if ((mDimWakeLock != null) && mDimWakeLock.isHeld())
					mDimWakeLock.release();
			}
		}
		
		static boolean was_playing;
		
		static void broadcastCallStateChanged(String state,String number)
		{
			if (state == null)
			{
				state = laststate;
				number = lastnumber;
			}
			try
			{
				Intent intent = new Intent(ACTION_PHONE_STATE_CHANGED);
				intent.putExtra("state",state);
				if (number != null) intent.putExtra("incoming_number", number);
				intent.putExtra(ResourceHelper.getApplicationName(mContext), true);
				mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE);
			}
			catch(SecurityException e)
			{
				Log.d(TAG, "Didn't broadcast phone state change.");
			}
			catch(Throwable e)
			{
				Log.w(TAG, "Failed to broadcast phone state change. " +
						e.getClass().getName() + ": " + e.getMessage());
			}
			if (state.equals("IDLE"))
			{
				if (was_playing)
				{
					if (pstn_state == null || pstn_state.equals("IDLE"))
					{
						try
						{
							mContext.sendBroadcast(new Intent(TOGGLEPAUSE_ACTION));
						}
						catch(Throwable e)
						{
							Log.w(TAG, "Failed to broadcast to stop pausing audio players. " +
									e.getClass().getName() + ": " + e.getMessage());
						}
					}
					was_playing = false;
				}
			}
			else
			{
				AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
				if ((laststate == null || laststate.equals("IDLE")) && (was_playing = am.isMusicActive()))
				{
					try
					{
						mContext.sendBroadcast(new Intent(PAUSE_ACTION));
					}
					catch(Throwable e)
					{
						Log.w(TAG, "Failed to broadcast to for pausing audio players. " +
								e.getClass().getName() + ": " + e.getMessage());
					}
				}
			}
			laststate = state;
			lastnumber = number;
		}

		public static void reRegister(int renew_time)
		{
			SipExpiredAlarm.setAlarm(mContext, renew_time - 15);
		}

		static Intent createIntent(Class<?>cls) {
        	Intent startActivity = new Intent();
        	startActivity.setClass(mContext,cls);
    	    startActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    	    return startActivity;
		}
		
		public static Intent createCallLogIntent() {
	        Intent intent = new Intent(Intent.ACTION_VIEW, null);
	        intent.setType("vnd.android.cursor.dir/calls");
	        return intent;
		}
		
		public static Intent createHomeIntent() {
	        Intent intent = new Intent(Intent.ACTION_MAIN, null);
	        intent.addCategory(Intent.CATEGORY_HOME);
	        return intent;
		}

	    static Intent createMWIIntent() {
			Intent intent;

			if (MWI_account != null)
				intent = new Intent(Intent.ACTION_CALL, Uri.parse(MWI_account));
			else
				intent = new Intent(Intent.ACTION_DIAL);
			return intent;
		}
		
		public static void moveTop() {
			onText(CALL_NOTIFICATION, mContext.getString(R.string.card_title_in_progress), android.R.drawable.stat_sys_phone_call, 0);
			mContext.startActivity(createIntent(Activity2.class)); 
		}

		public static boolean on_wlan;
		
		@SuppressWarnings("unused")
		public static boolean isFast()
		{
			if (ComSettingsChecker.getBoxInfo() == null)
			{
				// with connection to box only
        		on_wlan = false;
			}
			else if (SettingsExtendedActivity.isWlanOnly(mContext))
			{
				// over WLAN only
				ConnectivityManager connectivityManager = (ConnectivityManager)mContext
						.getSystemService(Context.CONNECTIVITY_SERVICE);
				NetworkInfo ni = connectivityManager.getActiveNetworkInfo();
				on_wlan =((ni != null) && (ni.getType() == ConnectivityManager.TYPE_WIFI) &&
					ni.isConnectedOrConnecting());

				if ((ni != null) && !Sipdroid.release)
					Log.i("SipUA:","isFast() "+ni.getDetailedState());
			}
			else
			{
				// pretend to be connected over WLAN
        		on_wlan = true;
			}

    		return on_wlan;
		}
		
		public static int speakermode() {
			if(docked > 0 && headset <= 0)
				return AudioManager.MODE_NORMAL;
			else
				return AudioManager.MODE_IN_CALL;
		}
		
	    @Override
		public void onReceive(Context context, Intent intent) {
	        String intentAction = intent.getAction();
	        if (!Sipdroid.on(context)) return;
        	if (!Sipdroid.release) Log.i("SipUA:",intentAction);
        	if (mContext == null) mContext = context;
	        if (intentAction.equals(ACTION_DATA_STATE_CHANGED)) {
	            if(!engine(mContext).isRegistered()) // Fix NB/SH
	               engine(context).register();
	        } else
	        if (intentAction.equals(ACTION_PHONE_STATE_CHANGED) &&
	        		!intent.getBooleanExtra(ResourceHelper.getApplicationName(context), false)) {
	        	stopRingtone();
	    		pstn_state = intent.getStringExtra("state");
	    		pstn_time = SystemClock.elapsedRealtime();
	    		if (pstn_state.equals("IDLE") && call_state != UserAgent.UA_STATE_IDLE)
	    			broadcastCallStateChanged(null,null);
	    		if ((pstn_state.equals("OFFHOOK") && call_state == UserAgent.UA_STATE_INCALL) ||
		    			(pstn_state.equals("IDLE") && call_state == UserAgent.UA_STATE_HOLD))
		    			engine(context).togglehold();
	        } else
	        if (intentAction.equals(ACTION_DOCK_EVENT)) {
	        	docked = intent.getIntExtra(EXTRA_DOCK_STATE, -1);
	        	if (call_state == UserAgent.UA_STATE_INCALL)
	        	{
	        		engine(mContext).speaker(speakermode());
	        		updateProximity();
	        	}
	        } else
		    if (intentAction.equals(Intent.ACTION_HEADSET_PLUG)) {
	        	headset = intent.getIntExtra("state", -1);
	        	if(call_state == UserAgent.UA_STATE_INCALL)
	        	{
	        		engine(mContext).speaker(speakermode());
	        		updateProximity();
	        		Runnable listener = mPlugHeadsetListener; 
	        		if (listener != null) listener.run();
	        	}
	        }
		}
		
		public static boolean isMuted()
		{
			return mMuteNotification;
		}
}
