new sms/mms carrier app API

BUG: 18005911

Change-Id: Ib961badc1ccac270f1244f8d971d9abec324b73f
diff --git a/Android.mk b/Android.mk
index b77c2ed..b286cdb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -202,6 +202,8 @@
 	core/java/android/os/IUpdateLock.aidl \
 	core/java/android/os/IUserManager.aidl \
 	core/java/android/os/IVibratorService.aidl \
+	core/java/android/service/carriermessaging/ICarrierMessagingCallback.aidl \
+	core/java/android/service/carriermessaging/ICarrierMessagingService.aidl \
 	core/java/android/service/notification/INotificationListener.aidl \
 	core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
 	core/java/android/service/notification/IConditionListener.aidl \
@@ -522,6 +524,8 @@
 	frameworks/base/core/java/android/view/textservice/SpellCheckerInfo.aidl \
 	frameworks/base/core/java/android/view/textservice/SentenceSuggestionsInfo.aidl \
 	frameworks/base/core/java/android/view/textservice/SuggestionsInfo.aidl \
+	frameworks/base/core/java/android/service/carriermessaging/MessagePdu.aidl \
+	frameworks/base/core/java/android/service/carriermessaging/CarrierMessagingService.aidl \
 	frameworks/base/core/java/android/service/notification/StatusBarNotification.aidl \
 	frameworks/base/core/java/android/speech/tts/Voice.aidl \
 	frameworks/base/core/java/android/app/usage/UsageEvents.aidl \
diff --git a/api/current.txt b/api/current.txt
index d5a84ae..c8d4c74 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20,6 +20,7 @@
     field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
     field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
     field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
+    field public static final java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
     field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
@@ -26879,6 +26880,83 @@
 
 }
 
