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