| /* |
| * 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 the icon, status bar text, and display time for the mNotification. |
| mNotification = new Notification( |
| R.drawable.stat_sample, // the status icon |
| notificationText, // the status text |
| System.currentTimeMillis() // the time stamp |
| ); |
| |
| // 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 |
| ); |
| |
| // Creates a new content view for the mNotification. The view appears when the user |
| // shows the expanded status window. |
| mNotification.setLatestEventInfo( |
| this, // Put the content view in the current context |
| getText(R.string.alarm_service_label), // The text to use as the label of the entry |
| notificationText, // The text to use as the contents of the entry |
| mContentIntent // The intent to send when the entry is clicked |
| ); |
| |
| // 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 |
| ); |
| } |
| } |