Home | History | Annotate | Download | only in newalarm
      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.newalarm;
     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.IBinder;
     26 import android.os.Parcel;
     27 import android.os.RemoteException;
     28 import android.widget.Toast;
     29 
     30 /**
     31  * <p>
     32  * This class implements a service. The service is started by AlarmActivity, which contains a
     33  * repeating countdown timer that sends a PendingIntent. The user starts and stops the timer with
     34  * buttons in the UI.
     35  * </p>
     36  * <p>
     37  * When this service is started, it creates a Runnable and starts it in a new Thread. The
     38  * Runnable does a synchronized lock on the service's Binder object for 15 seconds, then issues
     39  * a stopSelf(). The net effect is a new worker thread that takes 15 seconds to run and then
     40  * shuts down the entire service. The activity restarts the service after 15 more seconds, when the
     41  * countdown timer triggers again.
     42  * </p>
     43  * <p>
     44  * This service is provided as the service under test for the sample test application
     45  * AlarmServiceTest.
     46  * </p>
     47  * <p>
     48  * Note: Since this sample is based on the Android 1.5 platform, it does not implement
     49  * onStartCommand. See the Javadoc for android.app.Service for more details.
     50  * </p>
     51  */
     52 public class AlarmService extends Service {
     53     // Defines a label for the thread that this service starts
     54     private static final String ALARM_SERVICE_THREAD = "AlarmService";
     55 
     56     // Defines 15 seconds
     57     public static final long WAIT_TIME_SECONDS = 15;
     58 
     59     // Define the number of milliseconds in one second
     60     public static final long MILLISECS_PER_SEC = 1000;
     61 
     62     /*
     63      * For testing purposes, the following variables are defined as fields and set to
     64      * package visibility.
     65      */
     66 
     67     // The NotificationManager used to send notifications to the status bar.
     68     NotificationManager mNotificationManager;
     69 
     70     // An Intent that displays the client if the user clicks the notification.
     71     PendingIntent mContentIntent;
     72 
     73     // A Notification to send to the Notification Manager when the service is started.
     74     Notification mNotification;
     75 
     76     // A Binder, used as the lock object for the worker thread.
     77     IBinder mBinder = new AlarmBinder();
     78 
     79     // A Thread object that will run the background task
     80     Thread mWorkThread;
     81 
     82     // The Runnable that is the service's "task". This illustrates how a service is used to
     83     // offload work from a client.
     84     Runnable mWorkTask = new Runnable() {
     85         public void run() {
     86             // Sets the wait time to 15 seconds, simulating a 15-second background task.
     87             long waitTime = System.currentTimeMillis() + WAIT_TIME_SECONDS * MILLISECS_PER_SEC;
     88 
     89             // Puts the wait in a while loop to ensure that it actually waited 15 seconds.
     90             // This covers the situation where an interrupt might have overridden the wait.
     91             while (System.currentTimeMillis() < waitTime) {
     92                 // Waits for 15 seconds or interruption
     93                 synchronized (mBinder) {
     94                     try {
     95                         // Waits for 15 seconds or until an interrupt triggers an exception.
     96                         // If an interrupt occurs, the wait is recalculated to ensure a net
     97                         // wait of 15 seconds.
     98                         mBinder.wait(waitTime - System.currentTimeMillis());
     99                     } catch (InterruptedException e) {
    100                     }
    101                 }
    102             }
    103             // Stops the current service. In response, Android calls onDestroy().
    104             stopSelf();
    105         }
    106     };
    107 
    108     /**
    109      *  Makes a full concrete subclass of Binder, rather than doing it in line, for readability.
    110      */
    111     public class AlarmBinder extends Binder {
    112         // Constructor. Calls the super constructor to set up the instance.
    113         public AlarmBinder() {
    114             super();
    115         }
    116 
    117         @Override
    118         protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
    119             throws RemoteException {
    120 
    121             // Call the parent method with the arguments passed in
    122             return super.onTransact(code, data, reply, flags);
    123         }
    124     }
    125 
    126     /**
    127      * Initializes the service when it is first started by a call to startService() or
    128      * bindService().
    129      */
    130     @Override
    131     public void onCreate() {
    132         // Gets a handle to the system mNotification service.
    133         mNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
    134 
    135         // Updates the status bar to indicate that this service is running.
    136         showNotification();
    137 
    138         // Creates a new thread. A new thread is used so that the service's work doesn't block
    139         // anything on the calling client's thread. By default, a service runs in the same
    140         // process and thread as the client that starts it.
    141         mWorkThread = new Thread(
    142             null,  // threadgroup (in this case, null)
    143             mWorkTask, // the Runnable that will run in this thread
    144             ALARM_SERVICE_THREAD
    145         );
    146         // Starts the thread
    147         mWorkThread.start();
    148     }
    149 
    150     /**
    151      * Stops the service in response to the stopSelf() issued when the wait is over. Other
    152      * clients that use this service could stop it by issuing a stopService() or a stopSelf() on
    153      * the service object.
    154      */
    155     @Override
    156     public void onDestroy() {
    157         // Cancels the status bar mNotification based on its ID, which is set in showNotification().
    158         mNotificationManager.cancel(R.string.alarm_service_started);
    159 
    160         // Sends a notification to the screen.
    161         Toast.makeText(
    162             this,  // the current context
    163             R.string.alarm_service_finished,  // the message to show
    164             Toast.LENGTH_LONG   // how long to keep the message on the screen
    165         ).show();  // show the text
    166     }
    167 
    168     // Returns the service's binder object to clients that issue onBind().
    169     @Override
    170     public IBinder onBind(Intent intent) {
    171         return mBinder;
    172     }
    173 
    174     /**
    175      * Displays a notification in the status bar that this service is running. This method
    176      * also creates an Intent for the AlarmActivity client and attaches it to the notification
    177      * line. If the user clicks the line in the expanded status window, the Intent triggers
    178      * AlarmActivity.
    179      */
    180     private void showNotification() {
    181         // Sets the text to use for the status bar and status list views.
    182         CharSequence notificationText = getText(R.string.alarm_service_started);
    183 
    184         // Sets the icon, status bar text, and display time for the mNotification.
    185         mNotification = new Notification(
    186             R.drawable.stat_sample,  // the status icon
    187             notificationText, // the status text
    188             System.currentTimeMillis()  // the time stamp
    189         );
    190 
    191         // Sets up the Intent that starts AlarmActivity
    192         mContentIntent = PendingIntent.getActivity(
    193             this,  // Start the Activity in the current context
    194             0,   // not used
    195             new Intent(this, AlarmActivity.class),  // A new Intent for AlarmActivity
    196             0  // Use an existing activity instance if available
    197         );
    198 
    199         // Creates a new content view for the mNotification. The view appears when the user
    200         // shows the expanded status window.
    201         mNotification.setLatestEventInfo(
    202             this,  //  Put the content view in the current context
    203             getText(R.string.alarm_service_label),  // The text to use as the label of the entry
    204             notificationText,  // The text to use as the contents of the entry
    205             mContentIntent  // The intent to send when the entry is clicked
    206         );
    207 
    208         // Sets a unique ID for the notification and sends it to NotificationManager to be
    209         // displayed. The ID is the integer marker for the notification string, which is
    210         // guaranteed to be unique within the entire application.
    211         mNotificationManager.notify(
    212             R.string.alarm_service_started,  // unique id for the mNotification
    213             mNotification   // the mNotification object
    214         );
    215     }
    216 }
    217