Android11 Wifi开启、扫描和连接

这篇具有很好参考价值的文章主要介绍了Android11 Wifi开启、扫描和连接。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

开启Wifi

开启Wifi开关,Wifi开关是WifiEnablerWifiEnabler实现了 SwitchWidgetController.OnSwitchChangeListener监听,打开/关闭开关会回调至

// 处理Switch 控件的状态变化事件   
 public boolean onSwitchToggled(boolean isChecked) {
        //Do nothing if called as a result of a state machine event
		// 通过Switch.setEnabled 方法设置Switch 控件状态时,不需要再次禁止/允许Wi-Fi,否则将造成循环调用的后果
        if (mStateMachineEvent) {
            return true;
        }
        // Show toast message if Wi-Fi is not allowed in airplane mode
		//如果在飞行模式时不允许单独使用Wi-Fi,使用Toast 信息框进行提示
        if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
            Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
            // Reset switch to off. No infinite check/listener loop.
            mSwitchWidget.setChecked(false);
            return false;
        }
		
        if (isChecked) {
            mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_WIFI_ON);
        } else {
            // Log if user was connected at the time of switching off.
            mMetricsFeatureProvider.action(
                mContext, SettingsEnums.ACTION_WIFI_OFF,
                mConnected.get()
            );
        }
		 //通过WifiManager.setWifiEnabled()开启/关闭wifi
        if (!mWifiManager.setWifiEnabled(isChecked)) {
            // Error
            mSwitchWidget.setEnabled(true);
            Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
        }
        return true;
    }

mWifiManager.setWifiEnabled(isChecked) 用于根据Switch控件的当前状态关闭或打开Wi-Fi。

onCheckedChanged方法的开始部分使用了一个mStateMachineEvent变量,当该变量为true时直接跳出了onCheckedChanged方法。实际上,增加这个跳出条件的原因是因为Switch控件的状态变化可以有如下两种情况。

  • 直接单击Switch 控件。

  • 调用Switch.setChecked 方法。

遗憾的是,上述两种情况都会触发onCheckedChanged方法的调用。不管是哪种方法使Switch控件的状态发生了变化,在onCheckedChanged中调用WifiManager.setWifiEnabled方法设置Wi-Fi状态都会再次触发 onCheckedChanged方法的调用。当再次调用onCheckedChanged 方法时就需要将mStateMachineEvent变量值设为true,这样onCheckedChanged方法在执行之初就会立刻返回(如果继续执行后面的代码,将会造成死循环),然后再将mStateMachineEvent变量值设为false。这样在下一次设置Wi-Fi状态时仍然可以继续执行onCheckedChanged方法了。

用广播方式设置 Switch 控件的状态

 /packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent . getAction ();
        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
            handleWifiStateChanged(mWifiManager.getWifiState());
        } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
            if (!mConnected.get()) {
                handleStateChanged(
                    WifiInfo.getDetailedStateOf(
                        (SupplicantState)
                                intent . getParcelableExtra (WifiManager.EXTRA_NEW_STATE)
                    )
                );
            }
        } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
            NetworkInfo info =(NetworkInfo) intent . getParcelableExtra (
                    WifiManager.EXTRA_NETWORK_INFO);
            mConnected.set(info.isConnected());
            handleStateChanged(info.getDetailedState());
        }
    }
};

对于Wi-Fi来说,这个广播接收器主要用于接收Wi-Fi的状态变化,并做进一步地处理。其中处理Wi-Fi状态变化的方法是handleWifiStateChanged

