Dianne Hackborn | bae0f4f | 2010-02-16 17:48:27 -0800 | [diff] [blame] | 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 |
| 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 |
| 120 | public void onCreate() { |
| 121 | mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); |
| 122 | |
| 123 | // Display a notification about us starting. |
| 124 | showNotification(); |
| 125 | } |
| 126 | |
| 127 | @Override |
| 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 |
| 141 | public IBinder onBind(Intent intent) { |
| 142 | return mMessenger.getBinder(); |
| 143 | } |
| 144 | |
| 145 | /** |
| 146 | * Show a notification while this service is running. |
| 147 | */ |
| 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 | |
Dianne Hackborn | bae0f4f | 2010-02-16 17:48:27 -0800 | [diff] [blame] | 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. |
Chris Wren | b6ba3c5 | 2015-06-11 10:56:59 -0400 | [diff] [blame^] | 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(); |
Dianne Hackborn | bae0f4f | 2010-02-16 17:48:27 -0800 | [diff] [blame] | 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) |