diff --git a/.gitmodules b/.gitmodules index 944c1c75a..cdfee6b31 100644 --- a/.gitmodules +++ b/.gitmodules @@ -46,7 +46,7 @@ url = git://git.linphone.org/belle-sip.git [submodule "submodules/externals/libxml2"] path = submodules/externals/libxml2 - url = git://git.gnome.org/libxml2.git + url = https://github.com/GNOME/libxml2.git ignore = dirty [submodule "submodules/externals/libupnp"] path = submodules/externals/libupnp diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 42bd8ad05..eb5f9c082 100755 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2,17 +2,13 @@ + android:versionCode="3995" + android:versionName="3.99.4"> - - - - @@ -266,24 +262,6 @@ - - - - diff --git a/res/layout/chat_imdn.xml b/res/layout/chat_imdn.xml index 26bb71254..21c5f59ae 100644 --- a/res/layout/chat_imdn.xml +++ b/res/layout/chat_imdn.xml @@ -26,12 +26,22 @@ android:layout_weight="0.2" android:padding="18dp"/> + + + @@ -115,6 +125,35 @@ android:layout_height="wrap_content" android:orientation="vertical"/> + + + + + + + + + + + android:text="@string/error"/> + + + + + + + + + \ No newline at end of file diff --git a/res/menu/chat_bubble_menu_with_resend.xml b/res/menu/chat_bubble_menu_with_resend.xml new file mode 100644 index 000000000..4ca08409b --- /dev/null +++ b/res/menu/chat_bubble_menu_with_resend.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/res/mipmap-anydpi-v26/ic_launcher.xml b/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 4ae7d1237..000000000 --- a/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/res/mipmap-anydpi-v26/ic_launcher_round.xml b/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index 4ae7d1237..000000000 --- a/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/res/mipmap-hdpi/ic_launcher.png b/res/mipmap-hdpi/ic_launcher.png index d8b1b9db8..af7722189 100644 Binary files a/res/mipmap-hdpi/ic_launcher.png and b/res/mipmap-hdpi/ic_launcher.png differ diff --git a/res/mipmap-hdpi/ic_launcher_background.png b/res/mipmap-hdpi/ic_launcher_background.png deleted file mode 100644 index d05b2f383..000000000 Binary files a/res/mipmap-hdpi/ic_launcher_background.png and /dev/null differ diff --git a/res/mipmap-hdpi/ic_launcher_foreground.png b/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index 6940bb70b..000000000 Binary files a/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/res/mipmap-hdpi/ic_launcher_round.png b/res/mipmap-hdpi/ic_launcher_round.png index b1736e316..a0dc2e060 100644 Binary files a/res/mipmap-hdpi/ic_launcher_round.png and b/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/res/mipmap-mdpi/ic_launcher.png b/res/mipmap-mdpi/ic_launcher.png index 4d25b6db5..4bf908cd7 100644 Binary files a/res/mipmap-mdpi/ic_launcher.png and b/res/mipmap-mdpi/ic_launcher.png differ diff --git a/res/mipmap-mdpi/ic_launcher_background.png b/res/mipmap-mdpi/ic_launcher_background.png deleted file mode 100644 index a976fd84d..000000000 Binary files a/res/mipmap-mdpi/ic_launcher_background.png and /dev/null differ diff --git a/res/mipmap-mdpi/ic_launcher_foreground.png b/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index c1087a7a7..000000000 Binary files a/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/res/mipmap-mdpi/ic_launcher_round.png b/res/mipmap-mdpi/ic_launcher_round.png index c89275fef..6822c177e 100644 Binary files a/res/mipmap-mdpi/ic_launcher_round.png and b/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/res/mipmap-xhdpi/ic_launcher.png b/res/mipmap-xhdpi/ic_launcher.png index 7c0c8055c..7e717e4d6 100644 Binary files a/res/mipmap-xhdpi/ic_launcher.png and b/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/res/mipmap-xhdpi/ic_launcher_background.png b/res/mipmap-xhdpi/ic_launcher_background.png deleted file mode 100644 index 98c831de5..000000000 Binary files a/res/mipmap-xhdpi/ic_launcher_background.png and /dev/null differ diff --git a/res/mipmap-xhdpi/ic_launcher_foreground.png b/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 8f722f9bc..000000000 Binary files a/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/res/mipmap-xhdpi/ic_launcher_round.png b/res/mipmap-xhdpi/ic_launcher_round.png index d67ff226e..af7199df7 100644 Binary files a/res/mipmap-xhdpi/ic_launcher_round.png and b/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/res/mipmap-xxhdpi/ic_launcher.png b/res/mipmap-xxhdpi/ic_launcher.png index b364380f0..78b30bafa 100644 Binary files a/res/mipmap-xxhdpi/ic_launcher.png and b/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/res/mipmap-xxhdpi/ic_launcher_background.png b/res/mipmap-xxhdpi/ic_launcher_background.png deleted file mode 100644 index baa7aa0ba..000000000 Binary files a/res/mipmap-xxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/res/mipmap-xxhdpi/ic_launcher_foreground.png b/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 1cb45a657..000000000 Binary files a/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/res/mipmap-xxhdpi/ic_launcher_round.png b/res/mipmap-xxhdpi/ic_launcher_round.png index 16045ffa1..62992b974 100644 Binary files a/res/mipmap-xxhdpi/ic_launcher_round.png and b/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/res/mipmap-xxxhdpi/ic_launcher.png b/res/mipmap-xxxhdpi/ic_launcher.png index 3f468bcb8..05c036329 100644 Binary files a/res/mipmap-xxxhdpi/ic_launcher.png and b/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/res/mipmap-xxxhdpi/ic_launcher_background.png b/res/mipmap-xxxhdpi/ic_launcher_background.png deleted file mode 100644 index c3a84f539..000000000 Binary files a/res/mipmap-xxxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 16fc7e6f0..000000000 Binary files a/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/res/mipmap-xxxhdpi/ic_launcher_round.png b/res/mipmap-xxxhdpi/ic_launcher_round.png index 54b7defbf..e5f1eef82 100644 Binary files a/res/mipmap-xxxhdpi/ic_launcher_round.png and b/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/res/raw/cpim_grammar b/res/raw/cpim_grammar index 6f8b36d95..c89e4f87f 100644 Binary files a/res/raw/cpim_grammar and b/res/raw/cpim_grammar differ diff --git a/res/raw/linphonerc_default b/res/raw/linphonerc_default index e05f6d691..3858ad0de 100644 --- a/res/raw/linphonerc_default +++ b/res/raw/linphonerc_default @@ -1,5 +1,3 @@ - - [sip] contact="Linphone Android" use_info=0 diff --git a/res/raw/linphonerc_factory b/res/raw/linphonerc_factory index 4f629029e..92ee60ca2 100644 --- a/res/raw/linphonerc_factory +++ b/res/raw/linphonerc_factory @@ -40,10 +40,12 @@ ec_calibrator_cool_tones=1 max_calls=10 history_max_size=100 enable_basic_to_client_group_chat_room_migration=0 +enable_simple_group_chat_message_state=0 +aggregate_imdn=1 [app] activation_code_length=4 -prefer_basic_chat_room=0 +prefer_basic_chat_room=1 [in-app-purchase] server_url=https://subscribe.linphone.org:444/inapp.php diff --git a/res/values/non_localizable_strings.xml b/res/values/non_localizable_strings.xml index ae91b9e03..e816c1744 100644 --- a/res/values/non_localizable_strings.xml +++ b/res/values/non_localizable_strings.xml @@ -58,6 +58,7 @@ pref_wizard_key pref_activated_key pref_debug_key + pref_java_debug_key first_launch_succeeded_once_key pref_wifi_only_key @@ -80,6 +81,7 @@ pref_escape_plus_key pref_friendlist_subscribe_key pref_link_account_key + pref_proxy_push_notif_key pref_echo_cancellation_key pref_autostart_key Outbound proxy diff --git a/res/values/strings.xml b/res/values/strings.xml index 5a422e2f7..3e9b0446f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -196,10 +196,10 @@ Sent Resend An error occurs when opening this file. - Infos + Info Admin Name your group - Infos + Info Admin Participants Leave the group @@ -221,6 +221,7 @@ Leave Do you want to delete and leave the selected conversations? + Delivery status Registered @@ -331,6 +332,7 @@ Change password Use as default Password changed + Allow push notification SIP Accounts @@ -427,6 +429,7 @@ Advanced Debug Debug + Use Java logger Friendlist subscribe Background mode Enable Animations @@ -521,5 +524,5 @@ Linphone Service Linphone Notification Group chat room subject - Group chat room infos + Group chat room info diff --git a/res/xml/account_preferences.xml b/res/xml/account_preferences.xml index 48322744c..6467d2efc 100644 --- a/res/xml/account_preferences.xml +++ b/res/xml/account_preferences.xml @@ -103,6 +103,11 @@ android:key="@string/pref_link_account_key" android:persistent="false"/> + + + + mUnreadChatsPerRoom; @@ -502,13 +499,6 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou String getDisplayedName(); } - - public interface NewOutgoingCallUiListener { - public void onWrongDestinationAddress(); - public void onCannotGetCallParameters(); - public void onAlreadyInCall(); - } - public void enableCamera(Call call, boolean enable) { if (call != null) { call.enableCamera(enable); @@ -538,17 +528,18 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou if (!mLc.tunnelAvailable()) return; - /*NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); - mLc.tunnelCleanServers(); + NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); + Tunnel tunnel = mLc.getTunnel(); + tunnel.cleanServers(); TunnelConfig config = mPrefs.getTunnelConfig(); if (config.getHost() != null) { - mLc.tunnelAddServer(config); + tunnel.addServer(config); manageTunnelServer(info); - }*/ // TODO FIXME + } } private boolean isTunnelNeeded(NetworkInfo info) { - /*if (info == null) { + if (info == null) { Log.i("No connectivity: tunnel should be disabled"); return false; } @@ -563,7 +554,7 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou && getString(R.string.tunnel_mode_entry_value_3G_only).equals(pref)) { Log.i("need tunnel: 'no wifi' connection"); return true; - }*/ // TODO FIXME + } return false; } @@ -571,19 +562,20 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou private void manageTunnelServer(NetworkInfo info) { if (mLc == null) return; if (!mLc.tunnelAvailable()) return; + Tunnel tunnel = mLc.getTunnel(); - /*Log.i("Managing tunnel"); + Log.i("Managing tunnel"); if (isTunnelNeeded(info)) { Log.i("Tunnel need to be activated"); - mLc.tunnelSetMode(Core.TunnelMode.enable); + tunnel.setMode(Tunnel.Mode.Enable); } else { Log.i("Tunnel should not be used"); String pref = mPrefs.getTunnelMode(); - mLc.tunnelSetMode(Core.TunnelMode.disable); + tunnel.setMode(Tunnel.Mode.Disable); if (getString(R.string.tunnel_mode_entry_value_auto).equals(pref)) { - mLc.tunnelSetMode(Core.TunnelMode.auto); + tunnel.setMode(Tunnel.Mode.Auto); } - }*/ // TODO FIXME + } } public synchronized final void destroyCore() { @@ -691,10 +683,18 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou Log.i("[Push Notification] Assuming GCM jar is not provided."); } }else if (getString(R.string.push_type).equals("firebase")){ - final String refreshedToken = com.google.firebase.iid.FirebaseInstanceId.getInstance().getToken(); - if (refreshedToken != null) { - Log.i("[Push Notification] current token is: " + refreshedToken); - LinphonePreferences.instance().setPushNotificationRegistrationID(refreshedToken); + try{ + Class firebaseClass = Class.forName("com.google.firebase.iid.FirebaseInstanceId"); + Object firebaseInstance = firebaseClass.getMethod("getInstance").invoke(null); + final String refreshedToken = (String)firebaseClass.getMethod("getToken").invoke(firebaseInstance); + + //final String refreshedToken = com.google.firebase.iid.FirebaseInstanceId.getInstance().getToken(); + if (refreshedToken != null) { + Log.i("[Push Notification] current token is: " + refreshedToken); + LinphonePreferences.instance().setPushNotificationRegistrationID(refreshedToken); + } + }catch(Exception e){ + Log.i("[Push Notification] firebase not available."); } } } @@ -1111,9 +1111,9 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou } else { String subject = cr.getSubject(); if (contact != null) { - LinphoneService.instance().displayGroupChatMessageNotification(subject, cr.getPeerAddress().asString(), contact.getFullName(), contact.getThumbnailUri(), textMessage); + LinphoneService.instance().displayGroupChatMessageNotification(subject, cr.getPeerAddress().asStringUriOnly(), contact.getFullName(), contact.getThumbnailUri(), textMessage); } else { - LinphoneService.instance().displayGroupChatMessageNotification(subject, cr.getPeerAddress().asString(), from.getUsername(), null, textMessage); + LinphoneService.instance().displayGroupChatMessageNotification(subject, cr.getPeerAddress().asStringUriOnly(), from.getUsername(), null, textMessage); } } } @@ -1121,6 +1121,7 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou public void setCurrentChatRoomAddress(Address address) { mCurrentChatRoomAddress = address; + LinphoneService.instance().setCurrentlyDisplayedChatRoom(address != null ? address.asStringUriOnly() : null); } @Override @@ -1624,6 +1625,12 @@ public class LinphoneManager implements CoreListener, SensorEventListener, Accou Log.d("Notify received for event "+eventName); if (content!=null) Log.d("with content "+content.getType()+"/"+content.getSubtype()+" data:"+content.getStringBuffer()); } + + @Override + public void onSubscribeReceived(Core lc, Event lev, String subscribeEvent, Content body) { + + } + @Override public void onPublishStateChanged(Core lc, Event ev, PublishState state) { Log.d("Publish state changed to " + state + " for event name " + ev.getName()); diff --git a/src/android/org/linphone/LinphonePreferences.java b/src/android/org/linphone/LinphonePreferences.java index 54038b447..d36a974e7 100644 --- a/src/android/org/linphone/LinphonePreferences.java +++ b/src/android/org/linphone/LinphonePreferences.java @@ -38,6 +38,8 @@ import org.linphone.core.NatPolicy; import org.linphone.core.ProxyConfig; import org.linphone.core.Config; //import org.linphone.core.TunnelConfig; +import org.linphone.core.Tunnel; +import org.linphone.core.TunnelConfig; import org.linphone.core.VideoActivationPolicy; import org.linphone.mediastream.Log; import org.linphone.purchase.Purchasable; @@ -395,6 +397,7 @@ public class LinphonePreferences { int port = 0; if (transport.equals(getString(R.string.pref_transport_udp_key))) { proxyAddr.setTransport(TransportType.Udp); + } else if (transport.equals(getString(R.string.pref_transport_tcp_key))) { proxyAddr.setTransport(TransportType.Tcp); } else if (transport.equals(getString(R.string.pref_transport_tls_key))) { @@ -724,6 +727,20 @@ public class LinphonePreferences { prxCfg.done(); } + public void enablePushNotifForProxy(int n, boolean enable) { + ProxyConfig prxCfg = getProxyConfig(n); + prxCfg.edit(); + prxCfg.setPushNotificationAllowed(enable); + prxCfg.done(); + + setPushNotificationEnabled(isPushNotificationEnabled()); + } + + public boolean isPushNotifEnabledForProxy(int n) { + ProxyConfig prxCfg = getProxyConfig(n); + return prxCfg.isPushNotificationAllowed(); + } + public boolean isFriendlistsubscriptionEnabled() { return getConfig().getBool("app", "friendlist_subscription_enabled", false); } @@ -1142,13 +1159,22 @@ public class LinphonePreferences { String appId = getString(R.string.push_sender_id); if (regId != null && lc.getProxyConfigList().length > 0) { for (ProxyConfig lpc : lc.getProxyConfigList()) { - String contactInfos = "app-id=" + appId + ";pn-type=" + getString(R.string.push_type) + ";pn-tok=" + regId + ";pn-silent=1"; - String prevContactParams = lpc.getContactParameters(); - if (prevContactParams == null || prevContactParams.compareTo(contactInfos)!=0) { + if (!lpc.isPushNotificationAllowed()) { lpc.edit(); - lpc.setContactUriParameters(contactInfos); + lpc.setContactUriParameters(null); lpc.done(); - Log.d("Push notif infos added to proxy config " + lpc.getIdentityAddress().asStringUriOnly()); + if (lpc.getIdentityAddress() != null) + Log.d("Push notif infos removed from proxy config " + lpc.getIdentityAddress().asStringUriOnly()); + } else { + String contactInfos = "app-id=" + appId + ";pn-type=" + getString(R.string.push_type) + ";pn-tok=" + regId + ";pn-silent=1"; + String prevContactParams = lpc.getContactParameters(); + if (prevContactParams == null || prevContactParams.compareTo(contactInfos) != 0) { + lpc.edit(); + lpc.setContactUriParameters(contactInfos); + lpc.done(); + if (lpc.getIdentityAddress() != null) + Log.d("Push notif infos added to proxy config " + lpc.getIdentityAddress().asStringUriOnly()); + } } } lc.refreshRegisters(); @@ -1159,7 +1185,8 @@ public class LinphonePreferences { lpc.edit(); lpc.setContactUriParameters(null); lpc.done(); - Log.d("Push notif infos removed from proxy config " + lpc.getIdentityAddress().asStringUriOnly()); + if (lpc.getIdentityAddress() != null) + Log.d("Push notif infos removed from proxy config " + lpc.getIdentityAddress().asStringUriOnly()); } lc.refreshRegisters(); } @@ -1192,14 +1219,22 @@ public class LinphonePreferences { // Advanced settings public void setDebugEnabled(boolean enabled) { getConfig().setBool("app", "debug", enabled); - Factory.instance().enableLogCollection(LogCollectionState.Enabled); - Factory.instance().setDebugMode(enabled, getString(R.string.app_name)); + LinphoneUtils.initLoggingService(enabled, mContext.getString(R.string.app_name)); } public boolean isDebugEnabled() { return getConfig().getBool("app", "debug", false); } + public void setJavaLogger(boolean enabled) { + getConfig().setBool("app", "java_logger", enabled); + LinphoneUtils.initLoggingService(isDebugEnabled(), mContext.getString(R.string.app_name)); + } + + public boolean useJavaLogger() { + return getConfig().getBool("app", "java_logger", false); + } + public void setBackgroundModeEnabled(boolean enabled) { getConfig().setBool("app", "background_mode", enabled); } @@ -1257,12 +1292,13 @@ public class LinphonePreferences { // End of advanced settings // Tunnel settings - /*private TunnelConfig tunnelConfig = null; + private TunnelConfig tunnelConfig = null; public TunnelConfig getTunnelConfig() { if(getLc().tunnelAvailable()) { - if(tunnelConfig == null) { - TunnelConfig servers[] = getLc().tunnelGetServers(); + Tunnel tunnel = getLc().getTunnel(); + if (tunnelConfig == null) { + TunnelConfig servers[] = tunnel.getServers(); if(servers.length > 0) { tunnelConfig = servers[0]; } else { @@ -1316,7 +1352,7 @@ public class LinphonePreferences { public void setTunnelMode(String mode) { getConfig().setString("app", "tunnel", mode); LinphoneManager.getInstance().initTunnelFromConf(); - }*/ + } // End of tunnel settings public boolean isProvisioningLoginViewEnabled() { diff --git a/src/android/org/linphone/LinphoneService.java b/src/android/org/linphone/LinphoneService.java index d1e1f9dce..3f0a4bdaa 100644 --- a/src/android/org/linphone/LinphoneService.java +++ b/src/android/org/linphone/LinphoneService.java @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import org.linphone.activities.LinphoneActivity; import org.linphone.compatibility.Compatibility; @@ -32,6 +34,9 @@ import org.linphone.core.Call; import org.linphone.core.Call.State; import org.linphone.core.Core; import org.linphone.core.GlobalState; +import org.linphone.core.LogLevel; +import org.linphone.core.LoggingService; +import org.linphone.core.LoggingServiceListener; import org.linphone.core.RegistrationState; import org.linphone.core.Factory; import org.linphone.core.LogCollectionState; @@ -64,6 +69,7 @@ import android.os.IBinder; import android.os.SystemClock; import android.provider.ContactsContract; import android.provider.MediaStore; +import android.util.ArrayMap; import android.view.WindowManager; /** @@ -89,7 +95,6 @@ public final class LinphoneService extends Service { private final static int NOTIF_ID=1; private final static int INCALL_NOTIF_ID=2; - private final static int MESSAGE_NOTIF_ID=3; private final static int CUSTOM_NOTIF_ID=4; private final static int MISSED_NOTIF_ID=5; private final static int SAS_NOTIF_ID=6; @@ -115,10 +120,8 @@ public final class LinphoneService extends Service { private Notification mNotif; private Notification mIncallNotif; - private Notification mMsgNotif; private Notification mCustomNotif; private Notification mSasNotif; - private int mMsgNotifCount; private PendingIntent mNotifContentIntent; private String mNotificationTitle; private boolean mDisableRegistrationStatus; @@ -128,7 +131,27 @@ public final class LinphoneService extends Service { private LinphoneOverlay mOverlay; private Application.ActivityLifecycleCallbacks activityCallbacks; + private class Notified { + int notificationId; + int numberOfUnreadMessage; + } + private HashMap mChatNotifMap; + private int mLastNotificationId; + + public void setCurrentlyDisplayedChatRoom(String address) { + if (address != null) { + resetMessageNotifCount(address); + } + } + + private void resetMessageNotifCount(String address) { + Notified notif = mChatNotifMap.get(address); + if (notif != null) { + notif.numberOfUnreadMessage = 0; + mNM.cancel(notif.notificationId); + } + } /*Believe me or not, but knowing the application visibility state on Android is a nightmare. After two days of hard work I ended with the following class, that does the job more or less reliabily. @@ -241,6 +264,9 @@ public final class LinphoneService extends Service { if (LinphoneManager.isInstanciated()) LinphoneManager.getInstance().subscribeFriendList(false); } + if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) { + LinphoneManager.getLcIfManagerNotDestroyedOrNull().enterBackground(); + } } protected void onForegroundMode() { @@ -249,6 +275,9 @@ public final class LinphoneService extends Service { if (LinphoneManager.isInstanciated()) LinphoneManager.getInstance().subscribeFriendList(true); } + if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) { + LinphoneManager.getLcIfManagerNotDestroyedOrNull().enterForeground(); + } } private void setupActivityMonitor(){ @@ -256,10 +285,6 @@ public final class LinphoneService extends Service { getApplication().registerActivityLifecycleCallbacks(activityCallbacks = new ActivityMonitor()); } - public void resetMessageNotifCount() { - mMsgNotifCount = 0; - } - public boolean displayServiceNotification() { return LinphonePreferences.instance().getServiceNotificationVisibility(); } @@ -289,6 +314,8 @@ public final class LinphoneService extends Service { @Override public void onCreate() { super.onCreate(); + mLastNotificationId = 8; // To not interfere with other notifs ids + mChatNotifMap = new HashMap(); setupActivityMonitor(); // In case restart after a crash. Main in LinphoneActivity @@ -298,8 +325,7 @@ public final class LinphoneService extends Service { LinphonePreferences.instance().setContext(getBaseContext()); Factory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath()); boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled(); - Factory.instance().enableLogCollection(LogCollectionState.Enabled); - Factory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name)); + LinphoneUtils.initLoggingService(isDebugEnabled, getString(R.string.app_name)); // Dump some debugging information to the logs Log.i(START_LINPHONE_LOGS); @@ -582,11 +608,6 @@ public final class LinphoneService extends Service { notifyWrapper(CUSTOM_NOTIF_ID, mCustomNotif); } - public void removeCustomNotification() { - mNM.cancel(CUSTOM_NOTIF_ID); - resetIntentLaunchedOnNotificationClick(); - } - public void displayGroupChatMessageNotification(String subject, String conferenceAddress, String fromName, Uri fromPictureUri, String message) { Intent notifIntent = new Intent(this, LinphoneActivity.class); notifIntent.putExtra("GoToChat", true); @@ -594,10 +615,15 @@ public final class LinphoneService extends Service { PendingIntent notifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT); - if (mMsgNotif == null) { - mMsgNotifCount = 1; + Notified notif = mChatNotifMap.get(conferenceAddress); + if (notif != null) { + notif.numberOfUnreadMessage += 1; } else { - mMsgNotifCount++; + notif = new Notified(); + notif.numberOfUnreadMessage = 1; + notif.notificationId = mLastNotificationId; + mLastNotificationId += 1; + mChatNotifMap.put(conferenceAddress, notif); } Bitmap bm = null; @@ -610,10 +636,10 @@ public final class LinphoneService extends Service { } else { bm = BitmapFactory.decodeResource(getResources(), R.drawable.topbar_avatar); } - mMsgNotif = Compatibility.createMessageNotification(getApplicationContext(), mMsgNotifCount, subject, + Notification notification = Compatibility.createMessageNotification(getApplicationContext(), notif.numberOfUnreadMessage, subject, getString(R.string.group_chat_notif).replace("%1", fromName).replace("%2", message), bm, notifContentIntent); - notifyWrapper(MESSAGE_NOTIF_ID, mMsgNotif); + notifyWrapper(notif.notificationId, notification); } public void displayMessageNotification(String fromSipUri, String fromName, Uri fromPictureUri, String message) { @@ -627,10 +653,15 @@ public final class LinphoneService extends Service { fromName = fromSipUri; } - if (mMsgNotif == null) { - mMsgNotifCount = 1; + Notified notif = mChatNotifMap.get(fromSipUri); + if (notif != null) { + notif.numberOfUnreadMessage += 1; } else { - mMsgNotifCount++; + notif = new Notified(); + notif.numberOfUnreadMessage = 1; + notif.notificationId = mLastNotificationId; + mLastNotificationId += 1; + mChatNotifMap.put(fromSipUri, notif); } Bitmap bm = null; @@ -643,9 +674,9 @@ public final class LinphoneService extends Service { } else { bm = BitmapFactory.decodeResource(getResources(), R.drawable.topbar_avatar); } - mMsgNotif = Compatibility.createMessageNotification(getApplicationContext(), mMsgNotifCount, fromName, message, bm, notifContentIntent); + Notification notification = Compatibility.createMessageNotification(getApplicationContext(), notif.numberOfUnreadMessage, fromName, message, bm, notifContentIntent); - notifyWrapper(MESSAGE_NOTIF_ID, mMsgNotif); + notifyWrapper(notif.notificationId, notification); } public void displayInappNotification(String message) { @@ -658,11 +689,6 @@ public final class LinphoneService extends Service { notifyWrapper(NOTIF_ID, mNotif); } - public void removeMessageNotification() { - mNM.cancel(MESSAGE_NOTIF_ID); - resetIntentLaunchedOnNotificationClick(); - } - public void displaySasNotification(String sas) { mSasNotif = Compatibility.createSimpleNotification(getApplicationContext(), getString(R.string.zrtp_notification_title), @@ -837,7 +863,10 @@ public final class LinphoneService extends Service { // Make sure our notification is gone. stopForegroundCompat(NOTIF_ID); mNM.cancel(INCALL_NOTIF_ID); - mNM.cancel(MESSAGE_NOTIF_ID); + for (Notified notif : mChatNotifMap.values()) { + mNM.cancel(notif.notificationId); + } + // This will prevent the app from crashing if the service gets killed in background mode if (LinphoneActivity.isInstanciated()) { @@ -857,17 +886,6 @@ public final class LinphoneService extends Service { } catch (ClassNotFoundException e) { Log.e(e); } - resetIntentLaunchedOnNotificationClick(); - } - - private void resetIntentLaunchedOnNotificationClick() { - Intent notifIntent = new Intent(this, incomingReceivedActivity); - mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT); - - /*if (mNotif != null) { - mNotif.contentIntent = mNotifContentIntent; - } - notifyWrapper(NOTIF_ID, mNotif);*/ } protected void onIncomingReceived() { diff --git a/src/android/org/linphone/LinphoneUtils.java b/src/android/org/linphone/LinphoneUtils.java index 29de3012c..2391e4b7f 100644 --- a/src/android/org/linphone/LinphoneUtils.java +++ b/src/android/org/linphone/LinphoneUtils.java @@ -23,11 +23,9 @@ import android.app.Activity; import android.app.AlertDialog; import android.content.ContentResolver; import android.content.ContentUris; -import android.content.ContentValues; import android.content.Context; import android.content.CursorLoader; import android.content.Intent; -import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -41,38 +39,34 @@ import android.os.Looper; import android.os.ParcelFileDescriptor; import android.provider.DocumentsContract; import android.provider.MediaStore; -import android.provider.MediaStore.Images; import android.telephony.TelephonyManager; import android.text.Spanned; import android.text.TextUtils; -import android.util.TypedValue; import android.view.KeyEvent; import android.view.View; -import android.view.View.OnClickListener; import android.webkit.MimeTypeMap; -import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import org.linphone.compatibility.Compatibility; import org.linphone.contacts.ContactsManager; -import org.linphone.core.DialPlan; import org.linphone.core.AccountCreator; import org.linphone.core.Address; import org.linphone.core.Call; import org.linphone.core.Call.State; -import org.linphone.core.ChatMessage; import org.linphone.core.Core; import org.linphone.core.Factory; import org.linphone.core.Friend; import org.linphone.core.FriendList; +import org.linphone.core.LogCollectionState; +import org.linphone.core.LogLevel; +import org.linphone.core.LoggingService; +import org.linphone.core.LoggingServiceListener; import org.linphone.core.ProxyConfig; import org.linphone.mediastream.Log; import org.linphone.mediastream.video.capture.hwconf.Hacks; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -81,7 +75,6 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; @@ -94,8 +87,6 @@ import java.util.Date; import java.util.List; import java.util.Locale; import java.util.regex.Pattern; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; import static android.view.View.GONE; import static android.view.View.VISIBLE; @@ -111,6 +102,39 @@ public final class LinphoneUtils { } + public static void initLoggingService(boolean isDebugEnabled, String appName) { + if (!LinphonePreferences.instance().useJavaLogger()) { + Factory.instance().enableLogCollection(LogCollectionState.Enabled); + Factory.instance().setDebugMode(isDebugEnabled, appName); + } else { + Factory.instance().setDebugMode(isDebugEnabled, appName); + Factory.instance().enableLogCollection(LogCollectionState.EnabledWithoutPreviousLogHandler); + Factory.instance().getLoggingService().setListener(new LoggingServiceListener() { + @Override + public void onLogMessageWritten(LoggingService logService, String domain, LogLevel lev, String message) { + switch (lev) { + case Debug: + android.util.Log.d(domain, message); + break; + case Message: + android.util.Log.i(domain, message); + break; + case Warning: + android.util.Log.w(domain, message); + break; + case Error: + android.util.Log.e(domain, message); + break; + case Fatal: + default: + android.util.Log.wtf(domain, message); + break; + } + } + }); + } + } + public static void dispatchOnUIThread(Runnable r) { mHandler.post(r); } diff --git a/src/android/org/linphone/activities/LinphoneActivity.java b/src/android/org/linphone/activities/LinphoneActivity.java index dc388dcd7..b51a9faa7 100644 --- a/src/android/org/linphone/activities/LinphoneActivity.java +++ b/src/android/org/linphone/activities/LinphoneActivity.java @@ -730,8 +730,6 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick changeCurrentFragment(FragmentsAvailable.GROUP_CHAT, extras); } - LinphoneService.instance().resetMessageNotifCount(); - LinphoneService.instance().removeMessageNotification(); LinphoneManager.getInstance().updateUnreadCountForChatRoom(sipUri, 0); displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount()); } @@ -798,8 +796,6 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick } } - LinphoneService.instance().resetMessageNotifCount(); - LinphoneService.instance().removeMessageNotification(); LinphoneManager.getInstance().updateUnreadCountForChatRoom(sipUri, 0); displayMissedChats(LinphoneManager.getInstance().getUnreadMessageCount()); } @@ -1470,7 +1466,6 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick } Bundle extras = intent.getExtras(); if (extras != null && extras.getBoolean("GoToChat", false)) { - LinphoneService.instance().removeMessageNotification(); String sipUri = extras.getString("ChatContactSipUri"); doNotGoToCallActivity = true; displayChat(sipUri, null, null); @@ -1478,7 +1473,6 @@ public class LinphoneActivity extends LinphoneGenericActivity implements OnClick doNotGoToCallActivity = true; changeCurrentFragment(FragmentsAvailable.HISTORY_LIST, null); } else if (extras != null && extras.getBoolean("GoToInapp", false)) { - LinphoneService.instance().removeMessageNotification(); doNotGoToCallActivity = true; displayInapp(); } else if (extras != null && extras.getBoolean("Notification", false)) { diff --git a/src/android/org/linphone/call/CallActivity.java b/src/android/org/linphone/call/CallActivity.java index 54a52d6d1..41bbe4883 100644 --- a/src/android/org/linphone/call/CallActivity.java +++ b/src/android/org/linphone/call/CallActivity.java @@ -1634,7 +1634,7 @@ public class CallActivity extends LinphoneGenericActivity implements OnClickList String.valueOf((int) stats.getUploadBandwidth()) + " kbits/s"); if (isVideo) { formatText(edl, getString(R.string.call_stats_estimated_download), - String.valueOf(0/*(int) stats.getEstimatedDownloadBandwidth()*/) + " kbits/s"); + String.valueOf(stats.getEstimatedDownloadBandwidth()) + " kbits/s"); } formatText(ice, getString(R.string.call_stats_ice), stats.getIceState().toString()); diff --git a/src/android/org/linphone/chat/ChatCreationFragment.java b/src/android/org/linphone/chat/ChatCreationFragment.java index 3860d9d2d..fef50b4fe 100644 --- a/src/android/org/linphone/chat/ChatCreationFragment.java +++ b/src/android/org/linphone/chat/ChatCreationFragment.java @@ -41,11 +41,13 @@ import org.linphone.LinphoneManager; import org.linphone.LinphonePreferences; import org.linphone.contacts.ContactAddress; import org.linphone.contacts.ContactsManager; +import org.linphone.contacts.LinphoneNumberOrAddress; import org.linphone.contacts.SearchContactsListAdapter; import org.linphone.core.Address; import org.linphone.core.ChatRoom; import org.linphone.core.ChatRoomListenerStub; import org.linphone.core.Core; +import org.linphone.core.Factory; import org.linphone.core.ProxyConfig; import org.linphone.mediastream.Log; import org.linphone.ui.ContactSelectView; @@ -127,7 +129,9 @@ public class ChatCreationFragment extends Fragment implements View.OnClickListen mSearchField.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - + if (before > count) { + ContactsManager.getInstance().getMagicSearch().resetSearchCache(); + } } @Override @@ -247,12 +251,22 @@ public class ChatCreationFragment extends Fragment implements View.OnClickListen private int getIndexOfCa(ContactAddress ca, List caList) { for (int i = 0 ; i < caList.size() ; i++) { - if (caList.get(i).getAddressAsDisplayableString().compareTo(ca.getAddressAsDisplayableString()) == 0) - return i; + if (ca.getAddress() != null && ca.getAddress().getUsername() != null) { + if (caList.get(i).getAddressAsDisplayableString().compareTo(ca.getAddressAsDisplayableString()) == 0) + return i; + } else if (ca.getPhoneNumber() != null && caList.get(i).getPhoneNumber() !=null) { + if (ca.getPhoneNumber().compareTo(caList.get(i).getPhoneNumber()) == 0) + return i; + } } return -1; } + private void resetAndResearch() { + ContactsManager.getInstance().getMagicSearch().resetSearchCache(); + mSearchAdapter.searchContacts(mSearchField.getText().toString(), mContactsList); + } + private void addSelectedContactAddress(ContactAddress ca) { View viewContact = LayoutInflater.from(LinphoneActivity.instance()).inflate(R.layout.contact_selected, null); if (ca.getContact() != null) { @@ -321,6 +335,7 @@ public class ChatCreationFragment extends Fragment implements View.OnClickListen mLinphoneContactsButton.setEnabled(true); mLinphoneContactsSelected.setVisibility(View.INVISIBLE); updateList(); + resetAndResearch(); } else if (id == R.id.linphone_contacts) { mSearchAdapter.setOnlySipContact(true); mLinphoneContactsSelected.setVisibility(View.VISIBLE); @@ -328,6 +343,7 @@ public class ChatCreationFragment extends Fragment implements View.OnClickListen mAllContactsButton.setEnabled(mOnlyDisplayLinphoneContacts = true); mAllContactsSelected.setVisibility(View.INVISIBLE); updateList(); + resetAndResearch(); } else if (id == R.id.back) { if (LinphoneActivity.instance().isTablet()) { LinphoneActivity.instance().goToChatList(); @@ -346,7 +362,7 @@ public class ChatCreationFragment extends Fragment implements View.OnClickListen if (chatRoom == null) { ProxyConfig lpc = lc.getDefaultProxyConfig(); if (lpc != null && lpc.getConferenceFactoryUri() != null && !LinphonePreferences.instance().useBasicChatRoomFor1To1()) { - mChatRoom = lc.createClientGroupChatRoom(getString(R.string.dummy_group_chat_subject)); + mChatRoom = lc.createClientGroupChatRoom(getString(R.string.dummy_group_chat_subject), true); mChatRoom.addListener(mChatRoomCreationListener); mChatRoom.addParticipant(participant); } else { diff --git a/src/android/org/linphone/chat/ChatEventsAdapter.java b/src/android/org/linphone/chat/ChatEventsAdapter.java index 802f4c677..509d9b246 100644 --- a/src/android/org/linphone/chat/ChatEventsAdapter.java +++ b/src/android/org/linphone/chat/ChatEventsAdapter.java @@ -159,6 +159,11 @@ public class ChatEventsAdapter extends ListSelectionAdapter { return i; } + public void removeItem(int i) { + mHistory.remove(i); + notifyDataSetChanged(); + } + @Override public View getView(int i, View view, ViewGroup viewGroup) { ChatBubbleViewHolder holder; @@ -183,7 +188,6 @@ public class ChatEventsAdapter extends ListSelectionAdapter { holder.messageStatus.setVisibility(View.INVISIBLE); holder.messageSendingInProgress.setVisibility(View.GONE); holder.imdmLayout.setVisibility(View.INVISIBLE); - holder.imdmLabel.setOnClickListener(null); holder.contactPicture.setImageBitmap(ContactsManager.getInstance().getDefaultAvatarBitmap()); if (isEditionEnabled()) { @@ -240,24 +244,12 @@ public class ChatEventsAdapter extends ListSelectionAdapter { holder.imdmIcon.setImageResource(R.drawable.chat_error); holder.imdmLabel.setText(R.string.error); holder.imdmLabel.setTextColor(mContext.getResources().getColor(R.color.colorI)); - holder.imdmLabel.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - //TODO resend message - } - }); } else if (status == ChatMessage.State.FileTransferError) { holder.imdmLayout.setVisibility(View.VISIBLE); holder.imdmIcon.setImageResource(R.drawable.chat_error); holder.imdmLabel.setText(R.string.file_transfer_error); holder.imdmLabel.setTextColor(mContext.getResources().getColor(R.color.colorI)); } - holder.imdmLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - LinphoneActivity.instance().goToChatMessageImdnInfos(mFragment.getRemoteSipUri(), message.getMessageId()); - } - }); if (isEditionEnabled()) { layoutParams.addRule(RelativeLayout.LEFT_OF, holder.delete.getId()); diff --git a/src/android/org/linphone/chat/GroupChatFragment.java b/src/android/org/linphone/chat/GroupChatFragment.java index 25e7ae599..0a8297be1 100644 --- a/src/android/org/linphone/chat/GroupChatFragment.java +++ b/src/android/org/linphone/chat/GroupChatFragment.java @@ -22,6 +22,9 @@ package org.linphone.chat; import android.app.Activity; import android.app.Dialog; import android.app.Fragment; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -33,12 +36,16 @@ import android.os.Parcelable; import android.provider.MediaStore; import android.text.Editable; import android.text.TextWatcher; +import android.view.ContextMenu; import android.view.LayoutInflater; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; @@ -152,7 +159,7 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con String displayName = LinphoneUtils.getAddressDisplayName(a); c.setFullName(displayName); } - ContactAddress ca = new ContactAddress(c, a.asString(), c.isFriend(), p.isAdmin()); + ContactAddress ca = new ContactAddress(c, a.asString(), "", c.isFriend(), p.isAdmin()); participants.add(ca); } LinphoneActivity.instance().goToChatGroupInfos(mRemoteSipAddress.asString(), participants, mChatRoom.getSubject(), mChatRoom.getMe() != null ? mChatRoom.getMe().isAdmin() : false, false); @@ -206,6 +213,7 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con mRemoteComposing = view.findViewById(R.id.remote_composing); mChatEventsList = view.findViewById(R.id.chat_message_list); + registerForContextMenu(mChatEventsList); return view; } @@ -320,6 +328,70 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con } } + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; + EventLog event = (EventLog) mEventsAdapter.getItem(info.position); + if (event.getType() != EventLog.Type.ConferenceChatMessage) { + return; + } + + MenuInflater inflater = getActivity().getMenuInflater(); + ChatMessage message = event.getChatMessage(); + if (message.getState() == ChatMessage.State.NotDelivered) { + inflater.inflate(R.menu.chat_bubble_menu_with_resend, menu); + } else { + inflater.inflate(R.menu.chat_bubble_menu, menu); + } + + if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) { + // Do not show messages' IDMN state in 1 to 1 chat room as it is already visible in the lower corner of the bubble + menu.removeItem(R.id.imdn_infos); + } + if (!message.hasTextContent()) { + // Do not show copy text option if message doesn't have any text + menu.removeItem(R.id.copy_text); + } + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); + + EventLog event = (EventLog) mEventsAdapter.getItem(info.position); + if (event.getType() != EventLog.Type.ConferenceChatMessage) { + return super.onContextItemSelected(item); + } + + ChatMessage message = event.getChatMessage(); + String messageId = message.getMessageId(); + + switch(item.getItemId()) { + case R.id.resend: + mEventsAdapter.removeItem(info.position); + message.resend(); + return true; + case R.id.imdn_infos: + LinphoneActivity.instance().goToChatMessageImdnInfos(getRemoteSipUri(), messageId); + return true; + case R.id.copy_text: + if (message.hasTextContent()) { + ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("Message", message.getTextContent()); + clipboard.setPrimaryClip(clip); + } + return true; + case R.id.delete_message: + mChatRoom.deleteMessage(message); + mEventsAdapter.removeItem(info.position); + return true; + default: + return super.onContextItemSelected(item); + } + } + /** * Keyboard management */ @@ -418,14 +490,14 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con } getContactsForParticipants(); + + mRemoteComposing.setVisibility(View.INVISIBLE); } private void displayChatRoomHeader() { Core core = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); if (core == null || mChatRoom == null) return; - mRemoteComposing.setVisibility(View.INVISIBLE); - if (core.getCallsNb() > 0) { mBackToCallButton.setVisibility(View.VISIBLE); } else { @@ -624,7 +696,7 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con public void onConferenceAddressGeneration(ChatRoom cr) { } - + @Override public void onParticipantDeviceFetchRequested(ChatRoom cr, Address addr) { @@ -632,7 +704,7 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con @Override public void onParticipantRegistrationSubscriptionRequested(ChatRoom cr, Address participantAddr){ } - + @Override public void onParticipantRegistrationUnsubscriptionRequested(ChatRoom cr, Address participantAddr){ } @@ -679,6 +751,19 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con } } + /*@Override + public void onAllInformationReceived(ChatRoom cr) { + // Currently flexisip doesn't send the participants list in the INVITE + // So we have to refresh the display when information is available + // In the meantime header will be chatroom-xxxxxxx + if (mChatRoom == null) mChatRoom = cr; + if (mChatRoom.hasCapability(ChatRoomCapabilities.OneToOne.toInt()) && mChatRoom.getParticipants().length > 0) { + mRemoteParticipantAddress = mChatRoom.getParticipants()[0].getAddress(); + } + getContactsForParticipants(); + displayChatRoomHeader(); + }*/ + @Override public void onChatMessageReceived(ChatRoom cr, EventLog event) { cr.markAsRead(); @@ -767,6 +852,16 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con } + @Override + public void onConferenceJoined(ChatRoom cr, EventLog eventLog) { + + } + + @Override + public void onConferenceLeft(ChatRoom cr, EventLog eventLog) { + + } + @Override public void onParticipantRemoved(ChatRoom cr, EventLog event) { getContactsForParticipants(); diff --git a/src/android/org/linphone/chat/GroupInfoAdapter.java b/src/android/org/linphone/chat/GroupInfoAdapter.java index ad69e317c..4577b3625 100644 --- a/src/android/org/linphone/chat/GroupInfoAdapter.java +++ b/src/android/org/linphone/chat/GroupInfoAdapter.java @@ -129,7 +129,7 @@ public class GroupInfoAdapter extends BaseAdapter { } else if (mChatRoom != null) { boolean found = false; for (Participant p : mChatRoom.getParticipants()) { - if (p.getAddress().asStringUriOnly().equals(ca.getAddress().asStringUriOnly())) { + if (p.getAddress().weakEqual(ca.getAddress())) { found = true; break; } diff --git a/src/android/org/linphone/chat/GroupInfoFragment.java b/src/android/org/linphone/chat/GroupInfoFragment.java index d5810e1e3..1b58b4dee 100644 --- a/src/android/org/linphone/chat/GroupInfoFragment.java +++ b/src/android/org/linphone/chat/GroupInfoFragment.java @@ -227,7 +227,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { public void onClick(View view) { if (!mIsAlreadyCreatedGroup) { mWaitLayout.setVisibility(View.VISIBLE); - mTempChatRoom = LinphoneManager.getLc().createClientGroupChatRoom(mSubjectField.getText().toString()); + mTempChatRoom = LinphoneManager.getLc().createClientGroupChatRoom(mSubjectField.getText().toString(), mParticipants.size() == 1); mTempChatRoom.addListener(mChatRoomCreationListener); Address addresses[] = new Address[mParticipants.size()]; @@ -249,7 +249,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { for (Participant p : mChatRoom.getParticipants()) { boolean found = false; for (ContactAddress c : mParticipants) { - if (c.getAddress().asStringUriOnly().equals(p.getAddress().asStringUriOnly())) { + if (c.getAddress().weakEqual(p.getAddress())) { found = true; break; } @@ -267,7 +267,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { for (ContactAddress c : mParticipants) { boolean found = false; for (Participant p : mChatRoom.getParticipants()) { - if (p.getAddress().asStringUriOnly().equals(c.getAddress().asStringUriOnly())) { + if (p.getAddress().weakEqual(c.getAddress())) { // Admin rights if (c.isAdmin() != p.isAdmin()) { mChatRoom.setParticipantAdminStatus(p, c.isAdmin()); @@ -348,7 +348,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { String displayName = LinphoneUtils.getAddressDisplayName(a); c.setFullName(displayName); } - ContactAddress ca = new ContactAddress(c, a.asString(), c.isFriend(), p.isAdmin()); + ContactAddress ca = new ContactAddress(c, a.asString(), "", c.isFriend(), p.isAdmin()); mParticipants.add(ca); } @@ -448,6 +448,16 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { } + @Override + public void onConferenceJoined(ChatRoom cr, EventLog eventLog) { + + } + + @Override + public void onConferenceLeft(ChatRoom cr, EventLog eventLog) { + + } + @Override public void onParticipantDeviceAdded(ChatRoom cr, EventLog event_log) { @@ -462,7 +472,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { public void onStateChanged(ChatRoom cr, ChatRoom.State newState) { } - + @Override public void onParticipantDeviceFetchRequested(ChatRoom cr, Address addr) { @@ -470,7 +480,7 @@ public class GroupInfoFragment extends Fragment implements ChatRoomListener { @Override public void onParticipantRegistrationSubscriptionRequested(ChatRoom cr, Address participantAddr){ } - + @Override public void onParticipantRegistrationUnsubscriptionRequested(ChatRoom cr, Address participantAddr){ } diff --git a/src/android/org/linphone/chat/ImdnFragment.java b/src/android/org/linphone/chat/ImdnFragment.java index b78aa84e9..88bcafad7 100644 --- a/src/android/org/linphone/chat/ImdnFragment.java +++ b/src/android/org/linphone/chat/ImdnFragment.java @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. package org.linphone.chat; import android.app.Fragment; +import android.media.Image; import android.os.Bundle; import android.support.annotation.Nullable; import android.text.Spanned; @@ -41,25 +42,29 @@ import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; import org.linphone.core.Address; import org.linphone.core.ChatMessage; +import org.linphone.core.ChatMessageListenerStub; import org.linphone.core.ChatRoom; import org.linphone.core.Core; +import org.linphone.core.ParticipantImdnState; public class ImdnFragment extends Fragment { private LayoutInflater mInflater; - private LinearLayout mRead, mDelivered, mUndelivered; + private LinearLayout mRead, mReadHeader, mDelivered, mDeliveredHeader, mSent, mSentHeader, mUndelivered, mUndeliveredHeader; private ImageView mBackButton; private ChatBubbleViewHolder mBubble; + private ViewGroup mContainer; private String mRoomUri, mMessageId; private Address mRoomAddr; private ChatRoom mRoom; + private ChatMessage mMessage; + private ChatMessageListenerStub mListener; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { super.onCreate(savedInstanceState); - String roomUri; if (getArguments() != null) { mRoomUri = getArguments().getString("SipUri"); mRoomAddr = LinphoneManager.getLc().createAddress(mRoomUri); @@ -75,6 +80,7 @@ public class ImdnFragment extends Fragment { } mInflater = inflater; + mContainer = container; View view = mInflater.inflate(R.layout.chat_imdn, container, false); mBackButton = view.findViewById(R.id.back); @@ -91,7 +97,12 @@ public class ImdnFragment extends Fragment { mRead = view.findViewById(R.id.read_layout); mDelivered = view.findViewById(R.id.delivered_layout); + mSent = view.findViewById(R.id.sent_layout); mUndelivered = view.findViewById(R.id.undelivered_layout); + mReadHeader = view.findViewById(R.id.read_layout_header); + mDeliveredHeader = view.findViewById(R.id.delivered_layout_header); + mSentHeader = view.findViewById(R.id.sent_layout_header); + mUndeliveredHeader = view.findViewById(R.id.undelivered_layout_header); mBubble = new ChatBubbleViewHolder(view.findViewById(R.id.bubble)); mBubble.eventLayout.setVisibility(View.GONE); @@ -107,17 +118,44 @@ public class ImdnFragment extends Fragment { mBubble.imdmLayout.setVisibility(View.INVISIBLE); mBubble.contactPicture.setImageBitmap(ContactsManager.getInstance().getDefaultAvatarBitmap()); + mMessage = mRoom.findMessage(mMessageId); + mListener = new ChatMessageListenerStub() { + @Override + public void onParticipantImdnStateChanged(ChatMessage msg, ParticipantImdnState state) { + refreshInfo(); + } + }; + mMessage.setListener(mListener); + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); layoutParams.setMargins(100, 10, 10, 10); - mBubble.background.setBackgroundResource(R.drawable.resizable_chat_bubble_outgoing); - Compatibility.setTextAppearance(mBubble.contactName, getActivity(), R.style.font3); - Compatibility.setTextAppearance(mBubble.fileTransferAction, getActivity(), R.style.font15); - mBubble.fileTransferAction.setBackgroundResource(R.drawable.resizable_confirm_delete_button); - mBubble.contactPictureMask.setImageResource(R.drawable.avatar_chat_mask_outgoing); + if (mMessage.isOutgoing()) { + mBubble.background.setBackgroundResource(R.drawable.resizable_chat_bubble_outgoing); + Compatibility.setTextAppearance(mBubble.contactName, getActivity(), R.style.font3); + Compatibility.setTextAppearance(mBubble.fileTransferAction, getActivity(), R.style.font15); + mBubble.fileTransferAction.setBackgroundResource(R.drawable.resizable_confirm_delete_button); + mBubble.contactPictureMask.setImageResource(R.drawable.avatar_chat_mask_outgoing); + } else { + mBubble.background.setBackgroundResource(R.drawable.resizable_chat_bubble_incoming); + Compatibility.setTextAppearance(mBubble.contactName, getActivity(), R.style.font9); + Compatibility.setTextAppearance(mBubble.fileTransferAction, getActivity(), R.style.font8); + mBubble.fileTransferAction.setBackgroundResource(R.drawable.resizable_assistant_button); + mBubble.contactPictureMask.setImageResource(R.drawable.avatar_chat_mask); + } - ChatMessage message = mRoom.findMessage(mMessageId); - Address remoteSender = message.getFromAddress(); + return view; + } + + @Override + public void onResume() { + super.onResume(); + + refreshInfo(); + } + + private void refreshInfo() { + Address remoteSender = mMessage.getFromAddress(); LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(remoteSender); String displayName; @@ -130,50 +168,123 @@ public class ImdnFragment extends Fragment { mBubble.contactPicture.setImageBitmap(ContactsManager.getInstance().getDefaultAvatarBitmap()); if (contact.hasPhoto()) { - LinphoneUtils.setThumbnailPictureFromUri(LinphoneActivity.instance(), mBubble.contactPicture, contact.getThumbnailUri()); + LinphoneUtils.setThumbnailPictureFromUri(getActivity(), mBubble.contactPicture, contact.getThumbnailUri()); } } else { displayName = LinphoneUtils.getAddressDisplayName(remoteSender); mBubble.contactPicture.setImageBitmap(ContactsManager.getInstance().getDefaultAvatarBitmap()); } - mBubble.contactName.setText(LinphoneUtils.timestampToHumanDate(getActivity(), message.getTime(), R.string.messages_date_format) + " - " + displayName); + mBubble.contactName.setText(LinphoneUtils.timestampToHumanDate(getActivity(), mMessage.getTime(), R.string.messages_date_format) + " - " + displayName); - if (message.hasTextContent()) { - String msg = message.getTextContent(); + if (mMessage.hasTextContent()) { + String msg = mMessage.getTextContent(); Spanned text = LinphoneUtils.getTextWithHttpLinks(msg); mBubble.messageText.setText(text); mBubble.messageText.setMovementMethod(LinkMovementMethod.getInstance()); mBubble.messageText.setVisibility(View.VISIBLE); } - String appData = message.getAppdata(); + String appData = mMessage.getAppdata(); if (appData != null) { // Something to display mBubble.fileName.setVisibility(View.VISIBLE); mBubble.fileName.setText(LinphoneUtils.getNameFromFilePath(appData)); // We purposely chose not to display the image } - // TODO: real values - View v = mInflater.inflate(R.layout.chat_imdn_cell, container, false); - v.findViewById(R.id.separator).setVisibility(View.GONE); - ((TextView)v.findViewById(R.id.time)).setText("Aujourd'hui - 17h58"); - ((TextView)v.findViewById(R.id.name)).setText("Albert"); - mRead.addView(v); - v = mInflater.inflate(R.layout.chat_imdn_cell, container, false); - ((TextView)v.findViewById(R.id.time)).setText("Aujourd'hui - 17h52"); - ((TextView)v.findViewById(R.id.name)).setText("Charlotte"); - mRead.addView(v); - v = mInflater.inflate(R.layout.chat_imdn_cell, container, false); - v.findViewById(R.id.separator).setVisibility(View.GONE); - ((TextView)v.findViewById(R.id.time)).setText("Aujourd'hui - 17h36"); - ((TextView)v.findViewById(R.id.name)).setText("Fabrice"); - mDelivered.addView(v); - v = mInflater.inflate(R.layout.chat_imdn_cell, container, false); - v.findViewById(R.id.separator).setVisibility(View.GONE); - ((TextView)v.findViewById(R.id.name)).setText("Heloïse"); - mUndelivered.addView(v); - // End of todo + mRead.removeAllViews(); + mDelivered.removeAllViews(); + mSent.removeAllViews(); + mUndelivered.removeAllViews(); - return view; + ParticipantImdnState[] participants = mMessage.getParticipantsByImdnState(ChatMessage.State.Displayed); + mReadHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE); + boolean first = true; + for (ParticipantImdnState participant : participants) { + Address address = participant.getParticipant().getAddress(); + + LinphoneContact participantContact = ContactsManager.getInstance().findContactFromAddress(address); + String participantDisplayName = participantContact != null ? participantContact.getFullName() : LinphoneUtils.getAddressDisplayName(address); + + View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false); + v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE); + ((TextView)v.findViewById(R.id.time)).setText(LinphoneUtils.timestampToHumanDate(getActivity(), participant.getStateChangeTime(), R.string.messages_date_format)); + ((TextView)v.findViewById(R.id.name)).setText(participantDisplayName); + if (participantContact != null && participantContact.hasPhoto()) { + LinphoneUtils.setThumbnailPictureFromUri(getActivity(), ((ImageView)v.findViewById(R.id.contact_picture)), participantContact.getThumbnailUri()); + } else { + ((ImageView)v.findViewById(R.id.contact_picture)).setImageBitmap(ContactsManager.getInstance().getDefaultAvatarBitmap()); + } + + mRead.addView(v); + first = false; + } + + participants = mMessage.getParticipantsByImdnState(ChatMessage.State.DeliveredToUser); + mDeliveredHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE); + first = true; + for (ParticipantImdnState participant : participants) { + Address address = participant.getParticipant().getAddress(); + + LinphoneContact participantContact = ContactsManager.getInstance().findContactFromAddress(address); + String participantDisplayName = participantContact != null ? participantContact.getFullName() : LinphoneUtils.getAddressDisplayName(address); + + View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false); + v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE); + ((TextView)v.findViewById(R.id.time)).setText(LinphoneUtils.timestampToHumanDate(getActivity(), participant.getStateChangeTime(), R.string.messages_date_format)); + ((TextView)v.findViewById(R.id.name)).setText(participantDisplayName); + if (participantContact != null && participantContact.hasPhoto()) { + LinphoneUtils.setThumbnailPictureFromUri(getActivity(), ((ImageView)v.findViewById(R.id.contact_picture)), participantContact.getThumbnailUri()); + } else { + ((ImageView)v.findViewById(R.id.contact_picture)).setImageBitmap(ContactsManager.getInstance().getDefaultAvatarBitmap()); + } + + mDelivered.addView(v); + first = false; + } + + participants = mMessage.getParticipantsByImdnState(ChatMessage.State.Delivered); + mSentHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE); + first = true; + for (ParticipantImdnState participant : participants) { + Address address = participant.getParticipant().getAddress(); + + LinphoneContact participantContact = ContactsManager.getInstance().findContactFromAddress(address); + String participantDisplayName = participantContact != null ? participantContact.getFullName() : LinphoneUtils.getAddressDisplayName(address); + + View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false); + v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE); + ((TextView)v.findViewById(R.id.time)).setText(LinphoneUtils.timestampToHumanDate(getActivity(), participant.getStateChangeTime(), R.string.messages_date_format)); + ((TextView)v.findViewById(R.id.name)).setText(participantDisplayName); + if (participantContact != null && participantContact.hasPhoto()) { + LinphoneUtils.setThumbnailPictureFromUri(getActivity(), ((ImageView)v.findViewById(R.id.contact_picture)), participantContact.getThumbnailUri()); + } else { + ((ImageView)v.findViewById(R.id.contact_picture)).setImageBitmap(ContactsManager.getInstance().getDefaultAvatarBitmap()); + } + + mSent.addView(v); + first = false; + } + + participants = mMessage.getParticipantsByImdnState(ChatMessage.State.NotDelivered); + mUndeliveredHeader.setVisibility(participants.length == 0 ? View.GONE : View.VISIBLE); + first = true; + for (ParticipantImdnState participant : participants) { + Address address = participant.getParticipant().getAddress(); + + LinphoneContact participantContact = ContactsManager.getInstance().findContactFromAddress(address); + String participantDisplayName = participantContact != null ? participantContact.getFullName() : LinphoneUtils.getAddressDisplayName(address); + + View v = mInflater.inflate(R.layout.chat_imdn_cell, mContainer, false); + v.findViewById(R.id.separator).setVisibility(first ? View.GONE : View.VISIBLE); + ((TextView)v.findViewById(R.id.name)).setText(participantDisplayName); + if (participantContact != null && participantContact.hasPhoto()) { + LinphoneUtils.setThumbnailPictureFromUri(getActivity(), ((ImageView)v.findViewById(R.id.contact_picture)), participantContact.getThumbnailUri()); + } else { + ((ImageView)v.findViewById(R.id.contact_picture)).setImageBitmap(ContactsManager.getInstance().getDefaultAvatarBitmap()); + } + + mUndelivered.addView(v); + first = false; + } } } diff --git a/src/android/org/linphone/contacts/ContactAddress.java b/src/android/org/linphone/contacts/ContactAddress.java index 736f320a0..8d1bfa4f8 100644 --- a/src/android/org/linphone/contacts/ContactAddress.java +++ b/src/android/org/linphone/contacts/ContactAddress.java @@ -23,12 +23,15 @@ import android.view.View; import org.linphone.core.Address; import org.linphone.core.Factory; +import org.linphone.core.SearchResult; import java.io.Serializable; public class ContactAddress implements Serializable { private LinphoneContact contact; + private SearchResult result; private String address; + private String phoneNumber; private boolean isLinphoneContact; private boolean isSelect = false; private boolean isAdmin = false; @@ -58,13 +61,32 @@ public class ContactAddress implements Serializable { return contact; } + public SearchResult getResult() { + return result; + } + + public void setResult(SearchResult result) { + this.result = result; + } + public String getAddressAsDisplayableString() { + Address addr = getAddress(); + if (addr != null && addr.getUsername() != null) return addr.asStringUriOnly(); return address; } public Address getAddress() { - String presence = contact.getPresenceModelForUriOrTel(address); - return Factory.instance().createAddress(presence != null ? presence : address); + String presence = contact.getPresenceModelForUriOrTel((phoneNumber != null && !phoneNumber.isEmpty()) ? phoneNumber: address); + Address addr = Factory.instance().createAddress(presence != null ? presence : address); + // Remove the user=phone URI param if existing, it will break everything otherwise + if (addr.hasUriParam("user")) { + addr.removeUriParam("user"); + } + return addr; + } + + public String getPhoneNumber() { + return phoneNumber; } public void setSelect(boolean select) { @@ -75,16 +97,19 @@ public class ContactAddress implements Serializable { return isLinphoneContact; } - public ContactAddress(LinphoneContact c, String a, boolean isLC){ + private void init(LinphoneContact c, String a, String pn, boolean isLC) { this.contact = c; this.address = a; + this.phoneNumber = pn; this.isLinphoneContact = isLC; } - public ContactAddress(LinphoneContact c, String a, boolean isLC, boolean isAdmin){ - this.contact = c; - this.address = a; - this.isLinphoneContact = isLC; + public ContactAddress(LinphoneContact c, String a, String pn, boolean isLC) { + init(c, a, pn, isLC); + } + + public ContactAddress(LinphoneContact c, String a, String pn, boolean isLC, boolean isAdmin) { + init(c, a, pn, isLC); this.isAdmin = isAdmin; } diff --git a/src/android/org/linphone/contacts/ContactDetailsFragment.java b/src/android/org/linphone/contacts/ContactDetailsFragment.java index b67f213c8..a4c92ac7a 100644 --- a/src/android/org/linphone/contacts/ContactDetailsFragment.java +++ b/src/android/org/linphone/contacts/ContactDetailsFragment.java @@ -82,7 +82,7 @@ public class ContactDetailsFragment extends Fragment implements OnClickListener ProxyConfig lpc = lc.getDefaultProxyConfig(); if (lpc != null && lpc.getConferenceFactoryUri() != null && !LinphonePreferences.instance().useBasicChatRoomFor1To1()) { mWaitLayout.setVisibility(View.VISIBLE); - mChatRoom = lc.createClientGroupChatRoom(getString(R.string.dummy_group_chat_subject)); + mChatRoom = lc.createClientGroupChatRoom(getString(R.string.dummy_group_chat_subject), true); mChatRoom.addListener(mChatRoomCreationListener); mChatRoom.addParticipant(participant); } else { diff --git a/src/android/org/linphone/contacts/ContactsManager.java b/src/android/org/linphone/contacts/ContactsManager.java index ba265d913..0a60449eb 100644 --- a/src/android/org/linphone/contacts/ContactsManager.java +++ b/src/android/org/linphone/contacts/ContactsManager.java @@ -42,8 +42,10 @@ import org.linphone.LinphoneService; import org.linphone.R; import org.linphone.core.Address; import org.linphone.core.Core; +import org.linphone.core.Factory; import org.linphone.core.Friend; import org.linphone.core.FriendList; +import org.linphone.core.MagicSearch; import org.linphone.core.ProxyConfig; import org.linphone.mediastream.Log; @@ -61,6 +63,7 @@ public class ContactsManager extends ContentObserver { private static ContactsManager instance; private List contacts, sipContacts; + private MagicSearch magicSearch; private boolean preferLinphoneContacts = false, isContactPresenceDisabled = true; private ContentResolver contentResolver; private Context context; @@ -84,6 +87,9 @@ public class ContactsManager extends ContentObserver { contactsUpdatedListeners = new ArrayList(); contacts = new ArrayList(); sipContacts = new ArrayList(); + if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) { + magicSearch = LinphoneManager.getLcIfManagerNotDestroyedOrNull().createMagicSearch(); + } } public void destroy() { @@ -91,6 +97,10 @@ public class ContactsManager extends ContentObserver { instance = null; } + public MagicSearch getMagicSearch() { + return magicSearch; + } + public boolean contactsFetchedOnce() { return contacts.size() > 0; } @@ -220,6 +230,7 @@ public class ContactsManager extends ContentObserver { } public synchronized LinphoneContact findContactFromAddress(Address address) { + if (address == null) return null; Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); Friend lf = lc.findFriend(address); if (lf != null) { @@ -301,6 +312,9 @@ public class ContactsManager extends ContentObserver { LinphoneContact contact = (LinphoneContact) friend.getUserData(); if (contact != null) { contact.clearAddresses(); + if (contact.hasAddress()) { + sipContacts.add(contact); + } contacts.add(contact); if (contact.getAndroidId() != null) { androidContactsCache.put(contact.getAndroidId(), contact); diff --git a/src/android/org/linphone/contacts/SearchContactsListAdapter.java b/src/android/org/linphone/contacts/SearchContactsListAdapter.java index 8dc4ff2fa..fa454258f 100644 --- a/src/android/org/linphone/contacts/SearchContactsListAdapter.java +++ b/src/android/org/linphone/contacts/SearchContactsListAdapter.java @@ -33,10 +33,11 @@ import org.linphone.LinphoneUtils; import org.linphone.R; import org.linphone.activities.LinphoneActivity; import org.linphone.core.Address; +import org.linphone.core.ProxyConfig; +import org.linphone.core.SearchResult; import java.util.ArrayList; import java.util.List; -import java.util.Locale; public class SearchContactsListAdapter extends BaseAdapter { @@ -87,8 +88,13 @@ public class SearchContactsListAdapter extends BaseAdapter { private boolean contactIsSelected(ContactAddress ca) { for (ContactAddress c : contactsSelected) { Address addr = c.getAddress(); - if (addr == null) continue; - if (addr.asStringUriOnly().compareTo(ca.getAddress().asStringUriOnly()) == 0) return true; + if (addr.getUsername() != null && ca.getAddress() != null) { + if (addr.asStringUriOnly().compareTo(ca.getAddress().asStringUriOnly()) == 0) return true; + } else { + if (c.getPhoneNumber() != null && ca.getPhoneNumber() != null) { + if (c.getPhoneNumber().compareTo(ca.getPhoneNumber()) == 0) return true; + } + } } return false; } @@ -122,11 +128,18 @@ public class SearchContactsListAdapter extends BaseAdapter { for (LinphoneContact contact : contacts) { for (LinphoneNumberOrAddress noa : contact.getNumbersOrAddresses()) { if (!mOnlySipContact || (mOnlySipContact && (noa.isSIPAddress() || contact.getPresenceModelForUriOrTel(noa.getValue()) != null))) { - Address address = LinphoneManager.getLc().interpretUrl(noa.getValue()); - if (address != null) { - ContactAddress ca = new ContactAddress(contact, address.asString(), contact.isFriend()); - list.add(ca); + ContactAddress ca = null; + if (noa.isSIPAddress()) { + Address address = LinphoneManager.getLc().interpretUrl(noa.getValue()); + if (address != null) { + ca = new ContactAddress(contact, address.asString(), "", contact.isFriend()); + } + } else { + ProxyConfig prx = LinphoneManager.getLc().getDefaultProxyConfig(); + String number = (prx != null) ? prx.normalizePhoneNumber(noa.getValue()) : noa.getValue(); + ca = new ContactAddress(contact, "", number, contact.isFriend()); } + if (ca != null) list.add(ca); } } } @@ -156,6 +169,9 @@ public class SearchContactsListAdapter extends BaseAdapter { if (search == null || search.length() == 0 || search.trim().length() == 0) { contacts = getContactsList(); resultContactsSearch.setAdapter(this); + if (ContactsManager.getInstance() != null) { + ContactsManager.getInstance().getMagicSearch().resetSearchCache(); + } oldSize = 0; return; } @@ -163,29 +179,39 @@ public class SearchContactsListAdapter extends BaseAdapter { search = search.trim(); List result = new ArrayList<>(); - String searchAddress = "sip:" + search + "@" + LinphoneManager.getLc().getDefaultProxyConfig().getDomain(); - if (search.contains("@") || search.startsWith("sip:")) { - searchAddress = search; - } - - boolean searchFound = false; - if (search != null) { - for (ContactAddress c : (search.length() < oldSize) ? getContactsList() : getContacts()) { - String address = c.getAddressAsDisplayableString(); - if (address.equals(searchAddress)) searchFound = true; - if (address.startsWith("sip:")) address = address.substring(4); - if (c.getContact() != null && c.getContact().getFullName() != null - && c.getContact().getFullName().toLowerCase(Locale.getDefault()).startsWith(search.toLowerCase(Locale.getDefault())) - || address.toLowerCase(Locale.getDefault()).startsWith(search.toLowerCase(Locale.getDefault()))) { - result.add(c); + String domain = ""; + ProxyConfig prx = LinphoneManager.getLc().getDefaultProxyConfig(); + if (prx != null) domain = prx.getDomain(); + SearchResult[] results = ContactsManager.getInstance().getMagicSearch().getContactListFromFilter(search, mOnlySipContact ? domain :""); + for (SearchResult sr : results) { + boolean found = false; + LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(sr.getAddress()); + if (contact == null) { + contact = new LinphoneContact(); + if (sr.getFriend() != null) { + contact.setFriend(sr.getFriend()); + contact.refresh(); } } + if (sr.getAddress() != null || sr.getPhoneNumber() != null) { + for (ContactAddress ca : result) { + String normalizedPhoneNumber = (ca.getPhoneNumber() != null) ? prx.normalizePhoneNumber(ca.getPhoneNumber()) : null; + if ((sr.getAddress() != null && ca.getAddress() != null + && ca.getAddress().asStringUriOnly().equals(sr.getAddress().asStringUriOnly())) + || (sr.getPhoneNumber() != null && normalizedPhoneNumber != null + && sr.getPhoneNumber().equals(normalizedPhoneNumber))) { + found = true; + break; + } + } + } + if (!found) { + result.add(new ContactAddress(contact, + (sr.getAddress() != null) ? sr.getAddress().asStringUriOnly() : "", + sr.getPhoneNumber(), + contact.isFriend())); + } } - if (!searchFound) { - LinphoneContact searchContact = new LinphoneContact(); - searchContact.setFullName(search); - result.add(new ContactAddress(searchContact, searchAddress, false)); - } oldSize = search.length(); contacts = result; @@ -208,7 +234,7 @@ public class SearchContactsListAdapter extends BaseAdapter { } ContactAddress contact = getItem(position); - final String a = contact.getAddressAsDisplayableString(); + final String a = (contact.getAddressAsDisplayableString().isEmpty()) ? contact.getPhoneNumber() : contact.getAddressAsDisplayableString(); LinphoneContact c = contact.getContact(); holder.avatar.setImageBitmap(ContactsManager.getInstance().getDefaultAvatarBitmap()); @@ -216,11 +242,20 @@ public class SearchContactsListAdapter extends BaseAdapter { LinphoneUtils.setThumbnailPictureFromUri(LinphoneActivity.instance(), holder.avatar, c.getThumbnailUri()); } - String address = null; - if (c != null) { - address = c.getPresenceModelForUriOrTel(a); + String address = contact.getAddressAsDisplayableString(); + if (c != null && c.getFullName() != null) { + if (address == null) + address = c.getPresenceModelForUriOrTel(a); holder.name.setVisibility(View.VISIBLE); holder.name.setText(c.getFullName()); + } else if (contact.getAddress() != null) { + if (contact.getAddress().getUsername() != null) { + holder.name.setVisibility(View.VISIBLE); + holder.name.setText(contact.getAddress().getUsername()); + } else if (contact.getAddress().getDisplayName() != null) { + holder.name.setVisibility(View.VISIBLE); + holder.name.setText(contact.getAddress().getDisplayName()); + } } else { holder.name.setVisibility(View.GONE); } diff --git a/src/android/org/linphone/firebase/FirebaseIdService.java b/src/android/org/linphone/firebase/FirebaseIdService.java index efff496e3..37f23983a 100644 --- a/src/android/org/linphone/firebase/FirebaseIdService.java +++ b/src/android/org/linphone/firebase/FirebaseIdService.java @@ -32,6 +32,7 @@ public class FirebaseIdService extends FirebaseInstanceIdService { // Get updated InstanceID token. final String refreshedToken = FirebaseInstanceId.getInstance().getToken(); android.util.Log.i("FirebaseIdService", "[Push Notification] Refreshed token: " + refreshedToken); + LinphoneUtils.dispatchOnUIThread(new Runnable() { @Override public void run() { diff --git a/src/android/org/linphone/firebase/FirebaseMessaging.java b/src/android/org/linphone/firebase/FirebaseMessaging.java index f7199d1ef..49cf49271 100644 --- a/src/android/org/linphone/firebase/FirebaseMessaging.java +++ b/src/android/org/linphone/firebase/FirebaseMessaging.java @@ -52,5 +52,4 @@ public class FirebaseMessaging extends FirebaseMessagingService { }); } } - } diff --git a/src/android/org/linphone/fragments/AccountPreferencesFragment.java b/src/android/org/linphone/fragments/AccountPreferencesFragment.java index 29cec9696..fd13a8039 100644 --- a/src/android/org/linphone/fragments/AccountPreferencesFragment.java +++ b/src/android/org/linphone/fragments/AccountPreferencesFragment.java @@ -260,6 +260,18 @@ public class AccountPreferencesFragment extends PreferencesListFragment implemen return true; } }; + OnPreferenceChangeListener pushNotificationListener = new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + boolean value = (Boolean) newValue; + if (isNewAccount) { + //TODO + } else { + mPrefs.enablePushNotifForProxy(n, value); + } + return true; + } + }; OnPreferenceChangeListener disableChangedListener = new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { @@ -443,6 +455,12 @@ public class AccountPreferencesFragment extends PreferencesListFragment implemen Preference linkAccount = advanced.getPreference(10); linkAccount.setOnPreferenceClickListener(linkAccountListener); + CheckBoxPreference pushNotif = (CheckBoxPreference) advanced.getPreference(11); + pushNotif.setOnPreferenceChangeListener(pushNotificationListener); + if(!isNewAccount){ + pushNotif.setChecked(mPrefs.isPushNotifEnabledForProxy(n)); + } + PreferenceCategory manage = (PreferenceCategory) getPreferenceScreen().findPreference(getString(R.string.pref_manage_key)); final CheckBoxPreference disable = (CheckBoxPreference) manage.getPreference(0); disable.setEnabled(true); diff --git a/src/android/org/linphone/fragments/HistoryDetailFragment.java b/src/android/org/linphone/fragments/HistoryDetailFragment.java index b4890d691..e6754af9f 100644 --- a/src/android/org/linphone/fragments/HistoryDetailFragment.java +++ b/src/android/org/linphone/fragments/HistoryDetailFragment.java @@ -204,7 +204,7 @@ public class HistoryDetailFragment extends Fragment implements OnClickListener { ProxyConfig lpc = lc.getDefaultProxyConfig(); if (lpc != null && lpc.getConferenceFactoryUri() != null && !LinphonePreferences.instance().useBasicChatRoomFor1To1()) { mWaitLayout.setVisibility(View.VISIBLE); - mChatRoom = lc.createClientGroupChatRoom(getString(R.string.dummy_group_chat_subject)); + mChatRoom = lc.createClientGroupChatRoom(getString(R.string.dummy_group_chat_subject), true); mChatRoom.addListener(mChatRoomCreationListener); mChatRoom.addParticipant(participant); } else { diff --git a/src/android/org/linphone/fragments/SettingsFragment.java b/src/android/org/linphone/fragments/SettingsFragment.java index 0fe756646..f036b03bd 100644 --- a/src/android/org/linphone/fragments/SettingsFragment.java +++ b/src/android/org/linphone/fragments/SettingsFragment.java @@ -221,6 +221,7 @@ public class SettingsFragment extends PreferencesListFragment { if (getResources().getBoolean(R.bool.disable_every_log)) { uncheckAndHidePreference(R.string.pref_debug_key); + uncheckAndHidePreference(R.string.pref_java_debug_key); } if (!LinphoneManager.getLc().upnpAvailable()) { @@ -289,16 +290,16 @@ public class SettingsFragment extends PreferencesListFragment { return; } - /*setPreferenceDefaultValueAndSummary(R.string.pref_tunnel_host_key, mPrefs.getTunnelHost()); + setPreferenceDefaultValueAndSummary(R.string.pref_tunnel_host_key, mPrefs.getTunnelHost()); setPreferenceDefaultValueAndSummary(R.string.pref_tunnel_port_key, String.valueOf(mPrefs.getTunnelPort())); ListPreference tunnelModePref = (ListPreference) findPreference(getString(R.string.pref_tunnel_mode_key)); String tunnelMode = mPrefs.getTunnelMode(); tunnelModePref.setSummary(tunnelMode); - tunnelModePref.setValue(tunnelMode);*/ + tunnelModePref.setValue(tunnelMode); } private void setTunnelPreferencesListener() { - /*findPreference(getString(R.string.pref_tunnel_host_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + findPreference(getString(R.string.pref_tunnel_host_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { String host = newValue.toString(); @@ -328,7 +329,7 @@ public class SettingsFragment extends PreferencesListFragment { preference.setSummary(mode); return true; } - });*/ + }); } private void initAccounts() { @@ -1267,6 +1268,7 @@ public class SettingsFragment extends PreferencesListFragment { private void initAdvancedSettings() { ((CheckBoxPreference)findPreference(getString(R.string.pref_friendlist_subscribe_key))).setChecked(mPrefs.isFriendlistsubscriptionEnabled()); ((CheckBoxPreference)findPreference(getString(R.string.pref_debug_key))).setChecked(mPrefs.isDebugEnabled()); + ((CheckBoxPreference)findPreference(getString(R.string.pref_java_debug_key))).setChecked(mPrefs.useJavaLogger()); ((CheckBoxPreference)findPreference(getString(R.string.pref_background_mode_key))).setChecked(mPrefs.isBackgroundModeEnabled()); ((CheckBoxPreference)findPreference(getString(R.string.pref_service_notification_key))).setChecked(mPrefs.getServiceNotificationVisibility()); ((CheckBoxPreference)findPreference(getString(R.string.pref_autostart_key))).setChecked(mPrefs.isAutoStartEnabled()); @@ -1296,6 +1298,15 @@ public class SettingsFragment extends PreferencesListFragment { } }); + findPreference(getString(R.string.pref_java_debug_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + boolean value = (Boolean) newValue; + mPrefs.setJavaLogger(value); + return true; + } + }); + findPreference(getString(R.string.pref_background_mode_key)).setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { diff --git a/src/android/org/linphone/gcm/GCMReceiver.java b/src/android/org/linphone/gcm/GCMReceiver.java deleted file mode 100644 index 75b38602b..000000000 --- a/src/android/org/linphone/gcm/GCMReceiver.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.linphone.gcm; -/* -GCMReceiver.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France - -This program 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 2 -of the License, or (at your option) any later version. - -This program 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 program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -import android.content.Context; - -import com.google.android.gcm.GCMBroadcastReceiver; - - -public class GCMReceiver extends GCMBroadcastReceiver { - @Override - protected String getGCMIntentServiceClassName(Context context) { - return "org.linphone.gcm.GCMService"; - } -} \ No newline at end of file diff --git a/src/android/org/linphone/gcm/GCMService.java b/src/android/org/linphone/gcm/GCMService.java deleted file mode 100644 index f956cd418..000000000 --- a/src/android/org/linphone/gcm/GCMService.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.linphone.gcm; -/* -GCMService.java -Copyright (C) 2017 Belledonne Communications, Grenoble, France - -This program 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 2 -of the License, or (at your option) any later version. - -This program 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 program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -import static android.content.Intent.ACTION_MAIN; - -import org.linphone.LinphoneManager; -import org.linphone.LinphonePreferences; -import org.linphone.LinphoneService; -import org.linphone.LinphoneUtils; -import org.linphone.R; -import org.linphone.core.Factory; -import org.linphone.core.LogCollectionState; -import org.linphone.mediastream.Log; - -import android.content.Context; -import android.content.Intent; - -import com.google.android.gcm.GCMBaseIntentService; - -// Warning ! Do not rename the service ! -public class GCMService extends GCMBaseIntentService { - - public GCMService() { - - } - - private void initLogger(Context context) { - LinphonePreferences.instance().setContext(context); - boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled(); - Factory.instance().enableLogCollection(isDebugEnabled ? LogCollectionState.Enabled : LogCollectionState.Disabled); - Factory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name)); - } - - @Override - protected void onError(Context context, String errorId) { - initLogger(context); - Log.e("[Push Notification] Error while registering: " + errorId); - } - - @Override - protected void onMessage(Context context, Intent intent) { - initLogger(context); - Log.d("[Push Notification] Received"); - - if (!LinphoneService.isReady()) { - context.startService(new Intent(ACTION_MAIN).setClass(context, LinphoneService.class)); - } else if (LinphoneManager.isInstanciated() && LinphoneManager.getLc().getCallsNb() == 0) { - LinphoneUtils.dispatchOnUIThread(new Runnable(){ - @Override - public void run() { - if (LinphoneManager.isInstanciated() && LinphoneManager.getLc().getCallsNb() == 0){ - LinphoneManager.getLc().setNetworkReachable(false); - LinphoneManager.getLc().setNetworkReachable(true); - } - } - }); - } - } - - @Override - protected void onRegistered(Context context, final String regId) { - initLogger(context); - Log.d("[Push Notification] Registered: " + regId); - LinphoneUtils.dispatchOnUIThread(new Runnable(){ - @Override - public void run() { - LinphonePreferences.instance().setPushNotificationRegistrationID(regId); - } - }); - } - - @Override - protected void onUnregistered(Context context, String regId) { - initLogger(context); - Log.w("[Push Notification] Unregistered: " + regId); - - LinphoneUtils.dispatchOnUIThread(new Runnable(){ - @Override - public void run() { - LinphonePreferences.instance().setPushNotificationRegistrationID(null); - } - }); - } - - protected String[] getSenderIds(Context context) { - return new String[] { context.getString(R.string.push_sender_id) }; - } -} diff --git a/src/android/org/linphone/receivers/DozeReceiver.java b/src/android/org/linphone/receivers/DozeReceiver.java index d417920bb..60b525a73 100644 --- a/src/android/org/linphone/receivers/DozeReceiver.java +++ b/src/android/org/linphone/receivers/DozeReceiver.java @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import org.linphone.LinphoneManager; import org.linphone.LinphonePreferences; import org.linphone.LinphoneService; +import org.linphone.LinphoneUtils; import org.linphone.R; import org.linphone.core.Core; import org.linphone.core.Factory; @@ -43,8 +44,7 @@ public class DozeReceiver extends android.content.BroadcastReceiver { if (!LinphoneService.isReady()) return; boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled(); - Factory.instance().enableLogCollection(isDebugEnabled ? LogCollectionState.Enabled : LogCollectionState.Disabled); - Factory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name)); + LinphoneUtils.initLoggingService(isDebugEnabled, context.getString(R.string.app_name)); Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); if (lc == null) return; diff --git a/src/android/org/linphone/receivers/KeepAliveReceiver.java b/src/android/org/linphone/receivers/KeepAliveReceiver.java index 64fa88b67..12b8b9cf8 100644 --- a/src/android/org/linphone/receivers/KeepAliveReceiver.java +++ b/src/android/org/linphone/receivers/KeepAliveReceiver.java @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import org.linphone.LinphoneManager; import org.linphone.LinphonePreferences; import org.linphone.LinphoneService; +import org.linphone.LinphoneUtils; import org.linphone.R; import org.linphone.compatibility.Compatibility; import org.linphone.core.Core; @@ -46,8 +47,7 @@ public class KeepAliveReceiver extends BroadcastReceiver { return; } else { boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled(); - Factory.instance().enableLogCollection(isDebugEnabled ? LogCollectionState.Enabled : LogCollectionState.Disabled); - Factory.instance().setDebugMode(isDebugEnabled, context.getString(R.string.app_name)); + LinphoneUtils.initLoggingService(isDebugEnabled, context.getString(R.string.app_name)); Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); if (lc == null) return; diff --git a/src/android/org/linphone/ui/Digit.java b/src/android/org/linphone/ui/Digit.java index c1b544695..4eb3fa583 100644 --- a/src/android/org/linphone/ui/Digit.java +++ b/src/android/org/linphone/ui/Digit.java @@ -19,6 +19,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import org.linphone.LinphoneUtils; import org.linphone.call.CallActivity; import org.linphone.LinphoneManager; import org.linphone.LinphonePreferences; @@ -139,7 +140,6 @@ public class Digit extends Button implements AddressAware { public void onClick(DialogInterface dialog, int which) { if(which == 0){ LinphonePreferences.instance().setDebugEnabled(false); - Factory.instance().enableLogCollection(LogCollectionState.Disabled); } if(which == 1) { Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); @@ -155,7 +155,6 @@ public class Digit extends Button implements AddressAware { public void onClick(DialogInterface dialog, int which) { if(which == 0) { LinphonePreferences.instance().setDebugEnabled(true); - Factory.instance().enableLogCollection(LogCollectionState.Enabled); } } }); diff --git a/submodules/bctoolbox b/submodules/bctoolbox index e9473d2e5..acf772700 160000 --- a/submodules/bctoolbox +++ b/submodules/bctoolbox @@ -1 +1 @@ -Subproject commit e9473d2e5772c9ad1aea83c504b9c6aa9a92bc67 +Subproject commit acf7727002fa4837a25582b5c798516b6b288fac diff --git a/submodules/belcard b/submodules/belcard index 8c1027652..7376c8ba9 160000 --- a/submodules/belcard +++ b/submodules/belcard @@ -1 +1 @@ -Subproject commit 8c1027652d3219521a6d9112614066a9cc9f8cb1 +Subproject commit 7376c8ba975617c8b2a7232c3acc428513a4ae8f diff --git a/submodules/belle-sip b/submodules/belle-sip index 91f5b7273..cbb4ab4c2 160000 --- a/submodules/belle-sip +++ b/submodules/belle-sip @@ -1 +1 @@ -Subproject commit 91f5b7273064a496ba1c314c5b78ad492289e584 +Subproject commit cbb4ab4c2a58e4fa1954043f6b17266e1685c887 diff --git a/submodules/belr b/submodules/belr index 18abde9e4..8e841b047 160000 --- a/submodules/belr +++ b/submodules/belr @@ -1 +1 @@ -Subproject commit 18abde9e43e8f98e22c09afee3e089c4e7691173 +Subproject commit 8e841b047641b1812a83880a90e89d702747ca5b diff --git a/submodules/linphone b/submodules/linphone index 3d7e53022..64fc28497 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 3d7e530222c9ff128f3db96108da6320987b17bf +Subproject commit 64fc28497ffb0cf93ec851f2f2f6cfd72f116c3a diff --git a/submodules/mediastreamer2 b/submodules/mediastreamer2 index 1149d4bef..5dc5219af 160000 --- a/submodules/mediastreamer2 +++ b/submodules/mediastreamer2 @@ -1 +1 @@ -Subproject commit 1149d4befcdd8a0f16b90a336d683a27081c59c0 +Subproject commit 5dc5219afe2d6f4d32a91ad6017ffc070eaf4eb6