Android/WI-FI | Posted by 덩치 2015.05.08 11:13

Wifi 비활성화일 때 스캔하는 방법

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO



일반적으로 많이 알려진 Wifi Scan 방법은 Wifi 활성화 돼 있을때만 가능하다.


때문에 Wifi Scan이 필요할 때, 사용자의 Wifi를 강제로 Enable 시킨 뒤 스캔을 하고, 스캔이 끝다면 다시 비활성화 시키는


방식으로 많이들 구현한다.


그런데 Android 버전 4.3(SDK 18)부터 추가된 '항상 검색 허용' 설정을 이용하면 Wifi비활성화 상태라


Wifi스캔할 수 있다.




해당 옵션이 활성화 돼 있을때만 위와같은 동작이 가능하다.


소스코드상으로는 해당 설정을 컨트롤 할 수 없으며, 사용자가 직접 설정할 수 있다.



따라서 SDK 버전이 18 이상인지, '항상 검색 허용' 설정이 활성화상태인지 체크를 한 다음


조건을 만족하지 않는다면 기존 방식을 이용하고, 만족한다면 Wifi를 건들지 않고 바로 스캔을 진행할 수 있다.



위 조건을 구현하는 방법은 아래와 같다.


if (Build.VERSION.SDK_INT >= 18) {  //  4.3 버전 이상인지 체크한다.

if (mWM.isScanAlwaysAvailable()) {  //  항상검색 허용 설정이 활성화상태인지 체크한다.

mWM.startScan();  // 바로 스캔 실행

return;

}

}

mWM.setWifiEnabled(true);

// 위 조건을 만족하지 않는다면 Wifi 상태에 변화를 줘서 BroadcastReceiver에 액션이 들어오게 하여 스캔을 진행한다.

// 자세한 방법은 http://biig.tistory.com/14 참조


끝.







펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO


이 포스팅에서 다루게 될 내용 :

1. Wi-Fi 주파수 추출법

2. 주파수에 다른 채널값 추출법




위 표는 IEEE 802.11b/g/n 2.4GHz 방식과 IEEE 802.11a/n 5GHz 방식의 표준을 나타낸 표이다.


쉽게 말해 일반적으로 말하는 2.4G 대역 와이파이와 5G 대역 와이파이의 주파수와 채널에 대한 정보이다.


먼저 연결된 Wi-Fi의 주파수를 검출하는 방법에 대해 알아보자.


주파수는 WifiManager를 이용하여 와이파이 스캔을 실시하고, 이 결과를 이용하여 추출하게 되는데 방법은 아래와 같다.


WifiManager mWM = (WifiManager) context.getSystemService(WIFI_SERVICE);

WifiInfo wifiInfo = mWM.getConnectionInfo();


try {

for (ScanResult scanResult : mWM.getScanResults()) {

if (wifiInfo != null && wifiInfo.getBSSID() != null

&& wifiInfo.getBSSID().equals(scanResult.BSSID)) {


mCurrentFrequency = scanResult.frequency;

break;

}

}

} catch (Exception e) {


}


주변 Wifi를 스캔하여 현재 연결된 WifiBSSID와 일치하는 와이파이의 주파수를 추출하고 있다.


이렇게 추출된 주파수와 채널값에는 일정한 규칙이 있다.


이 규칙을 공식으로 만들어 채널값을 계산할 수 있다.


방법은 아래와 같다.


public static int convertFrequencyToChannel(int freq) {

if(freq >= 2412 && freq <= 2484) {

if (freq == 2484)

return (freq-2412) /5;

return (freq-2412) /5 + 1;

}else if( freq >= 5170 && freq <= 5825) {

return (freq-5170) /5 + 34;

}

else {

return -1;

}

}


해당 계산식을 적용하면 표에 나와있는 채널값과 동일한 값이 얻어지는것을 확인 할 수 있다.


범위 확인중인 주파수 영역을 벗어나는 새로운 주파수가 추가된다면 소스코드의 수정이 필요할 수 있다.



펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO

wifi를 검색하는 방법에 대해서는 이전 글에서 알아보았다.


wifi에 연결하기 위해서는 보안방식과 비밀번호, ssid가 필요한데

보안방식과 ssid는 이전글의 ScanResult에서 뽑아낼 수가 있다.


비밀번호를 모르면 당연히 보안이 걸려있는 wifi에는 연결이 불가능.


일단 소스를 살펴보자


open일때

wfc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);

wfc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);

wfc.allowedProtocols.set(WifiConfiguration.Protocol.WPA);

wfc.allowedAuthAlgorithms.clear();

