[Android Software/Hacking General [Developers Only]] kevmegforest:
I'm building a complete build of Android with tropo: (Google tropo)

Here's my tropo hosted script in javascript:

if (typeof number == 'undefined') {//IF the call doesn't come from me (there's no variable set)
var callerId=currentCall.callerID;
var textmessage=currentCall.initialText
hangup()
call('(Put your phone number Here', {network: 'SMS'});
//Analyse message and format it for sending
var message = new Array();
var nbMessages=((textmessage.length())/149) ;//.length() ????? why????
var i=0;
for(i=0;i<nbMessages;i++){
message[i]=callerId+textmessage.substr(i*149,149);
say(message[i]);
wait(1000);
}
hangup()
}
else //SENDING PART:number and text are parameters
{
call(number, {network:"SMS"});
say(text);
}

I've used the CM9 source code for the galaxy s2 that I downloaded and builded following this guide: (Google teamhacksung CyanogenMod9 How to build)

For sending, I simply post an HTTP Post request to my tropo app

Here's the code

I modified the SMSManager.java class in android.telephony package

public void sendTextMessage(
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
if (TextUtils.isEmpty(destinationAddress)) {
throw new IllegalArgumentException("Invalid destinationAddress");
}

if (TextUtils.isEmpty(text)) {
throw new IllegalArgumentException("Invalid message body");
}
/* OLD METHOD FOR SMS BY CARRIER
try {
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
if (iccISms != null) {
iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent);
}
} catch (RemoteException ex) {
// ignore it
}*/

//My new Method via tropo
//Création de l'objet Tropo SMS
TropoSms sms = new TropoSms(destinationAddress, text, sentIntent,deliveryIntent);
sms.send();

}
/**/
public void sendMultipartTextMessage(
String destinationAddress, String scAddress, ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
if (TextUtils.isEmpty(destinationAddress)) {
throw new IllegalArgumentException("Invalid destinationAddress");
}
if (parts == null || parts.size() < 1) {
throw new IllegalArgumentException("Invalid message body");
}

if (parts.size() > 1) {

/*//OLD METHOD FOR SMS CARRIER
try {
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
if (iccISms != null) {
iccISms.sendMultipartText(destinationAddress, scAddress, parts,
sentIntents, deliveryIntents);
}
} catch (RemoteException ex) {
// ignore it
}*/

//My tropo Method
for(int i=0; i< parts.size();i++){
TropoSms sms = new TropoSms(destinationAddress, parts.get(i), sentIntents.get(i),deliveryIntents.get(i));
sms.send();
}

} else {
PendingIntent sentIntent = null;
PendingIntent deliveryIntent = null;
if (sentIntents != null && sentIntents.size() > 0) {
sentIntent = sentIntents.get(0);
}
if (deliveryIntents != null && deliveryIntents.size() > 0) {
deliveryIntent = deliveryIntents.get(0);
}
sendTextMessage(destinationAddress, scAddress, parts.get(0),
sentIntent, deliveryIntent);
}
}

Here I created the Tropo SMS class in the android.telephony.tropo package

/**
*
*/
package android.telephony.tropo;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;

import android.telephony.SmsManager;

/**
* @author kevmegforest
*
*/
public class TropoSms {

protected String destinationAddress="Undefined";
protected String message="Undefined";
protected PendingIntent sentIntent;
protected PendingIntent deliveryIntent;
private static String token="1...4c";

public TropoSms(){
}
public TropoSms(String sendAddress, String text, PendingIntent sendIntent, PendingIntent deliverIntent){
destinationAddress=sendAddress;
message=text;
sentIntent=sendIntent;
deliveryIntent=deliverIntent;

}
/**------------------------------------------
* SETTERS AND GETTERS
* @return
*/
public String getDestinationAddress() {
return destinationAddress;
}

public String getMessage() {
return message;
}
//--------------------------------------------------
/**
* Methods
*/

public void send(){ //Success return true //Fail return false
boolean success=true;
this.message=manageText();
HttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000); //Timeout Limit
HttpResponse response;

HttpPost post = new HttpPost("https://api.tropo.com/1.0/sessions");

//Creating JSON object

JSONObject json= new JSONObject();
try {
json.put("token", token);

json.put("number", this.destinationAddress	);

json.put("text", this.message);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
success=false;

}

try {
StringEntity se = new StringEntity(json.toString());
post.setEntity(se);
//Post headers Setup
post.addHeader("accept", "application/json");
post.addHeader("content-type","application/json");
response=client.execute(post);
//Checking response
//HOW TO
if(response.getStatusLine().getStatusCode() !=200)
success=false;

} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
success =false;
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
success=false;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
success=false;
}
this.manageIntent(success);
client.getConnectionManager().shutdown();//Ending connection

}

