[Android App] Explanation and practice of checking the WiFi information of the mobile phone connection and scanning the surrounding WiFi (with source code and demo, super detailed and must-see)

If you need all the codes, please like and follow the collection and leave a private message in the comment area~~~

1. Check whether WiFi is connected and output WiFi information

The traditional positioning method is not suitable for indoor vertical positioning. The reasons are as follows: (1) Satellite positioning requires no obstructions. It is more accurate outdoors, but the signal becomes poor indoors. (2) Base station positioning depends on the communication service of the operator. If you are in a remote space where the base station signal has not been covered, you cannot use the base station positioning. Indoor WiFi positioning is incorporated into the IEEE 802.11 standard, called WLAN RTT (IEEE 802.11mc).

RTT is the abbreviation of Round-Trip-Time, that is, the round-trip time, which can be used to calculate the distance between the two ends of the network

The implementation steps of indoor WiFi definition have the following three steps

(1) Check whether the wireless network is connected to obtain WiFi information through the wireless network manager WifiManager.

(2) To scan the surrounding wireless networks, use the startScan and getScanResults methods of the wireless network manager.

(3) Calculate the round-trip delay of the WiFi router. Use WifiRttManager to measure the distance of the target router.

There are two main ways to access the Internet, namely, data connection and WiFi. However, the connection manager ConnectivityManager can only judge whether the Internet can be accessed in general, and cannot obtain detailed information about the WiFi connection. When the current network type is WiFi, if you want to know the WiFi connection For specific information, you also need to obtain some of it through the wireless network manager WifiManager as follows

isWifiEnabled Determine whether the WLAN function is enabled

setWifiEnabled Turn on or off the WLAN function

getWifiState Get the current WiFi connection status

The actual combat effect is as follows, and the relevant information of the connected Wifi will be output 

 

 code show as below

package com.example.location;

import com.example.location.util.IPv4Util;
import com.example.location.util.NetUtil;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Looper;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.widget.TextView;

@SuppressLint("DefaultLocale")
public class WifiInfoActivity extends AppCompatActivity {
    private static final String TAG = "WifiInfoActivity";
    private TextView tv_info; // 声明一个文本视图对象
    private Handler mHandler = new Handler(Looper.myLooper()); // 声明一个处理器对象
    private String[] mWifiStateArray = {"正在断开", "已断开", "正在连接", "已连接", "未知"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_wifi_info);
        tv_info = findViewById(R.id.tv_info);
        mHandler.postDelayed(mRefresh, 50); // 延迟50毫秒后启动网络刷新任务
    }

    // 定义一个网络刷新任务
    private Runnable mRefresh = new Runnable() {
        @Override
        public void run() {
            getAvailableNet(); // 获取可用的网络信息
            // 延迟1秒后再次启动网络刷新任务
            mHandler.postDelayed(this, 1000);
        }
    };

    // 获取可用的网络信息
    private void getAvailableNet() {
        String desc = "";
        // 从系统服务中获取电话管理器
        TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        // 从系统服务中获取连接管理器
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        // 通过连接管理器获得可用的网络信息
        NetworkInfo info = cm.getActiveNetworkInfo();
        if (info != null && info.getState() == NetworkInfo.State.CONNECTED) { // 有网络连接
            if (info.getType() == ConnectivityManager.TYPE_WIFI) { // WiFi网络(无线热点)
                // 从系统服务中获取无线网络管理器
                WifiManager wm = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
                int state = wm.getWifiState(); // 获得无线网络的状态
                WifiInfo wifiInfo = wm.getConnectionInfo(); // 获得无线网络信息
                String SSID = wifiInfo.getSSID(); // 获得无线网络的名称
                if (TextUtils.isEmpty(SSID) || SSID.contains("unknown")) {
                    desc = "\n当前联网的网络类型是WiFi,但未成功连接已知的WiFi信号";
                } else {
                    desc = String.format("当前联网的网络类型是WiFi,状态是%s。\nWiFi名称是:%s\n路由器MAC是:%s\nWiFi信号强度是:%d\n连接速率是:%s\n手机的IP地址是:%s\n手机的MAC地址是:%s\n网络编号是:%s\n",
                            mWifiStateArray[state], SSID, wifiInfo.getBSSID(),
                            wifiInfo.getRssi(), wifiInfo.getLinkSpeed(),
                            IPv4Util.intToIp(wifiInfo.getIpAddress()),
                            wifiInfo.getMacAddress(), wifiInfo.getNetworkId());
                }
            } else if (info.getType() == ConnectivityManager.TYPE_MOBILE) { // 移动网络(数据连接)
                int net_type = info.getSubtype();
                desc = String.format("\n当前联网的网络类型是%s %s",
                        NetUtil.getNetworkTypeName(tm, net_type),
                        NetUtil.getClassName(tm, net_type));
            } else {
                desc = String.format("\n当前联网的网络类型是%d", info.getType());
            }
        } else { // 无网络连接
            desc = "\n当前无上网连接";
        }
        tv_info.setText(desc);
    }

}

