150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby/*
250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Copyright (C) 2011 The Android Open Source Project
350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Licensed under the Apache License, Version 2.0 (the "License");
550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * you may not use this file except in compliance with the License.
650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * You may obtain a copy of the License at
750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *      http://www.apache.org/licenses/LICENSE-2.0
950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby *
1050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * Unless required by applicable law or agreed to in writing, software
1150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * distributed under the License is distributed on an "AS IS" BASIS,
1250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * See the License for the specific language governing permissions and
1450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby * limitations under the License.
1550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby */
1650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
1750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambypackage com.android.cellbroadcastreceiver;
1850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
1950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.content.BroadcastReceiver;
2050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.content.Context;
2150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.content.Intent;
2200b87064abfb9d254fbbf72110643d2e626365e6Jake Hambyimport android.content.SharedPreferences;
2350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.os.RemoteException;
2450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.os.ServiceManager;
2500b87064abfb9d254fbbf72110643d2e626365e6Jake Hambyimport android.preference.PreferenceManager;
2650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.provider.Telephony;
2750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.telephony.TelephonyManager;
2800b87064abfb9d254fbbf72110643d2e626365e6Jake Hambyimport android.telephony.cdma.CdmaSmsCbProgramData;
2950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport android.util.Log;
3050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
3150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambyimport com.android.internal.telephony.ITelephony;
3200b87064abfb9d254fbbf72110643d2e626365e6Jake Hambyimport com.android.internal.telephony.cdma.sms.SmsEnvelope;
3350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
3450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hambypublic class CellBroadcastReceiver extends BroadcastReceiver {
3550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    private static final String TAG = "CellBroadcastReceiver";
3600b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby    static final boolean DBG = true;    // STOPSHIP: change to false before ship
3750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
3850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    @Override
3950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    public void onReceive(Context context, Intent intent) {
4050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        onReceiveWithPrivilege(context, intent, false);
4150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
4250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
4350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
44da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby        if (DBG) log("onReceive " + intent);
4550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
4650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        String action = intent.getAction();
4750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
4850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
4950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            startConfigService(context);
5050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
5150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            boolean airplaneModeOn = intent.getBooleanExtra("state", false);
5250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            if (!airplaneModeOn) {
5350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                startConfigService(context);
5450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
5550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        } else if (Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION.equals(action) ||
5650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION.equals(action)) {
5750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            // If 'privileged' is false, it means that the intent was delivered to the base
5850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            // no-permissions receiver class.  If we get an SMS_CB_RECEIVED message that way, it
5950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            // means someone has tried to spoof the message by delivering it outside the normal
6050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            // permission-checked route, so we just ignore it.
6150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            if (privileged) {
6250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                intent.setClass(context, CellBroadcastAlertService.class);
6350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                context.startService(intent);
6450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            } else {
6550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                Log.e(TAG, "ignoring unprivileged action received " + action);
6650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
6700b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby        } else if (Telephony.Sms.Intents.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION
6800b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                .equals(action)) {
6900b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby            if (privileged) {
70e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                CdmaSmsCbProgramData[] programDataList = (CdmaSmsCbProgramData[])
71e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                        intent.getParcelableArrayExtra("program_data_list");
72e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                if (programDataList != null) {
73e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                    handleCdmaSmsCbProgramData(context, programDataList);
74e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                } else {
75e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                    Log.e(TAG, "SCPD intent received with no program_data_list");
7600b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                }
7700b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby            } else {
7800b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                Log.e(TAG, "ignoring unprivileged action received " + action);
7900b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby            }
8050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        } else {
8150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            Log.w(TAG, "onReceive() unexpected action " + action);
8250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        }
8350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
8450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
8550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    /**
86e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl     * Handle Service Category Program Data message.
87e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl     * TODO: Send Service Category Program Results response message to sender
8800b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby     *
89e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl     * @param context
90e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl     * @param programDataList
9100b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby     */
92e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl    private void handleCdmaSmsCbProgramData(Context context,
93e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl            CdmaSmsCbProgramData[] programDataList) {
9400b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby        for (CdmaSmsCbProgramData programData : programDataList) {
9500b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby            switch (programData.getOperation()) {
9600b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                case CdmaSmsCbProgramData.OPERATION_ADD_CATEGORY:
97e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                    tryCdmaSetCategory(context, programData.getCategory(), true);
9800b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                    break;
9900b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby
10000b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                case CdmaSmsCbProgramData.OPERATION_DELETE_CATEGORY:
101e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                    tryCdmaSetCategory(context, programData.getCategory(), false);
10200b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                    break;
10300b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby
10400b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                case CdmaSmsCbProgramData.OPERATION_CLEAR_CATEGORIES:
10500b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                    tryCdmaSetCategory(context,
10600b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                            SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT, false);
10700b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                    tryCdmaSetCategory(context,
10800b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                            SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT, false);
10900b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                    tryCdmaSetCategory(context,
11000b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                            SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY, false);
11100b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                    tryCdmaSetCategory(context,
11200b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                            SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE, false);
11300b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                    break;
11400b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby
11500b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                default:
11600b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                    Log.e(TAG, "Ignoring unknown SCPD operation " + programData.getOperation());
11700b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby            }
11800b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby        }
11921f2b9ac08ca93cee099292ba597b9a45e846030Jake Hamby    }
12000b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby
121e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl    private void tryCdmaSetCategory(Context context, int category, boolean enable) {
122e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
123e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl
12400b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby        switch (category) {
12500b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby            case SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT:
126e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                sharedPrefs.edit().putBoolean(
127e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                        CellBroadcastSettings.KEY_ENABLE_CMAS_EXTREME_THREAT_ALERTS, enable)
128e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                        .apply();
12900b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                break;
13000b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby
13100b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby            case SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT:
132e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                sharedPrefs.edit().putBoolean(
133e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                        CellBroadcastSettings.KEY_ENABLE_CMAS_SEVERE_THREAT_ALERTS, enable)
134e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                        .apply();
13500b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                break;
13600b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby
13700b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby            case SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY:
138e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                sharedPrefs.edit().putBoolean(
139e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                        CellBroadcastSettings.KEY_ENABLE_CMAS_AMBER_ALERTS, enable).apply();
14000b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                break;
14100b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby
14200b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby            case SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE:
143e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                sharedPrefs.edit().putBoolean(
144e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                        CellBroadcastSettings.KEY_ENABLE_CMAS_TEST_ALERTS, enable).apply();
14500b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby                break;
14600b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby
14700b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby            default:
148e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                Log.w(TAG, "Ignoring SCPD command to " + (enable ? "enable" : "disable")
149e707fd18bd5170f8f8f0320921899f1683747c6bEd Heyl                        + " alerts in category " + category);
15000b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby        }
15100b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby    }
15200b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby
15300b87064abfb9d254fbbf72110643d2e626365e6Jake Hamby    /**
15450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby     * Tell {@link CellBroadcastConfigService} to enable the CB channels.
15550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby     * @param context the broadcast receiver context
15650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby     */
15750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    static void startConfigService(Context context) {
15850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        if (phoneIsCdma()) {
159da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby            if (DBG) log("CDMA phone detected; doing nothing");
16050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        } else {
16150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            Intent serviceIntent = new Intent(CellBroadcastConfigService.ACTION_ENABLE_CHANNELS,
16250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                    null, context, CellBroadcastConfigService.class);
16350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            context.startService(serviceIntent);
16450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        }
16550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
16650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby
16750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    /**
16850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby     * @return true if the phone is a CDMA phone type
16950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby     */
17050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    private static boolean phoneIsCdma() {
17150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        boolean isCdma = false;
17250a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        try {
17350a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
17450a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            if (phone != null) {
17550a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby                isCdma = (phone.getActivePhoneType() == TelephonyManager.PHONE_TYPE_CDMA);
17650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            }
17750a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        } catch (RemoteException e) {
17850a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby            Log.w(TAG, "phone.getActivePhoneType() failed", e);
17950a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        }
18050a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby        return isCdma;
18150a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby    }
182da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby
183da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby    private static void log(String msg) {
184da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby        Log.d(TAG, msg);
185da5c415f6d0999131e93384b5fb90422ada8e4daJake Hamby    }
18650a624a47ce645a7992e346e40a4e7ec5e0df9b7Jake Hamby}
187