测试应用流量的时候,需要区分前台和后台试用的流量,但是目前一些Android 手机自带的流量监控已经没有那么细的一个区分,通常只有一个百分数。由于测试需要我自己写了一个APP 来测试
原理很简单,其实就是 使用 TrafficStats 来获取流量,其api如下:
static long getMobileRxBytes() //获取通过Mobile连接收到的字节总数,不包含WiFi
static long getMobileRxPackets() //获取Mobile连接收到的数据包总数
static long getMobileTxBytes() //Mobile发送的总字节数
static long getMobileTxPackets() //Mobile发送的总数据包数
static long getTotalRxBytes() //获取总的接受字节数,包含Mobile和WiFi等
static long getTotalRxPackets() //总的接受数据包数,包含Mobile和WiFi等
static long getTotalTxBytes() //总的发送字节数,包含Mobile和WiFi等
static long getTotalTxPackets() //发送的总数据包数,包含Mobile和WiFi等
static long getUidRxBytes(int uid) //获取某个网络UID的接受字节数
static long getUidTxBytes(int uid) //获取某个网络UID的发送字节数
代码:
activity_main.xml
<RelativeLayout 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"
android:orientation="vertical"
tools:context="com.maple.trafficmonitoring.MainActivity">
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listView"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="@+id/btnStart" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="流量监控"
android:id="@+id/btnStart"
android:background="@drawable/test_button"
android:textSize="@dimen/text_size_test"
android:textColor="@color/white"
android:layout_above="@+id/btnStart1"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
RelativeLayout>
MainActivity
package com.maple.trafficmonitoring;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.TrafficStats;
import android.os.Parcelable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import java.math.BigDecimal;
import java.util.List;
public class MainActivity extends Activity {
private Button btnStart,btnStart1;
private ListView lstViProgramme; ;
private ProcessInfo processInfo;
private int pid;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnStart = (Button) findViewById(R.id.btnStart);
lstViProgramme = (ListView) findViewById(R.id.listView);
btnStart1 = (Button) findViewById(R.id.btnStart1);
processInfo = new ProcessInfo();
lstViProgramme.setAdapter(new ListAdapter());
lstViProgramme.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
RadioButton rdBtn = (RadioButton) ((LinearLayout) view).getChildAt(0);
rdBtn.setChecked(true);
}
});
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ListAdapter adapter = (ListAdapter) lstViProgramme.getAdapter();
if (adapter.checkedProg != null){
String packageName = adapter.checkedProg.getPackageName();
String APPName = adapter.checkedProg.getProcessName();
Intent intent = new Intent(MainActivity.this,StartMonitor.class);
intent.putExtra("packageName",packageName);
intent.putExtra("APPName",APPName);
startActivity(intent);
}else {
Toast.makeText(MainActivity.this, "请选择需要测试的应用程序", Toast.LENGTH_SHORT).show();
}
}
});
private class ListAdapter extends BaseAdapter {
List programes;
Programe checkedProg;
int lastCheckedPosition = -1;
public ListAdapter() {
programes = processInfo.getAllPackages(getBaseContext());
}
@Override
public int getCount() {
return programes.size();
}
@Override
public Object getItem(int position) {
return programes.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Programe pr = (Programe) programes.get(position);
if (convertView == null)
convertView = getLayoutInflater().inflate(R.layout.list_item, parent, false);
Viewholder holder = (Viewholder) convertView.getTag();
if (holder == null) {
holder = new Viewholder();
convertView.setTag(holder);
holder.imgViAppIcon = (ImageView) convertView.findViewById(R.id.image);
holder.txtAppName = (TextView) convertView.findViewById(R.id.text);
holder.rdoBtnApp = (RadioButton) convertView.findViewById(R.id.rb);
holder.rdoBtnApp.setFocusable(false);
holder.rdoBtnApp.setOnCheckedChangeListener(checkedChangeListener);
}
holder.imgViAppIcon.setImageDrawable(pr.getIcon());
holder.txtAppName.setText(pr.getProcessName());
holder.rdoBtnApp.setId(position);
holder.rdoBtnApp.setChecked(checkedProg != null && getItem(position) == checkedProg);
return convertView;
}
CompoundButton.OnCheckedChangeListener checkedChangeListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
final int checkedPosition = buttonView.getId();
if (lastCheckedPosition != -1) {
RadioButton tempButton = (RadioButton) findViewById(lastCheckedPosition);
if ((tempButton != null) && (lastCheckedPosition != checkedPosition)) {
tempButton.setChecked(false);
}
}
checkedProg = programes.get(checkedPosition);
lastCheckedPosition = checkedPosition;
}
}
};
}
/**
* save status of all installed processes
*
* @author andrewleo
*/
static class Viewholder {
TextView txtAppName;
ImageView imgViAppIcon;
RadioButton rdoBtnApp;
}
}
StartMonitor
package com.maple.trafficmonitoring;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.TrafficStats;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
/**
* Created by liu on 1/12/16.
*/
public class StartMonitor extends Activity{
private Drawable icon ;
private int uid = 0,i;
private String version;
private ImageView imageView;
private TextView tv ,tv2, tv3,tv5,tv4,tv6,tvTime,testTime,tv7;
private Button btnStart;
private int Hcont=0,interval=5,Qcont=0,cont = 0;
private SeekBar timeBar ,TestTimeBar;
private long r;
private long rx;
private long tx;
private long Tms;
private long Htraf=0;
private long Qtraf=0;
private boolean first = false,testEnd=true,isTime=true,SaveCSV = false;
private Context c;
private String packageName;
private String AppName;
private String rt;
private WriteCSV write= new WriteCSV();
private String mDateTime;
private CheckBox chkSaveCsv;
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
@Override
public void run() {
i = Integer.parseInt(String.valueOf(tvTime.getText()))*1000;
int isB = isBackground(c);
rx = TrafficStats.getUidRxBytes(uid);
tx = TrafficStats.getUidTxBytes(uid);
rt = String.valueOf(Qtraf + Htraf);
tv5.setText(getString(R.string.str)+AppName+getString(R.string.UseTotal) + bytes2kb(Qtraf + Htraf));
if (isB==1){
long ms = Hcont * i;
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
formatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00"));
String hms = formatter.format(ms);
Htraf = rx + tx - r - Qtraf;
tv6.setText(getString(R.string.BackgroundOperation) + hms + getString(R.string.useTraffic) +bytes2kb(Htraf) );
Hcont = Hcont + 1;
System.out.println(rx + tx + " " + hms);
writeData("后台",hms,rt,String.valueOf(Qtraf),String.valueOf(Htraf));
}else if (isB == 2) {
long ms =Qcont * i;
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
formatter.setTimeZone(TimeZone.getTimeZone("GMT+00:00"));
String hms = formatter.format(ms);
Qtraf = rx + tx - r - Htraf;
tv7.setText(getString(R.string.foreground) + hms + getString(R.string.useTraffic) +bytes2kb(Qtraf) );
Qcont = Qcont + 1;
System.out.println(rx + tx+ " " + hms);
writeData("前台",hms,rt,String.valueOf(Qtraf),String.valueOf(Htraf));
}
Tms = cont*i;
cont=cont+1;
handler.postDelayed(this, i);// 50是延时时长
if (isB ==3){
Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage(packageName);
startActivity(LaunchIntent);
}
if (!testTime.getText().equals(getString(R.string.timeless))){
int lg = Integer.parseInt(String.valueOf(testTime.getText()));
System.out.println(lg*60*60*1000+" "+Tms);
if (lg*60*60*1000 <= Tms){
stop();
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start_monitor);
ints();
Intent intent = getIntent();
packageName = intent.getStringExtra("packageName");
AppName = intent.getStringExtra("APPName");
PackageManager pm = getPackageManager();
try {
ApplicationInfo ai = pm.getApplicationInfo(packageName,PackageManager.GET_ACTIVITIES);
uid = ai.uid;
icon = ai.loadIcon(pm);
PackageInfo packageInfo = pm.getPackageInfo(packageName,0);
version = packageInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
imageView.setImageDrawable(icon);
tv.setText(getString(R.string.ApplicationName)+AppName);
tv2.setText(getString(R.string.packageName)+packageName);
tv3.setText(getString(R.string.Version)+version);
try {
c = createPackageContext(packageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
Log.e("000000", String.valueOf(c));
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (btnStart.getText().equals(getString(R.string.Start))) {
tv4.setText(R.string.testing);
btnStart.setText(R.string.Stop);
timeBar.setEnabled(false);
TestTimeBar.setEnabled(false);
chkSaveCsv.setClickable(false);
Toast.makeText(StartMonitor.this, R.string.startTest, Toast.LENGTH_SHORT).show();
if(first){
Hcont=1;
Qcont=1;
cont = 1;
}
first=true;
testEnd=false;
Htraf=0;
Qtraf=0;
tv6.setText(getString(R.string.foreground) + "00:00:00" + getString(R.string.useTraffic) +bytes2kb(Htraf) );
tv7.setText(getString(R.string.foreground) + "00:00:00" + getString(R.string.useTraffic) +bytes2kb(Qtraf) );
r = TrafficStats.getUidRxBytes(uid) + TrafficStats.getUidTxBytes(uid);
handler.postDelayed(runnable, i);// 打开定时器,执行操作
}else {
stop();
}
}
});
}
private void stop (){
handler.removeCallbacks(runnable);
tv4.setText(R.string.EndTest);
timeBar.setEnabled(true);
TestTimeBar.setEnabled(true);
chkSaveCsv.setClickable(true);
testEnd=true;
isTime=true;
btnStart.setText(getString(R.string.Start));
}
private void ints (){
imageView = (ImageView) findViewById(R.id.imageView);
tv = (TextView) findViewById(R.id.textView);
tv2 = (TextView) findViewById(R.id.textView2);
tv3 = (TextView) findViewById(R.id.textView3);
tv5 = (TextView) findViewById(R.id.textView5);
tv4 = (TextView) findViewById(R.id.textView4);
tv6 = (TextView) findViewById(R.id.textView6);
tv7 = (TextView) findViewById(R.id.textView7);
chkSaveCsv = (CheckBox) findViewById(R.id.SaveCSV);
chkSaveCsv.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
SaveCSV=isChecked;
}
});
btnStart = (Button) findViewById(R.id.btnStart);
testEnd=true;
testTime = (TextView) findViewById(R.id.TestTime);
testTime.setText(getString(R.string.timeless));
TestTimeBar = (SeekBar) findViewById(R.id.TestTimeline);
TestTimeBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (progress==0){
testTime.setText(getString(R.string.timeless));
}else {
testTime.setText(Integer.toString(progress));
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
tvTime = (TextView) findViewById(R.id.time);
tvTime .setText(String.valueOf(interval));
timeBar = (SeekBar) findViewById(R.id.timeline);
timeBar.setProgress(interval);
timeBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
tvTime.setText(Integer.toString(arg1 + 1));
}
@Override
public void onStartTrackingTouch(SeekBar arg0) {
}
@Override
public void onStopTrackingTouch(SeekBar arg0) {
// when tracking stoped, update preferences
}
});
}
//单位转换
public static String bytes2kb(long bytes) {
BigDecimal filesize = new BigDecimal(bytes);
BigDecimal megabyte = new BigDecimal(1024 * 1024);
float returnValue = filesize.divide(megabyte, 2, BigDecimal.ROUND_UP)
.floatValue();
if (returnValue > 1)
return (returnValue + "MB");
BigDecimal kilobyte = new BigDecimal(1024);
returnValue = filesize.divide(kilobyte, 2, BigDecimal.ROUND_UP)
.floatValue();
return (returnValue + "KB");
}
public int isBackground(Context context) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List appProcesses = activityManager
.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
if (appProcess.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
Log.i(context.getPackageName(), "处于后台"
+ appProcess.processName);
return 1;
} else {
Log.i(context.getPackageName(), "处于前台"
+ appProcess.processName);
return 2;
}
}
}
return 3;
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (testEnd){
return super.onKeyDown(keyCode, event);
}else {
return true;
}
}
return super.onKeyDown(keyCode, event);
}
private void writeData(String QorH,String time,String TotalFlow,String Q ,String H){
if (SaveCSV) {
if (isTime) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
Date curDate = new Date(System.currentTimeMillis());//获取当前时间
mDateTime = formatter.format(curDate);
isTime = false;
}
write.WriteCSV(QorH, time, TotalFlow, Q, H, mDateTime, AppName, version,getBaseContext());
}
}
}
WriteCSV
package com.maple.trafficmonitoring;
import android.content.Context;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
public class WriteCSV {
boolean aBoolean=true , bBoolean=true,cBoolean=true,dBoolean=true;
private String resultFilePath;
public void WriteCSV(String QorH, String time, String TotalFlow, String Q , String H, String mDateTime, String appName, String version, Context context){
try {
if (android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED)) {
// 在4.0以下的低版本上/sdcard连接至/mnt/sdcard,而4.0以上版本则连接至/storage/sdcard0,所以有外接sdcard,/sdcard路径一定存在
resultFilePath = "/sdcard" + File.separator + "traffic_monitor_"
+appName+ mDateTime + ".csv";
System.out.println("BBB"+resultFilePath);
// resultFilePath =
// android.os.Environment.getExternalStorageDirectory() +
// File.separator + "Emmagee_TestResult_" + mDateTime + ".csv";
} else {
resultFilePath = context.getFilesDir().getPath()
+ File.separator + "traffic_monitor_" + appName+mDateTime
+ ".csv";
System.out.println("AAA"+resultFilePath);
}
File csv = new File(resultFilePath);
BufferedWriter bw = new BufferedWriter(new FileWriter(csv, true)); // 附加
// 添加新的数据行
if (bBoolean){
bw.write("应用名称" +","+appName+ "\r\n" + "应用版本" +","+version + "\r\n" + "Android 系统版本" +","+android.os.Build.VERSION.RELEASE+"\r\n" +"手机型号:"+","+android.os.Build.MODEL);
bw.newLine();
bBoolean=false;
}
if (aBoolean){
bw.write("运行状态"+ "," + "时间"+ "," + "总流量(B)" + "," + "前台流量(B)" +"," +"后台流量(B)");
bw.newLine();
aBoolean=false;
}
bw.write(QorH + "," +time + "," + TotalFlow + "," + Q +"," +H);
bw.newLine();
bw.close();
} catch (FileNotFoundException e) {
// File对象的创建过程中的异常捕获
e.printStackTrace();
} catch (IOException e) {
// BufferedWriter在关闭对象捕捉异常
e.printStackTrace();
}
}
}
start_monitor.xml
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/light_purple">
"wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@mipmap/ic_launcher"
android:id="@+id/imageView"
android:layout_centerHorizontal="true" />
"wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView"
android:textSize="@dimen/text_size"
android:layout_gravity="center_horizontal"
android:layout_below="@+id/imageView"
android:layout_centerHorizontal="true" />
"wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView2"
android:layout_gravity="center_horizontal"
android:layout_below="@+id/textView"
android:textSize="@dimen/text_size"
android:layout_alignLeft="@+id/textView"
android:layout_alignStart="@+id/textView" />
"wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/textView3"
android:textSize="@dimen/text_size"
android:layout_gravity="center_horizontal"
android:layout_below="@+id/textView2"
android:layout_alignLeft="@+id/textView2"
android:layout_alignStart="@+id/textView2" />
"vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/linearLayout"
android:background="@color/white"
android:layout_above="@+id/btnStart"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:layout_below="@+id/linearLayout3">
"wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView8"
android:text="@string/Mark"
android:layout_marginTop="5dp"
android:textSize="@dimen/text_size"
android:layout_marginLeft="15dp"
android:textColor="@color/red"/>
"wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView4"
android:textSize="@dimen/text_size"
android:layout_marginLeft="15dp"
android:textColor="@color/red"/>
"wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView5"
android:textSize="@dimen/text_size"
android:layout_marginLeft="15dp"
/>
"wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView6"
android:textSize="@dimen/text_size"
android:layout_marginLeft="15dp"/>
"wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView7"
android:textSize="@dimen/text_size"
android:layout_marginLeft="15dp"/>
</LinearLayout>
@+id/btnStart"
android:layout_gravity="center_horizontal"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:textColor="@color/white"
android:textSize="@dimen/text_size_test"
android:background="@drawable/test_button"
/>
"
android:layout_width=" match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/textView3"
android:id="@+id/linearLayout2"
android:layout_marginTop="5dp">
"
android:layout_height=" wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:background="@color/white"
android:padding="@dimen/layout_vertical_margin_small" >
"
android:layout_height=" wrap_content"
android:text="@string/collecting_frequency"
android:textColor="@color/black"
android:textSize="@dimen/text_size" />
"
android:layout_height=" wrap_content"
android:background="@color/white"
android:gravity="right" >
@+ id/time"
android:layout_width="50sp"
android:layout_height="wrap_content"
android:gravity="center_vertical|right"
android:textColor="@color/black"
android:textSize="@dimen/text_size" >
@+id/timeline"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:max="59"
android:maxHeight="4.0dip"
android:minHeight="4.0dip"
android:paddingBottom="@dimen/layout_vertical_margin_small"
android:paddingLeft="16.0dip"
android:paddingRight="16.0dip"
android:background="@color/white"
android:progressDrawable="@drawable/custom_seekbar"
android:thumb="@drawable/seekbar_thumb" />
"
android:layout_height=" @dimen/line_height"
android:background="@color/light_gray" />
"
android:layout_height=" wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:background="@color/white"
android:padding="@dimen/layout_vertical_margin_small">
"
android:layout_height=" wrap_content"
android:text="@string/testTime"
android:textColor="@color/black"
android:textSize="@dimen/text_size" />
"
android:layout_height=" wrap_content"
android:background="@color/white"
android:gravity="right" >
@+ id/TestTime"
android:layout_width="70sp"
android:layout_height="wrap_content"
android:gravity="center_vertical|right"
android:textColor="@color/black"
>
@+id/TestTimeline"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:max="24"
android:maxHeight="4.0dip"
android:minHeight="4.0dip"
android:paddingBottom="@dimen/layout_vertical_margin_small"
android:paddingLeft="16.0dip"
android:paddingRight="16.0dip"
android:progressDrawable="@drawable/custom_seekbar"
android:thumb="@drawable/seekbar_thumb"
android:background="@color/white"/>
"
android:layout_height=" @dimen/line_height"
android:background="@color/light_gray" />
"
android:layout_width=" match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/linearLayout2"
android:background="@color/white"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:padding="@dimen/layout_vertical_margin_small"
android:id="@+id/linearLayout3">
"
android:layout_height=" wrap_content"
android:text="@string/SaveCsv"
android:textColor="@color/black"
android:textSize="@dimen/text_size"
android:layout_gravity="center"/>
"
android:layout_height=" wrap_content"
android:background="@color/white"
android:gravity="right" >
@+ id/SaveCSV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:background="@drawable/custom_checkbox"
android:button="@null"
android:checked="false"
android:gravity="right"
android:paddingLeft="@dimen/image_padding"
android:paddingRight="@dimen/image_padding"/>