Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8215559c authored by Cheuksan Wang's avatar Cheuksan Wang
Browse files

Use the AIDL based API to communicate with the carrier app.

Implements SMS sending.

BUG: 18005911

Change-Id: I467036b59b51905532e7ce1591dcb2e2856ef2d3
parent 373f9fa9
Loading
Loading
Loading
Loading
+99 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.telephony;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.service.carrier.CarrierMessagingService;
import android.service.carrier.ICarrierMessagingService;

import com.android.internal.util.Preconditions;

/**
 * Provides basic structure for platform to connect to the carrier messaging service.
 * <p>
 * <code>
 * CarrierMessagingServiceManager carrierMessagingServiceManager =
 *     new CarrierMessagingServiceManagerImpl();
 * if (carrierMessagingServiceManager.bindToCarrierMessagingService(context, carrierPackageName)) {
 *   // wait for onServiceReady callback
 * } else {
 *   // Unable to bind: handle error.
 * }
 * </code>
 * <p> Upon completion {@link #disposeConnection} should be called to unbind the
 * CarrierMessagingService.
 * @hide
 */
public abstract class CarrierMessagingServiceManager {
    // Populated by bindToCarrierMessagingService. bindToCarrierMessagingService must complete
    // prior to calling disposeConnection so that mCarrierMessagingServiceConnection is initialized.
    private volatile CarrierMessagingServiceConnection mCarrierMessagingServiceConnection;

    /**
     * Binds to the carrier messaging service under package {@code carrierPackageName}. This method
     * should be called exactly once.
     *
     * @param context the context
     * @param carrierPackageName the carrier package name
     * @return true upon successfully binding to a carrier messaging service, false otherwise
     */
    public boolean bindToCarrierMessagingService(Context context, String carrierPackageName) {
        Preconditions.checkState(mCarrierMessagingServiceConnection == null);

        Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
        intent.setPackage(carrierPackageName);
        mCarrierMessagingServiceConnection = new CarrierMessagingServiceConnection();
        return context.bindService(intent, mCarrierMessagingServiceConnection,
                Context.BIND_AUTO_CREATE);
    }

    /**
     * Unbinds the carrier messaging service. This method should be called exactly once.
     *
     * @param context the context
     */
    public void disposeConnection(Context context) {
        Preconditions.checkNotNull(mCarrierMessagingServiceConnection);
        context.unbindService(mCarrierMessagingServiceConnection);
        mCarrierMessagingServiceConnection = null;
    }

    /**
     * Implemented by subclasses to use the carrier messaging service once it is ready.
     *
     * @param carrierMessagingService the carrier messaing service interface
     */
    protected abstract void onServiceReady(ICarrierMessagingService carrierMessagingService);