private void manageIntent(boolean sendsuccess)
{
if(sendsuccess)
{
try {
this.sentIntent.send(Activity.RESULT_OK);
} catch (CanceledException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}else{
try {
this.sentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE);
} catch (CanceledException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}

private String manageText()
{
String correctedText=this.message;//The last character in each table is the one to replace with
char characterToReplaceA[]={'à','â','ä','a'};
char characterToReplaceC[]={'ç','c'};
char characterToReplaceE[]={'é','è','ê','ë','e'};
char characterToReplaceI[]={'ì','î','ï','i'};
char characterToReplaceO[]={'ò','ô','ö','o'};
char characterToReplaceU[]={'ù','û','ü','u'};
char characterToReplace[][]={characterToReplaceA,characterToReplaceC,characterToReplaceE,characterToReplaceI,characterToReplaceO,characterToReplaceU};
for(int i=0;i<characterToReplace.length;i++){
for(int j=0;j<(characterToReplace[i].length-1);j++){
correctedText=correctedText.replace(characterToReplace[i][j],characterToReplace[i][characterToReplace[i].length-1]);
correctedText=correctedText.replace(Character.toUpperCase(characterToReplace[i][j]),Character.toUpperCase(characterToReplace[i][characterToReplace[i].length-1]));

}
}

return correctedText;

}

}

The sending part works really well. Since it's an API change I can use any SMS App in android and it would work.

But I have a problem with receiving.

My tropo script can only modify the body message of the sms. So when someone send a SMS message to tropo, I prefixed the body message with 10 characters representing it's phone number like this:

original message: "Hello"

new message:"15551231234Hello"

I then send this message to my phone

The modified class SubmitPdu in android.telephony package in the SMSMessage.java file

It's wherethe SMS app get the sms with the createfrompdu() method

public static SmsMessage createFromPdu(byte[] pdu, String format) {
SmsMessageBase wrappedMessage;

if (FORMAT_3GPP2.equals(format)) {
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
} else if (FORMAT_3GPP.equals(format)) {
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
} else {
Log.e(LOG_TAG, "createFromPdu(): unsupported message format " + format);
return null;
}
//Verify here if it comes from TROPO
Log.d("SMSNumberCompare", "Original number:"+wrappedMessage.getOriginatingAddress());
Log.d("SMSNumberCompare", "Tropo number:"+TropoSmsReceiver.TROPO_APP_PHONE_NUMBER);

if(PhoneNumberUtils.compare(wrappedMessage.getOriginatingAddress(), TropoSmsReceiver.TROPO_APP_PHONE_NUMBER)){
Log.d("SMSNumberCompare", "Comparison:"+(PhoneNumberUtils.compare(wrappedMessage.getOriginatingAddress(), TropoSmsReceiver.TROPO_APP_PHONE_NUMBER)));
//Creating TropoReceive Object
TropoSmsReceiver tropo = (TropoSmsReceiver) wrappedMessage; //Downcasting
tropo.formatFromTropo();
//upcasting
wrappedMessage=tropo;
}

return new SmsMessage(wrappedMessage);
}

And here's my TropoSmsReceiver Class which extends the SmsMessageBase class

package com.android.internal.telephony.tropo;

import android.telephony.PhoneNumberUtils;
import android.telephony.SmsMessage.MessageClass;
import android.util.Log;

import com.android.internal.telephony.SmsMessageBase;

public class TropoSmsReceiver extends SmsMessageBase {

public final static String TROPO_APP_PHONE_NUMBER="###########";

//My new Methods
//this method will format the text to get the parameters transferred from the tropo text
public void formatFromTropo(){
Log.d("TropoFormat", "old address"+this.originatingAddress.address);
this.originatingAddress.address=PhoneNumberUtils.formatNumber(this.messageBody.substring(0, 10), PhoneNumberUtils.FORMAT_NANP );
Log.d("TropoFormat", "new address"+this.originatingAddress.address);
this.messageBody=this.messageBody.substring(11);
Log.d("TropoFormat", "new Body"+this.messageBody);
}

@Override
public MessageClass getMessageClass() {
// TODO Auto-generated method stub
return null;
}

@Override
public int getProtocolIdentifier() {
// TODO Auto-generated method stub
return 0;
}

@Override
public boolean isReplace() {
// TODO Auto-generated method stub
return false;
}

@Override
public boolean isCphsMwiMessage() {
// TODO Auto-generated method stub
return false;
}

@Override
public boolean isMWIClearMessage() {
// TODO Auto-generated method stub
return false;
}

@Override
public boolean isMWISetMessage() {
// TODO Auto-generated method stub
return false;
}

@Override
public boolean isMwiDontStore() {
// TODO Auto-generated method stub
return false;
}

@Override
public int getStatus() {
// TODO Auto-generated method stub
return 0;
}

@Override
public boolean isStatusReportMessage() {
// TODO Auto-generated method stub
return false;
}

@Override
public boolean isReplyPathPresent() {
// TODO Auto-generated method stub
return false;
}

}

The interesting part is my new method formatFromTropo()

But I have a problem, it doesn't work.

It builds sucessfully

In the logcat, the debug log says it goes in the if statement (it says Comparison: true and it's placement is in the if)

But when the tropo.formatFromTropo() is called the catlog has no mention of any log declared in the TropoSmsReceiver File. How is that possible? Can you help me?

It's my first android project (app or android Source change) and java project so you can give me many recommendations(and comments) too. :o

Thank you