/** * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr) * This file is part of CSipSimple. * * CSipSimple 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. * If you own a pjsip commercial license you can also redistribute it * and/or modify it under the terms of the GNU Lesser General Public License * as an android library. * * CSipSimple 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 CSipSimple. If not, see <http://www.gnu.org/licenses/>. */ package com.csipsimple.utils; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.media.AudioManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.provider.Settings; import android.telephony.TelephonyManager; import android.text.TextUtils; import com.csipsimple.api.SipConfigManager; import com.csipsimple.service.MediaManager; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; public class PreferencesProviderWrapper { private static final String THIS_FILE = "Prefs"; private ContentResolver resolver; private ConnectivityManager connectivityManager; private Context context; public static final String LIB_CAP_TLS = PreferencesWrapper.LIB_CAP_TLS; public static final String LIB_CAP_SRTP = PreferencesWrapper.LIB_CAP_SRTP; public static final String HAS_BEEN_QUIT = PreferencesWrapper.HAS_BEEN_QUIT; public static final String HAS_ALREADY_SETUP_SERVICE = PreferencesWrapper.HAS_ALREADY_SETUP_SERVICE; public PreferencesProviderWrapper(Context aContext) { context = aContext; resolver = aContext.getContentResolver(); connectivityManager = (ConnectivityManager) aContext .getSystemService(Context.CONNECTIVITY_SERVICE); } /** * Set all values to default */ public void resetAllDefaultValues() { Uri uri = SipConfigManager.RAZ_URI; resolver.update(uri, new ContentValues(), null, null); } // Api compat part public boolean getPreferenceBooleanValue(String string, boolean b) { return SipConfigManager.getPreferenceBooleanValue(context, string, b); } public Boolean getPreferenceBooleanValue(String string) { return SipConfigManager.getPreferenceBooleanValue(context, string); } public String getPreferenceStringValue(String key) { return SipConfigManager.getPreferenceStringValue(context, key); } public String getPreferenceStringValue(String key, String defaultVal) { return SipConfigManager.getPreferenceStringValue(context, key, defaultVal); } public int getPreferenceIntegerValue(String key) { return SipConfigManager.getPreferenceIntegerValue(context, key); } public float getPreferenceFloatValue(String key) { return SipConfigManager.getPreferenceFloatValue(context, key); } public float getPreferenceFloatValue(String key, float f) { return SipConfigManager.getPreferenceFloatValue(context, key, f); } public void setPreferenceStringValue(String key, String newValue) { SipConfigManager.setPreferenceStringValue(context, key, newValue); } public void setPreferenceBooleanValue(String key, boolean newValue) { SipConfigManager.setPreferenceBooleanValue(context, key, newValue); } public void setPreferenceFloatValue(String key, float newValue) { SipConfigManager.setPreferenceFloatValue(context, key, newValue); } // Network part // Check for wifi private boolean isValidWifiConnectionFor(NetworkInfo ni, String suffix) { boolean valid_for_wifi = getPreferenceBooleanValue("use_wifi_" + suffix, true); // We consider ethernet as wifi if (valid_for_wifi && ni != null) { int type = ni.getType(); // Wifi connected if (ni.isConnected() && // 9 = ConnectivityManager.TYPE_ETHERNET (type == ConnectivityManager.TYPE_WIFI || type == 9)) { return true; } } return false; } // Check for acceptable mobile data network connection private boolean isValidMobileConnectionFor(NetworkInfo ni, String suffix) { boolean valid_for_3g = getPreferenceBooleanValue("use_3g_" + suffix, false); boolean valid_for_edge = getPreferenceBooleanValue("use_edge_" + suffix, false); boolean valid_for_gprs = getPreferenceBooleanValue("use_gprs_" + suffix, false); boolean valid_for_roaming = getPreferenceBooleanValue("use_roaming_" + suffix, true); if(!valid_for_roaming && ni != null) { if(ni.isRoaming()) { return false; } } if ((valid_for_3g || valid_for_edge || valid_for_gprs) && ni != null) { int type = ni.getType(); // Any mobile network connected if (ni.isConnected() && // Type 3,4,5 are other mobile data ways (type == ConnectivityManager.TYPE_MOBILE || (type <= 5 && type >= 3))) { int subType = ni.getSubtype(); // 3G (or better) if (valid_for_3g && subType >= TelephonyManager.NETWORK_TYPE_UMTS) { return true; } // GPRS (or unknown) if (valid_for_gprs && (subType == TelephonyManager.NETWORK_TYPE_GPRS || subType == TelephonyManager.NETWORK_TYPE_UNKNOWN)) { return true; } // EDGE if (valid_for_edge && subType == TelephonyManager.NETWORK_TYPE_EDGE) { return true; } } } return false; } // Check for other (wimax for example) private boolean isValidOtherConnectionFor(NetworkInfo ni, String suffix) { boolean valid_for_other = getPreferenceBooleanValue("use_other_" + suffix, true); // boolean valid_for_other = true; if (valid_for_other && ni != null && ni.getType() != ConnectivityManager.TYPE_MOBILE && ni.getType() != ConnectivityManager.TYPE_WIFI) { return ni.isConnected(); } return false; } private boolean isValidAnywayConnectionFor(NetworkInfo ni, String suffix) { return getPreferenceBooleanValue("use_anyway_" + suffix, false); } // Generic function for both incoming and outgoing private boolean isValidConnectionFor(NetworkInfo ni, String suffix) { if (isValidWifiConnectionFor(ni, suffix)) { Log.d(THIS_FILE, "We are valid for WIFI"); return true; } if (isValidMobileConnectionFor(ni, suffix)) { Log.d(THIS_FILE, "We are valid for MOBILE"); return true; } if (isValidOtherConnectionFor(ni, suffix)) { Log.d(THIS_FILE, "We are valid for OTHER"); return true; } if (isValidAnywayConnectionFor(ni, suffix)) { Log.d(THIS_FILE, "We are valid ANYWAY"); return true; } return false; } /** * Say whether current connection is valid for outgoing calls * * @return true if connection is valid */ public boolean isValidConnectionForOutgoing() { return isValidConnectionForOutgoing(true); } /** * Say whether current connection is valid for outgoing calls * @param considerQuit pass true if we should consider app quitted as a reason to not consider available for outgoing * @return true if connection is valid */ public boolean isValidConnectionForOutgoing(boolean considerQuit) { if(considerQuit) { if (getPreferenceBooleanValue(PreferencesWrapper.HAS_BEEN_QUIT, false)) { // Don't go further, we have been explicitly stopped return false; } } NetworkInfo ni = connectivityManager.getActiveNetworkInfo(); return isValidConnectionFor(ni, "out"); } /** * Say whether current connection is valid for incoming calls * * @return true if connection is valid */ public boolean isValidConnectionForIncoming() { NetworkInfo ni = connectivityManager.getActiveNetworkInfo(); return isValidConnectionFor(ni, "in"); } public ArrayList<String> getAllIncomingNetworks() { ArrayList<String> incomingNetworks = new ArrayList<String>(); String[] availableNetworks = { "3g", "edge", "gprs", "wifi", "other" }; for (String network : availableNetworks) { if (getPreferenceBooleanValue("use_" + network + "_in")) { incomingNetworks.add(network); } } return incomingNetworks; } public int getLogLevel() { int prefsValue = SipConfigManager.getPreferenceIntegerValue(context, SipConfigManager.LOG_LEVEL, 1); if (prefsValue <= 6 && prefsValue >= 1) { return prefsValue; } return 1; } /** * Get the audio codec quality setting * * @return the audio quality */ public int getInCallMode() { String mode = getPreferenceStringValue(SipConfigManager.SIP_AUDIO_MODE); try { return Integer.parseInt(mode); } catch (NumberFormatException e) { Log.e(THIS_FILE, "In call mode " + mode + " not well formated"); } return AudioManager.MODE_NORMAL; } /** * Get current clock rate * @param mediaManager * * @return clock rate in Hz */ public long getClockRate(MediaManager mediaManager) { String clockRate = getPreferenceStringValue(SipConfigManager.SND_CLOCK_RATE); long defaultRate = 16000; try { long rate = Integer.parseInt(clockRate); if(rate == 0) { return mediaManager.getBestSampleRate(defaultRate); } return rate; } catch (NumberFormatException e) { Log.e(THIS_FILE, "Clock rate " + clockRate + " not well formated"); } return defaultRate; } public boolean useRoutingApi() { return getPreferenceBooleanValue(SipConfigManager.USE_ROUTING_API); } public boolean useModeApi() { return getPreferenceBooleanValue(SipConfigManager.USE_MODE_API); } public boolean generateForSetCall() { return getPreferenceBooleanValue(SipConfigManager.SET_AUDIO_GENERATE_TONE); } public float getInitialVolumeLevel() { return (float) (getPreferenceFloatValue(SipConfigManager.SND_STREAM_LEVEL, 8.0f) / 10.0f); } /** * Get sip ringtone * * @return string uri */ public String getRingtone() { String ringtone = getPreferenceStringValue(SipConfigManager.RINGTONE, Settings.System.DEFAULT_RINGTONE_URI.toString()); if (TextUtils.isEmpty(ringtone)) { ringtone = Settings.System.DEFAULT_RINGTONE_URI.toString(); } return ringtone; } // / ---- PURE SIP SETTINGS ----- public boolean isTCPEnabled() { return getPreferenceBooleanValue(SipConfigManager.ENABLE_TCP); } public boolean isUDPEnabled() { return getPreferenceBooleanValue(SipConfigManager.ENABLE_UDP); } public boolean isTLSEnabled() { return getPreferenceBooleanValue(SipConfigManager.ENABLE_TLS); } public boolean useIPv6() { return getPreferenceBooleanValue(SipConfigManager.USE_IPV6); } private int getPrefPort(String key) { int port = getPreferenceIntegerValue(key); if (isValidPort(port)) { return port; } return Integer.parseInt(PreferencesWrapper.STRING_PREFS.get(key)); } public int getUDPTransportPort() { return getPrefPort(SipConfigManager.UDP_TRANSPORT_PORT); } public int getTCPTransportPort() { return getPrefPort(SipConfigManager.TCP_TRANSPORT_PORT); } public int getTLSTransportPort() { return getPrefPort(SipConfigManager.TLS_TRANSPORT_PORT); } private int getKeepAliveInterval(String wifi_key, String mobile_key) { NetworkInfo ni = connectivityManager.getActiveNetworkInfo(); if (ni != null && ni.getType() == ConnectivityManager.TYPE_WIFI) { return getPreferenceIntegerValue(wifi_key); } return getPreferenceIntegerValue(mobile_key); } /** * Retrieve UDP keep alive interval for the current connection * * @return KA Interval in second */ public int getUdpKeepAliveInterval() { return getKeepAliveInterval(SipConfigManager.KEEP_ALIVE_INTERVAL_WIFI, SipConfigManager.KEEP_ALIVE_INTERVAL_MOBILE); } /** * Retrieve TCP keep alive interval for the current connection * * @return KA Interval in second */ public int getTcpKeepAliveInterval() { return getKeepAliveInterval(SipConfigManager.TCP_KEEP_ALIVE_INTERVAL_WIFI, SipConfigManager.TCP_KEEP_ALIVE_INTERVAL_MOBILE); } /** * Retrieve TLS keep alive interval for the current connection * * @return KA Interval in second */ public int getTlsKeepAliveInterval() { return getKeepAliveInterval(SipConfigManager.TLS_KEEP_ALIVE_INTERVAL_WIFI, SipConfigManager.TLS_KEEP_ALIVE_INTERVAL_MOBILE); } public int getRTPPort() { return getPrefPort(SipConfigManager.RTP_PORT); } public boolean enableDNSSRV() { return getPreferenceBooleanValue(SipConfigManager.ENABLE_DNS_SRV); } public int getTLSMethod() { return getPreferenceIntegerValue(SipConfigManager.TLS_METHOD); } public String getUserAgent(Context ctx) { String userAgent = getPreferenceStringValue(SipConfigManager.USER_AGENT); if (userAgent.equalsIgnoreCase(CustomDistribution.getUserAgent())) { // If that's the official -not custom- user agent, send the release, // the device and the api level PackageInfo pinfo = getCurrentPackageInfos(ctx); if (pinfo != null) { userAgent += "_" + android.os.Build.DEVICE + "-" + Compatibility.getApiLevel() + "/r" + pinfo.versionCode; } } return userAgent; } public final static PackageInfo getCurrentPackageInfos(Context ctx) { PackageInfo pinfo = null; try { pinfo = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), 0); } catch (NameNotFoundException e) { Log.e(THIS_FILE, "Impossible to find version of current package !!"); } return pinfo; } // Utils /** * Check TCP/UDP validity of a network port */ private boolean isValidPort(int port) { return (port >= 0 && port < 65535); } /** * Get a property from android property subsystem * * @param prop property to get * @return the value of the property command line or null if failed */ public String getSystemProp(String prop) { // String re1 = "^\\d+(\\.\\d+){3}$"; // String re2 = "^[0-9a-f]+(:[0-9a-f]*)+:[0-9a-f]+$"; try { String line; Process p = Runtime.getRuntime().exec("getprop " + prop); InputStream in = p.getInputStream(); InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr); while ((line = br.readLine()) != null) { return line; } } catch (Exception e) { // ignore resolutely } return null; } // Media part /** * Get auto close time after end of the call To avoid crash after hangup -- * android 1.5 only but even sometimes crash */ public int getAutoCloseTime() { return getPreferenceIntegerValue(SipConfigManager.SND_AUTO_CLOSE_TIME); } /** * Whether echo cancellation is enabled * * @return true if enabled */ public boolean hasEchoCancellation() { return getPreferenceBooleanValue(SipConfigManager.ECHO_CANCELLATION); } public long getEchoCancellationTail() { if (!hasEchoCancellation()) { return 0; } return getPreferenceIntegerValue(SipConfigManager.ECHO_CANCELLATION_TAIL); } /** * Get the audio codec quality setting * * @return the audio quality */ public long getMediaQuality() { String mediaQuality = getPreferenceStringValue(SipConfigManager.SND_MEDIA_QUALITY); // prefs.getString(SND_MEDIA_QUALITY, String.valueOf(defaultValue)); try { int prefsValue = Integer.parseInt(mediaQuality); if (prefsValue <= 10 && prefsValue >= 0) { return prefsValue; } } catch (NumberFormatException e) { Log.e(THIS_FILE, "Audio quality " + mediaQuality + " not well formated"); } return 4; } /** * Get whether turn is enabled * * @return 1 if enabled (pjstyle) */ public int getStunEnabled() { return getPreferenceBooleanValue(SipConfigManager.ENABLE_STUN) ? 1 : 0; } /** * Get turn server * * @return host:port or blank if not set */ public String getTurnServer() { return getPreferenceStringValue(SipConfigManager.TURN_SERVER); } /** * Setup codecs list Should be only done by the service that get infos from * the sip stack(s) * * @param codecs the list of codecs */ public void setCodecList(List<String> codecs) { if (codecs != null) { setPreferenceStringValue(PreferencesWrapper.CODECS_LIST, TextUtils.join(PreferencesWrapper.CODECS_SEPARATOR, codecs)); } } public void setVideoCodecList(List<String> codecs) { if (codecs != null) { setPreferenceStringValue(PreferencesWrapper.CODECS_VIDEO_LIST, TextUtils.join(PreferencesWrapper.CODECS_SEPARATOR, codecs)); } } public void setLibCapability(String cap, boolean canDo) { setPreferenceBooleanValue(PreferencesWrapper.BACKUP_PREFIX + cap, canDo); } // DTMF public boolean useSipInfoDtmf() { return (getPreferenceIntegerValue(SipConfigManager.DTMF_MODE) == SipConfigManager.DTMF_MODE_INFO); } public boolean forceDtmfInBand() { return (getPreferenceIntegerValue(SipConfigManager.DTMF_MODE) == SipConfigManager.DTMF_MODE_INBAND); } public boolean forceDtmfRTP() { return (getPreferenceIntegerValue(SipConfigManager.DTMF_MODE) == SipConfigManager.DTMF_MODE_RTP); } // Codecs /** * Get the codec priority * * @param codecName codec name formated in the pjsip format (the * corresponding pref is * codec_{{lower(codecName)}}_{{codecFreq}}) * @param defaultValue the default value if the pref is not found MUST be * casteable as Integer/short * @return the priority of the codec as defined in preferences */ public short getCodecPriority(String codecName, String type, String defaultValue) { String key = SipConfigManager.getCodecKey(codecName, type); if (key != null) { String val = getPreferenceStringValue(key, defaultValue); if (!TextUtils.isEmpty(val)) { try { return (short) Integer.parseInt(val); } catch (NumberFormatException e) { Log.e(THIS_FILE, "Impossible to parse " + val); } } } return (short) Integer.parseInt(defaultValue); } /** * Set the priority for the codec for a given bandwidth type * * @param codecName the name of the codec as announced by codec * @param type bandwidth type <br/> * For now, valid constants are : * {@link SipConfigManager#CODEC_NB} and * {@link SipConfigManager#CODEC_WB} * @param newValue Short value for preference as a string. */ public void setCodecPriority(String codecName, String type, String newValue) { String key = SipConfigManager.getCodecKey(codecName, type); if (key != null) { setPreferenceStringValue(key, newValue); } // TODO : else raise error } public static File getRecordsFolder(Context ctxt) { return PreferencesWrapper.getRecordsFolder(ctxt); } }