+package android.service.carriermessaging {
+
+  public abstract class CarrierMessagingService extends android.app.Service {
+    ctor public CarrierMessagingService();
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public int onDownloadMms(android.net.Uri, java.lang.String);
+    method public boolean onFilterSms(android.service.carriermessaging.MessagePdu, java.lang.String, int);
+    method public android.service.carriermessaging.CarrierMessagingService.SendSmsResponse onSendDataSms(byte[], java.lang.String, java.lang.String, int);
+    method public android.service.carriermessaging.CarrierMessagingService.SendMmsResult onSendMms(android.net.Uri, java.lang.String);
+    method public java.util.List<android.service.carriermessaging.CarrierMessagingService.SendSmsResponse> onSendMultipartTextSms(java.util.List<java.lang.String>, java.lang.String, java.lang.String);
+    method public android.service.carriermessaging.CarrierMessagingService.SendSmsResponse onSendTextSms(java.lang.String, java.lang.String, java.lang.String);
+    field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
+    field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
+    field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final int SEND_STATUS_ERROR = 2; // 0x2
+    field public static final int SEND_STATUS_OK = 0; // 0x0
+    field public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.carriermessaging.CarrierMessagingService";
+  }
+
+  public static final class CarrierMessagingService.SendMmsResult {
+    ctor public CarrierMessagingService.SendMmsResult(int, byte[]);
+    method public int getResult();
+    method public byte[] getSendConfPdu();
+  }
+
+  public static final class CarrierMessagingService.SendSmsResponse implements android.os.Parcelable {
+    ctor public CarrierMessagingService.SendSmsResponse(int, byte[], int);
+    method public int describeContents();
+    method public byte[] getAckPdu();
+    method public int getErrorCode();
+    method public int getMessageRef();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.carriermessaging.CarrierMessagingService.SendSmsResponse> CREATOR;
+  }
+
+  public abstract interface ICarrierMessagingCallback implements android.os.IInterface {
+    method public abstract void onDownloadMmsComplete(int) throws android.os.RemoteException;
+    method public abstract void onFilterComplete(boolean) throws android.os.RemoteException;
+    method public abstract void onSendMmsComplete(int, byte[]) throws android.os.RemoteException;
+    method public abstract void onSendMultipartSmsComplete(int, java.util.List<android.service.carriermessaging.CarrierMessagingService.SendSmsResponse>) throws android.os.RemoteException;
+    method public abstract void onSendSmsComplete(int, android.service.carriermessaging.CarrierMessagingService.SendSmsResponse) throws android.os.RemoteException;
+  }
+
+  public static abstract class ICarrierMessagingCallback.Stub extends android.os.Binder implements android.service.carriermessaging.ICarrierMessagingCallback {
+    ctor public ICarrierMessagingCallback.Stub();
+    method public android.os.IBinder asBinder();
+    method public static android.service.carriermessaging.ICarrierMessagingCallback asInterface(android.os.IBinder);
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+  }
+
+  public abstract interface ICarrierMessagingService implements android.os.IInterface {
+    method public abstract void downloadMms(android.net.Uri, java.lang.String, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+    method public abstract void filterSms(android.service.carriermessaging.MessagePdu, java.lang.String, int, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+    method public abstract void sendDataSms(byte[], java.lang.String, java.lang.String, int, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+    method public abstract void sendMms(android.net.Uri, java.lang.String, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+    method public abstract void sendMultipartTextSms(java.util.List<java.lang.String>, java.lang.String, java.lang.String, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+    method public abstract void sendTextSms(java.lang.String, java.lang.String, java.lang.String, android.service.carriermessaging.ICarrierMessagingCallback) throws android.os.RemoteException;
+  }
+
+  public static abstract class ICarrierMessagingService.Stub extends android.os.Binder implements android.service.carriermessaging.ICarrierMessagingService {
+    ctor public ICarrierMessagingService.Stub();
+    method public android.os.IBinder asBinder();
+    method public static android.service.carriermessaging.ICarrierMessagingService asInterface(android.os.IBinder);
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+  }
+
+  public final class MessagePdu implements android.os.Parcelable {
+    ctor public MessagePdu(java.util.List<byte[]>);
+    method public int describeContents();
+    method public java.util.List<byte[]> getPdus();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.carriermessaging.MessagePdu> CREATOR;
+  }
+
+}
+
 package android.service.dreams {
 
   public class DreamService extends android.app.Service implements android.view.Window.Callback {
diff --git a/core/java/android/service/carriermessaging/CarrierMessagingService.aidl b/core/java/android/service/carriermessaging/CarrierMessagingService.aidl
new file mode 100644
index 0000000..50c438a
--- /dev/null
+++ b/core/java/android/service/carriermessaging/CarrierMessagingService.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.service.carriermessaging;
+
+parcelable CarrierMessagingService.SendSmsResponse;
\ No newline at end of file
diff --git a/core/java/android/service/carriermessaging/CarrierMessagingService.java b/core/java/android/service/carriermessaging/CarrierMessagingService.java
new file mode 100644
index 0000000..101f69b
--- /dev/null
+++ b/core/java/android/service/carriermessaging/CarrierMessagingService.java
@@ -0,0 +1,370 @@
+/*
+ * 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.service.carriermessaging;
+
+import android.annotation.Nullable;
+import android.annotation.SdkConstant;
+import android.app.Service;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import java.util.List;
+
+/**
+ * A service that receives calls from the system when new SMS and MMS are
+ * sent or received.
+ * <p>To extend this class, you must declare the service in your manifest file with
+ * the {@link android.Manifest.permission#BIND_CARRIER_MESSAGING_SERVICE} permission
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * <pre>
+ * &lt;service android:name=".MyMessagingService"
+ *          android:label="&#64;string/service_name"
+ *          android:permission="android.permission.BIND_CARRIER_MESSAGING_SERVICE">
+ *     &lt;intent-filter>
+ *         &lt;action android:name="android.service.carriermessaging.CarrierMessagingService" />
+ *     &lt;/intent-filter>
+ * &lt;/service></pre>
+ */
+public abstract class CarrierMessagingService extends Service {
+    /**
+     * The {@link android.content.Intent} that must be declared as handled by the service.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE
+            = "android.service.carriermessaging.CarrierMessagingService";
+
+    /**
+     * Indicates that an SMS or MMS message was successfully sent.
+     */
+    public static final int SEND_STATUS_OK = 0;
+
+    /**
+     * SMS/MMS sending failed. We should retry via the carrier network.
+     */
+    public static final int SEND_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
+
+    /**
+     * SMS/MMS sending failed. We should not retry via the carrier network.
+     */
+    public static final int SEND_STATUS_ERROR = 2;
+
+    /**
+     * Successfully downloaded an MMS message.
+     */
+    public static final int DOWNLOAD_STATUS_OK = 0;
+
+    /**
+     * MMS downloading failed. We should retry via the carrier network.
+     */
+    public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1;
+
+    /**
+     * MMS downloading failed. We should not retry via the carrier network.
+     */
+    public static final int DOWNLOAD_STATUS_ERROR = 2;
+
+    private final ICarrierMessagingWrapper mWrapper = new ICarrierMessagingWrapper();
+
+    /**
+     * Implement this method to filter SMS messages.
+     *
+     * @param pdu the PDUs of the message
+     * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
+     * @param destPort the destination port of a binary SMS, this will be -1 for text SMS
+     *
+     * @return True to keep an inbound SMS message and delivered to SMS apps. False to
+     * drop the message.
+     */
+    public boolean onFilterSms(MessagePdu pdu, String format, int destPort) {
+        // optional
+        return true;
+    }
+
+    /**
+     * Implement this method to intercept text SMSs sent from the devcie.
+     *
+     * @param text the text to send
+     * @param format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     *
+     * @return a {@link SendSmsResponse}.
+     */
+    public SendSmsResponse onSendTextSms(String text, String format, String destAddress) {
+        // optional
+        return null;
+    }
+
+    /**
+     * Implement this method to intercept binary SMSs sent from the device.
+     *
+     * @param data the binary content
+     * @param format format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     * @param destPort the destination port
+     *
+     * @return a {@link SendSmsResponse}
+     */
+    public SendSmsResponse onSendDataSms(byte[] data, String format, String destAddress,
+            int destPort) {
+        // optional
+        return null;
+    }
+
+    /**
+     * Implement this method to intercept long SMSs sent from the device.
+     *
+     * @param parts a {@link List} of the message parts
+     * @param format format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     *
+     * @return a {@link List} of {@link SendSmsResponse}, one for each message part.
+     */
+    public List<SendSmsResponse> onSendMultipartTextSms(List<String> parts, String format,
+            String destAddress) {
+        // optional
+        return null;
+    }
+
+    /**
+     * Implement this method to intercept MMSs sent from the device.
+     *
+     * @param pduUri the content provider URI of the PDU to send
+     * @param locationUrl the optional URL to send this MMS PDU. If this is not specified,
+     *                    the PDU should be sent to the default MMSC URL.
+     *
+     * @return a {@link SendMmsResult}.
+     */
+    public SendMmsResult onSendMms(Uri pduUri, @Nullable String locationUrl) {
+        // optional
+        return null;
+    }
+
+    /**
+     * Implement this method to download MMSs received.
+     *
+     * @param contentUri the content provider URI of the PDU to be downloaded.
+     * @param locationUrl the URL of the message to be downloaded.
+     *
+     * @return a {@link SendMmsResult}.
+     */
+    public int onDownloadMms(Uri contentUri, String locationUrl) {
+        // optional
+        return DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (!SERVICE_INTERFACE.equals(intent.getAction())) {
+            return null;
+        }
+        return mWrapper;
+    }
+
+    /**
+     * The result of sending an MMS.
+     */
+    public static final class SendMmsResult {
+        private int mResult;
+        private byte[] mSendConfPdu;
+
+        public SendMmsResult(int result, byte[] sendConfPdu) {
+            mResult = result;
+            mSendConfPdu = sendConfPdu;
+        }
+
+        /**
+         * @return the result which is one of {@link #SEND_STATUS_OK},
+         *         {@link #SEND_STATUS_RETRY_ON_CARRIER_NETWORK}, and {@link #SEND_STATUS_ERROR}
+         */
+        public int getResult() {
+            return mResult;
+        }
+
+        /**
+         * @return the SendConf PDU, which confirms that the message was sent.
+         */
+        public byte[] getSendConfPdu() {
+            return mSendConfPdu;
+        }
+    }
+
+    /**
+     * Object passed in callbacks upon successful completion of
+     * {@link ICarrierMessagingService#sendTextSms},
+     * {@link ICarrierMessagingService#sendDataSms}, and
+     * {@link ICarrierMessagingService#sendMultipartTextSms}.
+     * Contains message reference and ackPdu.
+     */
+    public static final class SendSmsResponse implements Parcelable {
+        private int mMessageRef;
+        private byte[] mAckPdu;
+        private int mErrorCode;
+
+        /**
+         * @param messageRef message reference of the just-sent SMS
+         * @param ackPdu ackPdu for the just-sent SMS
+         * @param errorCode error code. See 3GPP 27.005, 3.2.5 for GSM/UMTS,
+         *     3GPP2 N.S0005 (IS-41C) Table 171 for CDMA, -1 if unknown or not applicable.
+         */
+        public SendSmsResponse(int messageRef, byte[] ackPdu, int errorCode) {
+            mMessageRef = messageRef;
+            mAckPdu = ackPdu;
+            mErrorCode = errorCode;
+        }
+
+        /**
+         * Returns the message reference of the just-sent SMS.
+         *
+         * @return the message reference
+         */
+        public int getMessageRef() {
+            return mMessageRef;
+        }
+
+        /**
+         * Returns the ackPdu for the just-sent SMS.
+         *
+         * @return the ackPdu
+         */
+        public byte[] getAckPdu() {
+            return mAckPdu;
+        }
+
+        /**
+         * Returns the error code upon encountering an error while sending the SMS, -1 if unknown or
+         * not applicable.
+         *
+         * @return errorCode the errorCode as defined in 3GPP 27.005, 3.2.5 for GSM/UMTS, and 3GPP2
+         * N.S0005 (IS-41C) Table 171 for CDMA, -1 if unknown or not applicable.
+         */
+        public int getErrorCode() {
+            return mErrorCode;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mMessageRef);
+            dest.writeByteArray(mAckPdu);
+            dest.writeInt(mErrorCode);
+        }
+
+        public static final Parcelable.Creator<SendSmsResponse> CREATOR
+                = new Parcelable.Creator<SendSmsResponse>() {
+                    @Override
+                    public SendSmsResponse createFromParcel(Parcel source) {
+                        return new SendSmsResponse(source.readInt(),
+                                                   source.createByteArray(),
+                                                   source.readInt());
+                    }
+
+                    @Override
+                    public SendSmsResponse[] newArray(int size) {
+                        return new SendSmsResponse[size];
+                    }
+        };
+    }
+
+    /**
+     * A wrapper around ICarrierMessagingService to enable the carrier messaging APP to implement
+     * methods it cares about in the {@link ICarrierMessagingService} interface.
+     */
+    private class ICarrierMessagingWrapper extends ICarrierMessagingService.Stub {
+        @Override
+        public void filterSms(MessagePdu pdu, String format, int destPort,
+                              ICarrierMessagingCallback callback) {
+            try {
+                callback.onFilterComplete(onFilterSms(pdu, format, destPort));
+            } catch (RemoteException ex) {
+            }
+        }
+
+        @Override
+        public void sendTextSms(String text, String format, String destAddress,
+                                ICarrierMessagingCallback callback) {
+            try {
+                SendSmsResponse sendSmsResponse = onSendTextSms(text, format, destAddress);
+                if (sendSmsResponse == null) {
+                    callback.onSendSmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
+                } else {
+                    callback.onSendSmsComplete(SEND_STATUS_OK, sendSmsResponse);
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+
+        @Override
+        public void sendDataSms(byte[] data, String format, String destAddress, int destPort,
+                                ICarrierMessagingCallback callback) {
+            try {
+                SendSmsResponse sendSmsResponse = onSendDataSms(data, format, destAddress,
+                        destPort);
+                if (sendSmsResponse == null) {
+                    callback.onSendSmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
+                } else {
+                    callback.onSendSmsComplete(SEND_STATUS_OK, sendSmsResponse);
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+
+        @Override
+        public void sendMultipartTextSms(List<String> parts, String format, String destAddress,
+                                         ICarrierMessagingCallback callback) {
+            try {
+                List<SendSmsResponse> sendSmsResponses =
+                        onSendMultipartTextSms(parts, format, destAddress);
+                if (sendSmsResponses == null) {
+                    callback.onSendMultipartSmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
+                } else {
+                    callback.onSendMultipartSmsComplete(SEND_STATUS_OK, sendSmsResponses);
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+
+        @Override
+        public void sendMms(Uri pduUri, String locationUrl, ICarrierMessagingCallback callback) {
+            try {
+                SendMmsResult result = onSendMms(pduUri, locationUrl);
+                if (result == null) {
+                    callback.onSendMmsComplete(SEND_STATUS_RETRY_ON_CARRIER_NETWORK, null);
+                } else {
+                    callback.onSendMmsComplete(SEND_STATUS_OK, result.getSendConfPdu());
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+
+        @Override
+        public void downloadMms(Uri contentUri, String locationUrl,
+                ICarrierMessagingCallback callback) {
+            try {
+                callback.onDownloadMmsComplete(onDownloadMms(contentUri, locationUrl));
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+}
diff --git a/core/java/android/service/carriermessaging/CarrierMessagingServiceManager.java b/core/java/android/service/carriermessaging/CarrierMessagingServiceManager.java
new file mode 100644
index 0000000..56ee2c1
--- /dev/null
+++ b/core/java/android/service/carriermessaging/CarrierMessagingServiceManager.java
@@ -0,0 +1,97 @@
+/*
+ * 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.service.carriermessaging;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+
+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 carirer 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) {
+        }
+    }
+}
diff --git a/core/java/android/service/carriermessaging/ICarrierMessagingCallback.aidl b/core/java/android/service/carriermessaging/ICarrierMessagingCallback.aidl
new file mode 100644
index 0000000..da56ad1
--- /dev/null
+++ b/core/java/android/service/carriermessaging/ICarrierMessagingCallback.aidl
@@ -0,0 +1,33 @@
+/**
+ * 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.service.carriermessaging;
+
+import android.service.carriermessaging.CarrierMessagingService;
+
+/**
+ * Callback interface definition for the Carrier Messaging Service client to get informed of the
+ * result of various API invocations.
+ */
+oneway interface ICarrierMessagingCallback {
+    void onFilterComplete(boolean keepMessage);
+    void onSendSmsComplete(
+        int result, in CarrierMessagingService.SendSmsResponse sendSmsResponse);
+    void onSendMultipartSmsComplete(
+        int result, in List<CarrierMessagingService.SendSmsResponse> sendSmsResponses);
+    void onSendMmsComplete(int result, in byte[] sendConfPdu);
+    void onDownloadMmsComplete(int result);
+}
diff --git a/core/java/android/service/carriermessaging/ICarrierMessagingService.aidl b/core/java/android/service/carriermessaging/ICarrierMessagingService.aidl
new file mode 100644
index 0000000..6e9e3fa
--- /dev/null
+++ b/core/java/android/service/carriermessaging/ICarrierMessagingService.aidl
@@ -0,0 +1,103 @@
+/**
+ * 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.service.carriermessaging;
+
+import android.net.Uri;
+import android.service.carriermessaging.ICarrierMessagingCallback;
+import android.service.carriermessaging.MessagePdu;
+
+/**
+ * <p class="note"><strong>Note:</strong>
+ * This service can only be implemented by a carrier privileged app.
+ */
+oneway interface ICarrierMessagingService {
+    /**
+     * Request filtering an incoming SMS message.
+     * The service will call callback.onFilterComplete with the filtering result.
+     *
+     * @param pdu the PDUs of the message
+     * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
+     * @param destPort the destination port of a data SMS. It will be -1 for text SMS
+     * @param callback the callback to notify upon completion
+     */
+    void filterSms(
+        in MessagePdu pdu, String format, int destPort, in ICarrierMessagingCallback callback);
+
+    /**
+     * Request sending a new text SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendSmsComplete} with the send
+     * status.
+     *
+     * @param text the text to send
+     * @param format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     * @param callback the callback to notify upon completion
+     */
+    void sendTextSms(String text, String format, String destAddress,
+            in ICarrierMessagingCallback callback);
+
+    /**
+     * Request sending a new data SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendSmsComplete} with the send
+     * status.
+     *
+     * @param data the data to send
+     * @param format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     * @param destPort port number of the recipient of the message
+     * @param callback the callback to notify upon completion
+     */
+    void sendDataSms(in byte[] data, String format, String destAddress, int destPort,
+            in ICarrierMessagingCallback callback);
+
+    /**
+     * Request sending a new multi-part text SMS from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendMultipartSmsComplete}
+     * with the send status.
+     *
+     * @param parts the parts of the multi-part text SMS to send
+     * @param format the format of the response PDU, typically "3gpp" or "3gpp2"
+     * @param destAddress phone number of the recipient of the message
+     * @param callback the callback to notify upon completion
+     */
+    void sendMultipartTextSms(in List<String> parts, String format, String destAddress,
+            in ICarrierMessagingCallback callback);
+
+    /**
+     * Request sending a new MMS PDU from the device.
+     * The service will call {@link ICarrierMessagingCallback#onSendMmsComplete} with the send
+     * status.
+     *
+     * @param pduUri the content provider URI of the PDU to send
+     * @param locationUrl the optional url to send this MMS PDU.
+     *         If this is not specified, PDU should be sent to the default MMSC url.
+     * @param callback the callback to notify upon completion
+     */
+    void sendMms(in Uri pduUri, String locationUrl, in ICarrierMessagingCallback callback);
+
+    /**
+     * Request downloading a new MMS.
+     * The service will call {@link ICarrierMessagingCallback#onDownloadMmsComplete} with the
+     * download status.
+     *
+     * @param pduUri the content provider URI of the PDU to be downloaded.
+     * @param locationUrl the URL of the message to be downloaded.
+     * @param callback the callback to notify upon completion
+     */
+    void downloadMms(in Uri pduUri, String locationUrl, in ICarrierMessagingCallback callback);
+}
+
diff --git a/core/java/android/service/carriermessaging/MessagePdu.aidl b/core/java/android/service/carriermessaging/MessagePdu.aidl
new file mode 100644
index 0000000..82b3fb3
--- /dev/null
+++ b/core/java/android/service/carriermessaging/MessagePdu.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.service.carriermessaging;
+
+parcelable MessagePdu;
\ No newline at end of file
diff --git a/core/java/android/service/carriermessaging/MessagePdu.java b/core/java/android/service/carriermessaging/MessagePdu.java
new file mode 100644
index 0000000..b81719f
--- /dev/null
+++ b/core/java/android/service/carriermessaging/MessagePdu.java
@@ -0,0 +1,94 @@
+/*
+ * 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.service.carriermessaging;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A parcelable list of PDUs representing contents of a possibly multi-part SMS.
+ */
+public final class MessagePdu implements Parcelable {
+    private static final int NULL_LENGTH = -1;
+
+    private final List<byte[]> mPduList;
+
+    /**
+     * @param pduList the list of message PDUs
+     */
+    public MessagePdu(List<byte[]> pduList) {
+        mPduList = pduList;
+    }
+
+    /**
+     * Returns the contents of a possibly multi-part SMS.
+     *
+     * @return the list of PDUs
+     */
+    public List<byte[]> getPdus() {
+        return mPduList;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Writes the PDU into a {@link Parcel}.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (mPduList == null) {
+            dest.writeInt(NULL_LENGTH);
+        } else {
+            dest.writeInt(mPduList.size());
+            for (byte[] messagePdu : mPduList) {
+                dest.writeByteArray(messagePdu);
+            }
+        }
+    }
+
+    /**
+     * Constructs a {@link MessagePdu} from a {@link Parcel}.
+     */
+    public static final Parcelable.Creator<MessagePdu> CREATOR
+            = new Parcelable.Creator<MessagePdu>() {
+                @Override
+                public MessagePdu createFromParcel(Parcel source) {
+                    int size = source.readInt();
+                    List<byte[]> pduList;
+                    if (size == NULL_LENGTH) {
+                        pduList = null;
+                    } else {
+                        pduList = new ArrayList<>(size);
+                        for (int i = 0; i < size; i++) {
+                            pduList.add(source.createByteArray());
+                        }
+                    }
+                    return new MessagePdu(pduList);
+                }
+
+                @Override
+                public MessagePdu[] newArray(int size) {
+                    return new MessagePdu[size];
+                }
+            };
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ffe2b60..2191ad6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2890,6 +2890,12 @@
         android:description="@string/permdesc_removeDrmCertificates"
         android:protectionLevel="signature|system" />
 
+    <!-- Must be required by a {@link android.service.carriermessaging.CarrierMessagingService}.
+         Any service that filters for this intent must be a carrier privileged app. -->
+    <permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"
+        android:label="@string/permlab_bindCarrierMessagingService"
+        android:description="@string/permdesc_bindCarrierMessagingService" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fe87919..d169843 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2209,6 +2209,11 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_removeDrmCertificates">Allows an application to remove DRM certficates. Should never be needed for normal apps.</string>
 
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindCarrierMessagingService">bind to a carrier messaging service</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindCarrierMessagingService">Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps.</string>
+
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->