2. Scan the surrounding wireless networks

Scanning the surrounding Wi-Fi mainly uses the startScan method and the getScanResults method of the WiFi rolling force. The former means to start scanning the surrounding network, and the latter means to obtain the list of scanned results. These two methods cannot be followed closely, because the scanning action is performed asynchronously. Have to wait until the scan end broadcast is received before getting the scan result in the broadcast receiver

After clicking to start scanning, the result is as follows, and the nearby WiFi information will be output

 code show as below

package com.example.location;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.TextView;

import com.example.location.adapter.ScanListAdapter;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RequiresApi(api = Build.VERSION_CODES.M)
public class WifiScanActivity extends AppCompatActivity {
    private final static String TAG = "WifiScanActivity";
    private TextView tv_result; // 声明一个文本视图对象
    private ListView lv_scan; // 声明一个列表视图对象
    private WifiManager mWifiManager; // 声明一个WiFi管理器对象
    private WifiScanReceiver mWifiScanReceiver = new WifiScanReceiver(); // 声明一个WiFi扫描接收器对象

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_wifi_scan);
        tv_result = findViewById(R.id.tv_result);
        lv_scan = findViewById(R.id.lv_scan);
        findViewById(R.id.btn_scan).setOnClickListener(v -> mWifiManager.startScan());
        // 从系统服务中获取WiFi管理器
        mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
    }

    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter filter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        registerReceiver(mWifiScanReceiver, filter); // 注册WiFi扫描的广播接收器
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(mWifiScanReceiver); // 注销WiFi扫描的广播接收器
    }

    // 定义一个扫描周边WiFi的广播接收器
    private class WifiScanReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 获取WiFi扫描的结果列表
            List<ScanResult> scanList = mWifiManager.getScanResults();
            if (scanList != null) {
                // 查找符合80211标准的WiFi路由器集合
                Map<String, ScanResult> m80211mcMap = find80211mcResults(scanList);
                runOnUiThread(() -> showScanResult(scanList, m80211mcMap));
            }
        }
    }

    // 查找符合80211标准的WiFi路由器集合
    private Map<String, ScanResult> find80211mcResults(List<ScanResult> originList) {
        Map<String, ScanResult> resultMap = new HashMap<>();
        for (ScanResult scanResult : originList) { // 遍历扫描发现的WiFi列表
            if (scanResult.is80211mcResponder()) { // 符合80211标准
                resultMap.put(scanResult.BSSID, scanResult); // BSSID表示MAC地址
            }
        }
        return resultMap;
    }

    // 显示过滤后的WiFi扫描结果
    private void showScanResult(List<ScanResult> list, Map<String, ScanResult> map) {
        tv_result.setText(String.format("找到%d个WiFi热点,其中有%d个支持RTT。",
                                        list.size(), map.size()));
        lv_scan.setAdapter(new ScanListAdapter(this, list, map));
    }

}

3. Calculate the round-trip delay RTT

This requires the router to have the RTT function, and also requires the mobile phone to support indoor wifi positioning. The effect is as follows

 code show as below

package com.example.location;

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.net.wifi.rtt.RangingRequest;
import android.net.wifi.rtt.RangingResult;
import android.net.wifi.rtt.RangingResultCallback;
import android.net.wifi.rtt.WifiRttManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import java.util.ArrayList;
import java.util.List;

