Notifications and Services

Landon Cox March 28, 2017 Networking so far

• Volley (retrieve quiz stored at URL) • User starts app • Check with server for new quiz

• Say you’re building a messaging app … • How else might you use the network? • Are the workflows different than those we’ve seen? How do we keep device data fresh? Solution 1: polling

• Basic idea • App periodically sends message to server • Asks, “is there anything new for me?”

• Very simple to implement • Create a timer • When timer fires, exchange messages with server

• What’s the problem? Impact of polling on battery

• Network power • LTE: 600 – 1700 mW • WiFi: 77 – 130 mW

• Assume radio stays in high-power state for 10 sec. • Energy per LTE poll: 1500 mW x 10 seconds = 15 Joules • 5 min frequency: 480 J/day • 30 sec. frequency: 4800 J/day • Total Pixel battery: ~40k Joules

• You probably have more than one app that needs to sync • If you have a lot of apps, your radios will always be in a high-power state

• Choosing the right period right is difficult • Check too often and drain the battery with useless messages • Check too infrequently and user experience will suffer http://dl.acm.org/citation.cfm?id=2307658 Every outgoing query will put the radio in a high- power state. Solution 2: push notifications

• Share persistent network connection across apps • Device and server maintain (TCP) connection • Radio can enter low-power state when no updates • Server pushes updates to device • Device can push updates to server • Updates should be small (< 4KB)

• On-device service routes updates to apps

• Example: Firebase Cloud Messaging (FCM) Share one persistent connection. High-power only when data is ready. Firebase cloud messaging (FCM)

• Formerly (GCM)

• On your device • Services (global, maintains connection to cloud) • FirebaseInstanceIDService (per app, receives instance ID) • FirebaseMessageService (per app, receives notifications)

• In the cloud • Firebase (routes messages to app server, devices) • App server (stores data, manages messaging) Firebase cloud messaging (FCM)

• Formerly Google Cloud Messaging (GCM)

• On your device • (global, maintains connection to cloud) • FirebaseInstanceIDService (per app, receives instance ID) • FirebaseMessageService (per app, receives data)

• In the cloud • Firebase (routes messages to app server, devices) • App server (stores data, manages messaging)

Next time Services

• Service • Performs tasks on main thread: onStartCommand • Defined as an app component • Because it is a component, it is externally visible

• Who schedules most work on threads? • Code already running inside our app Services

• Service • Performs tasks on main thread: onStartCommand • Defined as an app component • Because it is a component, it is externally visible

• Why might external visibility be useful? • Allows processes to communicate with each other Services

• Service • Performs tasks on main thread: onStartCommand • Defined as an app component • Because it is a component, it is externally visible

• Why are services essential for FCM? • Gives Google Play Services a place to send messages • Forward new data from Firebase to app’s Service Services

• Service • Performs tasks on main thread: onStartCommand • Defined as an app component • Because it is a component, it is externally visible

• Need to add Service to Android Manifest

AndroidManifest.xml:

/> Services

• Example Service • Create a subclass of Service • Use a worker thread to process IPC requests • Handle requests serially

public class MyService extends Service { protected int onStartCommand(Intent intent) { // process IPC request } What } thread does this run on? Services

• Example Service • Create a subclass of Service • Use a worker thread to process IPC requests • Handle requests serially

public class MyService extends Service { protected int onStartCommand(Intent intent) { // process IPC request } } What is an Intent? Quick Intents review Displaying a web URL

How does Android know which components could receive this Intent?

Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(" http://www.google.com/images?q=duke ")); startActivity(browserIntent); Intent filters

Restricts which actions the Activity will accept (Intent Action must match)

Intent filters

Describes categories of Intent Activity accepts (Intent categories must match all) Implementing MyService

• We can do this!

• Tools to use • Handler • Looper • HandlerThread

• Useful to peak under the FCM hood Implementing MyService

public class MyService extends Service { private Looper mLooper; What private ServiceHandler mHandler; needs to happen? protected void onCreate() { // on which thread does this code run? }

protected int onStartCommand(Intent intent) { // on which thread does this code run? }

private class ServiceHandler extends Handler { public ServiceHandler(Looper l) { super (l); } public void handleMessage(Message m) { … } } } https://developer.android.com/reference/android/app/Service.html Implementing MyService public class MyService extends Service { private Looper mLooper; private ServiceHandler mHandler;

protected void onCreate() { HandlerThread thread = new HandlerThread(…); thread.start(); // Get the Looper and use it for our Handler mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper); // on which thread does this code run? } … private class ServiceHandler extends Handler { public ServiceHandler(Looper l) { super (l); } public void handleMessage(Message m) { … } } } Implementing MyService public class MyService extends Service { private Looper mLooper; private ServiceHandler mHandler;

protected void onCreate() { // on which thread does this code run? }

protected int onStartCommand(Intent intent) { // on which thread does this code run? What } needs to happen? private class ServiceHandler extends Handler { public ServiceHandler(Looper l) { super (l); } public void handleMessage(Message m) { … } } } Implementing MyService public class MyService extends Service { private Looper mLooper; private ServiceHandler mHandler; … protected int onStartCommand(Intent intent) { Toast.makeText(…).show(); // For each start request, forward the Intent Message msg = mServiceHandler.obtainMessage(); msg.arg1 = intent; mServiceHandler.sendMessage(msg); return 0; // on which thread does this code run? } … } Implementing MyService public class MyService extends Service { private Looper mLooper; Lucky for you, you private ServiceHandler mHandler; can just subclass Firebase Services! protected void onCreate() { // on which thread does this code run? }

protected int onStartCommand(Intent intent) { // on which thread does this code run? }

private class ServiceHandler extends Handler { public ServiceHandler(Looper l) { super (l); } public void handleMessage(Message m) { … } } } Firebase services

• FirebaseInstanceIDService • Why does each app instance need a unique ID? • Who manages mapping from users to instance IDs?

• FirebaseMessageService • What should happen if your app is in the foreground? • What should happen if your app is in the background?

• Note: you will likely need to update via SDK manager

git clone https://github.com/firebase/quickstart-android.git