| /* | |
| * Copyright (C) 2010 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package com.example.android.newalarm; | |
| import android.app.Notification; | |
| import android.app.NotificationManager; | |
| import android.app.PendingIntent; | |
| import android.app.Service; | |
| import android.content.Intent; | |
| import android.os.Binder; | |
| import android.os.IBinder; | |
| import android.os.Parcel; | |
| import android.os.RemoteException; | |
| import android.widget.Toast; | |
| /** | |
| * <p> | |
| * This class implements a service. The service is started by AlarmActivity, which contains a | |
| * repeating countdown timer that sends a PendingIntent. The user starts and stops the timer with | |
| * buttons in the UI. | |
| * </p> | |
| * <p> | |
| * When this service is started, it creates a Runnable and starts it in a new Thread. The | |
| * Runnable does a synchronized lock on the service's Binder object for 15 seconds, then issues | |
| * a stopSelf(). The net effect is a new worker thread that takes 15 seconds to run and then | |
| * shuts down the entire service. The activity restarts the service after 15 more seconds, when the | |
| * countdown timer triggers again. | |
| * </p> | |
| * <p> | |
| * This service is provided as the service under test for the sample test application | |
| * AlarmServiceTest. | |
| * </p> | |
| * <p> | |
| * Note: Since this sample is based on the Android 1.5 platform, it does not implement | |
| * onStartCommand. See the Javadoc for android.app.Service for more details. | |
| * </p> | |
| */ | |
| public class AlarmService extends Service { | |
| // Defines a label for the thread that this service starts | |
| private static final String ALARM_SERVICE_THREAD = "AlarmService"; | |
| // Defines 15 seconds | |
| public static final long WAIT_TIME_SECONDS = 15; | |
| // Define the number of milliseconds in one second | |
| public static final long MILLISECS_PER_SEC = 1000; | |
| /* | |
| * For testing purposes, the following variables are defined as fields and set to | |
| * package visibility. | |
| */ | |
| // The NotificationManager used to send notifications to the status bar. | |
| NotificationManager mNotificationManager; | |
| // An Intent that displays the client if the user clicks the notification. | |
| PendingIntent mContentIntent; | |
| // A Notification to send to the Notification Manager when the service is started. | |
| Notification mNotification; | |
| // A Binder, used as the lock object for the worker thread. | |
| IBinder mBinder = new AlarmBinder(); | |
| // A Thread object that will run the background task | |
| Thread mWorkThread; | |
| // The Runnable that is the service's "task". This illustrates how a service is used to | |
| // offload work from a client. | |
| Runnable mWorkTask = new Runnable() { | |
| public void run() { | |
| // Sets the wait time to 15 seconds, simulating a 15-second background task. | |
| long waitTime = System.currentTimeMillis() + WAIT_TIME_SECONDS * MILLISECS_PER_SEC; | |
| // Puts the wait in a while loop to ensure that it actually waited 15 seconds. | |
| // This covers the situation where an interrupt might have overridden the wait. | |
| while (System.currentTimeMillis() < waitTime) { | |
| // Waits for 15 seconds or interruption | |
| synchronized (mBinder) { | |
| try { | |
| // Waits for 15 seconds or until an interrupt triggers an exception. | |
| // If an interrupt occurs, the wait is recalculated to ensure a net | |
| // wait of 15 seconds. | |
| mBinder.wait(waitTime - System.currentTimeMillis()); | |
| } catch (InterruptedException e) { | |
| } | |
| } | |
| } | |
| // Stops the current service. In response, Android calls onDestroy(). | |
| stopSelf(); | |
| } | |
| }; | |
| /** | |
| * Makes a full concrete subclass of Binder, rather than doing it in line, for readability. | |
| */ | |
| public class AlarmBinder extends Binder { | |
| // Constructor. Calls the super constructor to set up the instance. | |
| public AlarmBinder() { | |
| super(); | |
| } | |
| @Override | |
| protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) | |
| throws RemoteException { | |
| // Call the parent method with the arguments passed in | |
| return super.onTransact(code, data, reply, flags); | |
| } | |
| } | |
| /** | |
| * Initializes the service when it is first started by a call to startService() or | |
| * bindService(). | |
| */ | |
| @Override | |
| public void onCreate() { | |
| // Gets a handle to the system mNotification service. | |
| mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); | |
| // Updates the status bar to indicate that this service is running. | |
| showNotification(); | |
| // Creates a new thread. A new thread is used so that the service's work doesn't block | |
| // anything on the calling client's thread. By default, a service runs in the same | |
| // process and thread as the client that starts it. | |
| mWorkThread = new Thread( | |
| null, // threadgroup (in this case, null) | |
| mWorkTask, // the Runnable that will run in this thread | |
| ALARM_SERVICE_THREAD | |
| ); | |
| // Starts the thread | |
| mWorkThread.start(); | |
| } | |
| /** | |
| * Stops the service in response to the stopSelf() issued when the wait is over. Other | |
| * clients that use this service could stop it by issuing a stopService() or a stopSelf() on | |
| * the service object. | |
| */ | |
| @Override | |
| public void onDestroy() { | |
| // Cancels the status bar mNotification based on its ID, which is set in showNotification(). | |
| mNotificationManager.cancel(R.string.alarm_service_started); | |
| // Sends a notification to the screen. | |
| Toast.makeText( | |
| this, // the current context | |
| R.string.alarm_service_finished, // the message to show | |
| Toast.LENGTH_LONG // how long to keep the message on the screen | |
| ).show(); // show the text | |
| } | |
| // Returns the service's binder object to clients that issue onBind(). | |
| @Override | |
| public IBinder onBind(Intent intent) { | |
| return mBinder; | |
| } | |
| /** | |
| * Displays a notification in the status bar that this service is running. This method | |
| * also creates an Intent for the AlarmActivity client and attaches it to the notification | |
| * line. If the user clicks the line in the expanded status window, the Intent triggers | |
| * AlarmActivity. | |
| */ | |
| private void showNotification() { | |
| // Sets the text to use for the status bar and status list views. | |
| CharSequence notificationText = getText(R.string.alarm_service_started); | |
| // Sets up the Intent that starts AlarmActivity | |
| mContentIntent = PendingIntent.getActivity( | |
| this, // Start the Activity in the current context | |
| 0, // not used | |
| new Intent(this, AlarmActivity.class), // A new Intent for AlarmActivity | |
| 0 // Use an existing activity instance if available | |
| ); | |
| // Build the notification object. | |
| mNotification = new Notification.Builder(this) // The builder requires the context | |
| .setSmallIcon(R.drawable.stat_sample) // the status icon | |
| .setTicker(notificationText) // the status text | |
| .setWhen(System.currentTimeMillis()) // the time stamp | |
| .setContentTitle(getText(R.string.alarm_service_label)) // the label of the entry | |
| .setContentText(notificationText) // the contents of the entry | |
| .setContentIntent(mContentIntent) // The intent to send when the entry is clicked | |
| .build(); | |
| // Sets a unique ID for the notification and sends it to NotificationManager to be | |
| // displayed. The ID is the integer marker for the notification string, which is | |
| // guaranteed to be unique within the entire application. | |
| mNotificationManager.notify( | |
| R.string.alarm_service_started, // unique id for the mNotification | |
| mNotification // the mNotification object | |
| ); | |
| } | |
| } |