wfc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);

 

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);

wep일때

wfc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);

wfc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);

wfc.allowedProtocols.set(WifiConfiguration.Protocol.WPA);

wfc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);

wfc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);

wfc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);

 

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);

wfc.wepKeys[0] = "123456abcd";   <<--이부분중요. \"부분 빼고 그냥 비밀번호만 넣는다

wfc.wepTxKeyIndex = 0;

wpa나 wpa2일때

wfc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);

wfc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);

wfc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);

wfc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);

wfc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);

wfc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);

wfc.preSharedKey = "\"".concat("123456abcd").concat("\"");


이렇게 보안방식별로 설정 방법이 다르다.

wpa와 wpa2는 설정이 같다고 하는데 필자의경우 wpa방식은 연결이 안되더라.

실제 테스트해본건 wpa2와 wep, open밖에 없다.

참고로 ScanResult.capabilites에서 뱉어주는 보안방식이 실제 open, web, wpa로 나오는건 아니고

[WPA-PSK-TKIP+CCMP][ESS]

[WPA2-PSK-CCMP][WPS][ESS]  이런식이며, 같은 방식도 length가 다른경우가 있다.

이부분은 알아서 잘 처리해주리라 믿고,



먼저 공통설정을

WifiConfiguration wfc = new WifiConfiguration(); (WifiConfiguration는 전역변수,지역변수 알아서 상황에 맞게 조절한다)

wfc = new WifiConfiguration();

wfc.SSID = "\"".concat(ssid 입력).concat("\"");

wfc.status = WifiConfiguration.Status.DISABLED;

wfc.priority = 40;

이렇게 해준다.


그리고 위의 보안방식에 따른 설정을 해 주고,


int networkId = wm.addNetwork(wfc);

if (networkId != -1) {

wm.enableNetwork(networkId, true);

}


이렇게 해주면 해당하는 wifi에 연결이 완료된다.

open형의 경우에는 level(신호세기)에 따라 정렬을 해 주고, 위의 소스를 적용시키면 가장 신호가 센놈으로

자동으로 연결될듯하다.



-끝-


Android/WI-FI | Posted by 덩치 2013.10.23 16:08

Wifi 목록 검색하는법

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO


전역변수로 

ScanResult scanResult;

WifiManager wm;

List apList;


WifiManager 초기화

wm = (WifiManager) getSystemService(WIFI_SERVICE);


검색

wm.startScan(); 때려주고


IntentFilter filter = new IntentFilter();

filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);

registerReceiver(wifiReceiver, filter);

이렇게 브로드캐스트리시버를 사용해줘야한다.

이유는 스캔이 끝났을 때를 체크하기 위해서이다


브로드캐스트리시버 선언

private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {

searchWifi();

}

}

};

스캔이끝났다는 방송이 전달되면 searchWifi() 호출


searchWifi를 보면

public void searchWifi() {

apList = wm.getScanResults();

if (wm.getScanResults() != null) {

int size = apList.size();

for (int i = 0; i < size; i++) {

scanResult = (ScanResult) apList.get(i);

}

}

}


이렇게 하면 scanResult에 Wifi에 대한 정보들이 입력된다. 호출은 반복문 안에서나 원하는 위치에서

scanResult.SSID 등으로 이용할 수 있다.

Wifi가 on인지 off인지 모를때는 필터액션에 와이파이 스테이트 체인지액션까지 넣어주면 더욱좋다


-끝-

Android/WI-FI | Posted by 덩치 2013.08.05 16:15

Wifi상태 체크 + 자동 연결해제

펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO


WifiChecker.zip


WifiManager , WifiInfo 를 이용해 와이파이 상태를 체크하고

신호세기가 10Mbps 이하로 내려가면 자동으로 와이파이를 비활성화 시키는 예제입니다.

주석은 따로 없습니다. 궁금하신점은 댓글남겨주세요.


자동으로 다른 와이파이 검색해서 연결을 변경해주면 더 좋으련만

어떤 클래스나 메소드를 사용해서 할 수 있는지를 몰라 구현은 못했습니다.

아시는분은 댓글좀 남겨주세요 ㅎㅎ

구현하는법 알아냈습니다. 궁금하시면 댓글로 메일남겨주세요 

적용 예시 : http://biig.tistory.com/15

소스반영은 안했습니다. (2013.10.23 수정)




package com.example.wifichecker;



import android.app.Activity;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.content.IntentFilter;

import android.net.wifi.WifiInfo;

import android.net.wifi.WifiManager;

import android.os.Bundle;

import android.os.Handler;

import android.widget.TextView;

import android.widget.Toast;


