上图的效果是有Settings的布局管理文件settings_headers.xml控制的,位置:packages/apps/Settings/res/xml/settings_headers.xml
<!-- WIRELESS and NETWORKS --> <header android:id="@+id/wireless_section" android:title="@string/header_category_wireless_networks" /> <!-- Wifi --> <header android:id="@+id/wifi_settings" android:fragment="com.android.settings.wifi.WifiSettings" android:title="@string/wifi_settings_title" android:icon="@drawable/ic_settings_wireless" /> <!-- Ethernet --> <header android:id="@+id/ethernet_settings" android:fragment="com.android.settings.ethernet.EthernetSettings" android:title="@string/ethernet_settings_title" android:icon="@drawable/ic_settings_ethernet" />
com.android.settings.Settings.java 这个activity 是通过回调onBuildHeaders方法来加载进入应用之后的第一个布局文件的:
public void onBuildHeaders(List<Header> headers) { if (!onIsHidingHeaders()) { loadHeadersFromResource(R.xml.settings_headers, headers); updateHeaderList(headers); } }
那么每一个header 是如果响应点击操作的呢.这个就要看Setting.java的onHeaderClick 方法了, onHeaderClick 方法会调用父类的onHeaderClick方法来打开相关的应用,其父类是根据我们配置在settings_headers.xml里面的 fragment和intent 来打开相对应的activity的.
public class Settings extends PreferenceActivity implements ButtonBarHandler, OnAccountsUpdateListener { @Override public void onHeaderClick(Header header, int position) { boolean revert = false; if (header.id == R.id.account_add) { revert = true; } super.onHeaderClick(header, position); if (revert && mLastHeader != null) { highlightHeader((int) mLastHeader.id); } else { mLastHeader = header; } } }
frameworks/base/core/java/android/preference/PreferenceActivity.java
public void onHeaderClick(Header header, int position) { if (header.fragment != null) { if (mSinglePane) { int titleRes = header.breadCrumbTitleRes; int shortTitleRes = header.breadCrumbShortTitleRes; if (titleRes == 0) { titleRes = header.titleRes; shortTitleRes = 0; } startWithFragment(header.fragment, header.fragmentArguments, null, 0, titleRes, shortTitleRes); } else { switchToHeader(header); } } else if (header.intent != null) { startActivity(header.intent); } }
点击后启动WifiSettings Activity,WifiSettings中onActivityCreated方法会获取WifiManager的控制句柄,并把控制WiFi开关的Switch与WifiEnabler关联起来,代码如下:
// On/off switch is hidden for Setup Wizard if (!mSetupWizardMode) { Switch actionBarSwitch = new Switch(activity); if (activity instanceof PreferenceActivity) { PreferenceActivity preferenceActivity = (PreferenceActivity) activity; if (preferenceActivity.onIsHidingHeaders() || !preferenceActivity.onIsMultiPane()) { final int padding = activity.getResources().getDimensionPixelSize( R.dimen.action_bar_switch_padding); actionBarSwitch.setPaddingRelative(0, 0, padding, 0); activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM); activity.getActionBar().setCustomView(actionBarSwitch, new ActionBar.LayoutParams( ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.END)); } } mWifiEnabler = new WifiEnabler(activity, actionBarSwitch); }
android/packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java
public class WifiEnabler implements CompoundButton.OnCheckedChangeListener { public WifiEnabler(Context context, Switch switch_) { mContext = context; mSwitch = switch_; mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); // The order matters! We really should not depend on this. :( mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); } public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { //Do nothing if called as a result of a state machine event if (mStateMachineEvent) { return; } // Show toast message if Wi-Fi is not allowed in airplane mode if (isChecked && !WirelessSettings.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/listenenr loop. buttonView.setChecked(false); return; } // Disable tethering if enabling Wifi int wifiApState = mWifiManager.getWifiApState(); if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) || (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) { mWifiManager.setWifiApEnabled(null, false); } mSwitch.setEnabled(false); if (!mWifiManager.setWifiEnabled(isChecked)) { // Error mSwitch.setEnabled(true); Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show(); } } }
由于WifiEnabler实现了CompoundButton.OnCheckedChangeListener,onCheckedChanged()会在按钮选中状态发生改变时被调用,即打开或关闭WiFi时调用此函数。
通过调用WifiManager.setWifiEnabled()实现打开动作。
frameworks/base/wifi/java/android/net/wifi/WifiManager.java
public class WifiManager { IWifiManager mService; public WifiManager(Context context, IWifiManager service) { mContext = context; mService = service; init(); } public boolean setWifiEnabled(boolean enabled) { try { return mService.setWifiEnabled(enabled); } catch (RemoteException e) { return false; } } }
通过AIDL调用,实际调用的是 WifiService的setWifiEnabled 函数
frameworks/base/services/java/com/android/server/wifi/WifiService.java
public synchronized boolean setWifiEnabled(boolean enable) { enforceChangePermission(); Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); if (DBG) { Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n"); } /* * Caller might not have WRITE_SECURE_SETTINGS, * only CHANGE_WIFI_STATE is enforced */ long ident = Binder.clearCallingIdentity(); try { if (! mSettingsStore.handleWifiToggled(enable)) { // Nothing to do if wifi cannot be toggled return true; } } finally { Binder.restoreCallingIdentity(ident); } mWifiController.sendMessage(CMD_WIFI_TOGGLED); return true; }
frameworks/base/services/java/com/android/server/wifi/WifiController.java
class WifiController extends StateMachine { WifiController(Context context, WifiService service, Looper looper) { super(TAG, looper); addState(mDefaultState); addState(mApStaDisabledState, mDefaultState); addState(mStaEnabledState, mDefaultState); addState(mDeviceActiveState, mStaEnabledState); addState(mDeviceInactiveState, mStaEnabledState); addState(mScanOnlyLockHeldState, mDeviceInactiveState); addState(mFullLockHeldState, mDeviceInactiveState); addState(mFullHighPerfLockHeldState, mDeviceInactiveState); addState(mNoLockHeldState, mDeviceInactiveState); addState(mStaDisabledWithScanState, mDefaultState); addState(mApEnabledState, mDefaultState); addState(mEcmState, mDefaultState);
if (isWifiEnabled && isScanningAlwaysAvailable) {
setInitialState(mStaDisabledWithScanState);
} else {
setInitialState(mApStaDisabledState);
}
} }
初始状态为ApStaDisabledState,当收到CMD_WIFI_TOGGLED消息后,状态会转换到DeviceActiveState。
class ApStaDisabledState extends State { public void enter() { mWifiStateMachine.setSupplicantRunning(false); // Supplicant can‘t restart right away, so not the time we switched off mDisabledTimestamp = SystemClock.elapsedRealtime(); mDeferredEnableSerialNumber++; mHaveDeferredEnable = false; } public boolean processMessage(Message msg) { switch (msg.what) { case CMD_WIFI_TOGGLED: case CMD_AIRPLANE_TOGGLED: if (mSettingsStore.isWifiToggleEnabled()) { if (doDeferEnable(msg)) { if (mHaveDeferredEnable) { mDeferredEnableSerialNumber++; } mHaveDeferredEnable = !mHaveDeferredEnable; break; } if (mDeviceIdle == false) { transitionTo(mDeviceActiveState); } else { checkLocksAndTransitionWhenDeviceIdle(); } } break; ........... }
由于DeviceActiveState的父状态为StaEnabledState,所以在有ApStaDisabledState进入DeviceActiveState时,会先进入StaEnabledState,然后再进入DeviceActiveState。因此,先调用StaEnabledState的enter():
class StaEnabledState extends State { @Override public void enter() { mWifiStateMachine.setSupplicantRunning(true); } public boolean processMessage(Message msg) { switch (msg.what) { } }
然后再调用DeviceActiveState的enter():
class DeviceActiveState extends State { @Override public void enter() { mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE); mWifiStateMachine.setDriverStart(true); mWifiStateMachine.setHighPerfModeEnabled(false); } public boolean processMessage(Message msg) { } }
frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java
public void setSupplicantRunning(boolean enable) { if (enable) { sendMessage(CMD_START_SUPPLICANT); } else { sendMessage(CMD_STOP_SUPPLICANT); } }
此时WiFi状态机为初始状态InitialState,处理CMD_START_SUPPLICANT的动作:
class InitialState extends State { public boolean processMessage(Message message) { switch (message.what) { case CMD_START_SUPPLICANT: if (mWifiNative.loadDriver()) {//加载驱动 try { mNwService.wifiFirmwareReload(mInterfaceName, "STA");//download firmware } catch (Exception e) { loge("Failed to reload STA firmware " + e); // continue } try { // A runtime crash can leave the interface up and // this affects connectivity when supplicant starts up. // Ensure interface is down before a supplicant start. mNwService.setInterfaceDown(mInterfaceName); // Set privacy extensions mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); // IPv6 is enabled only as long as access point is connected since: // - IPv6 addresses and routes stick around after disconnection // - kernel is unaware when connected and fails to start IPv6 negotiation // - kernel can start autoconfiguration when 802.1x is not complete mNwService.disableIpv6(mInterfaceName); } catch (RemoteException re) { loge("Unable to change interface settings: " + re); } catch (IllegalStateException ie) { loge("Unable to change interface settings: " + ie); } mWifiMonitor.killSupplicant(mP2pSupported); if(mWifiNative.startSupplicant(mP2pSupported)) {//重启WPA setWifiState(WIFI_STATE_ENABLING); if (DBG) log("Supplicant start successful"); mWifiMonitor.startMonitoring(); transitionTo(mSupplicantStartingState); } else { loge("Failed to start supplicant!"); } } else { loge("Failed to load driver"); } break; }
WifiNative通过JNI调用 wifi.c,加载WiFi驱动,加载成功后会创建网络接口wlan0,然后启动wpa_supplicant。都启动成功后界面上会显示WiFi激活。
原文:http://www.cnblogs.com/hunaiquan/p/5391363.html