Home | History | Annotate | Download | only in cellbroadcastreceiver
      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.content.BroadcastReceiver;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.SharedPreferences;
     23 import android.content.SharedPreferences.Editor;
     24 import android.os.UserManager;
     25 import android.preference.PreferenceManager;
     26 import android.provider.Telephony;
     27 import android.provider.Telephony.CellBroadcasts;
     28 import android.telephony.CarrierConfigManager;
     29 import android.telephony.cdma.CdmaSmsCbProgramData;
     30 import android.util.Log;
     31 
     32 import com.android.internal.telephony.TelephonyIntents;
     33 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
     34 
     35 public class CellBroadcastReceiver extends BroadcastReceiver {
     36     private static final String TAG = "CellBroadcastReceiver";
     37     static final boolean DBG = true;
     38     static final boolean VDBG = false;    // STOPSHIP: change to false before ship
     39 
     40     // Key to access the stored reminder interval default value
     41     private static final String CURRENT_INTERVAL_DEFAULT = "current_interval_default";
     42 
     43     // Intent actions and extras
     44     public static final String CELLBROADCAST_START_CONFIG_ACTION =
     45             "com.android.cellbroadcastreceiver.intent.START_CONFIG";
     46     public static final String ACTION_MARK_AS_READ =
     47             "com.android.cellbroadcastreceiver.intent.action.MARK_AS_READ";
     48     public static final String EXTRA_DELIVERY_TIME =
     49             "com.android.cellbroadcastreceiver.intent.extra.ID";
     50 
     51     @Override
     52     public void onReceive(Context context, Intent intent) {
     53         onReceiveWithPrivilege(context, intent, false);
     54     }
     55 
     56     protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
     57         if (DBG) log("onReceive " + intent);
     58 
     59         String action = intent.getAction();
     60 
     61         if (ACTION_MARK_AS_READ.equals(action)) {
     62             final long deliveryTime = intent.getLongExtra(EXTRA_DELIVERY_TIME, -1);
     63             new CellBroadcastContentProvider.AsyncCellBroadcastTask(context.getContentResolver())
     64                     .execute(new CellBroadcastContentProvider.CellBroadcastOperation() {
     65                         @Override
     66                         public boolean execute(CellBroadcastContentProvider provider) {
     67                             return provider.markBroadcastRead(CellBroadcasts.DELIVERY_TIME,
     68                                     deliveryTime);
     69                         }
     70                     });
     71         } else if (TelephonyIntents.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED.equals(action)
     72                 || CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)
     73                 || Intent.ACTION_BOOT_COMPLETED.equals(action)
     74                 || CELLBROADCAST_START_CONFIG_ACTION.equals(action)) {
     75             // Todo: Add the service state check once the new get service state API is done.
     76             // Do not rely on mServiceState as it gets reset to -1 time to time because
     77             // the process of CellBroadcastReceiver gets killed every time once the job is done.
     78             if (UserManager.get(context).isSystemUser()) {
     79                 startConfigService(context.getApplicationContext());
     80 
     81                 // Whenever carrier changes, we need to adjust the emergency alert
     82                 // reminder interval list because it might change since different
     83                 // countries/carriers might have different interval settings.
     84                 adjustReminderInterval(context);
     85             }
     86             else {
     87                 Log.e(TAG, "Not system user. Ignored the intent " + action);
     88             }
     89         } else if (Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION.equals(action) ||
     90                 Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION.equals(action)) {
     91             // If 'privileged' is false, it means that the intent was delivered to the base
     92             // no-permissions receiver class.  If we get an SMS_CB_RECEIVED message that way, it
     93             // means someone has tried to spoof the message by delivering it outside the normal
     94             // permission-checked route, so we just ignore it.
     95             if (privileged) {
     96                 intent.setClass(context, CellBroadcastAlertService.class);
     97                 context.startService(intent);
     98             } else {
     99                 loge("ignoring unprivileged action received " + action);
    100             }
    101         } else if (Telephony.Sms.Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION
    102                 .equals(action)) {
    103             if (privileged) {
    104                 CdmaSmsCbProgramData[] programDataList = (CdmaSmsCbProgramData[])
    105                         intent.getParcelableArrayExtra("program_data_list");
    106                 if (programDataList != null) {
    107                     handleCdmaSmsCbProgramData(context, programDataList);
    108                 } else {
    109                     loge("SCPD intent received with no program_data_list");
    110                 }
    111             } else {
    112                 loge("ignoring unprivileged action received " + action);
    113             }
    114         } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
    115             // rename registered notification channels on locale change
    116             CellBroadcastAlertService.createNotificationChannels(context);
    117         } else {
    118             Log.w(TAG, "onReceive() unexpected action " + action);
    119         }
    120     }
    121 
    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 = context.getResources().getString(
    128                 R.string.alert_reminder_interval_default_value);
    129         if (!newIntervalDefault.equals(currentIntervalDefault)) {
    130             Log.d(TAG, "Default interval changed from " + currentIntervalDefault + " to " +
    131                     newIntervalDefault);
    132 
    133             Editor editor = sp.edit();
    134             // Reset the value to default.
    135             editor.putString(
    136                     CellBroadcastSettings.KEY_ALERT_REMINDER_INTERVAL, newIntervalDefault);
    137             // Save the new default value.
    138             editor.putString(CURRENT_INTERVAL_DEFAULT, newIntervalDefault);
    139             editor.commit();
    140         } else {
    141             if (DBG) Log.d(TAG, "Default interval " + currentIntervalDefault + " did not change.");
    142         }
    143     }
    144 
    145     /**
    146      * Handle Service Category Program Data message.
    147      * TODO: Send Service Category Program Results response message to sender
    148      *
    149      * @param context
    150      * @param programDataList
    151      */
    152     private void handleCdmaSmsCbProgramData(Context context,
    153                                             CdmaSmsCbProgramData[] programDataList) {
    154         for (CdmaSmsCbProgramData programData : programDataList) {
    155             switch (programData.getOperation()) {
    156                 case CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY:
    157                     tryCdmaSetCategory(context, programData.getCategory(), true);
    158                     break;
    159 
    160                 case CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY:
    161                     tryCdmaSetCategory(context, programData.getCategory(), false);
    162                     break;
    163 
    164                 case CdmaSmsCbProgramData.OPERATION_CLEAR_CATEGORIES:
    165                     tryCdmaSetCategory(context,
    166                             SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, false);
    167                     tryCdmaSetCategory(context,
    168                             SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, false);
    169                     tryCdmaSetCategory(context,
    170                             SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, false);
    171                     tryCdmaSetCategory(context,
    172                             SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, false);
    173                     break;
    174 
    175                 default:
    176                     loge("Ignoring unknown SCPD operation " + programData.getOperation());
    177             }
    178         }
    179     }
    180 
    181     private void tryCdmaSetCategory(Context context, int category, boolean enable) {
    182         SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
    183 
    184         switch (category) {
    185             case SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT:
    186                 sharedPrefs.edit().putBoolean(
    187                         CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, enable)
    188                         .apply();
    189                 break;
    190 
    191             case SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT:
    192                 sharedPrefs.edit().putBoolean(
    193                         CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, enable)
    194                         .apply();
    195                 break;
    196 
    197             case SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY:
    198                 sharedPrefs.edit().putBoolean(
    199                         CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, enable).apply();
    200                 break;
    201 
    202             case SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE:
    203                 sharedPrefs.edit().putBoolean(
    204                         CellBroadcastSettings.KEY_ENABLE_CMAS_TEST_ALERTS, enable).apply();
    205                 break;
    206 
    207             default:
    208                 Log.w(TAG, "Ignoring SCPD command to " + (enable ? "enable" : "disable")
    209                         + " alerts in category " + category);
    210         }
    211     }
    212 
    213     /**
    214      * Tell {@link CellBroadcastConfigService} to enable the CB channels.
    215      * @param context the broadcast receiver context
    216      */
    217     static void startConfigService(Context context) {
    218         Intent serviceIntent = new Intent(CellBroadcastConfigService.ACTION_ENABLE_CHANNELS,
    219                 null, context, CellBroadcastConfigService.class);
    220         Log.d(TAG, "Start Cell Broadcast configuration.");
    221         context.startService(serviceIntent);
    222     }
    223 
    224     private static void log(String msg) {
    225         Log.d(TAG, msg);
    226     }
    227 
    228     private static void loge(String msg) {
    229         Log.e(TAG, msg);
    230     }
    231 }
    232