@RequiresApi(api = Build.VERSION_CODES.P)
public class WifiRttActivity extends AppCompatActivity {
    private final static String TAG = "WifiRttActivity";
    private TextView tv_result; // 声明一个文本视图对象
    private WifiManager mWifiManager; // 声明一个WiFi管理器对象
    private WifiScanReceiver mWifiScanReceiver = new WifiScanReceiver(); // 声明一个WiFi扫描接收器对象
    private WifiRttManager mRttManager; // 声明一个RTT管理器对象
    private WifiRttReceiver mWifiRttReceiver = new WifiRttReceiver(); // 声明一个RTT接收器对象

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_wifi_rtt);
        tv_result = findViewById(R.id.tv_result);
        findViewById(R.id.btn_indoor_rtt).setOnClickListener(v -> mWifiManager.startScan());
        // 从系统服务中获取WiFi管理器
        mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        // 从系统服务中获取RTT管理器
        mRttManager = (WifiRttManager) getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)) {
            tv_result.setText("当前设备支持室内WiFi定位");
        } else {
            tv_result.setText("当前设备不支持室内WiFi定位");
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter filterScan = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        registerReceiver(mWifiScanReceiver, filterScan); // 注册Wifi扫描的广播接收器
        IntentFilter filterRtt = new IntentFilter(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED);
        registerReceiver(mWifiRttReceiver, filterRtt); // 注册RTT状态变更的广播接收器
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(mWifiScanReceiver); // 注销Wifi扫描的广播接收器
        unregisterReceiver(mWifiRttReceiver); // 注销RTT状态变更的广播接收器
    }

    // 定义一个扫描周边WiFi的广播接收器
    private class WifiScanReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 获取WiFi扫描的结果列表
            List<ScanResult> scanList = mWifiManager.getScanResults();
            if (scanList != null) {
                // 查找符合80211标准的WiFi路由器集合
                List<ScanResult> m80211mcList = find80211mcResults(scanList);
                runOnUiThread(() -> {
                    String desc = String.format("找到%d个Wifi热点,其中有%d个支持RTT。",
                            scanList.size(), m80211mcList.size());
                    tv_result.setText(desc);
                });
                if (m80211mcList.size() > 0) {
                    rangingRtt(m80211mcList.get(0)); // 测量与RTT节点之间的距离
                }
            }
        }
    }

    // 查找符合80211标准的WiFi路由器集合
    private List<ScanResult> find80211mcResults(List<ScanResult> originList) {
        List<ScanResult> resultList = new ArrayList<>();
        for (ScanResult scanResult : originList) { // 遍历扫描发现的WiFi列表
            if (scanResult.is80211mcResponder()) { // 符合80211标准
                resultList.add(scanResult);
            }
        }
        return resultList;
    }

    // 测量与RTT节点之间的距离
    private void rangingRtt(ScanResult scanResult) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            tv_result.setText("请先授予定位权限");
            return;
        }
        RangingRequest.Builder builder = new RangingRequest.Builder();
        builder.addAccessPoint(scanResult); // 添加测距入口,参数为ScanResult类型
//            builder.addWifiAwarePeer(); // MacAddress类型
        RangingRequest request = builder.build();
        // 开始测量当前设备与指定RTT节点(路由器)之间的距离
        mRttManager.startRanging(request, getMainExecutor(), new RangingResultCallback() {
            // 测距失败时触发
            @Override
            public void onRangingFailure(int code) {
                Log.d(TAG, "RTT扫描失败,错误代码为"+code);
            }

            // 测距成功时触发
            @Override
            public void onRangingResults(List<RangingResult> results) {
                for (RangingResult result : results) {
                    if (result.getStatus() == RangingResult.STATUS_SUCCESS
                            && scanResult.BSSID.equals(result.getMacAddress().toString())) {
                        result.getDistanceMm(); // 获取当前设备与路由器之间的距离(单位毫米)
                        result.getDistanceStdDevMm(); // 获取测量偏差(单位毫米)
                        result.getRangingTimestampMillis(); // 获取测量耗时(单位毫秒)
                        result.getRssi(); // 获取路由器的信号
                    }
                }
            }
        });
    }

    private class WifiRttReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (mRttManager.isAvailable()) {
                runOnUiThread(() -> tv_result.setText("室内WiFi定位功能可以使用"));
            } else {
                runOnUiThread(() -> tv_result.setText("室内WiFi定位功能不可使用"));
            }
        }
    }

}

It's not easy to create and find it helpful, please like, follow and collect~~~

Guess you like

Origin blog.csdn.net/jiebaoshayebuhui/article/details/128104410
Recommended