CellBroadcastReceiver.java revision da5c415f6d0999131e93384b5fb90422ada8e4da
1/*
2 * Copyright (C) 2011 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
17package com.android.cellbroadcastreceiver;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.SharedPreferences;
23import android.os.RemoteException;
24import android.os.ServiceManager;
25import android.preference.PreferenceManager;
26import android.provider.Telephony;
27import android.telephony.TelephonyManager;
28import android.telephony.cdma.CdmaSmsCbProgramData;
29import android.util.Log;
30
31import com.android.internal.telephony.ITelephony;
32import com.android.internal.telephony.cdma.sms.SmsEnvelope;
33
34public class CellBroadcastReceiver extends BroadcastReceiver {
35    private static final String TAG = "CellBroadcastReceiver";
36    static final boolean DBG = true;    // STOPSHIP: change to false before ship
37
38    @Override
39    public void onReceive(Context context, Intent intent) {
40        onReceiveWithPrivilege(context, intent, false);
41    }
42
43    protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
44        if (DBG) log("onReceive " + intent);
45
46        String action = intent.getAction();
47
48        if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
49            startConfigService(context);
50        } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
51            boolean airplaneModeOn = intent.getBooleanExtra("state", false);
52            if (!airplaneModeOn) {
53                startConfigService(context);
54            }
55        } else if (Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION.equals(action) ||
56                Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION.equals(action)) {
57            // If 'privileged' is false, it means that the intent was delivered to the base
58            // no-permissions receiver class.  If we get an SMS_CB_RECEIVED message that way, it
59            // means someone has tried to spoof the message by delivering it outside the normal
60            // permission-checked route, so we just ignore it.
61            if (privileged) {
62                intent.setClass(context, CellBroadcastAlertService.class);
63                context.startService(intent);
64            } else {
65                Log.e(TAG, "ignoring unprivileged action received " + action);
66            }
67        } else if (Telephony.Sms.Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION
68                .equals(action)) {
69            if (privileged) {
70                CdmaSmsCbProgramData[] programDataList = (CdmaSmsCbProgramData[])
71                        intent.getParcelableArrayExtra("program_data_list");
72                if (programDataList != null) {
73                    handleCdmaSmsCbProgramData(context, programDataList);
74                } else {
75                    Log.e(TAG, "SCPD intent received with no program_data_list");
76                }
77            } else {
78                Log.e(TAG, "ignoring unprivileged action received " + action);
79            }
80        } else {
81            Log.w(TAG, "onReceive() unexpected action " + action);
82        }
83    }
84
85    /**
86     * Handle Service Category Program Data message.
87     * TODO: Send Service Category Program Results response message to sender
88     *
89     * @param context
90     * @param programDataList
91     */
92    private void handleCdmaSmsCbProgramData(Context context,
93            CdmaSmsCbProgramData[] programDataList) {
94        for (CdmaSmsCbProgramData programData : programDataList) {
95            switch (programData.getOperation()) {
96                case CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY:
97                    tryCdmaSetCategory(context, programData.getCategory(), true);
98                    break;
99
100                case CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY:
101                    tryCdmaSetCategory(context, programData.getCategory(), false);
102                    break;
103
104                case CdmaSmsCbProgramData.OPERATION_CLEAR_CATEGORIES:
105                    tryCdmaSetCategory(context,
106                            SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, false);
107                    tryCdmaSetCategory(context,
108                            SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, false);
109                    tryCdmaSetCategory(context,
110                            SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, false);
111                    tryCdmaSetCategory(context,
112                            SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, false);
113                    break;
114
115                default:
116                    Log.e(TAG, "Ignoring unknown SCPD operation " + programData.getOperation());
117            }
118        }
119    }
120
121    private void tryCdmaSetCategory(Context context, int category, boolean enable) {
122        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
123
124        switch (category) {
125            case SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT:
126                sharedPrefs.edit().putBoolean(
127                        CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, enable)
128                        .apply();
129                break;
130
131            case SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT:
132                sharedPrefs.edit().putBoolean(
133                        CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, enable)
134                        .apply();
135                break;
136
137            case SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY:
138                sharedPrefs.edit().putBoolean(
139                        CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, enable).apply();
140                break;
141
142            case SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE:
143                sharedPrefs.edit().putBoolean(
144                        CellBroadcastSettings.KEY_ENABLE_CMAS_TEST_ALERTS, enable).apply();
145                break;
146
147            default:
148                Log.w(TAG, "Ignoring SCPD command to " + (enable ? "enable" : "disable")
149                        + " alerts in category " + category);
150        }
151    }
152
153    /**
154     * Tell {@link CellBroadcastConfigService} to enable the CB channels.
155     * @param context the broadcast receiver context
156     */
157    static void startConfigService(Context context) {
158        if (phoneIsCdma()) {
159            if (DBG) log("CDMA phone detected; doing nothing");
160        } else {
161            Intent serviceIntent = new Intent(CellBroadcastConfigService.ACTION_ENABLE_CHANNELS,
162                    null, context, CellBroadcastConfigService.class);
163            context.startService(serviceIntent);
164        }
165    }
166
167    /**
168     * @return true if the phone is a CDMA phone type
169     */
170    private static boolean phoneIsCdma() {
171        boolean isCdma = false;
172        try {
173            ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
174            if (phone != null) {
175                isCdma = (phone.getActivePhoneType() == TelephonyManager.PHONE_TYPE_CDMA);
176            }
177        } catch (RemoteException e) {
178            Log.w(TAG, "phone.getActivePhoneType() failed", e);
179        }
180        return isCdma;
181    }
182
183    private static void log(String msg) {
184        Log.d(TAG, msg);
185    }
186}
187