management of statistics by calls

This commit is contained in:
Claire Rosset 2019-06-20 14:51:47 +02:00 committed by Sylvain Berfini
parent 0c875fc4e9
commit f81910644a
9 changed files with 1297 additions and 610 deletions

View file

@ -173,3 +173,6 @@ Group changes to describe their impact on the project, as follows:
- Crashes Android 6/7 at starting
- Permissions issues
- Layout of tablet views
### Changed
- management of the view for displaying call statistics

View file

@ -0,0 +1,168 @@
package org.linphone.call;
/*
CallStatsAdapter.java
Copyright (C) 2019 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 android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import java.util.ArrayList;
import java.util.List;
import org.linphone.R;
import org.linphone.contacts.ContactsManager;
import org.linphone.contacts.LinphoneContact;
import org.linphone.core.Call;
import org.linphone.utils.LinphoneUtils;
import org.linphone.views.ContactAvatar;
public class CallStatsAdapter extends BaseExpandableListAdapter {
private final Context mContext;
private List<Call> mCalls;
public CallStatsAdapter(Context mContext) {
this.mContext = mContext;
mCalls = new ArrayList<>();
}
public void updateListItems(List<Call> listCall) {
if (listCall != null) {
mCalls = listCall;
notifyDataSetChanged();
}
}
@Override
public View getChildView(
int groupPosition,
int childPosition,
boolean isLastChild,
View view,
ViewGroup viewGroup) {
CallStatsChildViewHolder holder;
if (view != null) {
Object possibleHolder = view.getTag();
if (possibleHolder instanceof CallStatsChildViewHolder) {
holder = (CallStatsChildViewHolder) possibleHolder;
view.setTag(holder);
}
} else {
// opening the statistics view
LayoutInflater inflater = LayoutInflater.from(mContext);
view = inflater.inflate(R.layout.call_stats_child, viewGroup, false);
}
// filling the view
holder = new CallStatsChildViewHolder(view, mContext);
view.setTag(holder);
holder.setCall(mCalls.get(groupPosition));
return view;
}
@Override
public View getGroupView(
int groupPosition, boolean isExpanded, View view, ViewGroup viewGroup) {
CallStatsViewHolder holder = null;
if (view != null) {
Object possibleHolder = view.getTag();
if (possibleHolder instanceof CallStatsViewHolder) {
holder = (CallStatsViewHolder) possibleHolder;
}
} else {
LayoutInflater inflater = LayoutInflater.from(mContext);
view = inflater.inflate(R.layout.call_stats_group, viewGroup, false);
}
if (holder == null) {
holder = new CallStatsViewHolder(view);
view.setTag(holder);
}
// Recovering the current call
Call call = (Call) getGroup(groupPosition);
// Search for the associated contact
LinphoneContact contact =
ContactsManager.getInstance().findContactFromAddress(call.getRemoteAddress());
if (contact != null) {
// Setting up the avatar
ContactAvatar.displayAvatar(contact, holder.avatarLayout);
// addition of the participant's name
holder.participantName.setText(contact.getFullName());
} else {
String displayName = LinphoneUtils.getAddressDisplayName(call.getRemoteAddress());
ContactAvatar.displayAvatar(displayName, holder.avatarLayout);
holder.participantName.setText(displayName);
}
// add sip address on group view
holder.sipUri.setText(call.getRemoteAddress().asString());
return view;
}
@Override
public int getGroupCount() {
return mCalls.size();
}
@Override
public int getChildrenCount(int groupPosition) {
return 1;
}
@Override
public Object getGroup(int groupPosition) {
if (mCalls.isEmpty() && groupPosition < mCalls.size()) {
return null;
}
return mCalls.get(groupPosition);
}
@Override
public Object getChild(int groupPosition, int childPosition) {
if (mCalls.isEmpty() && groupPosition < mCalls.size()) {
return null;
}
return mCalls.get(groupPosition);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return groupPosition;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return false;
}
}

View file

@ -0,0 +1,396 @@
package org.linphone.call;
/*
CallStatsChildViewHolder.java
Copyright (C) 2019 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 android.os.Handler;
import android.text.Html;
import android.view.View;
import android.widget.TextView;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.AddressFamily;
import org.linphone.core.Call;
import org.linphone.core.CallListenerStub;
import org.linphone.core.CallParams;
import org.linphone.core.CallStats;
import org.linphone.core.PayloadType;
import org.linphone.core.StreamType;
public class CallStatsChildViewHolder {
private Timer mTimer;
private Call mCall;
private final Handler mHandler = new Handler();
private CallListenerStub mListener;
private HashMap<String, String> mEncoderTexts;
private HashMap<String, String> mDecoderTexts;
private Context mContext;
private TextView mTitleAudio;
private TextView mTitleVideo;
private TextView mCodecAudio;
private TextView mCodecVideo;
private TextView mEncoderAudio;
private TextView mDecoderAudio;
private TextView mEncoderVideo;
private TextView mDecoderVideo;
private TextView mDisplayFilter;
private TextView mDlAudio;
private TextView mUlAudio;
private TextView mDlVideo;
private TextView mUlVideo;
private TextView mEdlVideo;
private TextView mIceAudio;
private TextView mIceVideo;
private TextView mVideoResolutionSent;
private TextView mVideoResolutionReceived;
private TextView mVideoFpsSent;
private TextView mVideoFpsReceived;
private TextView mSenderLossRateAudio;
private TextView mReceiverLossRateAudio;
private TextView mSenderLossRateVideo;
private TextView mReceiverLossRateVideo;
private TextView mIpAudio;
private TextView mIpVideo;
private TextView mJitterBufferAudio;
private View mVideoLayout;
private View mAudioLayout;
public CallStatsChildViewHolder(View view, Context context) {
mContext = context;
mEncoderTexts = new HashMap<>();
mDecoderTexts = new HashMap<>();
mTitleAudio = view.findViewById(R.id.call_stats_audio);
mTitleVideo = view.findViewById(R.id.call_stats_video);
mCodecAudio = view.findViewById(R.id.codec_audio);
mCodecVideo = view.findViewById(R.id.codec_video);
mEncoderAudio = view.findViewById(R.id.encoder_audio);
mDecoderAudio = view.findViewById(R.id.decoder_audio);
mEncoderVideo = view.findViewById(R.id.encoder_video);
mDecoderVideo = view.findViewById(R.id.decoder_video);
mDisplayFilter = view.findViewById(R.id.display_filter);
mDlAudio = view.findViewById(R.id.downloadBandwith_audio);
mUlAudio = view.findViewById(R.id.uploadBandwith_audio);
mDlVideo = view.findViewById(R.id.downloadBandwith_video);
mUlVideo = view.findViewById(R.id.uploadBandwith_video);
mEdlVideo = view.findViewById(R.id.estimatedDownloadBandwidth_video);
mIceAudio = view.findViewById(R.id.ice_audio);
mIceVideo = view.findViewById(R.id.ice_video);
mVideoResolutionSent = view.findViewById(R.id.video_resolution_sent);
mVideoResolutionReceived = view.findViewById(R.id.video_resolution_received);
mVideoFpsSent = view.findViewById(R.id.video_fps_sent);
mVideoFpsReceived = view.findViewById(R.id.video_fps_received);
mSenderLossRateAudio = view.findViewById(R.id.senderLossRateAudio);
mReceiverLossRateAudio = view.findViewById(R.id.receiverLossRateAudio);
mSenderLossRateVideo = view.findViewById(R.id.senderLossRateVideo);
mReceiverLossRateVideo = view.findViewById(R.id.receiverLossRateVideo);
mIpAudio = view.findViewById(R.id.ip_audio);
mIpVideo = view.findViewById(R.id.ip_video);
mJitterBufferAudio = view.findViewById(R.id.jitterBufferAudio);
mVideoLayout = view.findViewById(R.id.callStatsVideo);
mAudioLayout = view.findViewById(R.id.callStatsAudio);
mListener =
new CallListenerStub() {
public void onStateChanged(Call call, Call.State cstate, String message) {
if (cstate == Call.State.End || cstate == Call.State.Error) {
if (mTimer != null) {
org.linphone.core.tools.Log.i(
"[Call Stats] Call is terminated, stopping mCountDownTimer in charge of stats refreshing.");
mTimer.cancel();
}
}
}
};
}
public void setCall(Call call) {
if (mCall != null) {
mCall.removeListener(mListener);
}
mCall = call;
mCall.addListener(mListener);
init();
}
private void init() {
TimerTask mTask;
mTimer = new Timer();
mTask =
new TimerTask() {
@Override
public void run() {
if (mCall == null) {
mTimer.cancel();
return;
}
if (mTitleAudio == null
|| mCodecAudio == null
|| mDlVideo == null
|| mEdlVideo == null
|| mIceAudio == null
|| mVideoResolutionSent == null
|| mVideoLayout == null
|| mTitleVideo == null
|| mIpVideo == null
|| mIpAudio == null
|| mCodecVideo == null
|| mDlAudio == null
|| mUlAudio == null
|| mUlVideo == null
|| mIceVideo == null
|| mVideoResolutionReceived == null) {
mTimer.cancel();
return;
}
mHandler.post(
new Runnable() {
@Override
public void run() {
if (mCall == null) {
return;
}
if (mCall.getState() != Call.State.Released) {
CallParams params = mCall.getCurrentParams();
if (params != null) {
CallStats audioStats =
mCall.getStats(StreamType.Audio);
CallStats videoStats = null;
if (params.videoEnabled())
videoStats = mCall.getStats(StreamType.Video);
PayloadType payloadAudio =
params.getUsedAudioPayloadType();
PayloadType payloadVideo =
params.getUsedVideoPayloadType();
formatText(
mDisplayFilter,
mContext.getString(
R.string.call_stats_display_filter),
mCall.getCore().getVideoDisplayFilter());
displayMediaStats(
params,
audioStats,
payloadAudio,
mAudioLayout,
mTitleAudio,
mCodecAudio,
mDlAudio,
mUlAudio,
null,
mIceAudio,
mIpAudio,
mSenderLossRateAudio,
mReceiverLossRateAudio,
mEncoderAudio,
mDecoderAudio,
null,
null,
null,
null,
false,
mJitterBufferAudio);
displayMediaStats(
params,
videoStats,
payloadVideo,
mVideoLayout,
mTitleVideo,
mCodecVideo,
mDlVideo,
mUlVideo,
mEdlVideo,
mIceVideo,
mIpVideo,
mSenderLossRateVideo,
mReceiverLossRateVideo,
mEncoderVideo,
mDecoderVideo,
mVideoResolutionSent,
mVideoResolutionReceived,
mVideoFpsSent,
mVideoFpsReceived,
true,
null);
}
}
}
});
}
};
mTimer.scheduleAtFixedRate(mTask, 0, 1000);
}
private void displayMediaStats(
CallParams params,
CallStats stats,
PayloadType media,
View layout,
TextView title,
TextView codec,
TextView dl,
TextView ul,
TextView edl,
TextView ice,
TextView ip,
TextView senderLossRate,
TextView receiverLossRate,
TextView enc,
TextView dec,
TextView videoResolutionSent,
TextView videoResolutionReceived,
TextView videoFpsSent,
TextView videoFpsReceived,
boolean isVideo,
TextView jitterBuffer) {
if (stats != null) {
String mime = null;
layout.setVisibility(View.VISIBLE);
title.setVisibility(TextView.VISIBLE);
if (media != null) {
mime = media.getMimeType();
formatText(
codec,
mContext.getString(R.string.call_stats_codec),
mime + " / " + (media.getClockRate() / 1000) + "kHz");
}
if (mime != null) {
formatText(
enc,
mContext.getString(R.string.call_stats_encoder_name),
getEncoderText(mime));
formatText(
dec,
mContext.getString(R.string.call_stats_decoder_name),
getDecoderText(mime));
}
formatText(
dl,
mContext.getString(R.string.call_stats_download),
(int) stats.getDownloadBandwidth() + " kbits/s");
formatText(
ul,
mContext.getString(R.string.call_stats_upload),
(int) stats.getUploadBandwidth() + " kbits/s");
if (isVideo) {
formatText(
edl,
mContext.getString(R.string.call_stats_estimated_download),
stats.getEstimatedDownloadBandwidth() + " kbits/s");
}
formatText(
ice,
mContext.getString(R.string.call_stats_ice),
stats.getIceState().toString());
formatText(
ip,
mContext.getString(R.string.call_stats_ip),
(stats.getIpFamilyOfRemote() == AddressFamily.Inet6)
? "IpV6"
: (stats.getIpFamilyOfRemote() == AddressFamily.Inet)
? "IpV4"
: "Unknown");
formatText(
senderLossRate,
mContext.getString(R.string.call_stats_sender_loss_rate),
new DecimalFormat("##.##").format(stats.getSenderLossRate()) + "%");
formatText(
receiverLossRate,
mContext.getString(R.string.call_stats_receiver_loss_rate),
new DecimalFormat("##.##").format(stats.getReceiverLossRate()) + "%");
if (isVideo) {
formatText(
videoResolutionSent,
mContext.getString(R.string.call_stats_video_resolution_sent),
"\u2191 " + params.getSentVideoDefinition() != null
? params.getSentVideoDefinition().getName()
: "");
formatText(
videoResolutionReceived,
mContext.getString(R.string.call_stats_video_resolution_received),
"\u2193 " + params.getReceivedVideoDefinition() != null
? params.getReceivedVideoDefinition().getName()
: "");
formatText(
videoFpsSent,
mContext.getString(R.string.call_stats_video_fps_sent),
"\u2191 " + params.getSentFramerate());
formatText(
videoFpsReceived,
mContext.getString(R.string.call_stats_video_fps_received),
"\u2193 " + params.getReceivedFramerate());
} else {
formatText(
jitterBuffer,
mContext.getString(R.string.call_stats_jitter_buffer),
new DecimalFormat("##.##").format(stats.getJitterBufferSizeMs()) + " ms");
}
} else {
layout.setVisibility(View.GONE);
title.setVisibility(TextView.GONE);
}
}
private String getEncoderText(String mime) {
String ret = mEncoderTexts.get(mime);
if (ret == null) {
org.linphone.mediastream.Factory msfactory =
LinphoneManager.getCore().getMediastreamerFactory();
ret = msfactory.getEncoderText(mime);
mEncoderTexts.put(mime, ret);
}
return ret;
}
private String getDecoderText(String mime) {
String ret = mDecoderTexts.get(mime);
if (ret == null) {
org.linphone.mediastream.Factory msfactory =
LinphoneManager.getCore().getMediastreamerFactory();
ret = msfactory.getDecoderText(mime);
mDecoderTexts.put(mime, ret);
}
return ret;
}
private void formatText(TextView tv, String name, String value) {
tv.setText(Html.fromHtml("<b>" + name + " </b>" + value));
}
}

View file

@ -21,87 +21,75 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import android.app.Fragment;
import android.os.Bundle;
import android.os.Handler;
import android.text.Html;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ExpandableListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.drawerlayout.widget.DrawerLayout;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Arrays;
import org.linphone.LinphoneManager;
import org.linphone.R;
import org.linphone.core.AddressFamily;
import org.linphone.core.Call;
import org.linphone.core.CallListenerStub;
import org.linphone.core.CallParams;
import org.linphone.core.CallStats;
import org.linphone.core.Core;
import org.linphone.core.PayloadType;
import org.linphone.core.StreamType;
import org.linphone.core.tools.Log;
import org.linphone.core.CoreListenerStub;
public class CallStatsFragment extends Fragment {
private final Handler mHandler = new Handler();
private Timer mTimer;
private TimerTask mTask;
private View mView;
private DrawerLayout mSideMenu;
private RelativeLayout mSideMenuContent;
private HashMap<String, String> mEncoderTexts;
private HashMap<String, String> mDecoderTexts;
private Call mCall;
private CallListenerStub mListener;
private RelativeLayout mSideMenuContent;;
private ExpandableListView mExpandableList;
private CallStatsAdapter mAdapter;
private CoreListenerStub mListener;
@Nullable
@Override
public View onCreateView(
LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.call_stats, container, false);
mView = view;
mEncoderTexts = new HashMap<>();
mDecoderTexts = new HashMap<>();
mExpandableList = view.findViewById(R.id.devices_list);
mListener =
new CallListenerStub() {
public void onStateChanged(Call call, Call.State cstate, String message) {
new CoreListenerStub() {
@Override
public void onCallStateChanged(
Core lc, Call call, Call.State cstate, String message) {
if (cstate == Call.State.End || cstate == Call.State.Error) {
if (mTimer != null) {
Log.i(
"[Call Stats] Call is terminated, stopping mCountDownTimer in charge of stats refreshing.");
mTimer.cancel();
}
mAdapter.updateListItems(
Arrays.asList(LinphoneManager.getCore().getCalls()));
}
}
};
return view;
}
@Override
public void onResume() {
super.onResume();
Core core = LinphoneManager.getCore();
if (core != null) {
setCall(core.getCurrentCall());
if (mAdapter == null) {
mAdapter = new CallStatsAdapter(getActivity());
mExpandableList.setAdapter(mAdapter);
// allows you to open the first child in the list
mExpandableList.expandGroup(0);
}
// Sends calls from the list to the adapter
if (core != null && core.getCallsNb() >= 1) {
mAdapter.updateListItems(Arrays.asList(core.getCalls()));
}
core.addListener(mListener);
}
@Override
public void onPause() {
setCall(null);
super.onPause();
LinphoneManager.getCore().removeListener(mListener);
}
public void setDrawer(DrawerLayout drawer, RelativeLayout content) {
@ -131,294 +119,4 @@ public class CallStatsFragment extends Fragment {
mSideMenu.closeDrawer(mSideMenuContent, animate);
}
}
public void setCall(Call call) {
if (mCall != null) {
mCall.removeListener(mListener);
}
mCall = call;
init(mView);
}
private void init(View view) {
if (getResources().getBoolean(R.bool.hide_in_call_stats)) return;
if (mTimer != null && mTask != null) {
mTimer.cancel();
mTimer = null;
mTask = null;
}
if (mCall == null) {
return;
}
final TextView titleAudio = view.findViewById(R.id.call_stats_audio);
final TextView titleVideo = view.findViewById(R.id.call_stats_video);
final TextView codecAudio = view.findViewById(R.id.codec_audio);
final TextView codecVideo = view.findViewById(R.id.codec_video);
final TextView encoderAudio = view.findViewById(R.id.encoder_audio);
final TextView decoderAudio = view.findViewById(R.id.decoder_audio);
final TextView encoderVideo = view.findViewById(R.id.encoder_video);
final TextView decoderVideo = view.findViewById(R.id.decoder_video);
final TextView displayFilter = view.findViewById(R.id.display_filter);
final TextView dlAudio = view.findViewById(R.id.downloadBandwith_audio);
final TextView ulAudio = view.findViewById(R.id.uploadBandwith_audio);
final TextView dlVideo = view.findViewById(R.id.downloadBandwith_video);
final TextView ulVideo = view.findViewById(R.id.uploadBandwith_video);
final TextView edlVideo = view.findViewById(R.id.estimatedDownloadBandwidth_video);
final TextView iceAudio = view.findViewById(R.id.ice_audio);
final TextView iceVideo = view.findViewById(R.id.ice_video);
final TextView videoResolutionSent = view.findViewById(R.id.video_resolution_sent);
final TextView videoResolutionReceived = view.findViewById(R.id.video_resolution_received);
final TextView videoFpsSent = view.findViewById(R.id.video_fps_sent);
final TextView videoFpsReceived = view.findViewById(R.id.video_fps_received);
final TextView senderLossRateAudio = view.findViewById(R.id.senderLossRateAudio);
final TextView receiverLossRateAudio = view.findViewById(R.id.receiverLossRateAudio);
final TextView senderLossRateVideo = view.findViewById(R.id.senderLossRateVideo);
final TextView receiverLossRateVideo = view.findViewById(R.id.receiverLossRateVideo);
final TextView ipAudio = view.findViewById(R.id.ip_audio);
final TextView ipVideo = view.findViewById(R.id.ip_video);
final TextView jitterBufferAudio = view.findViewById(R.id.jitterBufferAudio);
final View videoLayout = view.findViewById(R.id.callStatsVideo);
final View audioLayout = view.findViewById(R.id.callStatsAudio);
mTimer = new Timer();
mTask =
new TimerTask() {
@Override
public void run() {
if (mCall == null) {
mTimer.cancel();
return;
}
if (titleAudio == null
|| codecAudio == null
|| dlVideo == null
|| edlVideo == null
|| iceAudio == null
|| videoResolutionSent == null
|| videoLayout == null
|| titleVideo == null
|| ipVideo == null
|| ipAudio == null
|| codecVideo == null
|| dlAudio == null
|| ulAudio == null
|| ulVideo == null
|| iceVideo == null
|| videoResolutionReceived == null) {
mTimer.cancel();
return;
}
mHandler.post(
new Runnable() {
@Override
public void run() {
if (mCall == null) return;
if (mCall.getState() != Call.State.Released) {
CallParams params = mCall.getCurrentParams();
if (params != null) {
CallStats audioStats =
mCall.getStats(StreamType.Audio);
CallStats videoStats = null;
if (params.videoEnabled())
videoStats = mCall.getStats(StreamType.Video);
PayloadType payloadAudio =
params.getUsedAudioPayloadType();
PayloadType payloadVideo =
params.getUsedVideoPayloadType();
formatText(
displayFilter,
getString(
R.string.call_stats_display_filter),
mCall.getCore().getVideoDisplayFilter());
displayMediaStats(
params,
audioStats,
payloadAudio,
audioLayout,
titleAudio,
codecAudio,
dlAudio,
ulAudio,
null,
iceAudio,
ipAudio,
senderLossRateAudio,
receiverLossRateAudio,
encoderAudio,
decoderAudio,
null,
null,
null,
null,
false,
jitterBufferAudio);
displayMediaStats(
params,
videoStats,
payloadVideo,
videoLayout,
titleVideo,
codecVideo,
dlVideo,
ulVideo,
edlVideo,
iceVideo,
ipVideo,
senderLossRateVideo,
receiverLossRateVideo,
encoderVideo,
decoderVideo,
videoResolutionSent,
videoResolutionReceived,
videoFpsSent,
videoFpsReceived,
true,
null);
}
}
}
});
}
};
mCall.addListener(mListener);
mTimer.scheduleAtFixedRate(mTask, 0, 1000);
}
private void formatText(TextView tv, String name, String value) {
tv.setText(Html.fromHtml("<b>" + name + " </b>" + value));
}
private String getEncoderText(String mime) {
String ret = mEncoderTexts.get(mime);
if (ret == null) {
org.linphone.mediastream.Factory msfactory =
LinphoneManager.getCore().getMediastreamerFactory();
ret = msfactory.getEncoderText(mime);
mEncoderTexts.put(mime, ret);
}
return ret;
}
private String getDecoderText(String mime) {
String ret = mDecoderTexts.get(mime);
if (ret == null) {
org.linphone.mediastream.Factory msfactory =
LinphoneManager.getCore().getMediastreamerFactory();
ret = msfactory.getDecoderText(mime);
mDecoderTexts.put(mime, ret);
}
return ret;
}
private void displayMediaStats(
CallParams params,
CallStats stats,
PayloadType media,
View layout,
TextView title,
TextView codec,
TextView dl,
TextView ul,
TextView edl,
TextView ice,
TextView ip,
TextView senderLossRate,
TextView receiverLossRate,
TextView enc,
TextView dec,
TextView videoResolutionSent,
TextView videoResolutionReceived,
TextView videoFpsSent,
TextView videoFpsReceived,
boolean isVideo,
TextView jitterBuffer) {
if (stats != null) {
String mime = null;
layout.setVisibility(View.VISIBLE);
title.setVisibility(TextView.VISIBLE);
if (media != null) {
mime = media.getMimeType();
formatText(
codec,
getString(R.string.call_stats_codec),
mime + " / " + (media.getClockRate() / 1000) + "kHz");
}
if (mime != null) {
formatText(enc, getString(R.string.call_stats_encoder_name), getEncoderText(mime));
formatText(dec, getString(R.string.call_stats_decoder_name), getDecoderText(mime));
}
formatText(
dl,
getString(R.string.call_stats_download),
(int) stats.getDownloadBandwidth() + " kbits/s");
formatText(
ul,
getString(R.string.call_stats_upload),
(int) stats.getUploadBandwidth() + " kbits/s");
if (isVideo) {
formatText(
edl,
getString(R.string.call_stats_estimated_download),
stats.getEstimatedDownloadBandwidth() + " kbits/s");
}
formatText(ice, getString(R.string.call_stats_ice), stats.getIceState().toString());
formatText(
ip,
getString(R.string.call_stats_ip),
(stats.getIpFamilyOfRemote() == AddressFamily.Inet6)
? "IpV6"
: (stats.getIpFamilyOfRemote() == AddressFamily.Inet)
? "IpV4"
: "Unknown");
formatText(
senderLossRate,
getString(R.string.call_stats_sender_loss_rate),
new DecimalFormat("##.##").format(stats.getSenderLossRate()) + "%");
formatText(
receiverLossRate,
getString(R.string.call_stats_receiver_loss_rate),
new DecimalFormat("##.##").format(stats.getReceiverLossRate()) + "%");
if (isVideo) {
formatText(
videoResolutionSent,
getString(R.string.call_stats_video_resolution_sent),
"\u2191 " + params.getSentVideoDefinition() != null
? params.getSentVideoDefinition().getName()
: "");
formatText(
videoResolutionReceived,
getString(R.string.call_stats_video_resolution_received),
"\u2193 " + params.getReceivedVideoDefinition() != null
? params.getReceivedVideoDefinition().getName()
: "");
formatText(
videoFpsSent,
getString(R.string.call_stats_video_fps_sent),
"\u2191 " + params.getSentFramerate());
formatText(
videoFpsReceived,
getString(R.string.call_stats_video_fps_received),
"\u2193 " + params.getReceivedFramerate());
} else {
formatText(
jitterBuffer,
getString(R.string.call_stats_jitter_buffer),
new DecimalFormat("##.##").format(stats.getJitterBufferSizeMs()) + " ms");
}
} else {
layout.setVisibility(View.GONE);
title.setVisibility(TextView.GONE);
}
}
}

View file

@ -0,0 +1,37 @@
package org.linphone.call;
/*
CallStatsViewHolder.java
Copyright (C) 2019 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.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.linphone.R;
public class CallStatsViewHolder {
public final RelativeLayout avatarLayout;
public final TextView participantName, sipUri;
public CallStatsViewHolder(View v) {
avatarLayout = v.findViewById(R.id.avatar_layout);
participantName = v.findViewById(R.id.name);
sipUri = v.findViewById(R.id.sipUri);
}
}

View file

@ -0,0 +1,306 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/call_stats_audio"
style="@style/call_stats_title_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center"
android:text="@string/call_stats_audio"
tools:gravity="center" />
<TableLayout
android:id="@+id/callStatsAudio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/call_stats_sip_adress"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:paddingLeft="5dp" />
<TextView
android:id="@+id/codec_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_codec" />
<TextView
android:id="@+id/encoder_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_encoder_name" />
<TextView
android:id="@+id/decoder_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_decoder_name" />
<TextView
android:id="@+id/uploadBandwith_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_upload" />
<TextView
android:id="@+id/downloadBandwith_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_download" />
<TextView
android:id="@+id/ice_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ice" />
<TextView
android:id="@+id/ip_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ip" />
<TextView
android:id="@+id/senderLossRateAudio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_sender_loss_rate" />
<TextView
android:id="@+id/receiverLossRateAudio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_receiver_loss_rate" />
<TextView
android:id="@+id/jitterBufferAudio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_jitter_buffer" />
</TableLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/call_stats_video"
style="@style/call_stats_title_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center"
android:text="@string/call_stats_video"
tools:gravity="center" />
<TableLayout
android:id="@+id/callStatsVideo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="left|center"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/codec_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_codec" />
<TextView
android:id="@+id/encoder_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_encoder_name" />
<TextView
android:id="@+id/decoder_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_decoder_name" />
<TextView
android:id="@+id/display_filter"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_decoder_name" />
<TextView
android:id="@+id/uploadBandwith_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_upload" />
<TextView
android:id="@+id/downloadBandwith_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_download" />
<TextView
android:id="@+id/estimatedDownloadBandwidth_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_estimated_download" />
<TextView
android:id="@+id/ice_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ice" />
<TextView
android:id="@+id/ip_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ip" />
<TextView
android:id="@+id/senderLossRateVideo"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_sender_loss_rate" />
<TextView
android:id="@+id/receiverLossRateVideo"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_receiver_loss_rate" />
<TextView
android:id="@+id/video_resolution_sent"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_resolution_sent" />
<TextView
android:id="@+id/video_resolution_received"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_resolution_received" />
<TextView
android:id="@+id/video_fps_sent"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_fps_sent" />
<TextView
android:id="@+id/video_fps_received"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_fps_received" />
</TableLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>

View file

@ -1,285 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/call_stats_audio"
style="@style/call_stats_title_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center"
android:text="@string/call_stats_audio"
tools:gravity="center" />
<TableLayout
android:id="@+id/callStatsAudio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/codec_audio"
style="@style/call_stats_font"
<ExpandableListView
android:id="@+id/devices_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_codec" />
android:divider="?attr/dividerColor"
android:childDivider="?attr/dividerColor"
android:dividerHeight="1dp"
android:groupIndicator="@null" />
<TextView
android:id="@+id/encoder_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_encoder_name" />
<TextView
android:id="@+id/decoder_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_decoder_name" />
<TextView
android:id="@+id/uploadBandwith_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_upload" />
<TextView
android:id="@+id/downloadBandwith_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_download" />
<TextView
android:id="@+id/ice_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ice" />
<TextView
android:id="@+id/ip_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ip" />
<TextView
android:id="@+id/senderLossRateAudio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_sender_loss_rate" />
<TextView
android:id="@+id/receiverLossRateAudio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_receiver_loss_rate" />
<TextView
android:id="@+id/jitterBufferAudio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_jitter_buffer" />
</TableLayout>
<TextView
android:id="@+id/call_stats_video"
style="@style/call_stats_title_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center"
android:text="@string/call_stats_video"
tools:gravity="center" />
<TableLayout
android:id="@+id/callStatsVideo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="left|center"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/codec_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_codec" />
<TextView
android:id="@+id/encoder_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_encoder_name" />
<TextView
android:id="@+id/decoder_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_decoder_name" />
<TextView
android:id="@+id/display_filter"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_decoder_name" />
<TextView
android:id="@+id/uploadBandwith_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_upload" />
<TextView
android:id="@+id/downloadBandwith_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_download" />
<TextView
android:id="@+id/estimatedDownloadBandwidth_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_estimated_download" />
<TextView
android:id="@+id/ice_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ice" />
<TextView
android:id="@+id/ip_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ip" />
<TextView
android:id="@+id/senderLossRateVideo"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_sender_loss_rate" />
<TextView
android:id="@+id/receiverLossRateVideo"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_receiver_loss_rate" />
<TextView
android:id="@+id/video_resolution_sent"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_resolution_sent" />
<TextView
android:id="@+id/video_resolution_received"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_resolution_received" />
<TextView
android:id="@+id/video_fps_sent"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_fps_sent" />
<TextView
android:id="@+id/video_fps_received"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_fps_received" />
</TableLayout>
</LinearLayout>
</ScrollView>
</RelativeLayout>

View file

@ -0,0 +1,294 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/call_stats_audio"
style="@style/call_stats_title_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center"
android:text="@string/call_stats_audio"
tools:gravity="center" />
<TableLayout
android:id="@+id/callStatsAudio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/call_stats_sip_adress"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:paddingLeft="5dp" />
<TextView
android:id="@+id/codec_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_codec" />
<TextView
android:id="@+id/encoder_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_encoder_name" />
<TextView
android:id="@+id/decoder_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_decoder_name" />
<TextView
android:id="@+id/uploadBandwith_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_upload" />
<TextView
android:id="@+id/downloadBandwith_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_download" />
<TextView
android:id="@+id/ice_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ice" />
<TextView
android:id="@+id/ip_audio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ip" />
<TextView
android:id="@+id/senderLossRateAudio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_sender_loss_rate" />
<TextView
android:id="@+id/receiverLossRateAudio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_receiver_loss_rate" />
<TextView
android:id="@+id/jitterBufferAudio"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_jitter_buffer" />
</TableLayout>
<TextView
android:id="@+id/call_stats_video"
style="@style/call_stats_title_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center"
android:text="@string/call_stats_video"
tools:gravity="center" />
<TableLayout
android:id="@+id/callStatsVideo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="left|center"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/codec_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_codec" />
<TextView
android:id="@+id/encoder_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_encoder_name" />
<TextView
android:id="@+id/decoder_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_decoder_name" />
<TextView
android:id="@+id/display_filter"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_decoder_name" />
<TextView
android:id="@+id/uploadBandwith_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_upload" />
<TextView
android:id="@+id/downloadBandwith_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_download" />
<TextView
android:id="@+id/estimatedDownloadBandwidth_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_estimated_download" />
<TextView
android:id="@+id/ice_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ice" />
<TextView
android:id="@+id/ip_video"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_ip" />
<TextView
android:id="@+id/senderLossRateVideo"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_sender_loss_rate" />
<TextView
android:id="@+id/receiverLossRateVideo"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_receiver_loss_rate" />
<TextView
android:id="@+id/video_resolution_sent"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_resolution_sent" />
<TextView
android:id="@+id/video_resolution_received"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_resolution_received" />
<TextView
android:id="@+id/video_fps_sent"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_fps_sent" />
<TextView
android:id="@+id/video_fps_received"
style="@style/call_stats_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingLeft="5dp"
android:text="@string/call_stats_video_fps_received" />
</TableLayout>
</LinearLayout>
</ScrollView>

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="10dp"
android:gravity="center_vertical">
<RelativeLayout
android:id="@+id/avatar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_margin="5dp"
android:gravity="center">
<include layout="@layout/contact_avatar" />
</RelativeLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp"
android:layout_toLeftOf="@+id/dropdown"
android:layout_toRightOf="@id/avatar"
android:orientation="vertical">
<org.linphone.views.MarqueeTextView
android:id="@+id/name"
style="@style/contact_name_list_cell_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true" />
<org.linphone.views.MarqueeTextView
android:id="@+id/sipUri"
style="@style/sip_uri_small_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"/>
</LinearLayout>
<ImageView
android:id="@id/dropdown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:src="@drawable/chevron_list_close"/>
</RelativeLayout>