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