private void handleWifiStateChanged(int state) {
    // Clear any previous state
    mSwitchWidget.setDisabledByAdmin(null);

    switch(state) {
        case WifiManager . WIFI_STATE_ENABLING : // 处理正在开启Wi-Fi的状态
        break;
        case WifiManager . WIFI_STATE_ENABLED : // 处理已经开启Wi-Fi的状态
        setSwitchBarChecked(true);
        mSwitchWidget.setEnabled(true);
        break;
        case WifiManager . WIFI_STATE_DISABLING : // 处理正在关闭Wi-Fi的状态
        break;
        case WifiManager . WIFI_STATE_DISABLED :  // 处理已经关闭Wi-Fi的状态
        setSwitchBarChecked(false);
        mSwitchWidget.setEnabled(true);
        break;
        default:                                   // 处理其他情况
        setSwitchBarChecked(false);
        mSwitchWidget.setEnabled(true);
    }
}



 /packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java
// 如果当前Wi-Fi 的状态与Switch 控件的状态不一致,改变Switch 控件的状态
private void setSwitchBarChecked(boolean checked) {
    mStateMachineEvent = true;
    mSwitchWidget.setChecked(checked);
    mStateMachineEvent = false;
}

setSwitchChecked方法代码可以看出,在改变Switch控件状态之前(调用Switch.setChecked方法),先将mStateMachineEvent变量设为true。这就意味着在设置Switch控件状态时不会由于触发了onCheckedChanged方法而再次设置Wi-Fi状态,从而进行递归调用。

从这一点可以看出,WifiEnabler类中的广播接收器的目的只是为了设置Switch控件的状态,并不是为了设置Wi-Fi的状态。这么做的目的是当用户通过WifiManager.setWifiEnabled方法设置Wi-Fi状态时,尽管可以成功设置Wi-Fi的状态,但却无法改变Switch控件的状态,所以就会造成当前Wi-Fi状态与Switch控件的状态不一致的情况。为了解决这个问题,WifiManager.setWifiEnabled方法在设置Wi-Fi状态后,会发送一个广播(WifiManager.WIFI_STATE_CHANGED_ACTION),然后WifiEnabler类中的广播接收器就会接收到这个广播,并根据当前Wi-Fi的状态改变Switch控件的状态。

扫描WiFi

开始扫描的逻辑是从WifiSettings触发的。
WifiTracker接收到wifi状态改变的广播以后,

final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
			// 处理网络状态变化的动作
            if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
                updateWifiState(
                        intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
                                WifiManager.WIFI_STATE_UNKNOWN));
            } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) { // 处理热点搜索完成的动作
                mStaleScanResults = false;
                mLastScanSucceeded =
                        intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, true);
				// 更新搜索到的热点
                fetchScansAndConfigsAndUpdateAccessPoints();
            } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)
                    || WifiManager.ACTION_LINK_CONFIGURATION_CHANGED.equals(action)) {
                fetchScansAndConfigsAndUpdateAccessPoints();
            } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { // 网络状态变化动作
                // TODO(sghuman): Refactor these methods so they cannot result in duplicate
                // onAccessPointsChanged updates being called from this intent.
                NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
                updateNetworkInfo(info);
                fetchScansAndConfigsAndUpdateAccessPoints();
            } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
                updateNetworkInfo(/* networkInfo= */ null);
            }
        }
    };


如果wifi已经打开了,则开始扫描Wifi

    private void updateWifiState(int state) {
        if (isVerboseLoggingEnabled()) {
            Log.d(TAG, "updateWifiState: " + state);
        }
        if (state == WifiManager.WIFI\_STATE\_ENABLED) {
            synchronized (mLock) {
                if (mScanner != null) {
// We only need to resume if mScanner isn't null because
// that means we want to be scanning.
                    mScanner.resume();
                }
            }
        }
        mListener.onWifiStateChanged(state);
    }

Scanner是用于扫描Wifi的类:

class Scanner extends Handler {
    static final int MSG_SCAN = 0;

    private int mRetry = 0;

    // 通过resume 方法可以触发循环扫描热点
    void resume () {
        if (isVerboseLoggingEnabled()) {
            Log.d(TAG, "Scanner resume");
        }
        if (!hasMessages(MSG_SCAN)) {
            sendEmptyMessage(MSG_SCAN);
        }
    }