    /**
     * A basic {@link ServiceConnection}.
     */
    private final class CarrierMessagingServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            onServiceReady(ICarrierMessagingService.Stub.asInterface(service));
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    }
}
+7 −74
Original line number Diff line number Diff line
@@ -278,8 +278,10 @@ public final class SmsManager {
     * @param format is the format of SMS pdu (3gpp or 3gpp2)
     * @param receivedIntent if not NULL this <code>PendingIntent</code> is
     *  broadcast when the message is successfully received by the
     *  android application framework. This intent is broadcasted at
     *  android application framework, or failed. This intent is broadcasted at
     *  the same time an SMS received from radio is acknowledged back.
     *  The result code will be <code>RESULT_SMS_HANDLED</code> for success, or
     *  <code>RESULT_SMS_GENERIC_ERROR</code> for error.
     *
     * @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2.
     */
@@ -300,26 +302,9 @@ public final class SmsManager {
    }

    /**
     * Update the status of a pending (send-by-IP) SMS message and resend by PSTN if necessary.
     * This outbound message was handled by the carrier app. If the carrier app fails to send
     * this message, it would be resent by PSTN.
     *
     * The caller should have carrier privileges.
     * @see android.telephony.TelephonyManager.hasCarrierPrivileges
     *
     * @param messageRef the reference number of the SMS message.
     * @param success True if and only if the message was sent successfully. If its value is
     *  false, this message should be resent via PSTN.
     * TODO: remove this method.
     */
    public void updateSmsSendStatus(int messageRef, boolean success) {
        try {
            ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
            if (iccISms != null) {
                iccISms.updateSmsSendStatus(messageRef, success);
            }
        } catch (RemoteException ex) {
          // ignore it
        }
    }

    /**
@@ -1029,69 +1014,17 @@ public final class SmsManager {
    public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";

    /**
     * Update the status of a pending (send-by-IP) MMS message handled by the carrier app.
     * If the carrier app fails to send this message, it may be resent via carrier network
     * depending on the status code.
     *
     * The caller should have carrier privileges.
     * @see android.telephony.TelephonyManager.hasCarrierPrivileges
     *
     * @param context application context
     * @param messageRef the reference number of the MMS message.
     * @param pdu non-empty (contains the SendConf PDU) if the message was sent successfully,
     *   otherwise, this param should be null.
     * @param status send status. It can be Activity.RESULT_OK or one of the MMS error codes.
     *   If status is Activity.RESULT_OK, the MMS was sent successfully.
     *   If status is MMS_ERROR_RETRY, this message would be resent via carrier
     *   network. The message will not be resent for other MMS error statuses.
     * @param contentUri the URI of the sent message
     * TODO: remove this method.
     */
    public void updateMmsSendStatus(Context context, int messageRef, byte[] pdu, int status,
            Uri contentUri) {
        try {
            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
            if (iMms == null) {
                return;
            }
            iMms.updateMmsSendStatus(messageRef, pdu, status);
        } catch (RemoteException ex) {
            // ignore it
        }
        if (contentUri != null) {
            context.revokeUriPermission(contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
    }

    /**
     * Update the status of a pending (download-by-IP) MMS message handled by the carrier app.
     * If the carrier app fails to download this message, it may be re-downloaded via carrier
     * network depending on the status code.
     *
     * The caller should have carrier privileges.
     * @see android.telephony.TelephonyManager.hasCarrierPrivileges
     *
     * @param context application context
     * @param messageRef the reference number of the MMS message.
     * @param status download status.  It can be Activity.RESULT_OK or one of the MMS error codes.
     *   If status is Activity.RESULT_OK, the MMS was downloaded successfully.
     *   If status is MMS_ERROR_RETRY, this message would be re-downloaded via carrier
     *   network. The message will not be re-downloaded for other MMS error statuses.
     * @param contentUri the URI of the downloaded message
     * TODO: remove this method.
     */
    public void updateMmsDownloadStatus(Context context, int messageRef, int status,
            Uri contentUri) {
        try {
            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
            if (iMms == null) {
                return;
            }
            iMms.updateMmsDownloadStatus(messageRef, status);
        } catch (RemoteException ex) {
            // ignore it
        }
        if (contentUri != null) {
            context.revokeUriPermission(contentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        }
    }

    /**
+0 −15
Original line number Diff line number Diff line
@@ -424,21 +424,6 @@ public class IccSmsInterfaceManager {
        mDispatcher.injectSmsPdu(pdu, format, receivedIntent);
    }

    /**
     * Update the status of a pending (send-by-IP) SMS message and resend by PSTN if necessary.
     * This outbound message was handled by the carrier app. If the carrier app fails to send
     * this message, it would be resent by PSTN.
     *
     * @param messageRef the reference number of the SMS message.
     * @param success True if and only if the message was sent successfully. If its value is
     *  false, this message should be resent via PSTN.
     * {@hide}
     */
    public void updateSmsSendStatus(int messageRef, boolean success) {
        enforceCarrierPrivilege();
        mDispatcher.updateSmsSendStatus(messageRef, success);
    }

    /**
     * Send a multi-part text based SMS.
     *
+8 −56
Original line number Diff line number Diff line
@@ -195,60 +195,6 @@ public final class ImsSMSDispatcher extends SMSDispatcher {
        Rlog.e(TAG, "sendSmsByPstn should never be called from here!");
    }

    @Override
    protected void updateSmsSendStatus(int messageRef, boolean success) {
        if (isCdmaMo()) {
            updateSmsSendStatusHelper(messageRef, mCdmaDispatcher.sendPendingList,
                                      mCdmaDispatcher, success);
            updateSmsSendStatusHelper(messageRef, mGsmDispatcher.sendPendingList,
                                      null, success);
        } else {
            updateSmsSendStatusHelper(messageRef, mGsmDispatcher.sendPendingList,
                                      mGsmDispatcher, success);
            updateSmsSendStatusHelper(messageRef, mCdmaDispatcher.sendPendingList,
                                      null, success);
        }
    }

    /**
     * Find a tracker in a list to update its status. If the status is successful,
     * send an EVENT_SEND_SMS_COMPLETE message. Otherwise, resend the message by PSTN if
     * feasible.
     *
     * @param messageRef the reference number of the tracker.
     * @param sendPendingList the list of trackers to look into.
     * @param smsDispatcher the dispatcher for resending the message by PSTN.
     * @param success true iff the message was sent successfully.
     */
    private void updateSmsSendStatusHelper(int messageRef,
                                           List<SmsTracker> sendPendingList,
                                           SMSDispatcher smsDispatcher,
                                           boolean success) {
        synchronized (sendPendingList) {
            for (int i = 0, count = sendPendingList.size(); i < count; i++) {
                SmsTracker tracker = sendPendingList.get(i);
                if (tracker.mMessageRef == messageRef) {
                    // Found it.  Remove from list and broadcast.
                    sendPendingList.remove(i);
                    if (success) {
                        Rlog.d(TAG, "Sending SMS by IP succeeded.");
                        sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
                                                  new AsyncResult(tracker, null, null)));
                    } else {
                        Rlog.d(TAG, "Sending SMS by IP failed.");
                        if (smsDispatcher != null) {
                            smsDispatcher.sendSmsByPstn(tracker);
                        } else {
                            Rlog.e(TAG, "No feasible way to send this SMS.");
                        }
                    }
                    // Only expect to see one tracker matching this messageref.
                    break;
                }
            }
        }
    }

    @Override
    protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent,
            PendingIntent deliveryIntent, Uri messageUri, String callingPkg) {
@@ -387,6 +333,11 @@ public final class ImsSMSDispatcher extends SMSDispatcher {
        dispatcher.sendSms(tracker);
    }

    @Override
    protected void sendSubmitPdu(SmsTracker tracker) {
        sendRawPdu(tracker);
    }

    @Override
    protected String getFormat() {
        // this function should be defined in Gsm/CdmaDispatcher.
@@ -402,12 +353,13 @@ public final class ImsSMSDispatcher extends SMSDispatcher {
    }

    @Override
    protected void sendNewSubmitPdu(String destinationAddress, String scAddress, String message,
            SmsHeader smsHeader, int format, PendingIntent sentIntent,
    protected SmsTracker getNewSubmitPduTracker(String destinationAddress, String scAddress,
            String message, SmsHeader smsHeader, int format, PendingIntent sentIntent,
            PendingIntent deliveryIntent, boolean lastPart,
            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
            String fullMessageText) {
        Rlog.e(TAG, "Error! Not implemented for IMS.");
        return null;
    }

    @Override
+8 −9
Original line number Diff line number Diff line
@@ -47,12 +47,11 @@ import android.os.UserManager;
import android.preference.PreferenceManager;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
import android.service.carriermessaging.CarrierMessagingService;
import android.service.carriermessaging.CarrierMessagingService.SendSmsResponse;
import android.service.carriermessaging.CarrierMessagingServiceManager;
import android.service.carriermessaging.ICarrierMessagingCallback;
import android.service.carriermessaging.ICarrierMessagingService;
import android.service.carriermessaging.MessagePdu;
import android.service.carrier.CarrierMessagingService;
import android.service.carrier.ICarrierMessagingCallback;
import android.service.carrier.ICarrierMessagingService;
import android.service.carrier.MessagePdu;
import android.telephony.CarrierMessagingServiceManager;
import android.telephony.Rlog;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
@@ -1089,7 +1088,7 @@ public abstract class InboundSmsHandler extends StateMachine {
            try {
                carrierMessagingService.filterSms(
                        new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort,
                        mSmsFilterCallback);
                        mPhone.getSubId(), mSmsFilterCallback);
            } catch (RemoteException e) {
                loge("Exception filtering the SMS: " + e);
                mSmsFilterCallback.onFilterComplete(true);
@@ -1128,12 +1127,12 @@ public abstract class InboundSmsHandler extends StateMachine {
        }

        @Override
        public void onSendSmsComplete(int result, SendSmsResponse sendSmsResponse) {
        public void onSendSmsComplete(int result, int messageRef) {
            loge("Unexpected onSendSmsComplete call with result: " + result);
        }

        @Override
        public void onSendMultipartSmsComplete(int result, List<SendSmsResponse> sendSmsResponse) {
        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
            loge("Unexpected onSendMultipartSmsComplete call with result: " + result);
        }

Loading