public class MainActivity extends Activity {

WifiManager wifiManager,wifiManager2;

WifiInfo wifiInfo,wifiInfo2;

TextView tv;

int speed;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

tv = (TextView)findViewById(R.id.tv);

wifiManager = (WifiManager)getSystemService(WIFI_SERVICE);

wifiInfo = wifiManager.getConnectionInfo();

IntentFilter filter = new IntentFilter();

filter.addAction(wifiManager.WIFI_STATE_CHANGED_ACTION);

registerReceiver(wifiReceiver,filter);

}


private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {

public void onReceive(Context context, Intent intent) {

if(wifiManager.getWifiState()==3){

hd.post(callback);

hd2.postDelayed(callback2, 10000);

}else{

hd.removeCallbacks(callback);

tv.setText("Wifi가 비활성화 상태입니다.");

}

}

};


Handler hd2 = new Handler();

public Runnable callback2 = new Runnable(){

public void run(){

hd2.postDelayed(this, 5000);

if(speed<10){

hd.removeCallbacks(callback);

hd2.removeCallbacks(callback2);

wifiManager.setWifiEnabled(false);

Toast.makeText(MainActivity.this, "Wifi 연결이 종료되었습니다.", Toast.LENGTH_SHORT).show();

tv.setText("Wifi가 비활성화 상태입니다.");

}

}

};

Handler hd = new Handler();

public Runnable callback = new Runnable(){

public void run() {

if(wifiManager.getWifiState()==3){

wifiManager2 = (WifiManager)getSystemService(WIFI_SERVICE);

wifiInfo2 = wifiManager2.getConnectionInfo();

String id = wifiInfo2.getSSID();

speed = (wifiInfo2.getLinkSpeed());

double aa = speed+0.0;

double aaa = aa/8.0;

String num = String.format("%.2f" , aaa);

double latency = wifiManager2.WIFI_MODE_FULL_HIGH_PERF;

String num2 = String.format("%.2f", latency);

String view = "Wifi Id : "+wifiInfo2.getSSID()+"\n"+"\n"+"Speed : "+num+"MBps" + "\n" +"\n"+ "Power : " + 

String.valueOf(wifiInfo2.getRssi()+"dBm"+"\n"+"\n"+"Power : "+num2+"ms");

tv.setText(view);

hd.postDelayed(this, 3000);

}else{

tv.setText("Wifi가 비활성화 상태입니다.");

hd.removeCallbacks(callback);

}

}

};

@Override

protected void onDestroy() {

// TODO Auto-generated method stub

super.onDestroy();

hd.removeCallbacks(callback);

hd2.removeCallbacks(callback2);

}

}



펌 OK (출처 표시), 상업적 이용 NO, 컨텐츠 변경 NO


Wificheck.zip


와이파이가 연결되어있다는 가정하에 만들었습니다.

연결안되어도 에러는 나지 않습니다. 와이파이 연결 후 속도측정용입니다.


공부할겸 만든거라 WifiInfo를 이용해 띄운 와이파이 명 , WifiManager를 이용해 띄운 속도 밖에 없습니다.


주석은 안달려있으니 궁금하신점은 댓글로 남겨주세요



매니패스트 퍼미션은


    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>


두줄 추가입니다



package com.example.wificheck;



import android.app.Activity;

import android.net.wifi.WifiInfo;

import android.net.wifi.WifiManager;

import android.os.Bundle;

import android.os.Handler;

import android.util.Log;

import android.view.Menu;

import android.widget.TextView;


public class MainActivity extends Activity {

WifiManager wifiManager,wifiManager2;

TextView tv;

WifiInfo wifi,wifi2;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

tv = (TextView)findViewById(R.id.tv);

wifiManager2 = (WifiManager)getSystemService(WIFI_SERVICE);

wifi2 = wifiManager2.getConnectionInfo();

handler.post(callback);

}

Handler handler = new Handler();

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.main, menu);

return true;

}


public Runnable callback = new Runnable(){

@Override

public void run() {

Boolean bool = wifiManager2.isWifiEnabled();

// TODO Auto-generated method stub

handler.postDelayed(callback, 1000);

wifiManager = (WifiManager)getSystemService(WIFI_SERVICE);

wifi = wifiManager.getConnectionInfo();

String wifiinfo = WifiInfo.LINK_SPEED_UNITS;

int speed = wifi.getLinkSpeed();

String name = wifi.getSSID();

String TEXT = "Wifi Name : "+name+"\n"+"Speed : "+ String.valueOf(speed)+" "+wifiinfo;

tv.setText(TEXT);

}

};

}