• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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.Bundle;
25 import android.os.Handler;
26 import android.os.HandlerThread;
27 import android.os.IBinder;
28 import android.os.Looper;
29 import android.os.Message;
30 import android.os.Process;
31 import android.util.Log;
32 import android.widget.Toast;
33 
34 import com.example.android.apis.R;
35 
36 /**
37  * This is an example of implementing an application service that runs locally
38  * in the same process as the application.  The {@link ServiceStartArgumentsController}
39  * class shows how to interact with the service.
40  *
41  * <p>Notice the use of the {@link NotificationManager} when interesting things
42  * happen in the service.  This is generally how background services should
43  * interact with the user, rather than doing something more disruptive such as
44  * calling startActivity().
45  *
46  * <p>For applications targeting Android 1.5 or beyond, you may want consider
47  * using the android.app.IntentService class, which takes care of all the
48  * work of creating the extra thread and dispatching commands to it.
49  */
50 public class ServiceStartArguments extends Service {
51     private NotificationManager mNM;
52     private Intent mInvokeIntent;
53     private volatile Looper mServiceLooper;
54     private volatile ServiceHandler mServiceHandler;
55 
56     private final class ServiceHandler extends Handler {
ServiceHandler(Looper looper)57         public ServiceHandler(Looper looper) {
58             super(looper);
59         }
60 
61         @Override
handleMessage(Message msg)62         public void handleMessage(Message msg)
63         {
64             Bundle arguments = (Bundle)msg.obj;
65 
66             String txt = arguments.getString("name");
67 
68             Log.i("ServiceStartArguments", "Message: " + msg + ", "
69                     + arguments.getString("name"));
70 
71             if ((msg.arg2&Service.START_FLAG_REDELIVERY) == 0) {
72                 txt = "New cmd #" + msg.arg1 + ": " + txt;
73             } else {
74                 txt = "Re-delivered #" + msg.arg1 + ": " + txt;
75             }
76 
77             showNotification(txt);
78 
79             // Normally we would do some work here...  for our sample, we will
80             // just sleep for 5 seconds.
81             long endTime = System.currentTimeMillis() + 5*1000;
82             while (System.currentTimeMillis() < endTime) {
83                 synchronized (this) {
84                     try {
85                         wait(endTime - System.currentTimeMillis());
86                     } catch (Exception e) {
87                     }
88                 }
89             }
90 
91             hideNotification();
92 
93             Log.i("ServiceStartArguments", "Done with #" + msg.arg1);
94             stopSelf(msg.arg1);
95         }
96 
97     };
98 
99     @Override
onCreate()100     public void onCreate() {
101         mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
102 
103         Toast.makeText(this, R.string.service_created,
104                 Toast.LENGTH_SHORT).show();
105 
106         // This is who should be launched if the user selects our persistent
107         // notification.
108         mInvokeIntent = new Intent(this, ServiceStartArgumentsController.class);
109 
110         // Start up the thread running the service.  Note that we create a
111         // separate thread because the service normally runs in the process's
112         // main thread, which we don't want to block.  We also make it
113         // background priority so CPU-intensive work will not disrupt our UI.
114         HandlerThread thread = new HandlerThread("ServiceStartArguments",
115                 Process.THREAD_PRIORITY_BACKGROUND);
116         thread.start();
117 
118         mServiceLooper = thread.getLooper();
119         mServiceHandler = new ServiceHandler(mServiceLooper);
120     }
121 
122     @Override
onStartCommand(Intent intent, int flags, int startId)123     public int onStartCommand(Intent intent, int flags, int startId) {
124         Log.i("ServiceStartArguments",
125                 "Starting #" + startId + ": " + intent.getExtras());
126         Message msg = mServiceHandler.obtainMessage();
127         msg.arg1 = startId;
128         msg.arg2 = flags;
129         msg.obj = intent.getExtras();
130         mServiceHandler.sendMessage(msg);
131         Log.i("ServiceStartArguments", "Sending: " + msg);
132 
133         // For the start fail button, we will simulate the process dying
134         // for some reason in onStartCommand().
135         if (intent.getBooleanExtra("fail", false)) {
136             // Don't do this if we are in a retry... the system will
137             // eventually give up if we keep crashing.
138             if ((flags&START_FLAG_RETRY) == 0) {
139                 // Since the process hasn't finished handling the command,
140                 // it will be restarted with the command again, regardless of
141                 // whether we return START_REDELIVER_INTENT.
142                 Process.killProcess(Process.myPid());
143             }
144         }
145 
146         // Normally we would consistently return one kind of result...
147         // however, here we will select between these two, so you can see
148         // how they impact the behavior.  Try killing the process while it
149         // is in the middle of executing the different commands.
150         return intent.getBooleanExtra("redeliver", false)
151                 ? START_REDELIVER_INTENT : START_NOT_STICKY;
152     }
153 
154     @Override
onDestroy()155     public void onDestroy() {
156         mServiceLooper.quit();
157 
158         hideNotification();
159 
160         // Tell the user we stopped.
161         Toast.makeText(ServiceStartArguments.this, R.string.service_destroyed,
162                 Toast.LENGTH_SHORT).show();
163     }
164 
165     @Override
onBind(Intent intent)166     public IBinder onBind(Intent intent) {
167         return null;
168     }
169 
170     /**
171      * Show a notification while this service is running.
172      */
showNotification(String text)173     private void showNotification(String text) {
174         // Set the icon, scrolling text and timestamp
175         Notification notification = new Notification(R.drawable.stat_sample, text,
176                 System.currentTimeMillis());
177 
178         // The PendingIntent to launch our activity if the user selects this notification
179         PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
180                 new Intent(this, AlarmService.class), 0);
181 
182         // Set the info for the views that show in the notification panel.
183         notification.setLatestEventInfo(this, getText(R.string.service_start_arguments_label),
184                        text, contentIntent);
185 
186         // We show this for as long as our service is processing a command.
187         notification.flags |= Notification.FLAG_ONGOING_EVENT;
188 
189         // Send the notification.
190         // We use a string id because it is a unique number.  We use it later to cancel.
191         mNM.notify(R.string.service_created, notification);
192     }
193 
hideNotification()194     private void hideNotification() {
195         mNM.cancel(R.string.service_created);
196     }
197 }
198 
199