1/*
2 * Copyright (C) 2013 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.internal.telephony;
18
19import static android.provider.Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG;
20
21import android.Manifest;
22import android.app.Activity;
23import android.app.AppOpsManager;
24import android.content.Context;
25import android.content.Intent;
26import android.os.Build;
27import android.os.Message;
28import android.os.UserHandle;
29import android.provider.Settings;
30import android.provider.Telephony;
31import android.telephony.SmsCbMessage;
32import android.telephony.SubscriptionManager;
33
34/**
35 * Dispatch new Cell Broadcasts to receivers. Acquires a private wakelock until the broadcast
36 * completes and our result receiver is called.
37 */
38public class CellBroadcastHandler extends WakeLockStateMachine {
39
40    private CellBroadcastHandler(Context context, Phone phone) {
41        this("CellBroadcastHandler", context, phone);
42    }
43
44    protected CellBroadcastHandler(String debugTag, Context context, Phone phone) {
45        super(debugTag, context, phone);
46    }
47
48    /**
49     * Create a new CellBroadcastHandler.
50     * @param context the context to use for dispatching Intents
51     * @return the new handler
52     */
53    public static CellBroadcastHandler makeCellBroadcastHandler(Context context, Phone phone) {
54        CellBroadcastHandler handler = new CellBroadcastHandler(context, phone);
55        handler.start();
56        return handler;
57    }
58
59    /**
60     * Handle Cell Broadcast messages from {@code CdmaInboundSmsHandler}.
61     * 3GPP-format Cell Broadcast messages sent from radio are handled in the subclass.
62     *
63     * @param message the message to process
64     * @return true if an ordered broadcast was sent; false on failure
65     */
66    @Override
67    protected boolean handleSmsMessage(Message message) {
68        if (message.obj instanceof SmsCbMessage) {
69            handleBroadcastSms((SmsCbMessage) message.obj);
70            return true;
71        } else {
72            loge("handleMessage got object of type: " + message.obj.getClass().getName());
73            return false;
74        }
75    }
76
77    /**
78     * Dispatch a Cell Broadcast message to listeners.
79     * @param message the Cell Broadcast to broadcast
80     */
81    protected void handleBroadcastSms(SmsCbMessage message) {
82        String receiverPermission;
83        int appOp;
84
85        Intent intent;
86        if (message.isEmergencyMessage()) {
87            log("Dispatching emergency SMS CB, SmsCbMessage is: " + message);
88            intent = new Intent(Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION);
89            // Explicitly send the intent to the default cell broadcast receiver.
90            intent.setPackage(mContext.getResources().getString(
91                    com.android.internal.R.string.config_defaultCellBroadcastReceiverPkg));
92            receiverPermission = Manifest.permission.RECEIVE_EMERGENCY_BROADCAST;
93            appOp = AppOpsManager.OP_RECEIVE_EMERGECY_SMS;
94        } else {
95            log("Dispatching SMS CB, SmsCbMessage is: " + message);
96            intent = new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION);
97            // Send implicit intent since there are various 3rd party carrier apps listen to
98            // this intent.
99            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
100            receiverPermission = Manifest.permission.RECEIVE_SMS;
101            appOp = AppOpsManager.OP_RECEIVE_SMS;
102        }
103
104        intent.putExtra("message", message);
105        SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
106
107        if (Build.IS_DEBUGGABLE) {
108            // Send additional broadcast intent to the specified package. This is only for sl4a
109            // automation tests.
110            final String additionalPackage = Settings.Secure.getString(
111                    mContext.getContentResolver(), CMAS_ADDITIONAL_BROADCAST_PKG);
112            if (additionalPackage != null) {
113                Intent additionalIntent = new Intent(intent);
114                additionalIntent.setPackage(additionalPackage);
115                mContext.sendOrderedBroadcastAsUser(additionalIntent, UserHandle.ALL,
116                        receiverPermission, appOp, null, getHandler(), Activity.RESULT_OK, null,
117                        null);
118            }
119        }
120
121        mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, receiverPermission, appOp,
122                mReceiver, getHandler(), Activity.RESULT_OK, null, null);
123    }
124}
125