diff --git a/res/drawable/cancel.xml b/res/drawable/cancel.xml
index b78cf842d..a22bb497e 100644
--- a/res/drawable/cancel.xml
+++ b/res/drawable/cancel.xml
@@ -1,9 +1,9 @@
+ android:drawable="@drawable/back_over" />
+ android:drawable="@drawable/back_disabled" />
+ android:drawable="@drawable/back_default" />
\ No newline at end of file
diff --git a/res/layout/active_call.xml b/res/layout/active_call.xml
index cba886790..5f1c0d514 100644
--- a/res/layout/active_call.xml
+++ b/res/layout/active_call.xml
@@ -45,12 +45,140 @@
-
+ android:paddingBottom="10dp">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values-FR/strings.xml b/res/values-FR/strings.xml
index 56499cb7d..b33195142 100644
--- a/res/values-FR/strings.xml
+++ b/res/values-FR/strings.xml
@@ -210,6 +210,12 @@
Aucun contact SIP dans votre carnet d\'adresse.
Aucun historique de chat.
+ Audio
+ Codec :
+ Bande passante envoi :
+ Bande passante reception :
+ Connexion ICE :
+
diff --git a/res/values/non_localizable_custom.xml b/res/values/non_localizable_custom.xml
index b673cbae8..3d805a543 100644
--- a/res/values/non_localizable_custom.xml
+++ b/res/values/non_localizable_custom.xml
@@ -28,6 +28,9 @@
true
false
+ true
+
+
true
true
true
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ee4094851..122e90beb 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -260,6 +260,12 @@
No SIP contact in your address book.
No chat history.
+ Audio
+ Codec:
+ Upload bandwidth:
+ Download bandwidth:
+ ICE connectivity:
+
Add to contacts button
diff --git a/src/org/linphone/AudioCallFragment.java b/src/org/linphone/AudioCallFragment.java
index af9062886..ecfdc157a 100644
--- a/src/org/linphone/AudioCallFragment.java
+++ b/src/org/linphone/AudioCallFragment.java
@@ -17,9 +17,13 @@ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+import java.util.Timer;
+import java.util.TimerTask;
+
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCall.State;
+import org.linphone.core.LinphoneCallStats;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.ui.AvatarWithShadow;
@@ -27,17 +31,21 @@ import android.app.Activity;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
+import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import android.widget.ViewFlipper;
/**
* @author Sylvain Berfini
@@ -51,6 +59,10 @@ public class AudioCallFragment extends Fragment implements OnClickListener {
private static final int conferenceMargin = 20;
private static final int topMarginWithImage = topMargin + rowImageHeight + botMarginIfImage;
+ private static final int FLIPPER_AVATAR_VIEW = 0;
+ private static final int FLIPPER_AUDIO_STATS_VIEW = 1;
+
+ private Handler mHandler = new Handler();
private RelativeLayout callsList;
private LayoutInflater inflater;
private ViewGroup container;
@@ -93,7 +105,7 @@ public class AudioCallFragment extends Fragment implements OnClickListener {
setContactName(callView, lAddress, sipUri, resources);
boolean hide = displayCallStatusIconAndReturnCallPaused(callView, call);
- displayOrHideContactPicture(callView, pictureUri, hide);
+ displayOrHideContactPictureAndStats(callView, pictureUri, call, hide);
setRowBackgroundAndPadding(callView, resources, index, call, !hide);
registerCallDurationTimer(callView, call);
previousCallIsActive = !hide;
@@ -142,14 +154,94 @@ public class AudioCallFragment extends Fragment implements OnClickListener {
return isCallPaused || isInConference;
}
- private void displayOrHideContactPicture(LinearLayout callView, Uri pictureUri, boolean hide) {
+ private void displayOrHideContactPictureAndStats(LinearLayout callView, Uri pictureUri, LinphoneCall call, boolean hide) {
+ ViewFlipper flipper = (ViewFlipper) callView.findViewById(R.id.flipper);
+ flipper.setDisplayedChild(FLIPPER_AVATAR_VIEW);
+
AvatarWithShadow contactPicture = (AvatarWithShadow) callView.findViewById(R.id.contactPicture);
if (pictureUri != null) {
LinphoneUtils.setImagePictureFromUri(callView.getContext(), contactPicture.getView(), Uri.parse(pictureUri.toString()), R.drawable.unknown_small);
}
if (hide) {
- contactPicture.setVisibility(View.GONE);
+ flipper.setVisibility(View.GONE);
}
+
+ if (getActivity().getResources().getBoolean(R.bool.display_call_stats)) {
+ View audioCallstats = callView.findViewById(R.id.audioCallStats);
+ if (call != null) {
+ flipper.setEnabled(true);
+ initAudioStatsRefresher(call, audioCallstats);
+ initFlipperListeners(flipper);
+ }
+ } else {
+ flipper.setEnabled(false);
+ }
+ }
+
+ private void initAudioStatsRefresher(final LinphoneCall call, final View view) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ final Timer timer = new Timer();
+ TimerTask lTask = new TimerTask() {
+ @Override
+ public void run() {
+ if (call == null) {
+ timer.cancel();
+ return;
+ }
+ final LinphoneCallStats audioStats = call.getAudioStats();
+ if (audioStats != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ TextView codec = (TextView) view.findViewById(R.id.audioCodec);
+ TextView dl = (TextView) view.findViewById(R.id.audioDownloadBandwith);
+ TextView ul = (TextView) view.findViewById(R.id.audioUploadBandwith);
+ TextView ice = (TextView) view.findViewById(R.id.ice);
+ if (codec == null || dl == null || ul == null || ice == null) {
+ timer.cancel();
+ return;
+ }
+ codec.setText(call.getCurrentParamsCopy().getUsedAudioCodec().getMime());
+ dl.setText(String.valueOf((int) audioStats.getDownloadBandwidth()) + " kbits/s");
+ ul.setText(String.valueOf((int) audioStats.getUploadBandwidth()) + " kbits/s");
+ ice.setText(audioStats.getIceState().toString());
+ }
+ });
+ }
+ }
+ };
+ timer.scheduleAtFixedRate(lTask, 0, 1500);
+ }
+ }).start();
+ }
+
+ private void initFlipperListeners(final ViewFlipper flipper) {
+ SwipeListener swipeListener = new SwipeListener() {
+ int currentView = FLIPPER_AVATAR_VIEW;
+
+ @Override
+ public void onLeftToRightSwipe() {
+ if (currentView == FLIPPER_AVATAR_VIEW) {
+ currentView = FLIPPER_AUDIO_STATS_VIEW;
+ } else {
+ currentView = FLIPPER_AVATAR_VIEW;
+ }
+ flipper.setDisplayedChild(currentView);
+ }
+
+ @Override
+ public void onRightToLeftSwipe() {
+ if (currentView == FLIPPER_AUDIO_STATS_VIEW) {
+ currentView = FLIPPER_AVATAR_VIEW;
+ } else {
+ currentView = FLIPPER_AUDIO_STATS_VIEW;
+ }
+ flipper.setDisplayedChild(currentView);
+ }
+ };
+ flipper.setOnTouchListener(new SwipeGestureDetector(swipeListener));
}
private void setRowBackgroundAndPadding(LinearLayout callView, Resources resources, int index, LinphoneCall call, boolean active) {
@@ -265,4 +357,48 @@ public class AudioCallFragment extends Fragment implements OnClickListener {
callsList.invalidate();
}
+
+ class SwipeGestureDetector implements OnTouchListener {
+ static final int MIN_DISTANCE = 100;
+ private float downX, upX;
+ private boolean lock;
+
+ private SwipeListener listener;
+
+ public SwipeGestureDetector(SwipeListener swipeListener) {
+ super();
+ listener = swipeListener;
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch(event.getAction()){
+ case MotionEvent.ACTION_DOWN:
+ lock = false;
+ downX = event.getX();
+ return true;
+
+ case MotionEvent.ACTION_MOVE:
+ if (lock) {
+ return false;
+ }
+ upX = event.getX();
+
+ float deltaX = downX - upX;
+
+ if (Math.abs(deltaX) > MIN_DISTANCE) {
+ lock = true;
+ if (deltaX < 0) { listener.onLeftToRightSwipe(); return true; }
+ if (deltaX > 0) { listener.onRightToLeftSwipe(); return true; }
+ }
+ break;
+ }
+ return false;
+ }
+ }
+
+ interface SwipeListener {
+ void onRightToLeftSwipe();
+ void onLeftToRightSwipe();
+ }
}
diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java
index 9d745eb7e..cccb02a50 100644
--- a/src/org/linphone/LinphoneManager.java
+++ b/src/org/linphone/LinphoneManager.java
@@ -494,13 +494,13 @@ public final class LinphoneManager implements LinphoneCoreListener {
} catch (LinphoneException e) {
Log.w("no config ready yet");
}
+
TimerTask lTask = new TimerTask() {
@Override
public void run() {
mLc.iterate();
}
};
-
mTimer.scheduleAtFixedRate(lTask, 0, 20);
IntentFilter lFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);