diff options
Diffstat (limited to 'src/java/com')
6 files changed, 219 insertions, 4 deletions
diff --git a/src/java/com/android/internal/telephony/ISms.aidl b/src/java/com/android/internal/telephony/ISms.aidl index 1fd9f70..0f50ff0 100644 --- a/src/java/com/android/internal/telephony/ISms.aidl +++ b/src/java/com/android/internal/telephony/ISms.aidl @@ -18,6 +18,9 @@ package com.android.internal.telephony; import android.app.PendingIntent; import com.android.internal.telephony.SmsRawData; +import com.android.internal.telephony.ISmsMiddleware; + +import java.util.List; /** Interface for applications to access the ICC phone book. * @@ -34,6 +37,9 @@ import com.android.internal.telephony.SmsRawData; */ interface ISms { + void registerSmsMiddleware(String name, ISmsMiddleware middleware); + void synthesizeMessages(String originatingAddress, String scAddress, in List<String> messages, long timestampMillis); + /** * Retrieves all messages currently stored on ICC. * diff --git a/src/java/com/android/internal/telephony/ISmsMiddleware.aidl b/src/java/com/android/internal/telephony/ISmsMiddleware.aidl new file mode 100644 index 0000000..1268f2e --- /dev/null +++ b/src/java/com/android/internal/telephony/ISmsMiddleware.aidl @@ -0,0 +1,12 @@ +package com.android.internal.telephony; + +import android.app.PendingIntent; + +interface ISmsMiddleware { + boolean onSendText(in String destAddr, in String scAddr, in String text, + in PendingIntent sentIntent, in PendingIntent deliveryIntent); + + boolean onSendMultipartText(in String destinationAddress, in String scAddress, + in List<String> parts, in List<PendingIntent> sentIntents, + in List<PendingIntent> deliveryIntents); +}
\ No newline at end of file diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java index 525bcd9..b4d13fd 100644 --- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java +++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java @@ -18,6 +18,7 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.content.Context; +import android.os.RemoteException; import android.util.Log; import com.android.internal.util.HexDump; @@ -48,6 +49,14 @@ public abstract class IccSmsInterfaceManager extends ISms.Stub { "android.permission.SEND_SMS", message); } + @Override + public void registerSmsMiddleware(String name, ISmsMiddleware middleware) throws android.os.RemoteException { + } + + @Override + public void synthesizeMessages(String originatingAddress, String scAddress, List<String> messages, long timestampMillis) throws RemoteException { + } + /** * Send a data based SMS to a specific application port. * diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java index f80aa67..44882ef 100644 --- a/src/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java +++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java @@ -16,26 +16,86 @@ package com.android.internal.telephony; +import java.util.Hashtable; +import java.util.List; + +import android.app.Activity; import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.PowerManager; +import android.os.RemoteException; import android.os.ServiceManager; - -import java.util.List; +import android.os.SystemProperties; +import android.provider.Telephony.Sms.Intents; +import android.telephony.SmsMessage; public class IccSmsInterfaceManagerProxy extends ISms.Stub { private IccSmsInterfaceManager mIccSmsInterfaceManager; + private Hashtable<String, ISmsMiddleware> mMiddleware = new Hashtable<String, ISmsMiddleware>(); - public IccSmsInterfaceManagerProxy(IccSmsInterfaceManager - iccSmsInterfaceManager) { + public IccSmsInterfaceManagerProxy(Context context, + IccSmsInterfaceManager iccSmsInterfaceManager) { + this.mContext = context; this.mIccSmsInterfaceManager = iccSmsInterfaceManager; if(ServiceManager.getService("isms") == null) { ServiceManager.addService("isms", this); } + + createWakelock(); } public void setmIccSmsInterfaceManager(IccSmsInterfaceManager iccSmsInterfaceManager) { this.mIccSmsInterfaceManager = iccSmsInterfaceManager; } + private void createWakelock() { + PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SMSDispatcher"); + mWakeLock.setReferenceCounted(true); + } + + @Override + public void registerSmsMiddleware(String name, ISmsMiddleware middleware) throws android.os.RemoteException { + if (!"1".equals(SystemProperties.get("persist.sys.sms_debug", "0"))) { + mContext.enforceCallingPermission( + "android.permission.INTERCEPT_SMS", ""); + } + mMiddleware.put(name, middleware); + } + + private Context mContext; + private PowerManager.WakeLock mWakeLock; + private static final int WAKE_LOCK_TIMEOUT = 5000; + private void dispatchPdus(byte[][] pdus) { + Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION); + intent.putExtra("pdus", pdus); + intent.putExtra("format", SmsMessage.FORMAT_SYNTHETIC); + dispatch(intent, SMSDispatcher.RECEIVE_SMS_PERMISSION); + } + + private void dispatch(Intent intent, String permission) { + // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any + // receivers time to take their own wake locks. + mWakeLock.acquire(WAKE_LOCK_TIMEOUT); + mContext.sendOrderedBroadcast(intent, permission); + } + + @Override + public void synthesizeMessages(String originatingAddress, String scAddress, List<String> messages, long timestampMillis) throws RemoteException { + // if not running in debug mode + if (!"1".equals(SystemProperties.get("persist.sys.sms_debug", "0"))) { + mContext.enforceCallingPermission( + "android.permission.BROADCAST_SMS", ""); + } + byte[][] pdus = new byte[messages.size()][]; + for (int i = 0; i < messages.size(); i++) { + SyntheticSmsMessage message = new SyntheticSmsMessage(originatingAddress, scAddress, messages.get(i), timestampMillis); + pdus[i] = message.getPdu(); + } + dispatchPdus(pdus); + } + public boolean updateMessageOnIccEf(int index, int status, byte[] pdu) throws android.os.RemoteException { return mIccSmsInterfaceManager.updateMessageOnIccEf(index, status, pdu); @@ -58,12 +118,30 @@ public class IccSmsInterfaceManagerProxy extends ISms.Stub { public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { + for (ISmsMiddleware middleware: mMiddleware.values()) { + try { + if (middleware.onSendText(destAddr, scAddr, text, sentIntent, deliveryIntent)) + return; + } + catch (Exception e) { + // TOOD: remove the busted middleware? + } + } mIccSmsInterfaceManager.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent); } public void sendMultipartText(String destAddr, String scAddr, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) throws android.os.RemoteException { + for (ISmsMiddleware middleware: mMiddleware.values()) { + try { + if (middleware.onSendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents)) + return; + } + catch (Exception e) { + // TOOD: remove the busted middleware? + } + } mIccSmsInterfaceManager.sendMultipartText(destAddr, scAddr, parts, sentIntents, deliveryIntents); } diff --git a/src/java/com/android/internal/telephony/PhoneProxy.java b/src/java/com/android/internal/telephony/PhoneProxy.java index 7cef426..38fe68d 100644 --- a/src/java/com/android/internal/telephony/PhoneProxy.java +++ b/src/java/com/android/internal/telephony/PhoneProxy.java @@ -71,6 +71,7 @@ public class PhoneProxy extends Handler implements Phone { mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean( TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false); mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy( + phone.getContext(), phone.getIccSmsInterfaceManager()); mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy( phone.getIccPhoneBookInterfaceManager()); diff --git a/src/java/com/android/internal/telephony/SyntheticSmsMessage.java b/src/java/com/android/internal/telephony/SyntheticSmsMessage.java new file mode 100644 index 0000000..14bfca8 --- /dev/null +++ b/src/java/com/android/internal/telephony/SyntheticSmsMessage.java @@ -0,0 +1,109 @@ +package com.android.internal.telephony; + +import org.json.JSONObject; + +import com.android.internal.telephony.SmsConstants.MessageClass; + +public class SyntheticSmsMessage extends SmsMessageBase { + public static class SyntheticAddress extends SmsAddress { + } + + public static boolean isSyntheticPdu(byte[] pdu) { + try { + JSONObject json = new JSONObject(new String(pdu)); + return json.optBoolean("synthetic", false); + } + catch (Exception e) { + } + return false; + } + + public static SyntheticSmsMessage createFromPdu(byte[] pdu) { + try { + // TODO: use Parcelable or Bundle or something that serializes? + JSONObject json = new JSONObject(new String(pdu)); + SyntheticSmsMessage message = new SyntheticSmsMessage( + json.getString("originatingAddress"), + json.optString("scAddress", null), + json.getString("messageBody"), + json.getLong("timestampMillis")); + return message; + } + catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public SyntheticSmsMessage(String originatingAddress, String scAddress, String messageBody, long timestampMillis) { + this.originatingAddress = new SyntheticAddress(); + this.originatingAddress.address = originatingAddress; + + this.messageBody = messageBody; + this.scTimeMillis = timestampMillis; + this.scAddress = scAddress; + + try { + JSONObject json = new JSONObject(); + json.put("originatingAddress", originatingAddress); + json.put("scAddress", scAddress); + json.put("messageBody", messageBody); + json.put("timestampMillis", timestampMillis); + json.put("synthetic", true); + this.mPdu = json.toString().getBytes(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public MessageClass getMessageClass() { + return SmsConstants.MessageClass.UNKNOWN; + } + + @Override + public int getProtocolIdentifier() { + return 0; + } + + @Override + public boolean isReplace() { + return false; + } + + @Override + public boolean isCphsMwiMessage() { + return false; + } + + @Override + public boolean isMWIClearMessage() { + return false; + } + + @Override + public boolean isMWISetMessage() { + return false; + } + + @Override + public boolean isMwiDontStore() { + return false; + } + + @Override + public int getStatus() { + return 0; + } + + @Override + public boolean isStatusReportMessage() { + return false; + } + + @Override + public boolean isReplyPathPresent() { + return false; + } +} |