├── .gitignore └── WifiIperf ├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml └── runConfigurations.xml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── android │ │ └── wifiiperf │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── iperf │ ├── java │ │ └── com │ │ │ └── android │ │ │ └── wifiiperf │ │ │ ├── CommandHelper.java │ │ │ ├── CommandResult.java │ │ │ └── MainActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── android │ └── wifiiperf │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | 43 | # Keystore files 44 | *.jks 45 | 46 | # External native build folder generated in Android Studio 2.2 and later 47 | .externalNativeBuild 48 | 49 | # Google Services (e.g. APIs or Firebase) 50 | google-services.json 51 | 52 | # Freeline 53 | freeline.py 54 | freeline/ 55 | freeline_project_description.json 56 | -------------------------------------------------------------------------------- /WifiIperf/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /WifiIperf/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WifiIperf/.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /WifiIperf/.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /WifiIperf/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /WifiIperf/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /WifiIperf/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /WifiIperf/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /WifiIperf/.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /WifiIperf/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /WifiIperf/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.3" 6 | defaultConfig { 7 | applicationId "com.android.wifiiperf" 8 | minSdkVersion 21 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 28 | testCompile 'junit:junit:4.12' 29 | } 30 | -------------------------------------------------------------------------------- /WifiIperf/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\uidq0530\myinstall\android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /WifiIperf/app/src/androidTest/java/com/android/wifiiperf/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.android.wifiiperf; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.android.wifiiperf", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /WifiIperf/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /WifiIperf/app/src/main/assets/iperf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xhunmon/wifiIperf/aa24c4c409f5551efac155aed6d36d87205de636/WifiIperf/app/src/main/assets/iperf -------------------------------------------------------------------------------- /WifiIperf/app/src/main/java/com/android/wifiiperf/CommandHelper.java: -------------------------------------------------------------------------------- 1 | package com.android.wifiiperf; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStreamReader; 8 | 9 | /** 10 | * user: uidq0530, 2017-08-22. 11 | * description: 12 | * 13 | * @author xhunmon 14 | */ 15 | 16 | public class CommandHelper { 17 | 18 | private static final String TAG = "CommandHelper"; 19 | //default time out, in millseconds 20 | public static int DEFAULT_TIMEOUT = 8000; 21 | public static final int DEFAULT_INTERVAL = 1000; 22 | public static long START; 23 | public static CommandResult exec(String command) throws IOException, InterruptedException { 24 | Log.i(TAG,"exec command: "+command); 25 | //创建一个子进程,并保存在process对象中 26 | Process process = Runtime.getRuntime().exec(command); 27 | 28 | CommandResult commandResult = wait(process); 29 | Log.i(TAG,"CommandResult: "+commandResult.toString()); 30 | if (process != null) { 31 | process.destroy(); 32 | } 33 | return commandResult; 34 | } 35 | 36 | private static boolean isOverTime() { 37 | return System.currentTimeMillis() - START >= DEFAULT_TIMEOUT; 38 | } 39 | 40 | private static CommandResult wait(Process process) throws InterruptedException, IOException { 41 | BufferedReader errorStreamReader = null; 42 | BufferedReader inputStreamReader = null; 43 | 44 | try { 45 | errorStreamReader = new BufferedReader(new InputStreamReader(process.getErrorStream())); 46 | inputStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream())); 47 | 48 | //timeout control 49 | START = System.currentTimeMillis(); 50 | boolean isFinished = false; 51 | Log.i(TAG,"wait isFinished: "+isFinished); 52 | for (;;) { 53 | if (isOverTime()) { 54 | CommandResult result = new CommandResult(); 55 | result.setExitValue(CommandResult.EXIT_VALUE_TIMEOUT); 56 | result.setOutput("Command process timeout"); 57 | return result; 58 | } 59 | Log.i(TAG,"wait for(;;) isFinished: "+isFinished); 60 | 61 | if (isFinished) { 62 | CommandResult result = new CommandResult(); 63 | result.setExitValue(process.waitFor()); //process.waitFor() 表示 等这条语句执行完后再往下执行 64 | 65 | //parse error info 66 | if (errorStreamReader.ready()) { 67 | StringBuilder buffer = new StringBuilder(); 68 | String line; 69 | while ((line = errorStreamReader.readLine()) != null) { 70 | buffer.append(line); 71 | } 72 | result.setError(buffer.toString()); 73 | Log.i(TAG,"for(;;) error: "+buffer.toString()); 74 | } 75 | 76 | //parse info 77 | if (inputStreamReader.ready()) { 78 | StringBuilder buffer = new StringBuilder(); 79 | String line; 80 | while ((line = inputStreamReader.readLine()) != null) { 81 | buffer.append(line); 82 | } 83 | result.setOutput(buffer.toString()); 84 | Log.i(TAG,"for(;;) parse: "+buffer.toString()); 85 | } 86 | return result; 87 | } 88 | 89 | try { 90 | isFinished = true; 91 | process.exitValue(); 92 | } catch (IllegalThreadStateException e) { 93 | // process hasn't finished yet 94 | isFinished = false; 95 | Thread.sleep(DEFAULT_INTERVAL); 96 | } 97 | } 98 | 99 | } finally { 100 | if (errorStreamReader != null) { 101 | try { 102 | errorStreamReader.close(); 103 | } catch (IOException e) { 104 | } 105 | } 106 | if (inputStreamReader != null) { 107 | try { 108 | inputStreamReader.close(); 109 | } catch (IOException e) { 110 | } 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /WifiIperf/app/src/main/java/com/android/wifiiperf/CommandResult.java: -------------------------------------------------------------------------------- 1 | package com.android.wifiiperf; 2 | 3 | /** 4 | * user: uidq0530, 2017-08-22. 5 | * description: 6 | * 7 | * @author xhunmon 8 | */ 9 | 10 | public class CommandResult { 11 | public static final int EXIT_VALUE_TIMEOUT = -1; 12 | 13 | private String output; 14 | private String error; 15 | private int exitValue; 16 | 17 | void setOutput(String output) { 18 | this.output = output; 19 | } 20 | 21 | public String getOutput() { 22 | return output; 23 | } 24 | 25 | 26 | public void setExitValue(int value) { 27 | exitValue = value; 28 | } 29 | 30 | public int getExitValue() { 31 | return exitValue; 32 | } 33 | 34 | public String getError() { 35 | return error; 36 | } 37 | 38 | public void setError(String error) { 39 | this.error = error; 40 | } 41 | } -------------------------------------------------------------------------------- /WifiIperf/app/src/main/java/com/android/wifiiperf/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.android.wifiiperf; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.net.wifi.WifiInfo; 6 | import android.net.wifi.WifiManager; 7 | import android.os.Bundle; 8 | import android.os.Handler; 9 | import android.os.Message; 10 | import android.util.Log; 11 | import android.view.View; 12 | import android.widget.CompoundButton; 13 | import android.widget.Switch; 14 | import android.widget.TextView; 15 | import android.widget.Toast; 16 | 17 | import java.io.File; 18 | import java.io.FileOutputStream; 19 | import java.io.InputStream; 20 | import java.nio.channels.FileChannel; 21 | import java.nio.channels.FileLock; 22 | import java.util.regex.Matcher; 23 | import java.util.regex.Pattern; 24 | 25 | public class MainActivity extends Activity implements View.OnClickListener, 26 | CompoundButton.OnCheckedChangeListener { 27 | 28 | private static final String TAG = "WifiActivity"; 29 | private static final int IPERF_ERROR = 1; 30 | private static final int IPERF_SCCESS = 2; 31 | private TextView mAddress; 32 | private TextView mShroughput; 33 | private TextView mSignalStrength; 34 | private WifiManager mWm; 35 | private String iperfreply; 36 | /*** 1. 拷贝iperf到该目录下*/ 37 | private static final String IPERF_PATH = "/data/data/com.android.wifiiperf/iperf"; 38 | /*** 2. 在Android应用中执行iperf命令*/ 39 | private static String iperfClientCmd = IPERF_PATH + " -c 172.19.0.179 -p 5001 -t 60 -P 1"; 40 | private static final String iperfServiceCmd = IPERF_PATH + " -s &"; 41 | private static String curIperfCmd = iperfServiceCmd; 42 | private boolean IPERF_OK = false; 43 | private Switch mSwitch; 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | setContentView(R.layout.activity_main); 49 | 50 | initView(); 51 | File file = new File(IPERF_PATH); 52 | Log.i(TAG,"file.exists(): "+file.exists()); 53 | if(!file.exists()){ 54 | copyiperf(); 55 | } 56 | } 57 | 58 | private void initView() { 59 | findViewById(R.id.btn_wifi_address).setOnClickListener(this); 60 | findViewById(R.id.btn_wifi_throughput).setOnClickListener(this); 61 | findViewById(R.id.btn_wifi_signal_strength).setOnClickListener(this); 62 | 63 | mAddress = (TextView) findViewById(R.id.wifi_address); 64 | mShroughput = (TextView) findViewById(R.id.wifi_throughput_show); 65 | mSignalStrength = (TextView) findViewById(R.id.wifi_signal_strength); 66 | 67 | mWm = (WifiManager) getSystemService(Context.WIFI_SERVICE); 68 | mSwitch = (Switch) findViewById(R.id.wifi_switch); 69 | mSwitch.setChecked(true); 70 | mSwitch.setOnCheckedChangeListener(this); 71 | } 72 | 73 | @Override 74 | public void onClick(View v) { 75 | switch (v.getId()) { 76 | case R.id.btn_wifi_address://获取wifi地址 77 | mAddress.setText(getLocalIpAddress()); 78 | Log.i(TAG, "btn_wifi_address: " + getLocalIpAddress()); 79 | break; 80 | case R.id.btn_wifi_throughput://获取wifi吞吐量 81 | iperfClientCmd = IPERF_PATH + " -c "+getLocalIpAddress()+" -p 5001 -t 60 -P 1"; 82 | sercomfun(curIperfCmd); 83 | break; 84 | case R.id.btn_wifi_signal_strength://获取wifi信号强度 85 | mSignalStrength.setText(getSignalStrength()); 86 | Log.i(TAG, "btn_wifi_signal_strength: " + getSignalStrength()); 87 | break; 88 | } 89 | } 90 | 91 | 92 | /** 93 | * 获取wifi地址 94 | */ 95 | private String getLocalIpAddress() { 96 | int paramInt = 0; 97 | WifiInfo info = mWm.getConnectionInfo(); 98 | if (info.getBSSID() == null) { 99 | return "请连接再试"; 100 | } else { 101 | paramInt = info.getIpAddress(); 102 | Log.i(TAG, "paramInt: " + paramInt+"0xFF¶mInt"+(0xFF & paramInt)); 103 | return new StringBuffer() 104 | .append(0xFF & paramInt).append(".") 105 | .append(0xFF & paramInt >> 8).append(".") 106 | .append(0xFF & paramInt >> 16).append(".") 107 | .append(0xFF & paramInt >> 24).toString(); 108 | } 109 | } 110 | 111 | /** 112 | * Wifi的连接速度及信号强度 113 | */ 114 | public String getSignalStrength() { 115 | int strength = 0; 116 | WifiInfo info = mWm.getConnectionInfo(); 117 | if (info.getBSSID() != null) { 118 | // 链接信号强度,5为获取的信号强度值在5以内 119 | strength = WifiManager.calculateSignalLevel(info.getRssi(), 5); 120 | // int speed = info.getLinkSpeed(); // 链接速度 121 | // String units = WifiInfo.LINK_SPEED_UNITS; // 链接速度单位 122 | // String ssid = info.getSSID(); // Wifi源名称 123 | } 124 | return strength + ""; 125 | } 126 | 127 | 128 | private Handler handler = new Handler() { 129 | @Override 130 | public void handleMessage(Message msg) { 131 | super.handleMessage(msg); 132 | switch (msg.what){ 133 | case IPERF_ERROR: 134 | mShroughput.setText((String)msg.obj); 135 | break; 136 | case IPERF_SCCESS: 137 | mShroughput.setText((String)msg.obj); 138 | break; 139 | } 140 | } 141 | }; 142 | 143 | /** 144 | * 1. 拷贝iperf到该目录下 145 | */ 146 | public void copyiperf() { 147 | File localfile; 148 | Process p; 149 | try { 150 | localfile = new File(IPERF_PATH); 151 | p = Runtime.getRuntime().exec("chmod 777 " + localfile.getAbsolutePath()); 152 | InputStream localInputStream = getAssets().open("iperf"); 153 | Log.i(TAG,"chmod 777 " + localfile.getAbsolutePath()); 154 | FileOutputStream localFileOutputStream = new FileOutputStream(localfile.getAbsolutePath()); 155 | FileChannel fc = localFileOutputStream.getChannel(); 156 | FileLock lock = fc.tryLock(); //给文件设置独占锁定 157 | if (lock == null) { 158 | Toast.makeText(this,"has been locked !",Toast.LENGTH_SHORT).show(); 159 | return; 160 | } else { 161 | FileOutputStream fos = new FileOutputStream(new File(IPERF_PATH)); 162 | byte[] buffer = new byte[1024]; 163 | int byteCount = 0; 164 | while ((byteCount = localInputStream.read(buffer)) != -1) {// 循环从输入流读取 165 | // buffer字节 166 | fos.write(buffer, 0, byteCount);// 将读取的输入流写入到输出流 167 | Log.i(TAG, "byteCount: "+byteCount); 168 | } 169 | fos.flush();// 刷新缓冲区 170 | localInputStream.close(); 171 | fos.close(); 172 | 173 | } 174 | //两次才能确保开启权限成功 175 | p = Runtime.getRuntime().exec("chmod 777 " + localfile.getAbsolutePath()); 176 | lock.release(); 177 | p.destroy(); 178 | Log.i(TAG, "the iperf file is ready"); 179 | } catch (Exception e) { 180 | e.printStackTrace(); 181 | } 182 | } 183 | 184 | /** 185 | * 2. 在Android应用中执行iperf命令 186 | */ 187 | private void sercomfun(final String cmd) { 188 | Log.i(TAG, "sercomfun = " + cmd); 189 | Thread lthread = new Thread(new Runnable() { 190 | @Override 191 | public void run() { 192 | try { 193 | String errorreply = ""; 194 | CommandHelper.DEFAULT_TIMEOUT = 150000; 195 | CommandResult result = CommandHelper.exec(cmd); 196 | if (result != null) { 197 | //start to connect the service 198 | if (result.getError() != null) { 199 | errorreply = result.getError(); 200 | Message m = new Message(); 201 | m.obj = errorreply; 202 | m.what = IPERF_ERROR; 203 | handler.sendMessage(m); 204 | Log.i(TAG,"Error:" + errorreply); 205 | } 206 | if (result.getOutput() != null) { 207 | iperfreply = getThroughput(result.getOutput()); 208 | IPERF_OK = true; 209 | Message m = new Message(); 210 | m.obj = iperfreply; 211 | m.what = IPERF_SCCESS; 212 | handler.sendMessage(m); 213 | Log.i(TAG,"Output:" + iperfreply); 214 | } 215 | Log.i(TAG,"result.getExitValue(): "+result.getExitValue()); 216 | } 217 | } catch (Exception e) { 218 | e.printStackTrace(); 219 | } 220 | } 221 | }); 222 | lthread.start(); 223 | } 224 | 225 | /** 226 | * 从获取到的吞吐量信息中截取需要的信息,如: 227 | * 0.0-10.0 sec 27.5 MBytes 23.0 Mbits/sec 228 | */ 229 | private String getThroughput(String str) { 230 | String regx = "0.0-.+?/sec"; 231 | String result = ""; 232 | Matcher matcher = Pattern.compile(regx).matcher(str); 233 | Log.i(TAG,"matcher regx : "+regx+" is "+matcher.matches()); 234 | if(matcher.find()){ 235 | Log.i(TAG,"group: "+matcher.group()); 236 | result = matcher.group(); 237 | } 238 | return result; 239 | } 240 | 241 | @Override 242 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 243 | if(buttonView.getId() == R.id.wifi_switch){ 244 | curIperfCmd = (isChecked?iperfServiceCmd 245 | :(IPERF_PATH + " -c "+getLocalIpAddress()+" -p 5001 -t 60 -P 1")); 246 | Log.i(TAG,"isChecked: "+isChecked+", curIperfCmd: "+curIperfCmd); 247 | } 248 | } 249 | 250 | @Override 251 | protected void onDestroy() { 252 | super.onDestroy(); 253 | 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /WifiIperf/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | 19 |