├── .idea └── vcs.xml ├── README.md ├── Screenshots ├── 1.gif ├── 2.gif ├── 3.gif ├── tcp.gif ├── tcp.png ├── tcp2.png ├── udp.gif └── wifi.png ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── bao │ │ └── wifidemo │ │ ├── activity │ │ ├── BaseActivity.java │ │ ├── MainActivity.kt │ │ ├── TcpClientActivity.java │ │ ├── TcpServerActivity.java │ │ ├── WifiControlActivity.java │ │ ├── WifiTcpActivity.kt │ │ └── WifiUdpActivity.java │ │ ├── application │ │ └── BaseApplication.kt │ │ ├── receiver │ │ └── WifiBroadcastReceiver.java │ │ ├── socket │ │ ├── ClientLastly.java │ │ └── ServerLastly.java │ │ └── utils │ │ ├── CheckPermission.java │ │ ├── Constants.kt │ │ └── WifiControlUtils.java │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ ├── ic_down.xml │ └── ic_launcher_background.xml │ ├── layout │ ├── global_black_line.xml │ ├── global_black_vertical_line.xml │ ├── main_activity.xml │ ├── tcp_client_activity.xml │ ├── tcp_server_activity.xml │ ├── wifi_control_activity.xml │ ├── wifi_tcp_activity.xml │ └── wifi_udp_activity.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.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 │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── local.properties └── settings.gradle /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WifiDemo 2 | Android Wifi控制、TCP、UDP通信,6.0以上适配 3 | 4 | [详细文档](https://www.jianshu.com/p/572ac573e4b8) 5 | 6 | ![wifi连接](https://upload-images.jianshu.io/upload_images/1627327-76fc1f9ea704758a.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/519/format/webp) 7 | 8 | ![wifi信息](https://upload-images.jianshu.io/upload_images/1627327-be923441db25be08.gif?imageMogr2/auto-orient/strip%7CimageView2/2/w/517/format/webp) 9 | 10 | 对于6.0以上,如果你要连接不是自己创建的配置,只需要在mWifiManager.getConfiguredNetworks(),翻出以前连接过的的Wifi 配置,获取对应的netId,就能重新连接上。 11 | 12 | 如果以前连接过的 Wifi 密码改了,但是名称没变,你是连不上的,也没权限去修改密码和删除(可能就是为了安全吧),你就要手动去处理这个Wifi 信息了。 13 | 14 | APP没有权限删除之前的连接过的 Wifi ,包括APP以前本身创建的 Wifi(先创建了,重装或者更新后,都不算是自己创建了)。 15 | 16 | 对于从来都没连接过的 Wifi,或者是删除过的 Wifi(相当于没连接过),和以前一样,只要用 SSID (Wifi名)、密码、加密方式创建新的 WifiConfiguration,无密码的就是要 SSID;然后 mWifiManager.enableNetwork 就连上了。 17 | 18 | ``` 19 | /** 20 | * 连接指定wifi 21 | * 6.0以上版本,直接查找时候有连接过,连接过的拿出wifiConfiguration用 22 | * 不要去创建新的wifiConfiguration,否者失败 23 | */ 24 | public void addNetWork(String SSID, String password, int Type) 25 | { 26 | int netId = -1; 27 | /*先执行删除wifi操作,1.如果删除的成功说明这个wifi配置是由本APP配置出来的; 28 | 2.这样可以避免密码错误之后,同名字的wifi配置存在,无法连接; 29 | 3.wifi直接连接成功过,不删除也能用, netId = getExitsWifiConfig(SSID).networkId;*/ 30 | if (removeWifi(SSID)) 31 | { 32 | //移除成功,就新建一个 33 | netId = mWifiManager.addNetwork(createWifiInfo(SSID, password, Type)); 34 | } else 35 | { 36 | //删除不成功,要么这个wifi配置以前就存在过,要么是还没连接过的 37 | if (getExitsWifiConfig(SSID) != null) 38 | { 39 | //这个wifi是连接过的,如果这个wifi在连接之后改了密码,那就只能手动去删除了 40 | netId = getExitsWifiConfig(SSID).networkId; 41 | } else 42 | { 43 | //没连接过的,新建一个wifi配置 44 | netId = mWifiManager.addNetwork(createWifiInfo(SSID, password, Type)); 45 | } 46 | } 47 | 48 | //这个方法的第一个参数是需要连接wifi网络的networkId,第二个参数是指连接当前wifi网络是否需要断开其他网络 49 | //无论是否连接上,都返回true。。。。 50 | mWifiManager.enableNetwork(netId, true); 51 | } 52 | 53 | /** 54 | * 获取配置过的wifiConfiguration 55 | */ 56 | public WifiConfiguration getExitsWifiConfig(String SSID) 57 | { 58 | wifiConfigurationList = mWifiManager.getConfiguredNetworks(); 59 | for (WifiConfiguration wifiConfiguration : wifiConfigurationList) 60 | { 61 | if (wifiConfiguration.SSID.equals("\"" + SSID + "\"")) 62 | { 63 | return wifiConfiguration; 64 | } 65 | } 66 | return null; 67 | } 68 | 69 | /** 70 | * 移除wifi,因为权限,无法移除的时候,需要手动去翻wifi列表删除 71 | * 注意:!!!只能移除自己应用创建的wifi。 72 | * 删除掉app,再安装的,都不算自己应用,具体看removeNetwork源码 73 | * 74 | * @param netId wifi的id 75 | */ 76 | public boolean removeWifi(int netId) 77 | { 78 | return mWifiManager.removeNetwork(netId); 79 | } 80 | 81 | /** 82 | * 移除wifi 83 | * 84 | * @param SSID wifi名 85 | */ 86 | public boolean removeWifi(String SSID) 87 | { 88 | if (getExitsWifiConfig(SSID) != null) 89 | { 90 | return removeWifi(getExitsWifiConfig(SSID).networkId); 91 | } else 92 | { 93 | return false; 94 | } 95 | } 96 | ``` 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Screenshots/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Goodbao/WifiDemo/db531872e7087bac8916eccb1340e6af56e03a4c/Screenshots/1.gif -------------------------------------------------------------------------------- /Screenshots/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Goodbao/WifiDemo/db531872e7087bac8916eccb1340e6af56e03a4c/Screenshots/2.gif -------------------------------------------------------------------------------- /Screenshots/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Goodbao/WifiDemo/db531872e7087bac8916eccb1340e6af56e03a4c/Screenshots/3.gif -------------------------------------------------------------------------------- /Screenshots/tcp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Goodbao/WifiDemo/db531872e7087bac8916eccb1340e6af56e03a4c/Screenshots/tcp.gif -------------------------------------------------------------------------------- /Screenshots/tcp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Goodbao/WifiDemo/db531872e7087bac8916eccb1340e6af56e03a4c/Screenshots/tcp.png -------------------------------------------------------------------------------- /Screenshots/tcp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Goodbao/WifiDemo/db531872e7087bac8916eccb1340e6af56e03a4c/Screenshots/tcp2.png -------------------------------------------------------------------------------- /Screenshots/udp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Goodbao/WifiDemo/db531872e7087bac8916eccb1340e6af56e03a4c/Screenshots/udp.gif -------------------------------------------------------------------------------- /Screenshots/wifi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Goodbao/WifiDemo/db531872e7087bac8916eccb1340e6af56e03a4c/Screenshots/wifi.png -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | compileSdkVersion 27 6 | defaultConfig { 7 | applicationId "com.bao.wifidemo" 8 | minSdkVersion 21 9 | targetSdkVersion 27 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 | ext.support_version = '27.0.2' 23 | dependencies { 24 | implementation fileTree(include: ['*.jar'], dir: 'libs') 25 | implementation "com.android.support:appcompat-v7:${support_version}" 26 | implementation "com.android.support:recyclerview-v7:${support_version}" 27 | implementation "com.android.support:design:${support_version}" 28 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 29 | //butterknife 30 | compile 'com.jakewharton:butterknife:8.8.1' 31 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' 32 | //动态权限 33 | compile 'com.yanzhenjie:permission:1.1.2' 34 | //工具大全 35 | compile 'com.blankj:utilcode:1.13.1' 36 | //kotlin 37 | compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 38 | //优化RecyclerView.Adapter 39 | compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.34' 40 | } 41 | repositories { 42 | mavenCentral() 43 | } 44 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 36 | 37 | 41 | 42 | 46 | 47 | 51 | 52 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/activity/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.activity; 2 | 3 | import android.content.Intent; 4 | import android.content.res.Configuration; 5 | import android.content.res.Resources; 6 | import android.os.Bundle; 7 | import android.support.annotation.Nullable; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.view.inputmethod.InputMethodManager; 10 | 11 | import com.bao.wifidemo.utils.Constants; 12 | import com.bao.wifidemo.utils.WifiControlUtils; 13 | import com.blankj.utilcode.util.AppUtils; 14 | 15 | import butterknife.ButterKnife; 16 | 17 | /** 18 | * Created by bao on 2018/3/26. 19 | */ 20 | public abstract class BaseActivity extends AppCompatActivity { 21 | 22 | 23 | private WifiControlUtils wifiControlUtils; 24 | 25 | @Override 26 | protected void onCreate(@Nullable Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(); 29 | ButterKnife.bind(this); 30 | init(); 31 | loadData(); 32 | 33 | 34 | wifiControlUtils = new WifiControlUtils(this); 35 | } 36 | 37 | 38 | public abstract void setContentView(); 39 | 40 | /** 41 | * 初始化工作 42 | */ 43 | public abstract void init(); 44 | 45 | /** 46 | * 加载数据 47 | */ 48 | public abstract void loadData(); 49 | 50 | @Override 51 | protected void onResume() { 52 | super.onResume(); 53 | 54 | if (AppUtils.isAppForeground()) { 55 | //连接指定wifi 56 | wifiControlUtils.addNetWork(Constants.INSTANCE.getWIFI_NAME(), Constants.INSTANCE.getWIFI_PWD(), WifiControlUtils.WIFI_CIPHER_WAP); 57 | } 58 | } 59 | 60 | @Override 61 | protected void onPause() { 62 | super.onPause(); 63 | if (!AppUtils.isAppForeground()) { 64 | //移除指定wifi 65 | wifiControlUtils.removeWifi(Constants.INSTANCE.getWIFI_NAME()); 66 | } 67 | } 68 | 69 | 70 | /** 71 | * 隐藏软件盘 72 | */ 73 | public void hideSoftInput() { 74 | InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 75 | if (getCurrentFocus() != null) { 76 | imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0); 77 | } 78 | } 79 | 80 | /** 81 | * 显示软键盘 82 | */ 83 | public void showInputMethod() { 84 | if (getCurrentFocus() != null) { 85 | InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 86 | imm.showSoftInputFromInputMethod(getCurrentFocus().getWindowToken(), 0); 87 | } 88 | } 89 | 90 | /** 91 | * 防止快速点击 92 | */ 93 | private boolean fastClick() { 94 | long lastClick = 0; 95 | if (System.currentTimeMillis() - lastClick <= 1000) { 96 | return false; 97 | } 98 | lastClick = System.currentTimeMillis(); 99 | return true; 100 | } 101 | 102 | /** 103 | * 跳转activity,不带参数 104 | * 105 | * @param clz 跳转的activity 106 | */ 107 | public void startActivity(Class clz) { 108 | startActivity(new Intent(this, clz)); 109 | } 110 | 111 | /** 112 | * 跳转activity,带参数 113 | * 114 | * @param clz 跳转的activity 115 | * @param bundle 传递的参数 116 | */ 117 | public void startActivity(Class clz, Bundle bundle) { 118 | Intent intent = new Intent(this, clz); 119 | if (bundle != null) { 120 | intent.putExtras(bundle); 121 | } 122 | startActivity(intent); 123 | } 124 | 125 | 126 | /** 127 | * 字体大小不跟系统设置 128 | */ 129 | @Override 130 | public Resources getResources() { 131 | Resources res = super.getResources(); 132 | if (res.getConfiguration().fontScale != 1) { 133 | //非默认值 134 | Configuration newConfig = new Configuration(); 135 | newConfig.setToDefaults(); 136 | //设置默认 137 | res.updateConfiguration(newConfig, res.getDisplayMetrics()); 138 | } 139 | return res; 140 | } 141 | 142 | 143 | @Override 144 | protected void onDestroy() { 145 | ButterKnife.bind(this).unbind(); 146 | super.onDestroy(); 147 | } 148 | } -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.activity 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.view.View 7 | import android.widget.TextView 8 | import com.bao.wifidemo.R 9 | import com.bao.wifidemo.utils.CheckPermission 10 | 11 | class MainActivity : AppCompatActivity(), View.OnClickListener { 12 | 13 | private var checkPermission: CheckPermission? = null 14 | 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | setContentView(R.layout.main_activity) 18 | 19 | checkPermission = object : CheckPermission(this@MainActivity) { 20 | override fun permissionSuccess() { 21 | //权限申请成功 22 | } 23 | } 24 | 25 | checkPermission!!.permission(CheckPermission.REQUEST_CODE_PERMISSION_LOCATION) 26 | 27 | findViewById(R.id.tv_wifi_control).setOnClickListener(this@MainActivity) 28 | findViewById(R.id.tv_wifi_tcp).setOnClickListener(this@MainActivity) 29 | findViewById(R.id.tv_wifi_udp).setOnClickListener(this@MainActivity) 30 | } 31 | 32 | override fun onClick(view: View?) { 33 | when (view!!.id) { 34 | R.id.tv_wifi_control -> { 35 | startActivity(WifiControlActivity::class.java) 36 | } 37 | 38 | R.id.tv_wifi_tcp -> { 39 | startActivity(WifiTcpActivity::class.java) 40 | } 41 | 42 | R.id.tv_wifi_udp -> { 43 | startActivity(WifiUdpActivity::class.java) 44 | } 45 | } 46 | } 47 | 48 | private fun startActivity(activity: Class<*>) { 49 | startActivity(Intent(this@MainActivity, activity)) 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/activity/TcpClientActivity.java: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.activity; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.os.Message; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.View; 9 | import android.widget.Button; 10 | import android.widget.EditText; 11 | import android.widget.TextView; 12 | 13 | import com.bao.wifidemo.R; 14 | import com.bao.wifidemo.socket.ClientLastly; 15 | 16 | import butterknife.BindView; 17 | import butterknife.ButterKnife; 18 | import butterknife.OnClick; 19 | 20 | /** 21 | * Created by bao on 2018/3/22. 22 | * tcp客户端 23 | */ 24 | 25 | public class TcpClientActivity extends AppCompatActivity 26 | { 27 | @BindView(R.id.et_message) 28 | EditText etMessage; 29 | @BindView(R.id.btn_send) 30 | Button btnSend; 31 | @BindView(R.id.tv_message) 32 | TextView tvMessage; 33 | 34 | private ClientLastly client; 35 | private StringBuffer receiveData = new StringBuffer(); 36 | private Handler handler = new Handler(new Handler.Callback() 37 | { 38 | @Override 39 | public boolean handleMessage(Message msg) 40 | { 41 | if (msg.arg1 == ClientLastly.CLIENT_ARG) 42 | { 43 | receiveData.append("接收到:"+(String) msg.obj); 44 | //收到数据 45 | tvMessage.setText(receiveData); 46 | receiveData.append("\r\n"); 47 | } 48 | return false; 49 | } 50 | }); 51 | 52 | @Override 53 | protected void onCreate(@Nullable Bundle savedInstanceState) 54 | { 55 | super.onCreate(savedInstanceState); 56 | setContentView(R.layout.tcp_client_activity); 57 | ButterKnife.bind(this); 58 | 59 | client = new ClientLastly(handler,getIntent().getStringExtra(WifiTcpActivity.Companion.getHOST_IP())); 60 | new Thread(client).start(); 61 | } 62 | 63 | @OnClick({R.id.btn_send}) 64 | public void onViewClicked(View view) 65 | { 66 | switch (view.getId()) 67 | { 68 | case R.id.btn_send: 69 | new Thread(new Runnable() 70 | { 71 | @Override 72 | public void run() 73 | { 74 | client.send(etMessage.getText().toString()); 75 | } 76 | }).start(); 77 | etMessage.setText(""); 78 | break; 79 | } 80 | } 81 | 82 | @Override 83 | protected void onDestroy() 84 | { 85 | client.close(); 86 | super.onDestroy(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/activity/TcpServerActivity.java: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.activity; 2 | 3 | import android.os.Bundle; 4 | import android.os.Handler; 5 | import android.os.Message; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.widget.Button; 9 | import android.widget.EditText; 10 | import android.widget.TextView; 11 | 12 | import com.bao.wifidemo.R; 13 | import com.bao.wifidemo.socket.ServerLastly; 14 | 15 | import butterknife.BindView; 16 | import butterknife.ButterKnife; 17 | import butterknife.OnClick; 18 | 19 | /** 20 | * Created by bao on 2018/3/22. 21 | * tcp服务器端 22 | */ 23 | 24 | public class TcpServerActivity extends AppCompatActivity 25 | { 26 | @BindView(R.id.et_message) 27 | EditText etMessage; 28 | @BindView(R.id.btn_send) 29 | Button btnSend; 30 | @BindView(R.id.tv_message) 31 | TextView tvMessage; 32 | 33 | private ServerLastly server; 34 | private StringBuffer receiveData = new StringBuffer(); 35 | private Handler handler = new Handler(new Handler.Callback() 36 | { 37 | @Override 38 | public boolean handleMessage(Message msg) 39 | { 40 | if (msg.arg1 == ServerLastly.SERVER_ARG) 41 | { 42 | receiveData.append("接收到:"+(String) msg.obj); 43 | tvMessage.setText(receiveData); 44 | receiveData.append("\r\n"); 45 | } 46 | return false; 47 | } 48 | }); 49 | 50 | 51 | @Override 52 | protected void onCreate(@Nullable Bundle savedInstanceState) 53 | { 54 | super.onCreate(savedInstanceState); 55 | setContentView(R.layout.tcp_server_activity); 56 | ButterKnife.bind(this); 57 | 58 | server = new ServerLastly(handler); 59 | new Thread(server).start(); 60 | } 61 | 62 | @OnClick(R.id.btn_send) 63 | public void onViewClicked() 64 | { 65 | new Thread(new Runnable() 66 | { 67 | @Override 68 | public void run() 69 | { 70 | server.send(etMessage.getText().toString()); 71 | } 72 | }).start(); 73 | etMessage.setText(""); 74 | } 75 | 76 | @Override 77 | protected void onDestroy() 78 | { 79 | server.close(); 80 | super.onDestroy(); 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/activity/WifiControlActivity.java: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.activity; 2 | 3 | import android.content.IntentFilter; 4 | import android.net.wifi.ScanResult; 5 | import android.net.wifi.WifiInfo; 6 | import android.net.wifi.WifiManager; 7 | import android.os.Bundle; 8 | import android.support.annotation.Nullable; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.view.View; 11 | import android.widget.EditText; 12 | import android.widget.TextView; 13 | 14 | import com.bao.wifidemo.R; 15 | import com.bao.wifidemo.receiver.WifiBroadcastReceiver; 16 | import com.bao.wifidemo.utils.Constants; 17 | import com.bao.wifidemo.utils.WifiControlUtils; 18 | import com.blankj.utilcode.util.ToastUtils; 19 | 20 | import butterknife.BindView; 21 | import butterknife.ButterKnife; 22 | import butterknife.OnClick; 23 | 24 | /** 25 | * Created by bao on 2018/3/21. 26 | * wifi控制Activity 27 | */ 28 | public class WifiControlActivity extends AppCompatActivity { 29 | @BindView(R.id.tv_open_wifi) 30 | TextView tvOpenWifi; 31 | @BindView(R.id.tv_close_wifi) 32 | TextView tvCloseWifi; 33 | @BindView(R.id.tv_scan_wifi) 34 | TextView tvScanWifi; 35 | @BindView(R.id.tv_wifi_info) 36 | TextView tvWifiInfo; 37 | @BindView(R.id.et_wifi_name) 38 | EditText etWifiName; 39 | @BindView(R.id.et_wifi_pwd) 40 | EditText etWifiPwd; 41 | @BindView(R.id.tv_connection_wifi) 42 | TextView tvConnectionWifi; 43 | @BindView(R.id.tv_disconnection_wifi) 44 | TextView tvDisconnectionWifi; 45 | @BindView(R.id.tv_delete_wifi) 46 | TextView tvDeleteWifi; 47 | @BindView(R.id.tv_wifi_message) 48 | TextView tvWifiMessage; 49 | 50 | private WifiBroadcastReceiver wifiBroadcastReceiver; 51 | private WifiControlUtils wifiControlUtils; 52 | 53 | private WifiInfo wifiInfo; 54 | 55 | @Override 56 | protected void onCreate(@Nullable Bundle savedInstanceState) { 57 | super.onCreate(savedInstanceState); 58 | setContentView(R.layout.wifi_control_activity); 59 | ButterKnife.bind(this); 60 | 61 | //动态注册wifi状态广播 62 | wifiBroadcastReceiver = new WifiBroadcastReceiver(); 63 | IntentFilter intentFilter = new IntentFilter(); 64 | intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 65 | intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 66 | intentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); 67 | registerReceiver(wifiBroadcastReceiver, intentFilter); 68 | 69 | wifiControlUtils = new WifiControlUtils(this); 70 | wifiInfo = wifiControlUtils.getWifiInfo(); 71 | } 72 | 73 | 74 | @Override 75 | protected void onResume() { 76 | super.onResume(); 77 | //连接指定wifi 78 | wifiControlUtils.addNetWork(Constants.INSTANCE.getWIFI_NAME(), Constants.INSTANCE.getWIFI_PWD(), WifiControlUtils.WIFI_CIPHER_WAP); 79 | } 80 | 81 | @Override 82 | protected void onPause() { 83 | super.onPause(); 84 | //移除指定wifi 85 | wifiControlUtils.removeWifi(Constants.INSTANCE.getWIFI_NAME()); 86 | wifiControlUtils.addNetWork(wifiInfo.getSSID()); 87 | } 88 | 89 | 90 | @OnClick({R.id.tv_open_wifi, R.id.tv_close_wifi, R.id.tv_scan_wifi 91 | , R.id.tv_connection_wifi, R.id.tv_disconnection_wifi, R.id.tv_delete_wifi 92 | , R.id.tv_wifi_message, R.id.tv_wifi_info}) 93 | public void onViewClicked(View view) { 94 | switch (view.getId()) { 95 | case R.id.tv_open_wifi: 96 | wifiControlUtils.openWifi(); 97 | break; 98 | case R.id.tv_close_wifi: 99 | wifiControlUtils.closeWifi(); 100 | break; 101 | case R.id.tv_scan_wifi: 102 | wifiControlUtils.scanWifi(); 103 | ToastUtils.showShort("扫描到" + wifiControlUtils.getWifiList().size() + "个wifi"); 104 | StringBuilder stringBuilder = new StringBuilder(); 105 | 106 | stringBuilder.append("上一次连接的wifi:"); 107 | stringBuilder.append(wifiInfo.getSSID()); 108 | stringBuilder.append(":"); 109 | stringBuilder.append(wifiInfo.getBSSID()); 110 | stringBuilder.append(" 强度:" + wifiInfo.getRssi()); 111 | stringBuilder.append("\n\n"); 112 | 113 | for (ScanResult scanResult : wifiControlUtils.getWifiList()) { 114 | stringBuilder.append(scanResult.SSID); 115 | stringBuilder.append(":"); 116 | stringBuilder.append(scanResult.BSSID); 117 | stringBuilder.append(" 强度:" + scanResult.level); 118 | stringBuilder.append("\n\n"); 119 | } 120 | tvWifiMessage.setText(stringBuilder.toString()); 121 | break; 122 | case R.id.tv_wifi_info: 123 | tvWifiMessage.setText(wifiControlUtils.getWifiInfo().toString()); 124 | break; 125 | case R.id.tv_connection_wifi: 126 | wifiControlUtils.addNetWork(etWifiName.getText().toString(), etWifiPwd.getText().toString(), WifiControlUtils.WIFI_CIPHER_WAP); 127 | break; 128 | case R.id.tv_disconnection_wifi: 129 | wifiControlUtils.disconnectWifi(etWifiName.getText().toString()); 130 | break; 131 | case R.id.tv_delete_wifi: 132 | if (!wifiControlUtils.removeWifi(etWifiName.getText().toString())) { 133 | ToastUtils.showShort(R.string.unable_remove); 134 | } 135 | break; 136 | case R.id.tv_wifi_message: 137 | tvWifiMessage.setText(wifiControlUtils.getWifiInfo().toString()); 138 | break; 139 | } 140 | } 141 | 142 | @Override 143 | protected void onDestroy() { 144 | super.onDestroy(); 145 | //注销广播 146 | unregisterReceiver(wifiBroadcastReceiver); 147 | } 148 | } -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/activity/WifiTcpActivity.kt: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.activity 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | import android.view.View 7 | import android.widget.EditText 8 | import android.widget.TextView 9 | import com.bao.wifidemo.R 10 | import com.blankj.utilcode.util.NetworkUtils 11 | import com.blankj.utilcode.util.ToastUtils 12 | 13 | /** 14 | * Created by bao on 2018/3/21. 15 | * Tcp通信Activity 16 | */ 17 | class WifiTcpActivity : AppCompatActivity(), View.OnClickListener { 18 | 19 | companion object { 20 | val HOST_IP = "ip" 21 | } 22 | 23 | private var et_server_ip: EditText? = null 24 | 25 | override fun onCreate(savedInstanceState: Bundle?) { 26 | super.onCreate(savedInstanceState) 27 | setContentView(R.layout.wifi_tcp_activity) 28 | 29 | 30 | et_server_ip = findViewById(R.id.et_server_ip) 31 | findViewById(R.id.tv_tcp_server).setOnClickListener(this@WifiTcpActivity) 32 | findViewById(R.id.tv_tcp_client).setOnClickListener(this@WifiTcpActivity) 33 | 34 | //toast本机ip地址 35 | ToastUtils.showLong(NetworkUtils.getIPAddress(true)) 36 | } 37 | 38 | override fun onClick(view: View?) { 39 | when (view!!.id) { 40 | R.id.tv_tcp_server -> { 41 | startActivity(Intent(this@WifiTcpActivity, TcpServerActivity::class.java)) 42 | } 43 | R.id.tv_tcp_client -> { 44 | var intent = Intent(this@WifiTcpActivity, TcpClientActivity::class.java) 45 | intent.putExtra(HOST_IP, et_server_ip!!.text.toString()) 46 | startActivity(intent) 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/activity/WifiUdpActivity.java: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.text.TextUtils; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.Button; 10 | import android.widget.TextView; 11 | 12 | import com.bao.wifidemo.R; 13 | import com.bao.wifidemo.utils.Constants; 14 | import com.blankj.utilcode.util.LogUtils; 15 | 16 | import java.io.BufferedReader; 17 | import java.io.IOException; 18 | import java.io.InputStreamReader; 19 | import java.net.DatagramPacket; 20 | import java.net.InetAddress; 21 | import java.net.MulticastSocket; 22 | import java.net.NetworkInterface; 23 | import java.net.ServerSocket; 24 | import java.net.Socket; 25 | import java.net.SocketException; 26 | import java.util.Enumeration; 27 | import java.util.concurrent.BlockingQueue; 28 | import java.util.concurrent.LinkedBlockingQueue; 29 | import java.util.concurrent.ThreadPoolExecutor; 30 | import java.util.concurrent.TimeUnit; 31 | 32 | import butterknife.BindView; 33 | import butterknife.ButterKnife; 34 | import butterknife.OnClick; 35 | 36 | /** 37 | * Created by bao on 2018/3/21. 38 | * Udp通信Activity 39 | * 测试端口号20001,接收端口号4001,ip:224.0.0.1 40 | */ 41 | public class WifiUdpActivity extends AppCompatActivity { 42 | @BindView(R.id.btn_start) 43 | Button btnStart; 44 | @BindView(R.id.btn_stop) 45 | Button btnStop; 46 | @BindView(R.id.tv_send_information) 47 | TextView tvSendInformation; 48 | @BindView(R.id.tv_receive_information) 49 | TextView tvReceiveInformation; 50 | 51 | /* 用于 udpReceiveAndTcpSend 的3个变量 */ 52 | private Socket socket = null; 53 | private MulticastSocket multicastSocket = null; 54 | private DatagramPacket datagramPacket; 55 | 56 | private TcpReceive tcpReceive; 57 | private UdpReceiveAndtcpSend udpReceiveAndtcpSend; 58 | private ThreadPoolExecutor threadPoolExecutor; 59 | 60 | @Override 61 | protected void onCreate(@Nullable Bundle savedInstanceState) { 62 | super.onCreate(savedInstanceState); 63 | setContentView(R.layout.wifi_udp_activity); 64 | ButterKnife.bind(this); 65 | 66 | 67 | tvSendInformation.append("\n\n"); 68 | tvReceiveInformation.append("\n\n"); 69 | /* 开一个线程接收tcp 连接*/ 70 | tcpReceive = new TcpReceive(); 71 | /* 开一个线程 接收udp多播 并 发送tcp 连接*/ 72 | udpReceiveAndtcpSend = new UdpReceiveAndtcpSend(); 73 | 74 | int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors(); 75 | int KEEP_ALIVE_TIME = 1; 76 | TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS; 77 | BlockingQueue blockingQueue = new LinkedBlockingQueue(); 78 | threadPoolExecutor = new ThreadPoolExecutor(NUMBER_OF_CORES 79 | , NUMBER_OF_CORES * 2 80 | , KEEP_ALIVE_TIME 81 | , KEEP_ALIVE_TIME_UNIT 82 | , blockingQueue); 83 | 84 | 85 | threadPoolExecutor.execute(tcpReceive); 86 | threadPoolExecutor.execute(udpReceiveAndtcpSend); 87 | } 88 | 89 | @OnClick({R.id.btn_start, R.id.btn_stop}) 90 | public void onViewClicked(View view) { 91 | switch (view.getId()) { 92 | case R.id.btn_start: 93 | /* 新开一个线程 发送 udp 多播 */ 94 | UdpBroadCast udpBroadCast = new UdpBroadCast("hi ~!" + System.getProperty("http.agent")); 95 | threadPoolExecutor.execute(udpBroadCast); 96 | break; 97 | case R.id.btn_stop: 98 | break; 99 | } 100 | } 101 | 102 | 103 | /** 104 | * 发送udp多播 105 | */ 106 | private class UdpBroadCast extends Thread { 107 | MulticastSocket sender = null; 108 | DatagramPacket datagramPacket1 = null; 109 | InetAddress group = null; 110 | 111 | byte[] data = new byte[1024]; 112 | 113 | public UdpBroadCast(String dataString) { 114 | data = dataString.getBytes(); 115 | } 116 | 117 | @Override 118 | public void run() { 119 | try { 120 | sender = new MulticastSocket(); 121 | //ip 122 | group = InetAddress.getByName(Constants.INSTANCE.getHOST_ADDRESS()); 123 | //端口号 124 | datagramPacket1 = new DatagramPacket(data, data.length, group, Constants.INSTANCE.getHOST_PORT()); 125 | sender.send(datagramPacket1); 126 | sender.close(); 127 | } catch (IOException e) { 128 | e.printStackTrace(); 129 | } 130 | } 131 | } 132 | 133 | /** 134 | * 接收udp多播 并 发送tcp 连接 135 | */ 136 | private class UdpReceiveAndtcpSend extends Thread { 137 | @Override 138 | public void run() { 139 | byte[] data = new byte[1024]; 140 | try { 141 | InetAddress groupAddress = InetAddress.getByName(Constants.INSTANCE.getHOST_ADDRESS()); 142 | multicastSocket = new MulticastSocket(Constants.INSTANCE.getHOST_PORT()); 143 | multicastSocket.joinGroup(groupAddress); 144 | } catch (Exception e) { 145 | e.printStackTrace(); 146 | } 147 | 148 | while (true) { 149 | try { 150 | datagramPacket = new DatagramPacket(data, data.length); 151 | if (multicastSocket != null) 152 | multicastSocket.receive(datagramPacket); 153 | } catch (Exception e) { 154 | e.printStackTrace(); 155 | } 156 | 157 | if (datagramPacket.getAddress() != null) { 158 | final String quest_ip = datagramPacket.getAddress().toString(); 159 | 160 | /* 若udp包的ip地址 是 本机的ip地址的话,丢掉这个包(不处理)*/ 161 | 162 | //String host_ip = getLocalIPAddress(); 163 | 164 | String host_ip = getLocalHostIp(); 165 | 166 | LogUtils.d("host_ip: -------------------- " + host_ip); 167 | LogUtils.d("quest_ip: -------------------- " + quest_ip.substring(1)); 168 | 169 | if (!TextUtils.isEmpty(host_ip) && host_ip.equals(quest_ip.substring(1))) { 170 | continue; 171 | } 172 | 173 | final String codeString = new String(data, 0, datagramPacket.getLength()); 174 | 175 | tvReceiveInformation.post(new Runnable() { 176 | @Override 177 | public void run() { 178 | tvReceiveInformation.append("收到来自: \n" + quest_ip.substring(1) + "\n" + "的udp请求\n"); 179 | tvReceiveInformation.append("请求内容: " + codeString + "\n\n"); 180 | } 181 | }); 182 | try { 183 | final String target_ip = datagramPacket.getAddress().toString().substring(1); 184 | tvSendInformation.post(new Runnable() { 185 | @Override 186 | public void run() { 187 | tvSendInformation.append("发送tcp请求到: \n" + target_ip + "\n"); 188 | } 189 | }); 190 | socket = new Socket(target_ip, Constants.INSTANCE.getPHONE_PORT()); 191 | } catch (IOException e) { 192 | e.printStackTrace(); 193 | } finally { 194 | 195 | try { 196 | if (socket != null) 197 | socket.close(); 198 | } catch (IOException e) { 199 | e.printStackTrace(); 200 | } 201 | } 202 | } 203 | } 204 | } 205 | } 206 | 207 | 208 | /** 209 | * 接收tcp连接 210 | */ 211 | private class TcpReceive extends Thread { 212 | ServerSocket serverSocket; 213 | Socket socket; 214 | BufferedReader in; 215 | String source_address; 216 | 217 | @Override 218 | public void run() { 219 | while (true) { 220 | serverSocket = null; 221 | socket = null; 222 | in = null; 223 | try { 224 | serverSocket = new ServerSocket(Constants.INSTANCE.getPHONE_PORT()); 225 | socket = serverSocket.accept(); 226 | if (socket != null) { 227 | in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 228 | StringBuilder sb = new StringBuilder(); 229 | sb.append(socket.getInetAddress().getHostAddress()); 230 | 231 | String line = null; 232 | while ((line = in.readLine()) != null) { 233 | sb.append(line); 234 | } 235 | 236 | source_address = sb.toString().trim(); 237 | tvReceiveInformation.post(new Runnable() { 238 | @Override 239 | public void run() { 240 | tvReceiveInformation.append("收到来自: " + "\n" + source_address + "\n" + "的tcp请求\n\n"); 241 | } 242 | }); 243 | } 244 | } catch (IOException e1) { 245 | e1.printStackTrace(); 246 | } finally { 247 | try { 248 | if (in != null) 249 | in.close(); 250 | if (socket != null) 251 | socket.close(); 252 | if (serverSocket != null) 253 | serverSocket.close(); 254 | } catch (IOException e) { 255 | e.printStackTrace(); 256 | } 257 | } 258 | } 259 | } 260 | } 261 | 262 | public String getLocalHostIp() { 263 | String ipaddress = ""; 264 | try { 265 | Enumeration en = NetworkInterface 266 | .getNetworkInterfaces(); 267 | // 遍历所用的网络接口 268 | while (en.hasMoreElements()) { 269 | // 得到每一个网络接口绑定的所有ip 270 | NetworkInterface nif = en.nextElement(); 271 | Enumeration inet = nif.getInetAddresses(); 272 | // 遍历每一个接口绑定的所有ip 273 | while (inet.hasMoreElements()) { 274 | InetAddress ip = inet.nextElement(); 275 | if (!ip.isLoopbackAddress()) { 276 | return ip.getHostAddress(); 277 | } 278 | } 279 | } 280 | } catch (SocketException e) { 281 | Log.e("feige", "获取本地ip地址失败"); 282 | e.printStackTrace(); 283 | } 284 | return ipaddress; 285 | } 286 | 287 | 288 | @Override 289 | protected void onDestroy() { 290 | //关闭 多播socket multicastSocket 291 | multicastSocket.close(); 292 | threadPoolExecutor.shutdownNow(); 293 | super.onDestroy(); 294 | } 295 | } -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/application/BaseApplication.kt: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.application 2 | 3 | import android.app.Application 4 | import com.blankj.utilcode.util.LogUtils 5 | import com.blankj.utilcode.util.Utils 6 | 7 | /** 8 | * 尝试一下下kotlin,O(∩_∩)O哈哈~ 9 | */ 10 | class BaseApplication : Application() { 11 | 12 | /** 13 | * 相当于下面这段代码,Kotlin里get,set方法可以不用写,默认就有 14 | * private static BaseApplication instance; 15 | 16 | public static BaseApplication getInstance() 17 | { 18 | return instance; 19 | } 20 | */ 21 | companion object { 22 | var instance: BaseApplication? = null 23 | } 24 | 25 | 26 | override fun onCreate() { 27 | super.onCreate() 28 | instance = this 29 | //超级强大的工具类:https://github.com/Blankj/AndroidUtilCode/blob/master/utilcode/README-CN.md 30 | Utils.init(this) 31 | LogUtils.getConfig().setGlobalTag("bao") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/receiver/WifiBroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.receiver; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.NetworkInfo; 7 | import android.net.wifi.SupplicantState; 8 | import android.net.wifi.WifiManager; 9 | 10 | import com.bao.wifidemo.R; 11 | import com.bao.wifidemo.utils.WifiControlUtils; 12 | import com.blankj.utilcode.util.LogUtils; 13 | import com.blankj.utilcode.util.ToastUtils; 14 | 15 | /** 16 | * Created by bao on 2018/3/21. 17 | * wifi状态广播 18 | */ 19 | public class WifiBroadcastReceiver extends BroadcastReceiver 20 | { 21 | private WifiControlUtils wifiControlUtils; 22 | 23 | @Override 24 | public void onReceive(Context context, Intent intent) 25 | { 26 | wifiControlUtils = new WifiControlUtils(context); 27 | 28 | //wifi正在改变状态 29 | if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) 30 | { 31 | //获取wifi状态 32 | int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLING); 33 | switch (wifiState) 34 | { 35 | case WifiManager.WIFI_STATE_DISABLED: 36 | //wifi已经关闭 37 | LogUtils.d(context.getString(R.string.wifi_state_disabled)); 38 | ToastUtils.showShort(context.getString(R.string.wifi_state_disabled)); 39 | break; 40 | case WifiManager.WIFI_STATE_DISABLING: 41 | //wifi正在关闭 42 | LogUtils.d(context.getString(R.string.wifi_state_disabling)); 43 | ToastUtils.showShort(context.getString(R.string.wifi_state_disabling)); 44 | break; 45 | case WifiManager.WIFI_STATE_ENABLED: 46 | //wifi已经开启 47 | LogUtils.d(context.getString(R.string.wifi_state_enabled)); 48 | ToastUtils.showShort(context.getString(R.string.wifi_state_enabled)); 49 | break; 50 | case WifiManager.WIFI_STATE_ENABLING: 51 | //wifi正在开启 52 | LogUtils.d(context.getString(R.string.wifi_state_enabling)); 53 | ToastUtils.showShort(context.getString(R.string.wifi_state_enabling)); 54 | break; 55 | } 56 | } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) 57 | { 58 | //网络状态改变 59 | NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); 60 | if (NetworkInfo.State.DISCONNECTED.equals(info.getState())) 61 | { 62 | //wifi网络连接断开 63 | } else if (NetworkInfo.State.CONNECTED.equals(info.getState())) 64 | { 65 | //获取当前网络,wifi名称 66 | ToastUtils.showLong(context.getString(R.string.wifi_connected, wifiControlUtils.getWifiInfo().getSSID())); 67 | } 68 | } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(intent.getAction())) 69 | { 70 | //wifi密码错误广播 71 | SupplicantState netNewState = intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE); 72 | //错误码 73 | int netConnectErrorCode = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, WifiManager.ERROR_AUTHENTICATING); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/socket/ClientLastly.java: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.socket; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | import android.text.TextUtils; 6 | 7 | import com.bao.wifidemo.utils.Constants; 8 | import com.blankj.utilcode.util.LogUtils; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.IOException; 12 | import java.io.InputStreamReader; 13 | import java.io.PrintWriter; 14 | import java.net.Socket; 15 | 16 | /** 17 | * 通过socket实现 18 | * 19 | * @author Administrator 20 | */ 21 | public class ClientLastly implements Runnable { 22 | private static final String TAG = "tcp_client"; 23 | public static final int CLIENT_ARG = 0x12; 24 | //超时时间,如果60S没通信,就会断开 25 | private int timeout = 60000; 26 | private Socket clientSocket; 27 | private PrintWriter printWriter; 28 | private BufferedReader bufferedReader; 29 | 30 | Handler handler; 31 | private String server_ip; 32 | 33 | public ClientLastly(Handler handler, String server_ip) { 34 | this.handler = handler; 35 | this.server_ip = server_ip; 36 | // try { 37 | // //连接服务器 38 | // clientSocket=new Socket("localhost", 8888); 39 | // Log.i(TAG, "Client=======连接服务器成功========="); 40 | // clientSocket.setSoTimeout(timeout); 41 | // printWriter=new PrintWriter(clientSocket.getOutputStream()); 42 | // bufferedReader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 43 | // } catch (IOException e) { 44 | // // TODO Auto-generated catch block 45 | // e.printStackTrace(); 46 | // } 47 | } 48 | 49 | //发数据 50 | public void send(String data) { 51 | LogUtils.dTag(TAG, "客户端发送:" + data); 52 | if (printWriter != null) { 53 | printWriter.println(data); 54 | printWriter.flush(); 55 | } 56 | } 57 | 58 | 59 | //接收据 60 | @Override 61 | public void run() { 62 | try { 63 | //连接服务器 64 | clientSocket = new Socket(server_ip, Constants.INSTANCE.getHOST_PORT()); 65 | LogUtils.dTag(TAG, "=======连接服务器成功========="); 66 | clientSocket.setSoTimeout(timeout); 67 | printWriter = new PrintWriter(clientSocket.getOutputStream()); 68 | bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 69 | } catch (IOException e) { 70 | // TODO Auto-generated catch block 71 | e.printStackTrace(); 72 | } 73 | 74 | try { 75 | if (bufferedReader != null && !TextUtils.isEmpty(bufferedReader.readLine())) { 76 | String result = ""; 77 | while ((result = bufferedReader.readLine()) != null) { 78 | LogUtils.dTag(TAG, "客户端接到的数据为:" + result); 79 | //将数据带回acitvity显示 80 | Message msg = handler.obtainMessage(); 81 | msg.arg1 = CLIENT_ARG; 82 | msg.obj = result; 83 | handler.sendMessage(msg); 84 | } 85 | } 86 | } catch (IOException e) { 87 | // TODO Auto-generated catch block 88 | e.printStackTrace(); 89 | } 90 | } 91 | 92 | public void close() { 93 | try { 94 | if (printWriter != null) { 95 | printWriter.close(); 96 | } 97 | if (bufferedReader != null) { 98 | bufferedReader.close(); 99 | } 100 | if (clientSocket != null) { 101 | clientSocket.close(); 102 | } 103 | } catch (IOException e) { 104 | // TODO Auto-generated catch block 105 | e.printStackTrace(); 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/socket/ServerLastly.java: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.socket; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | import android.text.TextUtils; 6 | 7 | import com.bao.wifidemo.utils.Constants; 8 | import com.blankj.utilcode.util.LogUtils; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.IOException; 12 | import java.io.InputStreamReader; 13 | import java.io.PrintWriter; 14 | import java.net.InetAddress; 15 | import java.net.ServerSocket; 16 | import java.net.Socket; 17 | 18 | /** 19 | * 通过Socket实现 20 | * 21 | * @author Administrator 22 | */ 23 | public class ServerLastly implements Runnable { 24 | private static final String TAG = "tcp_server"; 25 | public static final int SERVER_ARG = 0x11; 26 | private ServerSocket serverSocket; 27 | private Socket clientSocket; 28 | private PrintWriter printWriter; 29 | private BufferedReader bufferedReader; 30 | 31 | private Handler handler; 32 | 33 | /** 34 | * 此处不将连接代码写在构造方法中的原因: 35 | * 我在activity的onCreate()中创建示例,如果将连接代码 写在构造方法中,服务端会一直等待客户端连接,界面没有去描绘,会一直出现白屏。 36 | * 直到客户端连接上了,界面才会描绘出来。原因是构造方法阻塞了主线程,要另开一个线程。在这里我将它写在了run()中。 37 | */ 38 | public ServerLastly(Handler handler) { 39 | this.handler = handler; 40 | // Log.i(TAG, "Server=======打开服务========="); 41 | // try { 42 | // serverSocket=new ServerSocket(8888); 43 | // clientSocket=serverSocket.accept(); 44 | // Log.i(TAG, "Server=======客户端连接成功========="); 45 | // InetAddress inetAddress=clientSocket.getInetAddress(); 46 | // String ip=inetAddress.getHostAddress(); 47 | // Log.i(TAG, "===客户端ID为:"+ip); 48 | // printWriter=new PrintWriter(clientSocket.getOutputStream()); 49 | // bufferedReader=new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 50 | // 51 | // } catch (IOException e) { 52 | // // TODO Auto-generated catch block 53 | // e.printStackTrace(); 54 | // } 55 | } 56 | 57 | //发数据 58 | public void send(String data) { 59 | LogUtils.dTag(TAG, "服务端发送:" + data); 60 | if (printWriter != null) { 61 | printWriter.println(data); 62 | printWriter.flush(); 63 | } 64 | } 65 | 66 | //接数据 67 | @Override 68 | public void run() { 69 | LogUtils.dTag(TAG, "=======打开服务========="); 70 | try { 71 | serverSocket = new ServerSocket(Constants.INSTANCE.getHOST_PORT()); 72 | clientSocket = serverSocket.accept(); 73 | LogUtils.dTag(TAG, "======客户端连接成功========="); 74 | InetAddress inetAddress = clientSocket.getInetAddress(); 75 | String ip = inetAddress.getHostAddress(); 76 | LogUtils.dTag(TAG, "客户端ID为:" + ip); 77 | printWriter = new PrintWriter(clientSocket.getOutputStream()); 78 | bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 79 | 80 | } catch (IOException e) { 81 | // TODO Auto-generated catch block 82 | e.printStackTrace(); 83 | } 84 | 85 | 86 | try { 87 | if (bufferedReader != null &&!TextUtils.isEmpty(bufferedReader.readLine())) { 88 | String result = ""; 89 | while ((result = bufferedReader.readLine()) != null) { 90 | LogUtils.dTag(TAG, "服务端接到的数据为:" + result); 91 | //把数据带回activity显示 92 | Message msg = handler.obtainMessage(); 93 | msg.obj = result; 94 | msg.arg1 = SERVER_ARG; 95 | handler.sendMessage(msg); 96 | } 97 | } 98 | } catch (IOException e) { 99 | // TODO Auto-generated catch block 100 | e.printStackTrace(); 101 | } 102 | } 103 | 104 | public void close() { 105 | try { 106 | if (printWriter != null) { 107 | printWriter.close(); 108 | } 109 | if (bufferedReader != null) { 110 | bufferedReader.close(); 111 | } 112 | if (clientSocket != null) { 113 | clientSocket.close(); 114 | } 115 | if (serverSocket != null) { 116 | serverSocket.close(); 117 | } 118 | } catch (IOException e) { 119 | // TODO Auto-generated catch block 120 | e.printStackTrace(); 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/utils/CheckPermission.java: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.utils; 2 | 3 | import android.Manifest; 4 | import android.app.Activity; 5 | import android.content.DialogInterface; 6 | import android.os.Build; 7 | import android.support.annotation.NonNull; 8 | 9 | import com.bao.wifidemo.R; 10 | import com.yanzhenjie.permission.AndPermission; 11 | import com.yanzhenjie.permission.PermissionListener; 12 | import com.yanzhenjie.permission.Rationale; 13 | import com.yanzhenjie.permission.RationaleListener; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * Created by solexit04 on 2017/7/6. 19 | * 动态权限 20 | */ 21 | 22 | public abstract class CheckPermission 23 | { 24 | private Activity activity; 25 | 26 | public CheckPermission(Activity activity) 27 | { 28 | this.activity = activity; 29 | } 30 | 31 | //存储 32 | public static final int REQUEST_CODE_PERMISSION_STORAGE = 100; 33 | //相机 34 | public static final int REQUEST_CODE_PERMISSION_CAMERA = 101; 35 | //日历 36 | public static final int REQUEST_CODE_PERMISSION_CALENDAR = 102; 37 | //定位 38 | public static final int REQUEST_CODE_PERMISSION_LOCATION = 103; 39 | //短信 40 | public static final int REQUEST_CODE_PERMISSION_SMS = 104; 41 | //联系人 42 | public static final int REQUEST_CODE_PERMISSION_CONTACTS = 105; 43 | //打电话,手机状态 44 | public static final int REQUEST_CODE_PERMISSION_PHONE = 106; 45 | //麦克风 46 | public static final int REQUEST_CODE_PERMISSION_MICROPHONE = 107; 47 | //传感器 48 | public static final int REQUEST_CODE_PERMISSION_SENSORS = 108; 49 | //综合 50 | public static final int REQUEST_CODE_PERMISSION_OTHER = 109; 51 | 52 | /** 53 | * 检测权限 54 | */ 55 | public void permission(int permissionType) 56 | { 57 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 58 | { 59 | switch (permissionType) 60 | { 61 | case REQUEST_CODE_PERMISSION_LOCATION: 62 | AndPermission.with(activity) 63 | .requestCode(REQUEST_CODE_PERMISSION_LOCATION) 64 | .permission(Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.CHANGE_WIFI_STATE) 65 | .callback(permissionListener) 66 | // rationale作用是:用户拒绝一次权限,再次申请时先征求用户同意,再打开授权对话框; 67 | // 这样避免用户勾选不再提示,导致以后无法申请权限。 68 | // 你也可以不设置。 69 | .rationale(new RationaleListener() 70 | { 71 | @Override 72 | public void showRequestPermissionRationale(int requestCode, Rationale rationale) 73 | { 74 | // 这里的对话框可以自定义,只要调用rationale.resume()就可以继续申请。 75 | AndPermission.rationaleDialog(activity, rationale) 76 | .show(); 77 | } 78 | }) 79 | .start(); 80 | break; 81 | } 82 | } 83 | } 84 | 85 | /** 86 | * 回调监听。 87 | */ 88 | private PermissionListener permissionListener = new PermissionListener() 89 | { 90 | @Override 91 | public void onSucceed(int requestCode, @NonNull List grantPermissions) 92 | { 93 | permissionSuccess(); 94 | } 95 | 96 | @Override 97 | public void onFailed(int requestCode, @NonNull List deniedPermissions) 98 | { 99 | permissionError(); 100 | String title = activity.getString(R.string.permission_request_error); 101 | String message = "我们需要的一些权限被您拒绝或者系统发生错误申请失败,请您到设置页面手动授权,否则功能无法正常使用!"; 102 | switch (requestCode) 103 | { 104 | case REQUEST_CODE_PERMISSION_LOCATION: 105 | message = activity.getString(R.string.permission_location); 106 | break; 107 | } 108 | 109 | // 用户否勾选了不再提示并且拒绝了权限,那么提示用户到设置中授权。 110 | if (AndPermission.hasAlwaysDeniedPermission(activity, deniedPermissions)) 111 | { 112 | // 第二种:用自定义的提示语。 113 | AndPermission.defaultSettingDialog(activity, requestCode) 114 | .setTitle(title) 115 | .setMessage(message) 116 | .setPositiveButton(activity.getString(R.string.setting)) 117 | .setNegativeButton(activity.getString(R.string.cancel), new DialogInterface.OnClickListener() 118 | { 119 | @Override 120 | public void onClick(DialogInterface dialog, int which) 121 | { 122 | negativeButton(); 123 | } 124 | }) 125 | .show(); 126 | } 127 | } 128 | }; 129 | 130 | /** 131 | * 权限申请成功 132 | */ 133 | public abstract void permissionSuccess(); 134 | 135 | /** 136 | * 权限申请失败 137 | */ 138 | public void permissionError() 139 | { 140 | } 141 | 142 | /** 143 | * 取消按钮 144 | */ 145 | public void negativeButton() 146 | { 147 | activity.finish(); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/utils/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.utils 2 | 3 | object Constants { 4 | val HOST_ADDRESS = "255.255.255.255" 5 | 6 | val HOST_PORT = 20001 7 | val PHONE_PORT = 4001 8 | 9 | val WIFI_NAME = "bao_phone" 10 | val WIFI_PWD = "baozi888888" 11 | } -------------------------------------------------------------------------------- /app/src/main/java/com/bao/wifidemo/utils/WifiControlUtils.java: -------------------------------------------------------------------------------- 1 | package com.bao.wifidemo.utils; 2 | 3 | import android.content.Context; 4 | import android.net.wifi.ScanResult; 5 | import android.net.wifi.WifiConfiguration; 6 | import android.net.wifi.WifiInfo; 7 | import android.net.wifi.WifiManager; 8 | 9 | import com.blankj.utilcode.util.ToastUtils; 10 | 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.lang.reflect.Method; 13 | import java.util.List; 14 | 15 | /** 16 | * Created by bao on 2018/3/21. 17 | * wifi控制工具 18 | */ 19 | public class WifiControlUtils { 20 | //无密码 21 | static final public int WIFI_CIPHER_NPW = 0; 22 | //WEP加密 23 | static final public int WIFI_CIPHER_WEP = 1; 24 | //WAP加密 25 | static final public int WIFI_CIPHER_WAP = 2; 26 | 27 | private WifiManager mWifiManager; 28 | //能够阻止wifi进入睡眠状态,使wifi一直处于活跃状态 29 | private WifiManager.WifiLock mWifiLock; 30 | //扫描出的wifi列表 31 | private List wifiList; 32 | //已连接过的wifi列表 33 | private List wifiConfigurationList; 34 | 35 | 36 | public WifiControlUtils(Context context) { 37 | //获取wifiManager对象 38 | mWifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); 39 | } 40 | 41 | /** 42 | * 打开wifi 43 | */ 44 | public void openWifi() { 45 | if (!mWifiManager.isWifiEnabled()) { 46 | mWifiManager.setWifiEnabled(true); 47 | scanWifi(); 48 | } 49 | } 50 | 51 | /** 52 | * 关闭wifi 53 | */ 54 | public void closeWifi() { 55 | if (mWifiManager.isWifiEnabled()) { 56 | mWifiManager.setWifiEnabled(false); 57 | } 58 | } 59 | 60 | /** 61 | * 获取wifi连接信息 62 | **/ 63 | public WifiInfo getWifiInfo() { 64 | if (mWifiManager != null) { 65 | return mWifiManager.getConnectionInfo(); 66 | } 67 | return null; 68 | } 69 | 70 | 71 | /** 72 | * 搜索wifi 73 | */ 74 | public void scanWifi() { 75 | mWifiManager.startScan(); 76 | //得到扫描结果 77 | wifiList = mWifiManager.getScanResults(); 78 | //得到配置过的网络 79 | wifiConfigurationList = mWifiManager.getConfiguredNetworks(); 80 | } 81 | 82 | /** 83 | * 获取连接过的wifi 84 | */ 85 | public List getWifiConfigurationList() { 86 | //得到配置过的网络 87 | wifiConfigurationList = mWifiManager.getConfiguredNetworks(); 88 | return wifiConfigurationList; 89 | } 90 | 91 | /** 92 | * 获取扫描wifi的列表 93 | * 同名字的wifi可以出现多个,比如公司里面的wifi都叫同一个名字,但是由不同的路由器发出来的 94 | */ 95 | public List getWifiList() { 96 | //得到扫描结果 97 | wifiList = mWifiManager.getScanResults(); 98 | return wifiList; 99 | } 100 | 101 | /** 102 | * 创建一个WifiLock 103 | **/ 104 | public void createWifiLock() { 105 | mWifiLock = this.mWifiManager.createWifiLock("testLock"); 106 | } 107 | 108 | /** 109 | * 锁定WifiLock,当下载大文件时需要锁定 110 | **/ 111 | public void acquireWifiLock() { 112 | mWifiLock.acquire(); 113 | } 114 | 115 | /** 116 | * 解锁WifiLock 117 | **/ 118 | public void releaseWifilock() { 119 | if (mWifiLock.isHeld()) { 120 | //判断时候锁定 121 | mWifiLock.acquire(); 122 | } 123 | } 124 | 125 | public void addNetWork(String SSID) { 126 | int netId = -1; 127 | if (getExitsWifiConfig(SSID) != null) { 128 | //这个wifi是连接过的,如果这个wifi在连接之后改了密码,那就只能手动去删除了 129 | netId = getExitsWifiConfig(SSID).networkId; 130 | //这个方法的第一个参数是需要连接wifi网络的networkId,第二个参数是指连接当前wifi网络是否需要断开其他网络 131 | //无论是否连接上,都返回true。。。。 132 | mWifiManager.enableNetwork(netId, true); 133 | } 134 | } 135 | 136 | /** 137 | * 连接指定wifi 138 | * 6.0以上版本,直接查找时候有连接过,连接过的拿出wifiConfiguration用 139 | * 不要去创建新的wifiConfiguration,否者失败 140 | */ 141 | public void addNetWork(String SSID, String password, int Type) { 142 | int netId = -1; 143 | /*先执行删除wifi操作,1.如果删除的成功说明这个wifi配置是由本APP配置出来的; 144 | 2.这样可以避免密码错误之后,同名字的wifi配置存在,无法连接; 145 | 3.wifi直接连接成功过,不删除也能用, netId = getExitsWifiConfig(SSID).networkId;*/ 146 | if (removeWifi(SSID)) { 147 | //移除成功,就新建一个 148 | netId = mWifiManager.addNetwork(createWifiInfo(SSID, password, Type)); 149 | } else { 150 | //删除不成功,要么这个wifi配置以前就存在过,要么是还没连接过的 151 | if (getExitsWifiConfig(SSID) != null) { 152 | //这个wifi是连接过的,如果这个wifi在连接之后改了密码,那就只能手动去删除了 153 | netId = getExitsWifiConfig(SSID).networkId; 154 | } else { 155 | //没连接过的,新建一个wifi配置 156 | netId = mWifiManager.addNetwork(createWifiInfo(SSID, password, Type)); 157 | } 158 | } 159 | 160 | //这个方法的第一个参数是需要连接wifi网络的networkId,第二个参数是指连接当前wifi网络是否需要断开其他网络 161 | //无论是否连接上,都返回true。。。。 162 | mWifiManager.enableNetwork(netId, true); 163 | } 164 | 165 | /** 166 | * 获取配置过的wifiConfiguration 167 | */ 168 | public WifiConfiguration getExitsWifiConfig(String SSID) { 169 | wifiConfigurationList = mWifiManager.getConfiguredNetworks(); 170 | for (WifiConfiguration wifiConfiguration : wifiConfigurationList) { 171 | if (wifiConfiguration.SSID.equals("\"" + SSID + "\"")) { 172 | return wifiConfiguration; 173 | } 174 | } 175 | return null; 176 | } 177 | 178 | /** 179 | * 移除wifi,因为权限,无法移除的时候,需要手动去翻wifi列表删除 180 | * 注意:!!!只能移除自己应用创建的wifi。 181 | * 删除掉app,再安装的,都不算自己应用,具体看removeNetwork源码 182 | * 183 | * @param netId wifi的id 184 | */ 185 | public boolean removeWifi(int netId) { 186 | return mWifiManager.removeNetwork(netId); 187 | } 188 | 189 | /** 190 | * 移除wifi 191 | * 192 | * @param SSID wifi名 193 | */ 194 | public boolean removeWifi(String SSID) { 195 | if (getExitsWifiConfig(SSID) != null) { 196 | return removeWifi(getExitsWifiConfig(SSID).networkId); 197 | } else { 198 | return false; 199 | } 200 | } 201 | 202 | /** 203 | * 断开指定ID的网络 204 | * 205 | * @param netId 网络id 206 | */ 207 | public void disconnectWifi(int netId) { 208 | mWifiManager.disableNetwork(netId); 209 | mWifiManager.disconnect(); 210 | } 211 | 212 | /** 213 | * 断开指定SSID的网络 214 | * 215 | * @param SSID wifi名 216 | */ 217 | public void disconnectWifi(String SSID) { 218 | if (getExitsWifiConfig(SSID) != null) { 219 | disconnectWifi(getExitsWifiConfig(SSID).networkId); 220 | } 221 | } 222 | 223 | 224 | /** 225 | * 创建一个wifiConfiguration 226 | * 227 | * @param SSID wifi名称 228 | * @param password wifi密码 229 | * @param Type 加密类型 230 | * @return 231 | */ 232 | public WifiConfiguration createWifiInfo(String SSID, String password, int Type) { 233 | WifiConfiguration config = new WifiConfiguration(); 234 | config.allowedAuthAlgorithms.clear(); 235 | config.allowedGroupCiphers.clear(); 236 | config.allowedKeyManagement.clear(); 237 | config.allowedPairwiseCiphers.clear(); 238 | config.allowedProtocols.clear(); 239 | config.SSID = "\"" + SSID + "\""; 240 | 241 | //如果有相同配置的,就先删除 242 | WifiConfiguration tempConfig = getExitsWifiConfig(SSID); 243 | if (tempConfig != null) { 244 | mWifiManager.removeNetwork(tempConfig.networkId); 245 | mWifiManager.saveConfiguration(); 246 | } 247 | 248 | //无密码 249 | if (Type == WIFI_CIPHER_NPW) { 250 | //config.wepKeys[0] = ""; 251 | config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 252 | //config.wepTxKeyIndex = 0; 253 | } 254 | //WEP加密 255 | else if (Type == WIFI_CIPHER_WEP) { 256 | config.hiddenSSID = true; 257 | config.wepKeys[0] = "\"" + password + "\""; 258 | config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); 259 | config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); 260 | config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); 261 | config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40); 262 | config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104); 263 | config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 264 | config.wepTxKeyIndex = 0; 265 | } 266 | //WPA加密 267 | else if (Type == WIFI_CIPHER_WAP) //WIFICIPHER_WPA 268 | { 269 | config.preSharedKey = "\"" + password + "\""; 270 | config.hiddenSSID = true; 271 | config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); 272 | config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); 273 | config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); 274 | config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); 275 | //config.allowedProtocols.set(WifiConfiguration.Protocol.WPA); 276 | config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); 277 | config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); 278 | config.status = WifiConfiguration.Status.ENABLED; 279 | } 280 | return config; 281 | } 282 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_down.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/global_black_line.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/global_black_vertical_line.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 19 | 20 | 29 | 30 | 31 | 32 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tcp_client_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 |