1 /*
2  * Copyright (C) 2008 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.cdma;
18 
19 import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE;
20 
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.os.Build;
23 import android.os.Message;
24 import android.telephony.ServiceState;
25 import android.telephony.TelephonyManager;
26 
27 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
28 import com.android.internal.telephony.GsmCdmaPhone;
29 import com.android.internal.telephony.Phone;
30 import com.android.internal.telephony.PhoneConstants;
31 import com.android.internal.telephony.SMSDispatcher;
32 import com.android.internal.telephony.SmsConstants;
33 import com.android.internal.telephony.SmsController;
34 import com.android.internal.telephony.SmsDispatchersController;
35 import com.android.internal.telephony.SmsHeader;
36 import com.android.internal.telephony.SmsMessageBase;
37 import com.android.internal.telephony.util.SMSDispatcherUtil;
38 import com.android.telephony.Rlog;
39 
40 public class CdmaSMSDispatcher extends SMSDispatcher {
41     private static final String TAG = "CdmaSMSDispatcher";
42     private static final boolean VDBG = false;
43 
CdmaSMSDispatcher(Phone phone, SmsDispatchersController smsDispatchersController)44     public CdmaSMSDispatcher(Phone phone, SmsDispatchersController smsDispatchersController) {
45         super(phone, smsDispatchersController);
46         Rlog.d(TAG, "CdmaSMSDispatcher created");
47     }
48 
49     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
50     @Override
getFormat()51     public String getFormat() {
52         return SmsConstants.FORMAT_3GPP2;
53     }
54 
55     /**
56      * Send the SMS status report to the dispatcher thread to process.
57      * @param sms the CDMA SMS message containing the status report
58      */
sendStatusReportMessage(SmsMessage sms)59     public void sendStatusReportMessage(SmsMessage sms) {
60         if (VDBG) Rlog.d(TAG, "sending EVENT_HANDLE_STATUS_REPORT message");
61         sendMessage(obtainMessage(EVENT_HANDLE_STATUS_REPORT, sms));
62     }
63 
64     @Override
handleStatusReport(Object o)65     protected void handleStatusReport(Object o) {
66         if (o instanceof SmsMessage) {
67             if (VDBG) Rlog.d(TAG, "calling handleSmsStatusReport()");
68             byte[] pdu = ((SmsMessage) o).getPdu();
69             mSmsDispatchersController.handleSmsStatusReport(SmsConstants.FORMAT_3GPP2, pdu);
70         } else {
71             Rlog.e(TAG, "handleStatusReport() called for object type " + o.getClass().getName());
72         }
73     }
74 
75     @Override
shouldBlockSmsForEcbm()76     protected boolean shouldBlockSmsForEcbm() {
77         // We only block outgoing SMS during ECBM when using CDMA.
78         return mPhone.isInEcm() && isCdmaMo() && !isIms();
79     }
80 
81     @Override
getSubmitPdu(String scAddr, String destAddr, String message, boolean statusReportRequested, SmsHeader smsHeader, int priority, int validityPeriod)82     protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr,
83             String message, boolean statusReportRequested, SmsHeader smsHeader, int priority,
84             int validityPeriod) {
85         return SMSDispatcherUtil.getSubmitPduCdma(scAddr, destAddr, message,
86                 statusReportRequested, smsHeader, priority);
87     }
88 
89     @Override
getSubmitPdu(String scAddr, String destAddr, int destPort, byte[] message, boolean statusReportRequested)90     protected SmsMessageBase.SubmitPduBase getSubmitPdu(String scAddr, String destAddr,
91             int destPort, byte[] message, boolean statusReportRequested) {
92         return SMSDispatcherUtil.getSubmitPduCdma(scAddr, destAddr, destPort, message,
93                 statusReportRequested);
94     }
95 
96     @Override
calculateLength(CharSequence messageBody, boolean use7bitOnly)97     protected TextEncodingDetails calculateLength(CharSequence messageBody, boolean use7bitOnly) {
98         return SMSDispatcherUtil.calculateLengthCdma(messageBody, use7bitOnly);
99     }
100 
101     /** {@inheritDoc} */
102     @Override
sendSms(SmsTracker tracker)103     public void sendSms(SmsTracker tracker) {
104         int ss = mPhone.getServiceState().getState();
105 
106         Rlog.d(TAG, "sendSms: "
107                 + " isIms()=" + isIms()
108                 + " mRetryCount=" + tracker.mRetryCount
109                 + " mImsRetry=" + tracker.mImsRetry
110                 + " mMessageRef=" + tracker.mMessageRef
111                 + " mUsesImsServiceForIms=" + tracker.mUsesImsServiceForIms
112                 + " SS=" + ss
113                 + " " + SmsController.formatCrossStackMessageId(tracker.mMessageId));
114 
115         // if sms over IMS is not supported on data and voice is not available...
116         if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
117             tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE);
118             return;
119         }
120 
121         Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
122         byte[] pdu = (byte[]) tracker.getData().get("pdu");
123 
124         int currentDataNetwork = mPhone.getServiceState().getDataNetworkType();
125         boolean imsSmsDisabled = (currentDataNetwork == TelephonyManager.NETWORK_TYPE_EHRPD
126                 || (currentDataNetwork == TelephonyManager.NETWORK_TYPE_LTE
127                 || currentDataNetwork == TelephonyManager.NETWORK_TYPE_LTE_CA
128                 || currentDataNetwork == TelephonyManager.NETWORK_TYPE_NR)
129                 && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed())
130                 && mPhone.getServiceState().getVoiceNetworkType()
131                         == TelephonyManager.NETWORK_TYPE_1xRTT
132                 && ((GsmCdmaPhone) mPhone).mCT.mState != PhoneConstants.State.IDLE;
133 
134         // sms over cdma is used:
135         //   if sms over IMS is not supported AND
136         //   this is not a retry case after sms over IMS failed
137         //     indicated by mImsRetry > 0 OR
138         //   SMS over IMS is disabled because of the network type OR
139         //   SMS over IMS is being handled by the ImsSmsDispatcher implementation and has indicated
140         //   that the message should fall back to sending over CS.
141         if (0 == tracker.mImsRetry && !isIms() || imsSmsDisabled || tracker.mUsesImsServiceForIms) {
142             if (tracker.mRetryCount == 0 && tracker.mExpectMore) {
143                 mCi.sendCdmaSMSExpectMore(pdu, reply);
144             } else {
145                 mCi.sendCdmaSms(pdu, reply);
146             }
147         } else {
148             mCi.sendImsCdmaSms(pdu, tracker.mImsRetry, tracker.mMessageRef, reply);
149             // increment it here, so in case of SMS_FAIL_RETRY over IMS
150             // next retry will be sent using IMS request again.
151             tracker.mImsRetry++;
152         }
153     }
154 }
155