    public void handleMessage(Message message) {
        if (message.what != MSG_SCAN) return;
        // 开始扫描热点
        if (mWifiManager.startScan()) {
            mRetry = 0;
        } else if (++mRetry >= 3) {
            mRetry = 0;
            if (mContext != null) {
                Toast.makeText(mContext, R.string.wifi_fail_to_scan, Toast.LENGTH_LONG).show();
            }
            return;
        }
        // 发送延迟消息,会每10 秒搜索一次热点
        sendEmptyMessageDelayed(MSG_SCAN, WIFI_RESCAN_INTERVAL_MS);
    }
}

首先会由WifiSettings类中创建的广播接收器处理WifiManager.NETWORK_STATE_CHANGED_ACTION 广播动作,然后在处理的过程中调用了Scanner.resume 方法开始扫描热点。当热点扫描完成后,系统发送 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION广播。

调用fetchScansAndConfigsAndUpdateAccessPoints方法更新热点列表,具体更新是在updateAccessPoints()。这里的Scanner对象通过不断在Scanner. handleMessage方法中发送延迟消息,从而使系统每隔一定时间(10秒)就会扫描一次热点。

private void fetchScansAndConfigsAndUpdateAccessPoints() {
		// 获取所有搜索到的热点信息
        List<ScanResult> newScanResults = mWifiManager.getScanResults();

        // Filter all unsupported networks from the scan result list
        final List<ScanResult> filteredScanResults =
                filterScanResultsByCapabilities(newScanResults);

//        if (isVerboseLoggingEnabled()) {
            Log.i(TAG, "Fetched scan results: " + filteredScanResults);
//        }
		// 获取当前已经连接的热点信息
        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
        updateAccessPoints(filteredScanResults, configs);
    }

updateAccessPoints(filteredScanResults, configs);中会创建已经连接的热点信息的AccessPointer对象,调用accessPoint.update更新状态信息,将热点信息添加到热点,最后回调WifiSettings中的onAccessPointsChanged()更新UI;

连接Wifi

当用户单击一个热点后,就会弹出对话框要求输入密码,最后单击“连接”按钮进行连接。具体是在WifiSettings中的submit方法中:

 void submit(WifiConfigController configController) {

    final WifiConfiguration config = configController.getConfig();

    if (config == null) {
        if (mSelectedAccessPoint != null
                && mSelectedAccessPoint.isSaved()) {
            connect(mSelectedAccessPoint.getConfig(),
                    true /* isSavedNetwork */,
                    CONNECT_SOURCE_UNSPECIFIED);
        }
    } else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
        mWifiManager.save(config, mSaveListener);
    } else {
        mWifiManager.save(config, mSaveListener);
        if (mSelectedAccessPoint != null) { // Not an "Add network"
            connect(config, false /* isSavedNetwork */,
                    CONNECT_SOURCE_UNSPECIFIED);
        }
    }

    mWifiTracker.resumeScanning();
}



protected void connect(final WifiConfiguration config,
        boolean isSavedNetwork, @ConnectSource int connectSource) {
    // Log subtype if configuration is a saved network.
    mMetricsFeatureProvider.action(getContext(), SettingsEnums.ACTION_WIFI_CONNECT,
            isSavedNetwork);
    mConnectSource = connectSource;
	// 连接Wifi
    mWifiManager.connect(config, mConnectListener);
    mClickedConnect = true;
}

点击连接以后,如果config不为null,则先保存网络,再进行连接,所以即使连接失败,此网络依然在已保存网络列表里。文章来源地址https://www.toymoban.com/news/detail-733546.html

