• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.cellbroadcastreceiver;
18 
19 import android.app.ActivityManager;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.SharedPreferences;
24 import android.content.SharedPreferences.Editor;
25 import android.os.Bundle;
26 import android.os.UserManager;
27 import android.preference.PreferenceManager;
28 import android.provider.Telephony;
29 import android.provider.Telephony.CellBroadcasts;
30 import android.telephony.CarrierConfigManager;
31 import android.telephony.ServiceState;
32 import android.telephony.SubscriptionManager;
33 import android.telephony.cdma.CdmaSmsCbProgramData;
34 import android.util.Log;
35 
36 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
37 
38 public class CellBroadcastReceiver extends BroadcastReceiver {
39     private static final String TAG = "CellBroadcastReceiver";
40     static final boolean DBG = true;
41     static final boolean VDBG = false;    // STOPSHIP: change to false before ship
42 
43     // Key to access the stored reminder interval default value
44     private static final String CURRENT_INTERVAL_DEFAULT = "current_interval_default";
45 
46     // Intent actions and extras
47     public static final String CELLBROADCAST_START_CONFIG_ACTION =
48             "com.android.cellbroadcastreceiver.intent.START_CONFIG";
49     public static final String ACTION_MARK_AS_READ =
50             "com.android.cellbroadcastreceiver.intent.action.MARK_AS_READ";
51     public static final String EXTRA_DELIVERY_TIME =
52             "com.android.cellbroadcastreceiver.intent.extra.ID";
53 
54     @Override
onReceive(Context context, Intent intent)55     public void onReceive(Context context, Intent intent) {
56         onReceiveWithPrivilege(context, intent, false);
57     }
58 
onReceiveWithPrivilege(Context context, Intent intent, boolean privileged)59     protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
60         if (DBG) log("onReceive " + intent);
61 
62         String action = intent.getAction();
63 
64         if (ACTION_MARK_AS_READ.equals(action)) {
65             final long deliveryTime = intent.getLongExtra(EXTRA_DELIVERY_TIME, -1);
66             new CellBroadcastContentProvider.AsyncCellBroadcastTask(context.getContentResolver())
67                     .execute(new CellBroadcastContentProvider.CellBroadcastOperation() {
68                         @Override
69                         public boolean execute(CellBroadcastContentProvider provider) {
70                             return provider.markBroadcastRead(CellBroadcasts.DELIVERY_TIME,
71                                     deliveryTime);
72                         }
73                     });
74         } else if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) {
75             initializeSharedPreference(context.getApplicationContext());
76             startConfigService(context.getApplicationContext());
77         } else if (CELLBROADCAST_START_CONFIG_ACTION.equals(action)
78                 || SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED.equals(action)) {
79             startConfigService(context.getApplicationContext());
80         } else if (Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION.equals(action) ||
81                 Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION.equals(action)) {
82             // If 'privileged' is false, it means that the intent was delivered to the base
83             // no-permissions receiver class.  If we get an SMS_CB_RECEIVED message that way, it
84             // means someone has tried to spoof the message by delivering it outside the normal
85             // permission-checked route, so we just ignore it.
86             if (privileged) {
87                 intent.setClass(context, CellBroadcastAlertService.class);
88                 context.startService(intent);
89             } else {
90                 loge("ignoring unprivileged action received " + action);
91             }
92         } else if (Telephony.Sms.Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION
93                 .equals(action)) {
94             if (privileged) {
95                 CdmaSmsCbProgramData[] programDataList = (CdmaSmsCbProgramData[])
96                         intent.getParcelableArrayExtra("program_data_list");
97                 if (programDataList != null) {
98                     handleCdmaSmsCbProgramData(context, programDataList);
99                 } else {
100                     loge("SCPD intent received with no program_data_list");
101                 }
102             } else {
103                 loge("ignoring unprivileged action received " + action);
104             }
105         } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
106             // rename registered notification channels on locale change
107             CellBroadcastAlertService.createNotificationChannels(context);
108         } else if (Intent.ACTION_SERVICE_STATE.equals(action)) {
109             if (CellBroadcastSettings.getResourcesForDefaultSmsSubscriptionId(context).getBoolean(
110                     R.bool.reset_duplicate_detection_on_airplane_mode)) {
111                 Bundle extras = intent.getExtras();
112                 ServiceState ss = ServiceState.newFromBundle(extras);
113                 if (ss.getState() == ServiceState.STATE_POWER_OFF) {
114                     CellBroadcastAlertService.resetMessageDuplicateDetection();
115                 }
116             }
117         } else {
118             Log.w(TAG, "onReceive() unexpected action " + action);
119         }
120     }
121 
adjustReminderInterval(Context context)122     private void adjustReminderInterval(Context context) {
123         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
124         String currentIntervalDefault = sp.getString(CURRENT_INTERVAL_DEFAULT, "0");
125 
126         // If interval default changes, reset the interval to the new default value.
127         String newIntervalDefault =
128                 CellBroadcastSettings.getResourcesForDefaultSmsSubscriptionId(context)
129                         .getString(R.string.alert_reminder_interval_default_value);
130         if (!newIntervalDefault.equals(currentIntervalDefault)) {
131             Log.d(TAG, "Default interval changed from " + currentIntervalDefault + " to " +
132                     newIntervalDefault);
133 
134             Editor editor = sp.edit();
135             // Reset the value to default.
136             editor.putString(
137                     CellBroadcastSettings.KEY_ALERT_REMINDER_INTERVAL, newIntervalDefault);
138             // Save the new default value.
139             editor.putString(CURRENT_INTERVAL_DEFAULT, newIntervalDefault);
140             editor.commit();
141         } else {
142             if (DBG) Log.d(TAG, "Default interval " + currentIntervalDefault + " did not change.");
143         }
144     }
145 
initializeSharedPreference(Context context)146     private void initializeSharedPreference(Context context) {
147         if (UserManager.get(context).isSystemUser()) {
148             Log.d(TAG, "initializeSharedPreference");
149             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
150             if (!sp.getBoolean(PreferenceManager.KEY_HAS_SET_DEFAULT_VALUES, false)) {
151                 // Sets the default values of the shared preference if there isn't any.
152                 PreferenceManager.setDefaultValues(context, R.xml.preferences, false);
153 
154                 // If the device is in test harness mode, we need to disable emergency alert by
155                 // default.
156                 if (ActivityManager.isRunningInUserTestHarness()) {
157                     Log.d(TAG, "In test harness mode. Turn off emergency alert by default.");
158                     sp.edit().putBoolean(CellBroadcastSettings.KEY_ENABLE_ALERTS_MASTER_TOGGLE,
159                             false).apply();
160                 }
161             } else {
162                 Log.d(TAG, "Skip setting default values of shared preference.");
163             }
164 
165             adjustReminderInterval(context);
166         } else {
167             Log.e(TAG, "initializeSharedPreference: Not system user.");
168         }
169     }
170 
171     /**
172      * Handle Service Category Program Data message.
173      * TODO: Send Service Category Program Results response message to sender
174      *
175      * @param context
176      * @param programDataList
177      */
handleCdmaSmsCbProgramData(Context context, CdmaSmsCbProgramData[] programDataList)178     private void handleCdmaSmsCbProgramData(Context context,
179                                             CdmaSmsCbProgramData[] programDataList) {
180         for (CdmaSmsCbProgramData programData : programDataList) {
181             switch (programData.getOperation()) {
182                 case CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY:
183                     tryCdmaSetCategory(context, programData.getCategory(), true);
184                     break;
185 
186                 case CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY:
187                     tryCdmaSetCategory(context, programData.getCategory(), false);
188                     break;
189 
190                 case CdmaSmsCbProgramData.OPERATION_CLEAR_CATEGORIES:
191                     tryCdmaSetCategory(context,
192                             SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, false);
193                     tryCdmaSetCategory(context,
194                             SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, false);
195                     tryCdmaSetCategory(context,
196                             SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, false);
197                     tryCdmaSetCategory(context,
198                             SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, false);
199                     break;
200 
201                 default:
202                     loge("Ignoring unknown SCPD operation " + programData.getOperation());
203             }
204         }
205     }
206 
tryCdmaSetCategory(Context context, int category, boolean enable)207     private void tryCdmaSetCategory(Context context, int category, boolean enable) {
208         SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
209 
210         switch (category) {
211             case SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT:
212                 sharedPrefs.edit().putBoolean(
213                         CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, enable)
214                         .apply();
215                 break;
216 
217             case SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT:
218                 sharedPrefs.edit().putBoolean(
219                         CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, enable)
220                         .apply();
221                 break;
222 
223             case SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY:
224                 sharedPrefs.edit().putBoolean(
225                         CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, enable).apply();
226                 break;
227 
228             case SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE:
229                 sharedPrefs.edit().putBoolean(
230                         CellBroadcastSettings.KEY_ENABLE_TEST_ALERTS, enable).apply();
231                 break;
232 
233             default:
234                 Log.w(TAG, "Ignoring SCPD command to " + (enable ? "enable" : "disable")
235                         + " alerts in category " + category);
236         }
237     }
238 
239     /**
240      * Tell {@link CellBroadcastConfigService} to enable the CB channels.
241      * @param context the broadcast receiver context
242      */
startConfigService(Context context)243     static void startConfigService(Context context) {
244         if (UserManager.get(context).isSystemUser()) {
245             Intent serviceIntent = new Intent(CellBroadcastConfigService.ACTION_ENABLE_CHANNELS,
246                     null, context, CellBroadcastConfigService.class);
247             Log.d(TAG, "Start Cell Broadcast configuration.");
248             context.startService(serviceIntent);
249         } else {
250             Log.e(TAG, "startConfigService: Not system user.");
251         }
252     }
253 
log(String msg)254     private static void log(String msg) {
255         Log.d(TAG, msg);
256     }
257 
loge(String msg)258     private static void loge(String msg) {
259         Log.e(TAG, msg);
260     }
261 }
262