Added audio call stats

This commit is contained in:
Sylvain Berfini 2012-09-26 12:57:05 +02:00
parent 5e675d06d8
commit f400b4c562
7 changed files with 291 additions and 12 deletions

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/cancel_white_bg_over" />
android:drawable="@drawable/back_over" />
<item android:state_enabled="false"
android:drawable="@drawable/cancel_white_bg_disabled" />
android:drawable="@drawable/back_disabled" />
<item
android:drawable="@drawable/cancel_white_bg_default" />
android:drawable="@drawable/back_default" />
</selector>

View file

@ -45,12 +45,140 @@
</LinearLayout>
<org.linphone.ui.AvatarWithShadow
android:id="@+id/contactPicture"
android:layout_width="wrap_content"
<ViewFlipper
android:id="@+id/flipper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
linphone:picture="@drawable/unknown_small"
android:layout_gravity="center"
android:paddingBottom="10dp" />
android:paddingBottom="10dp">
<org.linphone.ui.AvatarWithShadow
android:id="@+id/contactPicture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top"
linphone:picture="@drawable/unknown_small" />
<TableLayout
android:id="@+id/audioCallStats"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="5dp">
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left|center_vertical"
android:text="@string/call_stats_audio"
android:textStyle="bold"
android:textColor="@color/text_default"
android:textSize="18dp"/>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left|center_vertical"
android:text="@string/call_stats_codec"
android:textStyle="bold"
android:textColor="@android:color/black"
android:textSize="14dp"/>
<TextView
android:id="@+id/audioCodec"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:gravity="right|center_vertical"
android:textColor="@android:color/black"
android:textSize="14dp"/>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left|center_vertical"
android:text="@string/call_stats_upload"
android:textStyle="bold"
android:textColor="@android:color/black"
android:textSize="14dp"/>
<TextView
android:id="@+id/audioUploadBandwith"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:gravity="right|center_vertical"
android:textColor="@android:color/black"
android:textSize="14dp"/>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left|center_vertical"
android:text="@string/call_stats_download"
android:textColor="@android:color/black"
android:textStyle="bold"
android:textSize="14dp"/>
<TextView
android:id="@+id/audioDownloadBandwith"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:gravity="right|center_vertical"
android:textColor="@android:color/black"
android:textSize="14dp"/>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left|center_vertical"
android:text="@string/call_stats_ice"
android:textStyle="bold"
android:textColor="@android:color/black"
android:textSize="14dp"/>
<TextView
android:id="@+id/ice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:gravity="right|center_vertical"
android:textColor="@android:color/black"
android:textSize="14dp"/>
</TableRow>
</TableLayout>
</ViewFlipper>
</LinearLayout>

View file

@ -210,6 +210,12 @@
<string name="no_sip_contact">Aucun contact SIP dans votre carnet d\'adresse.</string>
<string name="no_chat_history">Aucun historique de chat.</string>
<string name="call_stats_audio">Audio</string>
<string name="call_stats_codec">Codec :</string>
<string name="call_stats_upload">Bande passante envoi :</string>
<string name="call_stats_download">Bande passante reception :</string>
<string name="call_stats_ice">Connexion ICE :</string>
<!-- Used by Android to help blind people by describing them images -->
<string name="content_description_add_contact"></string>
<string name="content_description_about"></string>

View file

@ -28,6 +28,9 @@
<bool name="display_messages_time_and_status">true</bool> <!-- Used to show the time of each message arrival -->
<bool name="display_time_aside">false</bool> <!-- if display_messages_time = true, display time on the side of the message instead of below -->
<bool name="display_call_stats">true</bool>
<!-- Behavior Settings -->
<bool name="call_last_log_if_adress_is_empty">true</bool>
<bool name="allow_ringing_while_early_media">true</bool>
<bool name="allow_transfers">true</bool>

View file

@ -260,6 +260,12 @@
<string name="no_sip_contact">No SIP contact in your address book.</string>
<string name="no_chat_history">No chat history.</string>
<string name="call_stats_audio">Audio</string>
<string name="call_stats_codec">Codec:</string>
<string name="call_stats_upload">Upload bandwidth:</string>
<string name="call_stats_download">Download bandwidth:</string>
<string name="call_stats_ice">ICE connectivity:</string>
<!-- Used by Android to help blind people by describing them images -->
<string name="content_description_add_contact">Add to contacts button</string>
<string name="content_description_about"></string>

View file

@ -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();
}
}

View file

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