1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.apis.app;
18 
19 import android.app.Notification;
20 import android.app.NotificationManager;
21 import android.app.PendingIntent;
22 import android.app.Service;
23 import android.content.Intent;
24 import android.os.Binder;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.Message;
28 import android.os.Messenger;
29 import android.os.RemoteException;
30 import android.util.Log;
31 import android.widget.Toast;
32 
33 import java.util.ArrayList;
34 
35 // Need the following import to get access to the app resources, since this
36 // class is in a sub-package.
37 import com.example.android.apis.R;
38 import com.example.android.apis.app.RemoteService.Controller;
39 
40 /**
41  * This is an example of implementing an application service that uses the
42  * {@link Messenger} class for communicating with clients.  This allows for
43  * remote interaction with a service, without needing to define an AIDL
44  * interface.
45  *
46  * <p>Notice the use of the {@link NotificationManager} when interesting things
47  * happen in the service.  This is generally how background services should
48  * interact with the user, rather than doing something more disruptive such as
49  * calling startActivity().
50  */
51 //BEGIN_INCLUDE(service)
52 public class MessengerService extends Service {
53     /** For showing and hiding our notification. */
54     NotificationManager mNM;
55     /** Keeps track of all current registered clients. */
56     ArrayList<Messenger> mClients = new ArrayList<Messenger>();
57     /** Holds last value set by a client. */
58     int mValue = 0;
59 
60     /**
61      * Command to the service to register a client, receiving callbacks
62      * from the service.  The Message's replyTo field must be a Messenger of
63      * the client where callbacks should be sent.
64      */
65     static final int MSG_REGISTER_CLIENT = 1;
66 
67     /**
68      * Command to the service to unregister a client, ot stop receiving callbacks
69      * from the service.  The Message's replyTo field must be a Messenger of
70      * the client as previously given with MSG_REGISTER_CLIENT.
71      */
72     static final int MSG_UNREGISTER_CLIENT = 2;
73 
74     /**
75      * Command to service to set a new value.  This can be sent to the
76      * service to supply a new value, and will be sent by the service to
77      * any registered clients with the new value.
78      */
79     static final int MSG_SET_VALUE = 3;
80 
81     /**
82      * Handler of incoming messages from clients.
83      */
84     class IncomingHandler extends Handler {
85         @Override
handleMessage(Message msg)86         public void handleMessage(Message msg) {
87             switch (msg.what) {
88                 case MSG_REGISTER_CLIENT:
89                     mClients.add(msg.replyTo);
90                     break;
91                 case MSG_UNREGISTER_CLIENT:
92                     mClients.remove(msg.replyTo);
93                     break;
94                 case MSG_SET_VALUE:
95                     mValue = msg.arg1;
96                     for (int i=mClients.size()-1; i>=0; i--) {
97                         try {
98                             mClients.get(i).send(Message.obtain(null,
99                                     MSG_SET_VALUE, mValue, 0));
100                         } catch (RemoteException e) {
101                             // The client is dead.  Remove it from the list;
102                             // we are going through the list from back to front
103                             // so this is safe to do inside the loop.
104                             mClients.remove(i);
105                         }
106                     }
107                     break;
108                 default:
109                     super.handleMessage(msg);
110             }
111         }
112     }
113 
114     /**
115      * Target we publish for clients to send messages to IncomingHandler.
116      */
117     final Messenger mMessenger = new Messenger(new IncomingHandler());
118 
119     @Override
onCreate()120     public void onCreate() {
121         mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
122 
123         // Display a notification about us starting.
124         showNotification();
125     }
126 
127     @Override
onDestroy()128     public void onDestroy() {
129         // Cancel the persistent notification.
130         mNM.cancel(R.string.remote_service_started);
131 
132         // Tell the user we stopped.
133         Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show();
134     }
135 
136     /**
137      * When binding to the service, we return an interface to our messenger
138      * for sending messages to the service.
139      */
140     @Override
onBind(Intent intent)141     public IBinder onBind(Intent intent) {
142         return mMessenger.getBinder();
143     }
144 
145     /**
146      * Show a notification while this service is running.
147      */
showNotification()148     private void showNotification() {
149         // In this sample, we'll use the same text for the ticker and the expanded notification
150         CharSequence text = getText(R.string.remote_service_started);
151 
152         // The PendingIntent to launch our activity if the user selects this notification
153         PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
154                 new Intent(this, Controller.class), 0);
155 
156         // Set the info for the views that show in the notification panel.
157         Notification notification = new Notification.Builder(this)
158                 .setSmallIcon(R.drawable.stat_sample)  // the status icon
159                 .setTicker(text)  // the status text
160                 .setWhen(System.currentTimeMillis())  // the time stamp
161                 .setContentTitle(getText(R.string.local_service_label))  // the label of the entry
162                 .setContentText(text)  // the contents of the entry
163                 .setContentIntent(contentIntent)  // The intent to send when the entry is clicked
164                 .build();
165 
166         // Send the notification.
167         // We use a string id because it is a unique number.  We use it later to cancel.
168         mNM.notify(R.string.remote_service_started, notification);
169     }
170 }
171 //END_INCLUDE(service)
172