오늘날 통신 기술이 발달하면서 수많은 곳에서 WiFi들을 접할 수 있다.
이에따라 Application에서 Wifi를 활용해 다양한 작업을 수행할 수 있다.
이번 시간에는 Application에서 Wifi를 어떻게 활용할 수 있는지 알아보는 시간을 가질 것이다.
WifiManager 클래스
https://developer.android.com/reference/android/net/wifi/WifiManager.html?hl=ko
WifiManger 클래스는 WiFi connectivity와 관련한 모든 사항을 관리하는 주요 API를 제공해주는 클래스이다.
[주요 기능]
• 설정된 Wi-Fi 네트워크의 목록을 보여줌
• 현재 active Wi-Fi 네트워크에 대한 정보 제공
• 연결을 맺거나 끊을 수 있음
• 네트워크의 상태에 대한 동적 정보를 제공
• Access Point를 스캔하고 그 결과 정보를 제공
• Wi-Fi 상태 변화에 따라 전송되는 broadcast에 대한 intent action 이름을 정의
1
|
WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE)
|
이와 같이 getSystemService() 메서드를 이용해 WifiManager 객체를 생성할 수 있다.
WiFi 정보는 다양한 곳에서 활용할 수 있지만 이번 시간에는 실내 위치 인식을 목적으로 활용해보고자 한다.
Locationmanager 클래스에서 제공되는 위치 정보를 활용할 수도 있겠지만 이 정보는 실내 위치의 경우 GPS 위성 신호를 수신할 수 없기 때문에 정확한 위치 정보를 알수 없다. 또한 위도, 경도 데이터로 제공하기 때문에 사람이 이해하기 쉬운 위치/장소 정보는 아니다. 역지오코딩을 통해 주소 정보를 알 수 있다 하더라도 실내에 정확한 위치는 알기 힘들 것이다.
따라서 건물 안에서 내 주변의 WiFI AP를 스캔해 나의 위치를 알아내면 좀 더 알기 쉬우면서 정확한 위치/장소 정보를 알 수 있다.
AP에서 전송하는 신호의 세기, 실내 위치 정보 등을 사전에 수집해 일종의 맵 데이터베이스를 구축한다.
그리고 현재 수신되는 신호 정보와 수집된 정보를 비교해 현재 위치를 인식할 수 있다.(WiFi fingerprint)
즉, WiFi fingerprint란 위치에 따른 AP와 신호 강도에 대한 정보들의 데이터베이스라고 할 수 있다.
그럼 직접 WiFiManager를 통해 AP 정보들을 받아와보자.
WiFIManager를 활용하기 위해 필요한 permission은 아래와 같다.
getScanResults() 메서드를 사용하기 위해 필요하다.
1
2
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE">
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE">
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
getWifiInfo(); //받은 스캔 결과 처리
}
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(wifiReceiver, filter);
wm.startScan();
|
cs |
스캔 결과를 받기 위한 BroadcastReceiver를 선언해주고 등록한 다음 WifiManager 객체에서 stratSacn()을 통해
WiFi AP를 스캔할 수 있다.
받은 WiFI AP 결과를 List에 담아 처리하는 코드는 다음과 같다. 이제 scanResult를 활용해 AP 정보들을 확인할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
|
public void getWifiInfo() {
apList = wm.getScanResults();
if (wm.getScanResults() != null) {
int size = apList.size();
for (int i = 0; i < size; i++) {
scanResult = (ScanResult) apList.get(i);
// scanResult.SSID
// scanResult.BSSID
// scanResult.level
}
}
}
|
cs |
https://developer.android.com/reference/android/net/wifi/ScanResult.html
대표적으로 활용하는 정보는 4가지가 있다.
• SSID : 무선 네트워크 식별명(KUTAP, ollehWifi, iptime, …)
• BSSID : MAC 주소(0a:11:e3:98:f1:bb)
• RSSI(Received Signal Strength Indication) : 신호 수신 강도(-39 dBm) - 값이 높을수록 가까이 있음
• timestamp : 스캔 결과를 얻은 시점
이와 같이 실내 위치 정보를 받아와서 활용하는 예에는 특정 가게에 들어가는 경우 특정 앱을 실행하는 것이다.
예를 들어 스타벅스 매장에 들어가면 자동으로 스타벅스 앱이 실행되어 자신의 스마트폰으로 주문을 할 수 있다.
이를 구현하기 위해서 실내 장소에 대한 근접 감지 후 이를 알려주는 기능이 필요하다.
WiFiManagement를 활용해 Proximity Alert 기능을 수행하는 앱을 예제로 만들어보자.
이 예제의 기본적인 기능은 다음과 같다.
• Wifi AP 정보를 이용하여 proximity alert을 발생할 장소를 등록
• 주기적으로 Wifi scan을 수행하여 현재 위치가 alert 등록 장소인지 검사
• 현재 위치가 alert 등록 장소로 판단되면 alert
먼저 Proximity alert을 위해 등록할 장소를 입력받고 Scan을 진행하면 정보를 저장해야 한다. 따라서 UI에서 3개의 장소를 입력받을 수 있도록 구현해 볼 것이다. 따로 text 필드를 두지 않고 AP1, AP2, AP3을 선택할 수 있도록 UI를 구성해 START WIFI SCAN 버튼을 누르면 선택된 AP로 현재 위치를 저장하도록 구현할 것이다.
이러면 최대 3개까지 장소를 저장할 수 있다. 저장이 완료된 AP는 해당 ssid와 bssid를 함께 출력해 표시하도록 할 것이다.
지속적으로 WiFi Scan을 통해 현재 위치를 파악해야 하기 때문에 Service를 활용할 텐데 이러면 지속적으로 alert가 울리게 된다. 따라서 check 변수를 하나두어 특정 위치에 들어가거나 나갈 때에만 alert가 울리도록 설정해 줄 필요가 있다.
또한 현재 지점과 등록된 3개의 지점간의 거리를 측정한 후 가장 가까운 위치를 구해야 한다. 그리고 그 위치가 충분히 가까운지 판단할 수 있어야 한다.
이번 시간에는 쉽게 WiFiManager가 활용될 수 있다는 것을 보여주기 위한 예시이기 때문에 단순히 자카드 지수 방식을 활용해 가장 가까운 거리를 판단할 것이다.
두 집한간의 유사도를 측정하는 방법 중 하나로 현재 예제에 적용시키면 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
private void getWifiInfo() {
if(!doneWifiScan) { // wifiScan을 한 경우에만 getScanResult를 사용하도록 flag 변수 구현
int num = -1;
// num에 선택된 spinner를 체크해서 넣어준다.
if (temp_str.equals("AP1")) num = 0;
else if (temp_str.equals("AP2")) num = 1;
else num = 2;
scanResultList = wifiManager.getScanResults();
String str;
//중복되지 않게 해당 num번째 배열에 AP정보들을 집어넣는다.
for (int i = 1; i < scanResultList.size(); i++) {
ScanResult result = scanResultList.get(i);
// 화면의 TextView에 SSID와 BSSID를 이어붙여서 텍스트로 표시
str = result.SSID + result.BSSID;
if(!top10APId[num].contains(str)) top10APId[num].add(str);
}
//모두 처리되고 나면 가장 처음 들어온 AP의 SSID+BSSID를 text로 뿌려준다.
if (num == 0) {
ap1.setText(top10APId[num].get(0));
} else if (num == 1) {
ap2.setText(top10APId[num].get(0));
} else {
ap3.setText(top10APId[num].get(0));
}
doneWifiScan = true;
}
}
|
cs |
AP1과 현재 위치를 측정한다고 하면 AP1과 현재 위치에서 Scan 되는 AP 정보들이 있을 것이다. 그 정보들을 바탕으로 서로 교집합에 있는 AP 개수를 합집합 AP 개수로 나누면 자카드 지수가 나올 것이다.
아래 예제를 참고해 실제로 WiFiManager를 통해
특정 위치에 접근하거나, 벗어나는 것을 체크할 수 있다는 것을 확인해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
|
public class MainActivity extends AppCompatActivity {
boolean isPermitted = false;
boolean isWifiScan = false;
boolean doneWifiScan = true;
final int MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
TextView ap1;
TextView ap2;
TextView ap3;
ArrayList<String> top10APId[];
WifiManager wifiManager;
List<ScanResult> scanResultList;
private Spinner placeName;
private String temp_str;
private String[] str_placeName;
ArrayList<String> arrayList;
ArrayAdapter<String> arrayAdapter;
BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
getWifiInfo();
}
};
private void getWifiInfo() {
if(!doneWifiScan) { // wifiScan을 한 경우에만 getScanResult를 사용하도록 flag 변수 구현
int num = -1;
// num에 선택된 spinner를 체크해서 넣어준다.
if (temp_str.equals("AP1")) num = 0;
else if (temp_str.equals("AP2")) num = 1;
else num = 2;
scanResultList = wifiManager.getScanResults();
String str;
//중복되지 않게 해당 num번째 배열에 AP정보들을 집어넣는다.
for (int i = 1; i < scanResultList.size(); i++) {
ScanResult result = scanResultList.get(i);
// 화면의 TextView에 SSID와 BSSID를 이어붙여서 텍스트로 표시
str = result.SSID + result.BSSID;
if(!top10APId[num].contains(str)) top10APId[num].add(str);
}
//모두 처리되고 나면 가장 처음 들어온 AP의 SSID+BSSID를 text로 뿌려준다.
if (num == 0) {
ap1.setText(top10APId[num].get(0));
} else if (num == 1) {
ap2.setText(top10APId[num].get(0));
} else {
ap3.setText(top10APId[num].get(0));
}
doneWifiScan = true;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//초기 셋팅 과정
requestRuntimePermission();
temp_str = "temp_str";
str_placeName = new String[3];
top10APId = new ArrayList[3];
for(int i=0; i<3; i++)
top10APId[i] = new ArrayList<String>();
ap1 = (TextView)findViewById(R.id.ap1);
ap2 = (TextView)findViewById(R.id.ap2);
ap3 = (TextView)findViewById(R.id.ap3);
placeName = (Spinner)findViewById(R.id.placeName);
arrayList = new ArrayList<>();
arrayList.add("AP1");
arrayList.add("AP2");
arrayList.add("AP3");
//Spinner 연결 설정
arrayAdapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_spinner_dropdown_item, arrayList);
placeName.setAdapter(arrayAdapter);
placeName.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
str_placeName[i] = arrayList.get(i);
temp_str = str_placeName[i];
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
placeName.setSelection(0);
wifiManager = (WifiManager)getApplicationContext().getSystemService(WIFI_SERVICE);
if(wifiManager.isWifiEnabled() == false)
wifiManager.setWifiEnabled(true);
}
@Override
protected void onResume() {
super.onResume();
// wifi scan 결과 수신을 위한 BroadcastReceiver 등록
IntentFilter filter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(mReceiver, filter);
}
@Override
protected void onPause() {
super.onPause();
// wifi scan 결과 수신용 BroadcastReceiver 등록 해제
unregisterReceiver(mReceiver);
}
public void onClick(View view) {
if(view.getId() == R.id.start) {
// Start wifi scan 버튼이 눌렸을 때
doneWifiScan = false;
Toast.makeText(this, "WiFi scan start!!", Toast.LENGTH_LONG).show();
if(isPermitted) {
// wifi 스캔 시작
wifiManager.startScan();
isWifiScan = true;
} else {
Toast.makeText(getApplicationContext(),
"Location access 권한이 없습니다..", Toast.LENGTH_LONG).show();
}
}
else if(view.getId() == R.id.startAlert) {
// Start proximity alert 버튼이 눌렸을 때
// placeName이라는 변수로 참조하는 EditText에 쓰여진 장소 이름으로 proximity alert을 등록한다
// proximity alert을 주는 것은 Service로 구현
// Service를 AlertService라는 이름의 클래스로 구현하고 startService 메소드를 호출하여 이 Service를 시작
if(str_placeName.equals("")) { //Spinner 선택 했는지 검사
Toast.makeText(this, "Please select place name first.", Toast.LENGTH_LONG).show();
}
else if(!isWifiScan){ //WIfiScan 했는지 검사
Toast.makeText(this, "Wifi-Scan first!!", Toast.LENGTH_LONG).show();
}
else { // 결과값들을 Service로 보낸다.
Intent intent = new Intent(this, AlertService.class);
intent.putExtra("place", str_placeName);
intent.putStringArrayListExtra("ap1id", top10APId[0]);
intent.putStringArrayListExtra("ap2id", top10APId[1]);
intent.putStringArrayListExtra("ap3id", top10APId[2]);
// 위에서 key 값으로 쓰인 String 값은 여러 곳에서 반복해서 사용된다면
// String 상수로 정의해 놓고 사용하는 것이 좋음
// 이 예제에서는 AlertService에서 쓰임
startService(intent);
}
}
else if(view.getId() == R.id.stopAlert) {
// Stop proximity alert 버튼이 눌렸을 때
// AlertService 동작을 중단
stopService(new Intent(this, AlertService.class));
}
}
private void requestRuntimePermission() {
//*******************************************************************
// Runtime permission check
//*******************************************************************
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
}
} else {
// ACCESS_FINE_LOCATION 권한이 있는 것
isPermitted = true;
}
//*********************************************************************
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// read_external_storage-related task you need to do.
// ACCESS_FINE_LOCATION 권한을 얻음
isPermitted = true;
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
// 권한을 얻지 못 하였으므로 location 요청 작업을 수행할 수 없다
// 적절히 대처한다
isPermitted = false;
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
public class AlertService extends Service {
private static final String TAG = "AlertService";
boolean isVib = true;
WifiManager wifiManager;
List<ScanResult> scanList;
int maxIndex = -1;
String[] placeName = new String[3];
ArrayList<String> top10APId[] = new ArrayList[3];
Timer timer = new Timer();
TimerTask timerTask = null;
Vibrator vib;
BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION))
checkProximity();
}
};
// 등록 장소 근접 여부를 판단하고 그에 따라 알림을 주기 위한 메소드
private void checkProximity() {
scanList = wifiManager.getScanResults();
boolean isProximate = false;
double maxValue = 0.0;
int[] proximity_value = new int[3];
Arrays.fill(proximity_value, -100);
ArrayList<String> nowAPId = new ArrayList<String>();
String str;
for(int i = 1; i < scanList.size(); i++) {
ScanResult result = scanList.get(i);
str = result.SSID + result.BSSID;
nowAPId.add(str); // 현재 위치 정보 저장
}
double[] jaccard_index = new double[3];
Arrays.fill(jaccard_index, 0.0);
for(int i=0; i<3; i++) {
if(top10APId[i] == null) continue; //저장되지 않은 장소 생략 과정
int length = top10APId[i].size();
int count = 0;
for(int j=0; j<length; j++)
if(nowAPId.contains(top10APId[i].get(j))) count++; //두 장소를 비교하며 교집합 갯수를 구한다.
jaccard_index[i] = count / (double)(nowAPId.size() + top10APId[i].size() - count); // 교집합 / 합집합 (합집합은 전체 사이즈 - 교집합 사이즈)
}
for(int i=0;i<3; i++) //주기적으로 scan하고 있는지 확인하기 위한 출력력
System.out.println("jaccard_index[" + i +"]:"+jaccard_index[i]);
for(int i=0; i<3; i++){
if(jaccard_index[i] > 0.5){
isProximate = true; // 0.5보다 큰 값들이 존재하면 저장된 장소 근처에 있는 것으로 간주
}
}
if((isProximate && isVib) || (isProximate && maxIndex == -1)) { //저장장소이면서 현재 저장된 장소가 없으면 가장 가까운 위치가 어디인지 측정
maxValue = 0.0;
maxIndex = -1;
for (int i = 0; i < 3; i++) {
if (jaccard_index[i] > maxValue) {
maxValue = jaccard_index[i];
maxIndex = i;
}
}
}
if(isProximate) { //가까운 위치가 있는 경우
// 진동 패턴
// 0초 후에 시작 => 바로 시작, 200ms 동안 진동, 100ms 동안 쉼, 200ms 동안 진동, 100ms 동안 쉼, 200ms 동안 진동
long[] pattern = {0, 200, 100, 200, 100, 200};
// pattern 변수로 지정된 방식으로 진동한다, -1: 반복 없음. 한번의 진동 패턴 수행 후 완료
if(isVib) { //isVib 변수로 인해 지속적으로 alert가 울리지 않는다.
vib.vibrate(pattern, -1);
isVib = false;
Toast.makeText(this, "** " + placeName[maxIndex] + "에 있거나 그 근처에 있습니다 **", Toast.LENGTH_SHORT).show();
}
} else { //가까운 위치가 없는 경우
// 동작 확인용
if(!isVib) { //isVib 변수로 인해 지속적으로 alert가 울리지 않는다.
vib.vibrate(200);
isVib = true;
if(maxIndex != -1) Toast.makeText(this, "** " + placeName[maxIndex] + " 근처에 있지 않습니다 **", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate()");
vib = (Vibrator)getSystemService(VIBRATOR_SERVICE);
wifiManager = (WifiManager)getApplicationContext().getSystemService(WIFI_SERVICE);
IntentFilter filter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(mReceiver, filter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// intent: startService() 호출 시 넘기는 intent 객체
// flags: service start 요청에 대한 부가 정보. 0, START_FLAG_REDELIVERY, START_FLAG_RETRY
// startId: start 요청을 나타내는 unique integer id
Toast.makeText(this, "AlertService 시작", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onStartCommand()");
// 넘어온 intent에서 등록 장소 및 AP 정보 추출
for(int i=0; i<3; i++)
top10APId[i] = new ArrayList<String>();
placeName = intent.getStringArrayExtra("place");
top10APId[0] = intent.getStringArrayListExtra("ap1id");
top10APId[1] = intent.getStringArrayListExtra("ap2id");
top10APId[2] = intent.getStringArrayListExtra("ap3id");
// 주기적으로 wifi scan 수행하기 위한 timer 가동
startTimerTask();
return super.onStartCommand(intent, flags, startId);
}
public void onDestroy() {
Toast.makeText(this, "AlertService 중지", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onDestroy()");
stopTimerTask();
unregisterReceiver(mReceiver);
}
private void startTimerTask() {
// TimerTask 생성한다
timerTask = new TimerTask() {
@Override
public void run() {
wifiManager.startScan();
}
};
// TimerTask를 Timer를 통해 실행시킨다
timer.schedule(timerTask, 1000, 5000); // 1초 후에 타이머를 구동하고 10초마다 반복한다
//*** Timer 클래스 메소드 이용법 참고 ***//
// schedule(TimerTask task, long delay, long period)
// http://developer.android.com/intl/ko/reference/java/util/Timer.html
//***********************************//
}
private void stopTimerTask() {
// 1. 모든 태스크를 중단한다
if(timerTask != null) {
timerTask.cancel();
timerTask = null;
}
}
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context=".MainActivity"
android:orientation="vertical">
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/start"
android:text="Start WiFI Scan"
android:onClick="onClick"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AP1: "/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/ap1"/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AP2: "/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/ap2"/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AP3: "/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/ap3"/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Place Name"/>
<Spinner
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/placeName"/>
</LinearLayout>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/startAlert"
android:text="Start Proximity Alert"
android:onClick="onClick"/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/stopAlert"
android:text="Stop Proximity Alert"
android:onClick="onClick"/>
</LinearLayout>
|
cs |
'School Study > Mobile System Programming' 카테고리의 다른 글
GPS, WiFi를 이용한 위치 모니터링(Location Tracker) (0) | 2019.04.23 |
---|---|
Mobile Sensing Pipeline 2 (0) | 2019.04.23 |
Mobile Sensing Pipeline 1 (0) | 2019.04.17 |
Mobile Device Power Measurement (0) | 2019.04.16 |
Power Manager 알아보기 (0) | 2019.04.10 |