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);