In this lecture, we discuss a number of building blocks for MyRunds and any complex Android app:
Note, these are incomplete notes -- to be updated.
The demo code used in this lecture include:
Some excellent references.
Android supports a number of different ways to inform the user including:
We will focus on the status bar notification in this lecture. You will need to implement this type of notification for MyRuns4.
Typically a programmer develops an app and needs to inform the user of an event that is outside of the normal UI. For example if we consider MyRuns4 that you are coding right now. When the user starts an exercise using the GPS mode (or automatic) the code creates a service to process location updates. When this service starts on an independent thread in the background it informs the user that it is running by display first message (i.e., "MyRuns is recording your path" ) and then an icon (i.e., the D icon) in the notification area. We can see this below
To see the details of the MyRuns4 notification, the user needs to wipe down on the status bar (i.e., notification area) to open the notification drawer. The system controls the notification area and drawer and allows the user to view and interact with it at any point For example, in the case of MyRuns4 notification in the drawer the user can wipe down the status bar and click on the MyRuns notification in the drawer and it bring the app back into focus, as shown in the image below.
The simple notification app used in this lecture uses the status bar to inform the user that a service has been started (we will discuss services next). When the user starts the service an icon is displayed in the status bar. If you wipe down the status bar you will see that the notification drawer for the service displays an icon and text (i.e., Demo of Notification! course website). If you click on this notification the service will launch a browser to display the class webpage.
When the app starts up there is no service running and nothing in the status bar associated with the notify app, as shown below.
When the user starts the service the icon shows up in the status bar or notification area, as shown in the image below.
The user can wipe down the status bar and click on the notification which triggers the service to start the browser with the course page, as illustrated in the digram below.
In addition, the user could mindlessly ;-) start and stop the service and see the icon come and go -- be mindless, just do it.
This simple application introduces a number of new things. Importantly a background service is started to interact with the status bar. In MyRuns4 we will implement a service to manage location updated from the LocationManager.
Let's look at the code.
The activity simply takes input from the user and starts and stops the service.
public class NotifyActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonStartService = (Button)findViewById(R.id.startservice);
Button buttonStopService = (Button)findViewById(R.id.stopservice);
buttonStartService.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent(NotifyActivity.this, NotifyService.class);
NotifyActivity.this.startService(intent);
}});
buttonStopService.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View arg0) {
Intent intent = new Intent();
intent.setAction(NotifyService.ACTION);
intent.putExtra(NotifyService.STOP_SERVICE_BROADCAST_KEY,
NotifyService.RQS_STOP_SERVICE);
// Broadcast the given intent to all interested BroadcastReceivers
sendBroadcast(intent);
}});
}
}
The activity starts and stops in the service. A broadcast is used to stop the service; that is, the activity sends an intent to all interested BroadcastReceivers with stop command. In our example, on the service is listening on this broadcast and implements a BroadcastReceiver
public class NotifyService extends Service {
final static String ACTION = "NotifyServiceAction";
final static String STOP_SERVICE_BROADCAST_KEY="StopServiceBroadcastKey";
final static int RQS_STOP_SERVICE = 1;
NotifyServiceReceiver notifyServiceReceiver;
private final String myBlog = "http://www.cs.dartmouth.edu/~campbell/cs65/cs65.html";
@Override
public void onCreate() {
notifyServiceReceiver = new NotifyServiceReceiver();
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION);
registerReceiver(notifyServiceReceiver, intentFilter);
// Send Notification
String notificationTitle = "Demo of Notification!";
String notificationText = "Course Website";
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(myBlog));
PendingIntent pendingIntent
= PendingIntent.getActivity(getBaseContext(),
0, myIntent,
Intent.FLAG_ACTIVITY_NEW_TASK);
Notification notification = new Notification.Builder(this)
.setContentTitle(notificationTitle)
.setContentText(notificationText).setSmallIcon(R.drawable.icon)
.setContentIntent(pendingIntent).build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notification.flags = notification.flags
| Notification.FLAG_ONGOING_EVENT;
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
this.unregisterReceiver(notifyServiceReceiver);
super.onDestroy();
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
public class NotifyServiceReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context arg0, Intent arg1) {
int rqs = arg1.getIntExtra(STOP_SERVICE_BROADCAST_KEY, 0);
if (rqs == RQS_STOP_SERVICE){
stopSelf();
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
.cancelAll();
}
}
}
}
A service needs to be defined in the manifest as shown below.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="edu.dartmouth.cs.notifydemo"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="17" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name="edu.dartmouth.cs.notifydemo.NotifyActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="edu.dartmouth.cs.notifydemo.NotifyService"/>
</application>
</manifest>
The application binds to a sr