Wireless Networking with Android

Download Report

Transcript Wireless Networking with Android

Wireless Networking
with Android
Uichin Lee
KAIST KSE
Review
• Wireless link characteristics
• 802.11 WLAN (a, b, g, n)
– channels, associations, scanning
– multiple access: CSMA/CA (RTS-CTS-DATA-ACK)
• PAN: Bluetooth
– master vs. slave
– peer discovery (inquiry) + connection setup (paging)
– piconet (up to 7 slaves)
.
SNR
• RSS: received signal strength
– Measure of the power present in a received radio signal (at the
receiver antenna)
– Represented in decibels above a reference level of 1 mW (dBm)
– WiFi:
• 100mW (20dBm): EIRP for IEEE 802.11b/g Wireless LAN 20Mhz-wide
channels in the 2.4GHz ISM band (5mW per MHz).
• Typical range (−60 to −80 dBm) of wireless received signal power
– -60dBm => 0.0000001 mW
• SNR: signal to noise ratio
– SNR = Eb/No where Eb the energy per bit, and No noise power
spectral density
• SNR = (Signal Power/Bit Rate) / (Noise Power/Filter Bandwidth)
– CNR = Signal Power / Noise Power
– BER is a function of SNR; e.g., BER(BPSK) = ½erfc(sqrt(SNR))
Internet
Switches
Switch
Switch
• Filtering: whether a frame should be forwarded to
some interface or should be dropped
• Forwarding: determining the interfaces to which a
frame should be directed; and then moves the frame
to those interfaces
• Switch filtering and forwarding are done with a
switch table
– ADDR X: Interface Y: address X comes from interface Y
• Elimination of collisions:
– No wastage of bandwidth thanks to buffers
– Switch buffers frames and never transmit more than one
frame on a segment at any one time
– Switch provides a significant performance improvement over
LANs with broadcast links
Managing network connectivity
• Android broadcasts Intents that describe the
changes in network connectivity
– 3G, WiFi, etc.
• There are APIs for controlling network settings
and connections
• Android networking is handled by
ConnectivityManager (a network connectivity
service)
– Monitor the state of network connections
– Configure failover settings
– Control network radios
Managing network connectivity
• Accessing connectivity manager
String service = Context.CONNECTIVITY_SERVICE;
ConnectivityManager connectivity =
(ConnectivityManager) getSystemService(service);
• App needs read/write access permission on
network states
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
Accessing network status
// Get the active network information.
NetworkInfo activeNetwork = connectivity.getActiveNetworkInfo();
int networkType = activeNetwork.getType();
switch (networkType) {
case (ConnectivityManager.TYPE_MOBILE) : break;
case (ConnectivityManager.TYPE_WIFI) : break;
default: break;
}
// Get the mobile network information.
int network = ConnectivityManager.TYPE_MOBILE;
NetworkInfo mobileNetwork = connectivity.getNetworkInfo(network);
NetworkInfo.State state = mobileNetwork.getState();
NetworkInfo.DetailedState detailedState =
mobileNetwork.getDetailedState();
Preferred networks
• Preferred network configuration:
– getNetworkPreference()
– setNetworkPreference()
int networkPreference = connectivity.getNetworkPreference();
connectivity.setNetworkPreference(NetworkPreference.PREFER_WIFI);
• If the preferred connection is unavailable, or connectivity
on this network is lost, Android will automatically attempt
to connect to the secondary network.
• Control availability of the network types using the
setRadio() method.
connectivity.setRadio(NetworkType.WIFI, false);
connectivity.setRadio(NetworkType.MOBILE, true);
WiFi
Based on “Programming Android 2”
Managing your WiFi
• WifiManager: represents the Android WiFi
connectivity service
–
–
–
–
Configure WiFi network connections
Manage current WiFi connection
Scan for access points
Monitor changes in WiFi connectivities
Monitoring WiFi connectivity
• Accessing the WiFi Manager
String service = Context.WIFI_SERVICE;
WifiManager wifi = (WifiManager) getSystemService(service);
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
• Monitoring and changing Wifi state
– State: enabling, enabled, disabling, disabled, and unknown
if (!wifi.isWifiEnabled())
if (wifi.getWifiState() != WifiManager.WIFI_STATE_ENABLING)
wifi.setWifiEnabled(true);
Monitoring WiFi connectivity
• WifiManager broadcasts Intents whenever connectivity status
changes
– WIFI_STATE_CHANGED_ACTION
• Wi-Fi h/w status has changed: enabling, enabled, disabling, disabled, and unknown
• EXTRA_WIFI_STATE, EXTRA_PREVIOUS_STATE
– SUPPLICANT_CONNECTION_CHANGED_ACTION:
• Whenever connection state with the active supplicant (access point) changes
• Fired when a new conn is established, or existing conn is lost
(EXTRA_NEW_STATE = true/false)
– NEWTWORK_STATE_CHANGED_ACTION:
• Fired whenever wifi connectivity state changes
• EXTRA_NETWORK_INFO: NetworkInfo obj for current network status
• EXTRA_BSSID: BSSID of the access point that you’re connected to
– RSSI_CHANGED_ACTION:
• Monitor the signal strength of the connected WiFi network
• EXTRA_NEW_RSSI: current signal strength
Monitoring active connection details
• Once you connected to an access point, use
getConnectionInfo of WifiManager to find
info of that connection
– Returns “WifiInfo” object
WifiInfo info = wifi.getConnectionInfo();
if (info.getBSSID() != null) {
int strength = WifiManager.calculateSignalLevel(info.getRssi(), 5);
int speed = info.getLinkSpeed();
String units = WifiInfo.LINK_SPEED_UNITS;
String ssid = info.getSSID();
String cSummary = String.format("Connected to %s at %s%s. Strength
%s/5",
ssid, speed, units, strength);
}
Scanning hotspots
• Use WifiManager to scan access points using startScan()
• Android will broadcast scan results with an Intent of
“SCAN_RESULTS_AVAILABLE_ACTION”
// Register a broadcast receiver that listens for scan results.
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
List<ScanResult> results = wifi.getScanResults();
ScanResult bestSignal = null;
for (ScanResult result : results) {
if (bestSignal == null ||
WifiManager.compareSignalLevel(bestSignal.level,result.level)<0)
bestSignal = result;
}
String toastText = String.format("%s networks found. %s is
the strongest.",
results.size(), bestSignal.SSID);
Toast.makeText(getApplicationContext(), toastText, Toast.LENGTH_LONG);
}
}, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
// Initiate a scan.
wifi.startScan();
Creating a WiFi configuration
• To connect to a WiFi network, a WiFi
configuration must be created and registered
– Normally a user does this, but app can do this
• Network configuration is stored as
WifiConfiguration object
– SSID (service set ID, e.g., IPv4_KAIST)
– BSSID (MAC addr of an AP)
– networkId (unique ID that the supplicant uses to
identify this network configuration entry)
– priority (priority of this access point)
– status (current status: ENABLED, DISABLED, CURRENT)
Power Management
• Android supports its own Power Management
(on top of the standard Linux Power
Management)
– To make sure that CPU shouldn't consume power if
no applications or services require power
• Android requires that applications and
services request CPU resources with "wake
locks" through the Android application
framework and native Linux libraries.
• If there are no active wake locks, Android will
shut down the CPU.
Power Management
http://www.kandroid.org/android_pdk/power_management.html
WakeLock
Flag value
CPU
Screen
Keyboard
PARTIAL_WAKE_LOCK
On
Off
Off
SCREEN_DIM_WAKE_LOCK
On
Dim
Off
SCREEN_BRIGHT_WAKE_LOCK
On
BRIGHT
Off
FULL_WAKE_LOCK
On
Bright
Bright
// Acquire handle to the PowerManager service
PowerManager pm = (PowerManager)mContext.getSystemService(
Context.POWER_SERVICE);
// Create a wake lock and specify the power management flags for
screen, timeout, etc.
PowerManager.WakeLock wl = pm.newWakeLock(
PowerManager.SCREEN_DIM_WAKE_LOCK |
PowerManager.ON_AFTER_RELEASE, TAG);
// Acquire wake lock
wl.acquire(); // ...
// Release wake lock
wl.release();
Wifi background data transfer
• Background data transfer:
– Wifilock + Wakelock (partial)
// http://developer.android.com/reference/android/net/wifi/WifiManager.WifiLock.html
WifiManager.WifiLock wifiLock = null;
PowerManager.WakeLock wakeLock = null;
// acquire
if (wifiLock == null) {
WifiManager wifiManager = (WifiManager)
context.getSystemService(context.WIFI_SERVICE);
wifiLock = wifiManager.createWifiLock("wifilock");
wifiLock.setReferenceCounted(true);
wifiLock.acquire();
PowerManager powerManager = (PowerManager)
context.getSystemService(context.POWER_SERVICE);
wakeLock =
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "wakelock");
wakeLock.acquire();
}
// release
if (wifiLock != null) {
wifiLock.release();
wifiLock = null;
wakeLock.release();
wakeLock = null;
}
Background data transfer
• Setting > Accounts & sync settings > background data setting
• If this setting is off, an application cannot transfer data only
when it is active and in the foreground
– Services cannot transfer data (by definition)
• Use connectivity manager to check this:
–
boolean backgroundEnabled = connectivity.getBackgroundDataSetting();
• App can listen to changes in the background data transfer
preference:
registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent)
// do something..
},
new IntentFilter(ConnectivityManager.
ACTION_BACKGROUND_DATA_SERVICE_CHANGED)
);
Bluetooth
Based on “Programming Android 2”
Android Developer Guide:
http://developer.android.com/guide/topics/wireless/bluetooth.html
Main classes
• BluetoothAdapter:
– local Bluetooth device
• BluetoothDevice:
– representing each remote device with which we want to
communicate with
• BluetoothSocket:
– call “createRfcommSocketToServiceRecord()” on a
remote Bluetooth Device object to create a Bluetooth
socket
• BluetoothServerSocket:
– creating a Bluetooth server socket by calling
“listenUsingRfcommWithServiceRecord()” method
Overview
Master
(initiator)
Slave
Peer discovery: get a list of
neighboring peers
Setting BT as “discoverable”
=> respond to peer inquiry
Connect to a slave:
socket.connect(“one of slaves”);
(act as a client)
Accepting incoming
connections: Socket.accept()
(act as a server)
Bluetooth permissions
• To use Bluetooth features, at least one of two
Bluetooth permissions must be declared:
– BLUETOOTH
• Requesting/accepting a connection, and data transfer
– BLUETOOTH_ADMIN
• More powerful than BLUETOOTH; includes device
discovery, manipulating Bluetooth settings (on/off), etc.
<manifest ... >
<uses-permission android:name="android.permission.BLUETOOTH" />
...
</manifest>
Setting up Bluetooth
• Bluetooth setup:
1. Get the BluetoothAdapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
}
2. Enable Bluetooth
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ENABLE_BT)
if (resultCode == RESULT_OK )
// if user pressed “YES”
if (resultCode == RESULT_CANCELED) {
// if user pressed “NO”
}
Setting up Bluetooth
• App can also listen for “ACTION_STATE_CHANGED”
broadcast intent
– Android will broadcast whenever the Bluetooth state has
changed
• Broadcast contains the extra fields:
– EXTRA_STATE: current state
– EXTRA_PREVIOUS_STATE: previous state
– State values:
•
•
•
•
STATE_TURNING__ON
STATE_ON
STATE_TURNING_OFF
STATE_OFF
• Enabling “discoverability” will automatically enable
Bluetooth
Discoverability (slave)
•
Enabling “discoverability”
– New intent with
“ACTION_REQUEST_DISCOVERABLE”
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivityForResult(discoverableIntent, DISCOVERY_REQUEST);
– This will show a user permission dialog:
– Activity will receive the response through “onActivityResult()”
•
Activity.RESULT_CANCELLED (if a user canceled)
– The device will be “discoverable” for the specified duration (default: 2 minutes)
•
App can be notified of mode changes by registering a
BroadcastReceiver for the “ACTION_SCAN_MODE_CHANGED” Intent
– EXTRA_SCAN_MODE
– EXTRA_SCAN_MODE_PREVIOUS
– Values: SCAN_MODE_CONNECTABLE_DISCOVERABLE (inquiry scan + page scan
on), SCAN_MODE_CONNECTABLE (page scan on), SCAN_MODE_NONE (none)
•
App does not need to enable device “discoverablity” if you will be
initiating a connection to a remote node
– Only necessary when other parties discover an app that hosts a server socket for
accepting incoming connections
Discovering devices (master)
•
Discovering devices
– Call “startDiscovery()” – async method (about 12 second inquiry)
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
bt.startDiscovery();
– App registers a BroadcastReceiver for the ACTION_FOUND Intent to receive
information about each device discovered
•
It carries the extra fields: EXTRA_DEVICE (BluetoothDevice) and EXTRA_CLASS
(BluetoothClass)
– Call “cancelDiscovery()” to cancel discovery (check first with isDiscovering())
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device =
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
};
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
Device pairing (master/slave)
• Device pairing (or bonding)
– When a connection is made with a remote device for
the first time, a pairing request is automatically
presented to the user
– When paired, basic information about a device is kept
locally such as device name, class, MAC addr, some
secret keys (for secure comm)
– Android Bluetooth APIs require devices to be paired
before an RFCOMM connection can be established
Socket communications (slave)
• Server must hold an open BluetoothServerSocket
• Procedure:
1. Get BluetoothServerSocket by calling
listenUsingRfcommWithServiceRecord(String, UUID)
•
•
String is a name of your service written into Service
Discovery Protocol (SDP) DB
UUID is an entry in SDP DB (unique service identifier)
2. Listening for connection requests by calling accept()
•
•
Blocking call; return a connection if accepted
Matching if a remote device sent a req with a UUID
matching the one registered with this listening server
socket
Socket communications (slave)
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) { }
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) { break; }
// If a connection was accepted
if (socket != null) {
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(socket);
mmServerSocket.close();
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) { }
}
}
Socket communications (master)
• Must have “BluetoothDevice” of a remote device
(discovered via startDiscovery())
• Procedure:
1. Using BluetoothDevice, get a BluetoothSocket by
calling
“createRfcommSocketToServiceRecord(UUID)”
•
•
Initialize a BluetoothSocket with a given UUID
UUID is a hard-coded string unique to the “server”
2. Initiate a connection by calling “connect()”
•
•
System will perform an SDP lookup on the remote device to
match the UUID
If the lookup is successful and the remote device accepts
the connection, it will share the RFCOMM channel for comm
Socket communications (master)
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
BluetoothSocket tmp = null;
mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
Managing a connection
• Each device now has a connected
BluetoothSocket
• Sending/receiving data:
– First get InputStream/OutputStream from socket
– Read/write data to the streams with blocking calls,
read/write(byte[])
Managing a connection
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) { break; }
}
}
NFC
Reading NDEF data from an NFC tag
Beaming NDEF messages from one device to another with Android Beam
http://developer.android.com/guide/topics/nfc/nfc.html
http://developer.android.com/resources/samples/AndroidBeamDemo/src/com/exa
mple/android/beam/Beam.html
NFC: Near Field Communications
NFC Forum Technology
Architecture
NFC device
NFC card
emulation mode:
Smart key say for
mobile local
payment
NFC tag
NFC device
NFC device
P2P mode
(Android Beam):
either directly or
by establishing
NFC device
wireless links
NFC tag
Reader/writer
mode: low cost
solution to
distribute
info/services
http://www.nfc-forum.org/events/oulu_spotlight/Technical_Architecture.pdf
NFC Capabilities on Android
• Currently available Android NFC phones:
Google Nexus S, Samsung Galaxy S 2
• Use Android 2.3.3 (API Level 10) as the NFC
APIs drastically changed from 2.3.2.
• NFC in Android:
– Tag reader/writer
– P2P communication (Android-specific)
– Tag emulation (of certain NFC NDEF tags) – not
fully functional*
* http://stackoverflow.com/questions/6138077/can-an-android-nfc-phone-act-as-an-nfc-tag
Tag Dispatch System
•
•
Android-powered devices are usually looking for NFC tags when the
screen is unlocked, unless NFC is disabled in the device's Settings
menu.
Tag dispatch system analyzes scanned NFC tags, parses them, and tries
to locate applications that are interested in the scanned data
Reading Tag Example
<manifest ... >
<uses-permission android:name="android.permission.NFC" />
<uses-sdk android:minSdkVersion="10"/>
<uses-feature android:name="android.hardware.nfc"
android:required="true" />
</manifest>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
// The following example filters for a URI in the form of
http://developer.android.com/index.html.
<data android:scheme="http"
android:host="developer.android.com"
android:pathPrefix="/index.html" />
// for P2P beaming..
<data android:mimeType="application/com.example.android.beam" />
</intent-filter>
Reading Tag Example
public void onResume() {
super.onResume();
...
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
Parcelable[] rawMsgs =
intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null) {
msgs = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++) {
msgs[i] = (NdefMessage) rawMsgs[i];
}
}
}
//process the msgs array
}
Android Beaming (P2P)
• Simple P2P data exchange between two Androidpowered devices
• Sender app must be in the foreground
• Receiver must not be locked
• Sender’s close contact will invoke "Touch to Beam" UI
• Sender can then choose whether or not to beam the
message to receiver
• Note that if your activity enables Android Beam and
is in the foreground, the standard intent dispatch
system will be disabled.
– However, if your activity also enables foreground
dispatching, then it can still scan tags that match the intent
filters set in the foreground dispatching.
Android Beaming (P2P)
// Register callback to set NDEF message (OnCreate)
mNfcAdapter.setNdefPushMessageCallback(this, this);
// Register callback to listen for message-sent success
mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
NfcAdapter.CreateNdefMessageCallback.createNdefMessage(NfcEvent event)
NfcAdapter.OnNdefPushCompleteCallbackon.NdefPushComplete(NfcEvent event)
• CreateNdefMessageCallBack causes a Callback to be invoked
when another NFC device capable of NDEF push (Android Beam)
is within range.
– Instantly create an NdefMessage at the moment that another device is
within range for NFC and push it over (pushing is done automatically).
– Using this callback allows you to create a message with data that might
vary based on the content currently visible to the user.
• OnNdefPushCompleteCallbackon causes a Callback as soon as
sending of the NDEF Message is completed.
– You should implement this method in order to let the user know, when
the transfer is complete and thus the user can put his NFC device away.
http://developer.android.com/resources/samples/AndroidBeamDemo/src/com/example/android/beam/Beam.html
Android Beaming (P2P)
// Receiving a beam from the sender
@Override
public void onNewIntent(Intent intent) {
// onResume gets called after this to handle the intent
setIntent(intent);
}
@Override
public void onResume() {
super.onResume();
// Check to see that the Activity started due to an Android Beam
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
processIntent(getIntent());
}
}
// Parses the NDEF Message from the intent and prints to the TextView
void processIntent(Intent intent) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
// only one message sent during the beam
NdefMessage msg = (NdefMessage) rawMsgs[0];
// record 0 contains the MIME type, record 1 is the AAR, if present
mInfoText.setText(new String(msg.getRecords()[0].getPayload()));
}
http://developer.android.com/resources/samples/AndroidBeamDemo/src/com/example/android/beam/Beam.html
Summary
•
•
•
•
Managing network connectivity
WiFi management
Bluetooth communications through RFCOMM
NFC: tag reading and beaming