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.os.RemoteException;
     24 import android.os.ServiceManager;
     25 import android.os.UserHandle;
     26 import android.os.UserManager;
     27 import android.preference.PreferenceManager;
     28 import android.provider.Telephony;
     29 import android.telephony.CellBroadcastMessage;
     30 import android.telephony.ServiceState;
     31 import android.telephony.SubscriptionManager;
     32 import android.telephony.TelephonyManager;
     33 import android.telephony.cdma.CdmaSmsCbProgramData;
     34 import android.util.Log;
     35 
     36 import com.android.internal.telephony.cdma.sms.SmsEnvelope;
     37 import com.android.internal.telephony.TelephonyIntents;
     38 
     39 public class CellBroadcastReceiver extends BroadcastReceiver {
     40     private static final String TAG = "CellBroadcastReceiver";
     41     static final boolean DBG = false;    // STOPSHIP: change to false before ship
     42     private static int mServiceState = -1;
     43 
     44     public static final String CELLBROADCAST_START_CONFIG_ACTION =
     45             "android.cellbroadcastreceiver.START_CONFIG";
     46 
     47     @Override
     48     public void onReceive(Context context, Intent intent) {
     49         onReceiveWithPrivilege(context, intent, false);
     50     }
     51 
     52     protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
     53         if (DBG) log("onReceive " + intent);
     54 
     55         String action = intent.getAction();
     56 
     57         if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
     58             if (DBG) log("Intent: " + action);
     59             ServiceState serviceState = ServiceState.newFromBundle(intent.getExtras());
     60             if (serviceState != null) {
     61                 int newState = serviceState.getState();
     62                 if (newState != mServiceState) {
     63                     Log.d(TAG, "Service state changed! " + newState + " Full: " + serviceState +
     64                             " Current state=" + mServiceState);
     65                     mServiceState = newState;
     66                     if (((newState == ServiceState.STATE_IN_SERVICE) ||
     67                             (newState == ServiceState.STATE_EMERGENCY_ONLY)) &&
     68                             (UserManager.get(context).isSystemUser())) {
     69                         startConfigService(context.getApplicationContext());
     70                     }
     71                 }
     72             }
     73         } else if (TelephonyIntents.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED.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             else {
     82                 Log.e(TAG, "Not system user. Ignored the intent " + action);
     83             }
     84         } else if (Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION.equals(action) ||
     85                 Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION.equals(action)) {
     86             // If 'privileged' is false, it means that the intent was delivered to the base
     87             // no-permissions receiver class.  If we get an SMS_CB_RECEIVED message that way, it
     88             // means someone has tried to spoof the message by delivering it outside the normal
     89             // permission-checked route, so we just ignore it.
     90             if (privileged) {
     91                 intent.setClass(context, CellBroadcastAlertService.class);
     92                 context.startService(intent);
     93             } else {
     94                 loge("ignoring unprivileged action received " + action);
     95             }
     96         } else if (Telephony.Sms.Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION
     97                 .equals(action)) {
     98             if (privileged) {
     99                 CdmaSmsCbProgramData[] programDataList = (CdmaSmsCbProgramData[])
    100                         intent.getParcelableArrayExtra("program_data_list");
    101                 if (programDataList != null) {
    102                     handleCdmaSmsCbProgramData(context, programDataList);
    103                 } else {
    104                     loge("SCPD intent received with no program_data_list");
    105                 }
    106             } else {
    107                 loge("ignoring unprivileged action received " + action);
    108             }
    109         } else {
    110             Log.w(TAG, "onReceive() unexpected action " + action);
    111         }
    112     }
    113 
    114     /**
    115      * Handle Service Category Program Data message.
    116      * TODO: Send Service Category Program Results response message to sender
    117      *
    118      * @param context
    119      * @param programDataList
    120      */
    121     private void handleCdmaSmsCbProgramData(Context context,
    122                                             CdmaSmsCbProgramData[] programDataList) {
    123         for (CdmaSmsCbProgramData programData : programDataList) {
    124             switch (programData.getOperation()) {
    125                 case CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY:
    126                     tryCdmaSetCategory(context, programData.getCategory(), true);
    127                     break;
    128 
    129                 case CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY:
    130                     tryCdmaSetCategory(context, programData.getCategory(), false);
    131                     break;
    132 
    133                 case CdmaSmsCbProgramData.OPERATION_CLEAR_CATEGORIES:
    134                     tryCdmaSetCategory(context,
    135                             SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, false);
    136                     tryCdmaSetCategory(context,
    137                             SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, false);
    138                     tryCdmaSetCategory(context,
    139                             SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, false);
    140                     tryCdmaSetCategory(context,
    141                             SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, false);
    142                     break;
    143 
    144                 default:
    145                     loge("Ignoring unknown SCPD operation " + programData.getOperation());
    146             }
    147         }
    148     }
    149 
    150     private void tryCdmaSetCategory(Context context, int category, boolean enable) {
    151         SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
    152 
    153         switch (category) {
    154             case SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT:
    155                 sharedPrefs.edit().putBoolean(
    156                         CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, enable)
    157                         .apply();
    158                 break;
    159 
    160             case SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT:
    161                 sharedPrefs.edit().putBoolean(
    162                         CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, enable)
    163                         .apply();
    164                 break;
    165 
    166             case SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY:
    167                 sharedPrefs.edit().putBoolean(
    168                         CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, enable).apply();
    169                 break;
    170 
    171             case SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE:
    172                 sharedPrefs.edit().putBoolean(
    173                         CellBroadcastSettings.KEY_ENABLE_CMAS_TEST_ALERTS, enable).apply();
    174                 break;
    175 
    176             default:
    177                 Log.w(TAG, "Ignoring SCPD command to " + (enable ? "enable" : "disable")
    178                         + " alerts in category " + category);
    179         }
    180     }
    181 
    182     /**
    183      * Tell {@link CellBroadcastConfigService} to enable the CB channels.
    184      * @param context the broadcast receiver context
    185      */
    186     static void startConfigService(Context context) {
    187         Intent serviceIntent = new Intent(CellBroadcastConfigService.ACTION_ENABLE_CHANNELS,
    188                 null, context, CellBroadcastConfigService.class);
    189         Log.d(TAG, "Start Cell Broadcast configuration.");
    190         context.startService(serviceIntent);
    191     }
    192 
    193     /**
    194      * @return true if the phone is a CDMA phone type
    195      */
    196     static boolean phoneIsCdma() {
    197         boolean isCdma = false;
    198 
    199         int subId = SubscriptionManager.getDefaultSmsSubscriptionId();
    200         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
    201             subId = SubscriptionManager.getDefaultSubscriptionId();
    202         }
    203 
    204         TelephonyManager tm = TelephonyManager.getDefault();
    205         if (tm != null) {
    206             isCdma = (tm.getCurrentPhoneType(subId) == TelephonyManager.PHONE_TYPE_CDMA);
    207         }
    208         return isCdma;
    209     }
    210 
    211     private static void log(String msg) {
    212         Log.d(TAG, msg);
    213     }
    214 
    215     private static void loge(String msg) {
    216         Log.e(TAG, msg);
    217     }
    218 }
    219