Settings>Wireless Settings>WiFi Setting>WiFi Enable 에 대해서 분석을 해보았습니다.
Settings App 에서보면, WiFi Enable 버튼이 보일 것입니다.
이 버튼에 대한 소스를 보면 어떤식으로 Wifi가 Enable이 되는지 Disable이 되는지에 대해서 궁굼할 것입니다.
Source를 보면  다음과 같습니다.
WiFiSettings.java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);

    if (getIntent().getBooleanExtra("only_access_points", false)) {
        addPreferencesFromResource(R.xml.wifi_access_points);
    } else {
        addPreferencesFromResource(R.xml.wifi_settings);
        mWifiEnabler = new WifiEnabler(this,
                (CheckBoxPreference) findPreference("enable_wifi"));
        mNotifyOpenNetworks =
                (CheckBoxPreference) findPreference("notify_open_networks");
        mNotifyOpenNetworks.setChecked(Secure.getInt(getContentResolver(),
                Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
    }

    mAccessPoints = (ProgressCategory) findPreference("access_points");
    mAccessPoints.setOrderingAsAdded(false);
    mAddNetwork = findPreference("add_network");

    registerForContextMenu(getListView());
 

위의 소스를 보면 
WifiEnablerprivate final BroadcastReceiver mReceiver = new BroadcastReceiver() { 란 생성자를 확인할 수 있습니다.
이 생성자를 통해서 Wifi Enable CheckBoxPreference가 Check가 되는지 안되는지를 처리를 해줍니다.
그러면 WifiEnabler란 생성자를 소스로 보면 CheckBoxPreference를 전달 받아서 이를 이용해 Wifi의 상태값에 의해서 Enable인지 Disable인지를 그려주는 것을 확인할 수 있습니다.

그런데 여기서 의문점이 하나 생기게됩니다.
어떻게 CheckBoxPreference에 Create해 주었을때, 바로 Wifi의 Enable을 설정해주는지에 대해서 의문을 가지게 될것입니다.

소스상으로 보게되면 다음과 같이 receiver로 WiFi상태 값을 받아서 Check해주는 법 외에는 처리를 하지 않을 것입니다.
 
 @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
            handleWifiStateChanged(intent.getIntExtra(
                    WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
        } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) {
            handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState)
                    intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE)));
        } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
            handleStateChanged(((NetworkInfo) intent.getParcelableExtra(
                    WifiManager.EXTRA_NETWORK_INFO)).getDetailedState());
        }
    }
};
  
 private void registerForBroadcasts() {소스상에서 보여지는 것과 같이 Receiver로 받아서 처리해주는 방법외에는 없습니다. 그러면 여기서 또다른 의문이 생길것입니다. 도대체 어디서 Wifi의 상태값을 Broadcast로 보내주는 것일까....
그리고 Wifi Settings에 진입할 때 마다 정확하게 팍!팍! 보내주는 것일까...

그래서 이 부분에 대해서 소스를 분석한 결과 그 답은 WifiService에서 확인할 수 있었습니다.
WifiService.java의 위치는 다음과 같습니다.

frameworks/base/services/java/com/android/server/WifiService.java
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(Intent.ACTION_SCREEN_ON);
    intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
    intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
    intentFilter.addAction(ACTION_DEVICE_IDLE);
    intentFilter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
    mContext.registerReceiver(mReceiver, intentFilter);
}


    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            ...
            updateWifiState();
        }

위의 소스를 보면  ACTION_BATTERY_CHANGED 를 받아서 updateWifiState()함수를 호출 하는 것을 확인 할 수 있습니다.

여기서 updateWifiState() 함수를 따라가다보면  doUpdateWifiState 함수까지 따라 갈 수 있습니다. 이 함수를 보면, sendEnableMessage 함수를 호출하게 됩니다.

private void doUpdateWifiState() {
  ...
        if (wifiShouldBeEnabled) {
            if (wifiShouldBeStarted) {
                sWakeLock.acquire();
                sendEnableMessage(true, false, mLastEnableUid);
                sWakeLock.acquire();
                sendStartMessage(strongestLockMode);
          ...
}

sendEnableMessage 함수를 따라가다 보면, setWifiEnabledBlocking 이란 함수를 호출하게 되며, 결국은 setWifiEnabledState 함수를 호출하게 됩니다.

private void setWifiEnabledState(int wifiState, int uid) {
    final int previousWifiState = mWifiStateTracker.getWifiState();

    long ident = Binder.clearCallingIdentity();
    try {
        if (wifiState == WIFI_STATE_ENABLED) {
            mBatteryStats.noteWifiOn();
        } else if (wifiState == WIFI_STATE_DISABLED) {
            mBatteryStats.noteWifiOff();
        }
    } catch (RemoteException e) {
    } finally {
        Binder.restoreCallingIdentity(ident);
    }

    // Update state
    mWifiStateTracker.setWifiState(wifiState);

    // Broadcast
    final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
    intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState);
    intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState);
    mContext.sendStickyBroadcast(intent);
}

결국은 setWifiEnabledState란 함수를 통해서  WiFi의 상태 변화 값을 전달하게 됩니다.

위의 내용을 정리하자면,  ACTION_BATTERY_CHANGED란 BroadCast를 통해서 Wifi의 상태값을 Broadcast로 전달하게 되며, Settings App에서는 Wifi의 상태값을 전달 받아서 CheckBoxPreference의 Check값을 설정하게 되는 것입니다.

ACTION_BATTERY_CHANGED란 Intent는 주기적으로 호출이 되기는 하지만, Activity가 생성되거나, Rotation될때, 그리고 기타적인 요인에 의해서 호출되게 됩니다.
Battery Changed가 호출되는 시점에 대해서는  다음에 설명하도록 하겠습니다.

 
 

+ Recent posts