115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root/*
215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Copyright (C) 2008 The Android Open Source Project
315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Licensed under the Apache License, Version 2.0 (the "License");
515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * you may not use this file except in compliance with the License.
615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * You may obtain a copy of the License at
715a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
815a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *      http://www.apache.org/licenses/LICENSE-2.0
915a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
1015a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Unless required by applicable law or agreed to in writing, software
1115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * distributed under the License is distributed on an "AS IS" BASIS,
1215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * See the License for the specific language governing permissions and
1415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * limitations under the License.
1515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root */
1615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.app;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1983c6896cbf402623ef7d97f13ed65098df63429fTor Norbyeimport android.annotation.WorkerThread;
20ce8d4f51b9405003e664736d81e2374dfc117db9Ryan Lothianimport android.annotation.Nullable;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.HandlerThread;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
296e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * IntentService is a base class for {@link Service}s that handle asynchronous
306e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * requests (expressed as {@link Intent}s) on demand.  Clients send requests
31cae57d6205a8ebc8599ff89629307ecb8cabb3b8Wu-cheng Li * through {@link android.content.Context#startService(Intent)} calls; the
32cae57d6205a8ebc8599ff89629307ecb8cabb3b8Wu-cheng Li * service is started as needed, handles each Intent in turn using a worker
33cae57d6205a8ebc8599ff89629307ecb8cabb3b8Wu-cheng Li * thread, and stops itself when it runs out of work.
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
356e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * <p>This "work queue processor" pattern is commonly used to offload tasks
366e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * from an application's main thread.  The IntentService class exists to
376e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * simplify this pattern and take care of the mechanics.  To use it, extend
386e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * IntentService and implement {@link #onHandleIntent(Intent)}.  IntentService
396e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * will receive the Intents, launch a worker thread, and stop the service as
406e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * appropriate.
416e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor *
426e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * <p>All requests are handled on a single worker thread -- they may take as
436e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * long as necessary (and will not block the application's main loop), but
446e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * only one request will be processed at a time.
456e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor *
46b54e7a3d9f60ac605f404f9eb3c5e92ca51bbd23Joe Fernandez * <div class="special reference">
47b54e7a3d9f60ac605f404f9eb3c5e92ca51bbd23Joe Fernandez * <h3>Developer Guides</h3>
48b54e7a3d9f60ac605f404f9eb3c5e92ca51bbd23Joe Fernandez * <p>For a detailed discussion about how to create services, read the
491918214589a24b9decd6a70d9f97b8056ae92dcaHemal Patel * <a href="{@docRoot}guide/components/services.html">Services</a> developer
501918214589a24b9decd6a70d9f97b8056ae92dcaHemal Patel * guide.</p>
51b54e7a3d9f60ac605f404f9eb3c5e92ca51bbd23Joe Fernandez * </div>
52b54e7a3d9f60ac605f404f9eb3c5e92ca51bbd23Joe Fernandez *
536e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor * @see android.os.AsyncTask
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class IntentService extends Service {
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private volatile Looper mServiceLooper;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private volatile ServiceHandler mServiceHandler;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String mName;
59f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn    private boolean mRedelivery;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final class ServiceHandler extends Handler {
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ServiceHandler(Looper looper) {
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(looper);
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            onHandleIntent((Intent)msg.obj);
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            stopSelf(msg.arg1);
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
736e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor    /**
746e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * Creates an IntentService.  Invoked by your subclass's constructor.
756e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     *
766e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * @param name Used to name the worker thread, important only for debugging.
776e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     */
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public IntentService(String name) {
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super();
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mName = name;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
83f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn    /**
846e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * Sets intent redelivery preferences.  Usually called from the constructor
856e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * with your preferred semantics.
866e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     *
876e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * <p>If enabled is true,
88f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn     * {@link #onStartCommand(Intent, int, int)} will return
896e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
906e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * {@link #onHandleIntent(Intent)} returns, the process will be restarted
916e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * and the intent redelivered.  If multiple Intents have been sent, only
926e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * the most recent one is guaranteed to be redelivered.
936e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     *
946e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * <p>If enabled is false (the default),
956e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * {@link #onStartCommand(Intent, int, int)} will return
966e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
976e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * dies along with it.
98f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn     */
99f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn    public void setIntentRedelivery(boolean enabled) {
100f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn        mRedelivery = enabled;
101f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn    }
1026e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onCreate() {
1056e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor        // TODO: It would be nice to have an option to hold a partial wakelock
1066e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor        // during processing, and to have a static startService(Context, Intent)
1076e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor        // method that would launch the service & hand off a wakelock.
1086e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onCreate();
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        thread.start();
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mServiceLooper = thread.getLooper();
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mServiceHandler = new ServiceHandler(mServiceLooper);
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
118ce8d4f51b9405003e664736d81e2374dfc117db9Ryan Lothian    public void onStart(@Nullable Intent intent, int startId) {
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Message msg = mServiceHandler.obtainMessage();
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        msg.arg1 = startId;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        msg.obj = intent;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mServiceHandler.sendMessage(msg);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1257a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main    /**
1267a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main     * You should not override this method for your IntentService. Instead,
1277a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main     * override {@link #onHandleIntent}, which the system calls when the IntentService
1287a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main     * receives a start request.
1297a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main     * @see android.app.Service#onStartCommand
1307a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main     */
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
132ce8d4f51b9405003e664736d81e2374dfc117db9Ryan Lothian    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
133f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn        onStart(intent, startId);
134f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
135f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn    }
1366e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor
137f6f9f2d0256930ce0bb4913b2260b8480914edc2Dianne Hackborn    @Override
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onDestroy() {
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mServiceLooper.quit();
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1427a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main    /**
1437a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main     * Unless you provide binding for your service, you don't need to implement this
144ce8d4f51b9405003e664736d81e2374dfc117db9Ryan Lothian     * method, because the default implementation returns null.
1457a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main     * @see android.app.Service#onBind
1467a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main     */
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
148ce8d4f51b9405003e664736d81e2374dfc117db9Ryan Lothian    @Nullable
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public IBinder onBind(Intent intent) {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1546e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * This method is invoked on the worker thread with a request to process.
1556e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * Only one Intent is processed at a time, but the processing happens on a
1566e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * worker thread that runs independently from other application logic.
1576e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * So, if this code takes a long time, it will hold up other requests to
1586e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     * the same IntentService, but it will not hold up anything else.
1597a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main     * When all requests have been handled, the IntentService stops itself,
1607a14b93bee8e14ace67b8b7dc1579f76e4831773Scott Main     * so you should not call {@link #stopSelf}.
1616e3d9884e4d4e202c9b3b9a5539dd22ffac6467bDan Egnor     *
162cae57d6205a8ebc8599ff89629307ecb8cabb3b8Wu-cheng Li     * @param intent The value passed to {@link
163cae57d6205a8ebc8599ff89629307ecb8cabb3b8Wu-cheng Li     *               android.content.Context#startService(Intent)}.
164ce8d4f51b9405003e664736d81e2374dfc117db9Ryan Lothian     *               This may be null if the service is being restarted after
165ce8d4f51b9405003e664736d81e2374dfc117db9Ryan Lothian     *               its process has gone away; see
166ce8d4f51b9405003e664736d81e2374dfc117db9Ryan Lothian     *               {@link android.app.Service#onStartCommand}
167ce8d4f51b9405003e664736d81e2374dfc117db9Ryan Lothian     *               for details.
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
16983c6896cbf402623ef7d97f13ed65098df63429fTor Norbye    @WorkerThread
170ce8d4f51b9405003e664736d81e2374dfc117db9Ryan Lothian    protected abstract void onHandleIntent(@Nullable Intent intent);
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
172