[MUSIC] Welcome to our next lesson in the module on Android Services. Which presents a case study of the ping pong receiver service app. After completing this lesson, you'll know the run time behavior of the PingPongReceiverService app. You recognize the design of the PingPongReceiverService app. You will also understand the implementation of the PingPongReceiverService app, which is available at this URL. First we'll show the PingPongReceiverService app in action, starting by giving a high level of overview with a couple of screen shots. And then actually executing the app inside the Android Studio empire. This app has the same look and feel as the ping pong receiver apps for module five in book two. In particular, it props the user for a number of times to play ping pong and then it goes ahead and sends intents back and forth between a ping receiver and a pong service. The PongService runs in the same process as the PingReceiver. We're now inside the Android Studio emulator, where I'll go ahead and launch the PingPongReceiverService app. You can see as it comes up it logs the various hook methods the activity calls You come over here. Click on the floating action button, and it prompts us for the number of times we want to play ping pong. So, let's give a nice big number. Let's say we want to run this ten times. Click OK. Then let's click the play button, which is another floating action button. You can see it's up here playing ping pong. If we pull down the notification status bar, you can see up here it's going back and forth, ping, pong, ping, pong. And what's happening here, of course, is that the ping receiver is sending a start service request to the pong surface, which then is sending back the request to the ping receiver. Okay, so that's just a quick way to look at the operation of the program. You can see here all the various logging operations that are taking place between the pong service and the ping receiver. Now that we've shown how the PingPongReceiverService app runs, we'll talk about its design. This program plays ping pong by passing intents between a dynamically registered broadcast receiver and a started intent service. As always the lifecycle logging activity is used to define a common superclass for the logging lifecycle operations. The main activity provides the user interface that prompts the user for account and initiates the ping/pong interactions. The PingReceiver is a broadcast receiver that handles ping intents and starts a service by applying intents. And the PongService is an intent service that handles pong intents and broadcasts ping intents. Let's now go ahead and take a look through the source code of the PingPongReceiverService app which you can download at this link. Here we are inside the Android Studio project file for the PingPongReceiverService app. Let's start by taking a quick look at the Android manifest file as you can see, it finds an application that has an activity and the service. Here's the activity implementation location that's in the .activities MainActivity file as we can see here. And then down here, we have the service which is called the PongService which is in the service folder. So that's how things are laid out. As you can see here, we aren't exposing the palm service nor are we running it in a separate process. Let's go take a look at main activity. Main activity extends life cycle logging activity as always. This activity's going to prompt the user for the count and then play the ping pong by passing intense back and forth between the started service and the broadcast receiver that's registered dynamically. We have a number of fields. We have our edit text field that keeps track of the number of accounts the user wants to play. Whether or not the edit text is visible or not. A couple of floating action buttons used to set account as well or start or stop the game. We keep a notification ID which is used by the status bar notification service in order to update the status notification when pings and pongs are playing. We have our ping receiver, which is a dynamically registered broadcast receiver that handles the the ping intense. We'll see how that works in a second. And now we've got a bunch of methods, starting with the entry point method, the virtual constructor on Create. Nothing really exciting going on here. We call up to the super class. Layout the content view. And initialize the views. Once again, nothing really super exciting going on in the initialized views. Its essentially grabbing the edit text and the various floating action buttons and setting fields to be visible or invisible. Starts with them being invisible, as you can see here. And then we set ourselves with a listener that's going to display the start playing coding action button when the user hits the enter key or clicks enter. Let's now go take a look at on pause. This is the hook method that's called when the activity is about to lose focus. And as you can see here what it's going to do after calling it super class is it's going to check to see whether or not we have a ping receiver registered. And if we do we're going to unregister the ping receiver and we're going to update the status bar to indicate this particular game is now idle. Here's the on resume method. This gets called when they application is coming back into focus or if it's being launched the first time. Here we check to see whether or not we've already got a receiver. If not we're going to call a method called registerPingReceiver down here which will go ahead and register the receiver dynamically. And then we're going to ahead and resume the game from the last known iteration. And you can see how this works. We're calling. The ping receivers on receive hook method explicitly passing in a ping intent. It's going to pick up from wherever we left off last time which could be starting with zero if this is the first time in. Let's now go down here and take a look at register receiver, the register ping receiver creates a new intent filter which say we're a dynamic intent and we know how to handle the action view ping intent. And then we go ahead and register this ping receiver that we've just made earlier with the intent filter. So that will have received those particular intents. Here's the start or stop playing method. This gets called back when the user clicks on the floating action button. As you can see here, if we have got ourselves a non-null receiver. Then we're going to go ahead and stop playing. Otherwise, we're going to go ahead and get the count that the user gave, or whatever the default might be. And if the user gave account is less than zero, we're going to throw up an error. Otherwise, we're going to start playing the game. So let's see what happens when we start playing the game. First thing we do is we hide the keyboard. We then make ourselves a new ping receiver, which is going to be used in the onResume hook method we looked at a few minutes ago. Come up here, you can see where the ping receiver's being used right there. This down here, is where we actually allocate that ping receiver. We then dynamically register it. And then we go ahead and call the onReceive method, indicating this is the first time in. So we're going to go ahead and give it a count of one. And then we're going to toggle the floating action button to indicate that the user can stop it if they don't want to play the game anymore. Here is the stop playing button, this is what gets called back if the user clicks on the floating action button when it's in stop mode. As you can see we unregister the receiver. Null out the ping receiver, to indicate it's no longer in use, and then we go ahead and cancel the status bar notification and toggle back the floating action button to the play icon. And the last method we have in the activity is basically set count, and what set count is used to do is to get the count that the user has indicated. So that will either make the edit text visible or invisible, depending on what mode it was in. Okay, so that's basically the main activity. Let's now go over here and look at the ping receiver. This looks very much like the one we had done in moot two, in module five on broadcast receivers. This is a dynamically registered broadcastReceiver that handles ping intents. You can see here is the action that it knows how to handle. This is the ACTION_VIEW_PING that we define here. And we have ourselves a little title bar that we're going to use for the status bar, status notification bar. We're going to store some extra key strings in tense that we're going to fish out and use later. We'll keep track of the maximum number of times to play Ping Pong. We'll keep track of the current iteration, which allows us to be able to resume a paused game. We track of our enclosing activities, so we can call it back when we're all done playing Ping Pong. Here's the constructor for the Ping receiver. We stashed the main activity away along with the max count. Here's the make ping intent factory method that takes in a context account and a notification IP. Let's go ahead and take a look and see what that does. That makes a new intent which is an action view ping intent. It goes ahead and adds the count and the notification IDs as extras and it limits the receiver to components in this app package for extra security. We talked about that in the previous MOOC as well. Here is the ad hoc receive method, this is what really does all the heavy lifting for the ping receiver. This goes ahead and extracts the count from the extra field as an INT inside the ping intent which it's going to stash away in a couple of places. We're then going to go ahead and create a notification ID using the notification ID that was stashed away in the intent. and then assuming we are done, then we're going to tell the status bar we're finished, and we're going to stop playing. So in that particular case, we're going to go ahead and send a stop service call to the pong service telling it to go ahead and shut down because we're not going to need it anymore. And then we inform the activity that we've stopped playing. We call the stop playing method directly. That's why we had to stash that reference earlier. If we're not done playing we're going to update the status bar. And then we're going to go ahead and make a pong intent and this pong intent would be used in order to start a service. And that start service will then go ahead and run in the background as we'll see in a second. So the makePongIntent is a factor method defined by Pong Services we'll see here and that's going to be used to go ahead and start the service And here's the method we used to get back the current iteration, which we use as a starting point for resuming a game that was paused, when the application was paused. All right, let's now go over to PongService, Here's PongService. PongService extends IntentService so it's going to have a thread that runs in the background. And it defines title for the status bar called Pong and it also defines a couple of strings that uses as keys. You put a little delay in here so that's easier to see what the status bar is doing, if you go back and watch the video up running to see that it pauses line after actually is tell what's going on. We have to make ourselves a constructor that calls up to the IntentServices constructor given in the name of the service which in this case the PongService. Here's the make pom intent method. It's very similar to the one we used for making a ping intent, except you don't have to worry about limiting the package. So this goes ahead and makes an explicit intent with the pom service class. That's the Java Class File. And we add in the extras account, and the notification ID. And here at long last is really the work course of this service, which is the on handle intent method. Which as you may recall gets called back in a background thread because this is using the intent service. It gets the count from the intent, stashes it away, we get the notification id from the intent, stashes that away. We then go ahead and sleep for a thousand milliseconds just to give it a little bit of a delay and then we go ahead and update the status bar to indicate we've been ponged. [INAUDIBLE] Again just a little bit. And the last thing we do as we leave this service is we send a broadcast back to the dynamically registered broadcast receiver. And of course send broadcast takes an intent which is returned from the PingReceiver.makePingIntent factory method. And that's going to take the count that we were passed here. And add one to it, and then go ahead and make an intent, that count plus one, and the notification ID. And that will then come back to the registered broadcast receiver inside of the main activity in order to keep the ping pong operations going back and forth. So that's basically a walk-through of all the source code. That concludes our case study of the PingPongReceiverService app. [MUSIC]