到了这里,关于Android11 Wifi开启、扫描和连接的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Android Framework系列】第11章 LayoutInflater源码分析

    本章节我们主要目目的是了解 Activity 的 xml 布局解析、对 LayoutInfater 源码进行分析。 我们知道Android界面上的每一个控件都是一个个 View ,但是Android也提供了通过 xml 文件来进行布局控制,那么 xml 布局文件如何转成最终的 View 的呢?转换利器就是 LayoutInflater 。在分析 Layout

    2024年02月12日
    浏览(43)
  • 高通Android系列随身WIFI强行开启adb,关闭商家远程控制

    目前市面上便宜的随身wifi大概分为高通、中芯微、MTK几家的SOC。大部分Android产品都关闭了adb或者开启的是user adb,没有root权限。下面说说高通系列如何强行开root adb,以及关闭部分机器远程控制功能。 如果机器默认未开启adb,就需要直接使用硬件方式进入9008进行备份和刷机,

    2024年02月07日
    浏览(40)
  • android连接指定wifi

    在Android设备上,我们可以通过代码连接到特定的WiFi网络。这在许多应用中都是非常有用的,例如自动连接到家庭WiFi网络,或者在商家的应用中连接到特定店铺的WiFi网络。 本文将教您如何使用Android代码连接到指定的WiFi网络,并提供示例代码来帮助您实现此功能。 前提条件

    2024年01月16日
    浏览(40)
  • android通过代码连接wifi

    Android SDK API 29(对应Android 10)以下,可以在app之中通过代码直接设置wifi名称和密码进行连接。 API 29及其以上版本,增加了动态管理权限功能,弃用了之前的接口,同时app连接wifi时必须通过用户同意,具体方式是弹出一个页面显示要连接的wifi,用户点击连接之后再返回app。

    2024年02月20日
    浏览(39)
  • Android app应用连接WiFi的方法(兼容Android10)

    Android应用开发有时候会有应用直连app的需求,由于Android系统 api会时常变动,wifi连接api亦如此,Android10以下直接使用: Android 10以上则可以使用 或是WifiNetworkSuggestion 方式 最后分享工具类

    2024年02月04日
    浏览(84)
  • Android扫码连接WIFI实现

    0,目标         APP中实现扫WIFI分享码自动连接WIFI功能 1,前提条件         设备需要有个扫码器(摄像头拍照识别也行),APP调用扫码器读取WIFI连接分享码。 2,增加权限         在AndroidManifest.xml中增加权限 3,参数检查         扫码成功后,对内容进行一个

    2024年02月09日
    浏览(33)
  • Android 12 Wifi 开发(获取列表、连接、断开连接)

    获取Wifi列表: 扫描(这个方法早在Android 9.0 就被弃用), 不过如果不调用的话是没法及时获取Wifi列表的广播的。 (不需要也能正常获取,没有延迟,经实验毫无区别) 创建广播并接收: 配置并连接( 无系统签名 ): 配置并连接( 有系统签名 ): 断开连接(无系统签名

    2024年02月03日
    浏览(38)
  • Android 11.0 framework关于systemUI定制之导航栏透明背景的功能实现

    在11.0的系统rom产品定制化开发中,在对于系统原生SystemUI的导航栏背景在沉浸式导航栏的 情况下默认是会随着背景颜色的变化而改变的,在一些特定背景下导航栏的背景也是会改变的,所以由于产品开发需要 要求需要设置导航栏背景为透明的,所以就需要在Activity创建的时候

    2024年02月04日
    浏览(56)
  • Android11 实现有线网络和wifi共存

    Android 系统Framework进行一定适配后,可以实现wifi和有线网络端口都打开的, 进而在App端即可实现通过代码控制选择使用wifi或者有线网络进行网络请求。 本文只介绍wifi和有线网络端口同时打开的实现,app代码请求特定网络另外文章介绍。 Android 默认是只保留打开一个网络的,

    2024年02月07日
    浏览(40)
  • Android11编译第五弹:开启VPN权限

    问题:智能货柜上线以后,因为分布在全国各地,或者在国外,遇到问题需要调试设备的时候,需要及时连接设备,查看设备信息,拉取日志。 一种方式是直接上传日志到云端,通过云端查看日志信息,但是耗费流量,而且浪费云端资源; 二种方式:采用VPN网络,通过adb

    2024年02月09日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包