1/*
2 * Copyright (C) 2007-2008 Esmertec AG.
3 * Copyright (C) 2007-2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mms.transaction;
19
20import android.app.Service;
21import android.content.BroadcastReceiver;
22import android.content.Context;
23import android.content.Intent;
24import android.os.PowerManager;
25import android.provider.Telephony.Sms.Intents;
26
27/**
28 * Handle incoming SMSes.  Just dispatches the work off to a Service.
29 */
30public class SmsReceiver extends BroadcastReceiver {
31    static final Object mStartingServiceSync = new Object();
32    static PowerManager.WakeLock mStartingService;
33    private static SmsReceiver sInstance;
34
35    public static SmsReceiver getInstance() {
36        if (sInstance == null) {
37            sInstance = new SmsReceiver();
38        }
39        return sInstance;
40    }
41
42    @Override
43    public void onReceive(Context context, Intent intent) {
44        onReceiveWithPrivilege(context, intent, false);
45    }
46
47    protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
48        // If 'privileged' is false, it means that the intent was delivered to the base
49        // no-permissions receiver class.  If we get an SMS_RECEIVED message that way, it
50        // means someone has tried to spoof the message by delivering it outside the normal
51        // permission-checked route, so we just ignore it.
52        if (!privileged && intent.getAction().equals(Intents.SMS_DELIVER_ACTION)) {
53            return;
54        }
55
56        intent.setClass(context, SmsReceiverService.class);
57        intent.putExtra("result", getResultCode());
58        beginStartingService(context, intent);
59    }
60
61    // N.B.: <code>beginStartingService</code> and
62    // <code>finishStartingService</code> were copied from
63    // <code>com.android.calendar.AlertReceiver</code>.  We should
64    // factor them out or, even better, improve the API for starting
65    // services under wake locks.
66
67    /**
68     * Start the service to process the current event notifications, acquiring
69     * the wake lock before returning to ensure that the service will run.
70     */
71    public static void beginStartingService(Context context, Intent intent) {
72        synchronized (mStartingServiceSync) {
73            if (mStartingService == null) {
74                PowerManager pm =
75                    (PowerManager)context.getSystemService(Context.POWER_SERVICE);
76                mStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
77                        "StartingAlertService");
78                mStartingService.setReferenceCounted(false);
79            }
80            mStartingService.acquire();
81            context.startService(intent);
82        }
83    }
84
85    /**
86     * Called back by the service when it has finished processing notifications,
87     * releasing the wake lock if the service is now stopping.
88     */
89    public static void finishStartingService(Service service, int startId) {
90        synchronized (mStartingServiceSync) {
91            if (mStartingService != null) {
92                if (service.stopSelfResult(startId)) {
93                    mStartingService.release();
94                }
95            }
96        }
97    }
98}
99