05 - Android Connectivity & Google APIs

  • Description:
  • Practical part:

Lecture

Practical

Resources

Task 1 - Downloading remote content (1p)

Create a new project with a blank main Activity. Add an EditText, a Button and a TextView to the Activity's layout. When the user enters an URL into the EditText and clicks the Button download the remote HTTP content at that URL and display it into the TextView.

By design, the Android framework will not allow long-running or potentially blocking operations (such as network operations) to be carried out on the main UI thread. As such, within the onClick() method of the Button we want to start a new thread in which to download the HTTP data.

The simplest solution would be using a Thread instance. However, we want to modify a UI element (the TextView) right after the thread has finished downloading data, which cannot be done from a Thread's run() method. For such a scenario, the framework provides the AsyncTask class.

When defining the AsyncTask instance we can provide 3 parameters. Since we want to give our instance a String (the URL) to work with and have it return another String (the downloaded content) the first and third parameters will be String while the second one can be left Void:

button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v){
        AsyncTask<String, Void, String> task = new AsyncTask<String, Void, String>(){
        ...
        };
    }
});

The most important method within the AsyncTask is doInBackground(), which is executed on another thread. Since we have defined the AsyncTask as having a String as the first and third parameters, the signature of the doInBackground() method will be:

@Override
protected String doInBackground(String... params){
...
}

In order to retrieve HTTP data, we can use the HttpURLConnection API, using params[0] as the remote URL:

URL url = new URL(params[0]);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();

The actual contents can be retrieved by using the InputStream provided by the HttpURLConnection instance:

InputStream is = connection.getInputStream();

The String contents returned from the doInBackground() method are passed as the parameter to the onPostExecute() method, which will be executed on the main UI thread. As such, within this method we can safely update the contents of the TextView:

@Override
protected void onPostExecute(String content) {
  textView.setText(content);
}

Having defined the AsyncTask launch it using the execute method, which receives the text from the EditText element as a parameter:

task.execute(editText.getText().toString());

If you try to run the application at this time, it will stop since, by default, applications are not granted Internet access by the framework. In order to be able to connect to remote resources, you need to add the necessary permission to the AndroidManifest.xml:

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

For each of the following tasks, do not forget to add the required permissions in the manifest file in order to be able to retrieve information about the location, Bluetooth, WiFi)

Task 2 - Getting the current location (2p)

For this task, you will need to have enabled either the GPS of your mobile device or an active WiFi connection (or both).

On Android, the location can be gathered using three providers:

  • GPS provider which uses the GPS driver of your mobile device to track your connection (it is slow and not very precise)
  • network provider which relies on having an active Internet connection (it has high levels of accuracy)
  • passive provider which relies on having the current location determined by other applications

Add a button and a TextView to the activity. When clicking on the button, the TextView will have to show the current coordinates (latitude and longitude).

In order to get the current location, the main activity will have to implement the LocationListener interface which provides methods for detecting when the location has changed or when a location provider has been enabled or disabled.

Getting the location requires sending a request to the location providers to determine the current location. The request is sent using a LocationManager object. Make sure to send a request for every active network provider. The request will also need a time between updates and a minimum distance to be considered for updating the location. Set these values to 1 minute and 5 meters. These requests will be sent upon clicking the button.

The LocationListener interface offers a callback through which the user can perform operations if the location coordinates have changed. Implement this callback to set the text of the TextView object to the current coordinates.

Take into account the fact that the location updates take time. Therefore the TextView will not be changed immediately, it will be changed after 10-12 seconds if a network provider was used to determine the location or more than 20 seconds if a GPS provider is used.

Task 3 - Getting the last known location periodically (2p)

The LocationManager object also offers a method through which you can get the last known location on the device (it could be the current one or an outdated one). We will want to periodically log the last known location.

A periodic operation can be done on Android using a service with an infinite loop in which you execute that operation. However, a more scheduler oriented approach is using the AlarmManager object.

An alarm manager is usually implemented as a broadcast receiver as follows:

public class LocationAlarmReceiver extends BroadcastReceiver {

	private static final String TAG = "LocationAlarmReceiver";
	
	@Override
	public void onReceive(Context context, Intent intent) {    	 
        // TODO
        // Get the last know location and log it
        // There is no need to verify the intent since it will be triggered only through the setAlarm method
	}

    public void setAlarm(Context context) {
        AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent i = new Intent(context, LocationAlarmReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
        am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 2, pi); // Milliseconds * Second * Minute
    }

    public void cancelAlarm(Context context) {
        Intent intent = new Intent(context, LocationAlarmReceiver.class);
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(sender);
    }
}

Add two buttons to the main activity:

  • one that starts the location alarm
  • one that stops the location alarm

Occasionally press the button that updates the current location and see if the changes are reflected in the logs.

Task 4 - Scaning for Bluetooth devices periodically (2p)

Similar to Task 3, we will want to log the detected Bluetooth devices periodically.

public class BluetoothReceiver extends BroadcastReceiver {

	public static final String TAG = "BluetoothReceiver";
	
	@Override
	public void onReceive(Context context, Intent intent) {
		String action = intent.getAction();
		// TODO
                // Every device that is discovered will be received in this callback method through a certain intent action
                // which will be further used to determine the Bluetooth device that was detected.
	}
}

In order to periodically discover Bluetooth devices, we will use the following alarm manager object:

public class BluetoothAlarmReceiver extends BroadcastReceiver {

	private static final String TAG = "BluetoothAlarmReceiver";
	
	@Override
	public void onReceive(Context context, Intent intent) {
		BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
		Log.v(TAG, "Starting Bluetooth discovery");
		adapter.startDiscovery();
	}
	
    public void setAlarm(Context context) {
        AlarmManager am =( AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent i = new Intent(context, BluetoothAlarmReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
        am.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 3, pi); // Milliseconds * Second * Minute
    }

    public void cancelAlarm(Context context) {
        Intent intent = new Intent(context, BluetoothAlarmReceiver.class);
        PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(sender);
    }
}

Take into account the fact a Bluetooth discovery lasts between 12 and 15 seconds.

Add two buttons to the main activity:

  • one that starts the Bluetooth alarm
  • one that stops the Bluetooth alarm

Task 5 - Scaning for WiFi devices periodically (3p)

In a similar fashion to Task 3 and Task 4, implement an alarm manager that periodically scans the WiFi network for WiFi devices and prints their MAC address. (Hint: WiFiManager).

Add two buttons to the main activity:

  • one that starts the WiFi alarm
  • one that stops the WiFi alarm

Bonus - Wakelocks (3p)

When a mobile device has its display closed, it usually enters into sleep mode which means that the CPU is inactive. Once the display is closed, most applications do not perform actions or execute operations as frequently as they do when the display is on. However there are applications that require having the CPU active even when the screen is closed. This can be achieved using wakelocks. Wakelocks are generally used within gaming applications so that the screen is active all the time.

When the device has its display closed, the wireless driver is also affected by the sleep mode. Performing a WiFi scan in sleep mode would yield the results from the last time when the device was active.

For this task, you will have to add a wakelock to the WiFi scan alarm manager. This wakelock will have to activate the display and disable the lockscreen if it is present.

Take into account the fact that a WiFi scan lasts around 15-20 seconds.

osp/lectures/lecture-connectivity.txt ยท Last modified: 2016/11/06 18:57 by laura.gheorghe
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0