I am creating an application for android OS, which allows user to send encrypted SMS to other users. But my application has only interface for sending an SMS, not for showing it. When application receives an SMS, I wan't to decrypt it and then somehow to show the decrypted SMS through the bult-in SMS Application. Is there a way to accomplish that? For now my receiver just shows the SMS using Toast.
Here is Receiver's code (It is not full but you will get the idea):
public class SMSReceiver extends BroadcastReceiver{
private static final byte HANDSHAKE_ID = (byte) 120;
private static final byte ENCRYPTED_ID = (byte) 125;
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Bundle pudsBundle = intent.getExtras();
Object[] pdus = (Object[]) pudsBundle.get("pdus");
SmsMessage messages = SmsMessage.createFromPdu((byte[]) pdus[0]);
Log.i("Message: ", messages.getMessageBody());
String msgBody = messages.getDisplayMessageBody();
byte[] msgBytes = msgBody.getBytes();
if ( msgBytes[0] == HANDSHAKE_ID ) {
//Obtain secret key from message
//TO-DO
Toast.makeText(context, "Received a secret key from: " + messages.getOriginatingAddress(), Toast.LENGTH_LONG).show();
} else if ( msgBytes[0] == ENCRYPTED_ID ) {
//Obtain encrypted message
//TO-DO
Toast.makeText(context, plainText, Toast.LENGTH_LONG).show();
}
}
Also if it is possible I want to prevent other Apps to see(receive) the message if first byte of the message is one of following constants: HANDSHAKE_ID or ENCRYPTED_ID and visible after decryption? But the main problem that I wan't to solve is how to show plaintext with Android's Built-In SMS Application. Thanks!
Related
I have created an android application that listens for incoming sms. The issue i am encountering is that it also reads previous sms. The goal of the app was to grab sms from a specific originating address and store it in a database.
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Log.i(TAG, "Intent Received: "+intent.getAction());
if (intent.getAction()==SMS_RECEIVED){
Bundle dataBundle = intent.getExtras();
if(dataBundle != null){
//creating PDU protocol Data unit object which is a protocol for transferring message
Object[] mypdu = (Object[])dataBundle.get("pdus");
final SmsMessage[] message = new SmsMessage[mypdu.length];
for(int i =0; i< mypdu.length; i++){
//for build version >= API
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
String format = dataBundle.getString("format");
//From PDU we get all object and smsMessage using following line of code
message[i] = SmsMessage.createFromPdu((byte[])mypdu[i],format);
}else{
message[i] = SmsMessage.createFromPdu((byte[]) mypdu[i]);
}
msg += message[i].getMessageBody().toString().replace("null","");
originatingAddress = message[i].getOriginatingAddress();
}
msg = msg.replace("null","");
if(originatingAddress.trim().equals("MPESA")) {
Toast.makeText(context.getApplicationContext(), "message: " + msg, Toast.LENGTH_SHORT).show();
}
}
}
// throw new UnsupportedOperationException("Not yet implemented");
}
}
Please try with below way
(1)The Simple way you can achieve to store the unique of record on every SMS is timestamp is only unique in this case whenever you get SMS store timestamp of every Sms as a Unique or primary key as you want in database, like system.currentTimeMillisecond to get time of current SMS and store as LONG type Column in your database,
(2) you can also check with unique time on every SMS get but it is complex to check with every existing records
Hope this process will help in your way with prevent of duplicate record store in database
I have an auto reply sms Android application I built and I don't want the auto reply (sent sms) to show in the default messaging app. I have searched and searched and couldn't find an answer. Is there a way to bypass writing the sent sms into the default messaging app?
Here my BroadcastReciever I am using to get the data and send out the message
public class SmsReceiver extends BroadcastReceiver {
ParseUser user = ParseUser.getCurrentUser();
// Auto reply message composed of the current reply and url from that business
String msg = user.getString("myCurrentReply") + " " + user.getString("couponUrlChosen");
List smsFromList = user.getList("smsFrom");
String userName = (String) user.get("username");
#Override
public void onReceive(final Context context, Intent intent) {
Bundle bundle = intent.getExtras();
Object messages[] = (Object[]) bundle.get("pdus");
SmsMessage smsMessage[] = new SmsMessage[messages.length];
for (int n = 0; n < messages.length; n++) {
smsMessage[n] = SmsMessage.createFromPdu((byte[]) messages[n]);
}
final String pno = smsMessage[0].getOriginatingAddress();
user.put("lastSmsFrom", pno);
user.saveInBackground();
// show first message
Toast toast = Toast.makeText(context, "Received SMS: " + smsMessage[0].getMessageBody(), Toast.LENGTH_LONG);
toast.show();
// Check Phone Number from SMS Received against Array in User Row
ParseQuery<ParseObject> query = ParseQuery.getQuery("_User");
Log.d("Username: ", userName);
query.whereEqualTo("username", userName);
query.whereContainedIn("lastSmsFrom", smsFromList);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> smsList, ParseException e) {
if (e == null) {
Log.d("Errors", "none");
if (smsList.size() == 0) {
// Send SMS
sendSms(pno, msg);
// Add Phone number to smsFrom in currentUsers Row
user.addUnique("smsFrom", pno);
// Save Phone Number in Array
user.saveInBackground();
Log.d("List size: ", " " + smsList.size());
}
} else {
Log.d("Error Message: ",
e.getMessage());
}
Log.d("Already sent to this number today. ", " " + smsList.size());
}
});
}
private void sendSms(String phonenumber, String message) {
SmsManager manager = SmsManager.getDefault();
manager.sendTextMessage(phonenumber, null, message, null, null);
}
}
Prior to KitKat, SMS sent using SmsManager require the app sending the message to insert it into the Provider, so it would just be a matter of omitting that.
Starting with KitKat, any app that is not the default SMS app and uses SmsManager to send messages will have the messages automatically written to the Provider for it by the system. There's no way to prevent this, and, furthermore, the app won't be able to delete those messages, either, as it won't have write access to the Provider.*
The app that is the default SMS app is responsible for writing its outgoing messages, so it would be able to omit that step. The system does no automatic writes for the default SMS app.
* There is a security hole in 4.4 only, by which a non-default app can gain write access to the Provider. It is detailed in my answer here, but it will not work in versions after KitKat.
i try to write an unit test on an BroadcastReceiver that gets informed when an SMS was received. Its not meant to be the default Application. Instead i just need this for an two factor authentication. For this case i created an PDU with [1].
But when i pass it down to the BroadcastReceiver the phone nr of the Sender never gets read by android it's just null. The body text is returned.
#TargetApi(Build.VERSION_CODES.KITKAT)
#Test
public void testOnReceive() throws Exception {
final byte[] decodedPDU = BaseEncoding.base16().decode(PDU);
final ReceiveSmsBroadcastReceiver receiveSmsBroadcastReceiver = spy(new ReceiveSmsBroadcastReceiver(true));
final Intent intent = new Intent();
intent.putExtra("format",SmsConstants.FORMAT_3GPP);
intent.putExtra("pdus", new Object[]{decodedPDU});
intent.setAction("android.provider.Telephony.SMS_RECEIVED");
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, 1);
receiveSmsBroadcastReceiver.onReceive(InstrumentationRegistry.getTargetContext(), intent);
In the receiver i do this to get the SMSMessage Objects:
#TargetApi(Build.VERSION_CODES.KITKAT)
private void getSMSKitKat(final Context context, final Intent intent) {
final SmsMessage[] messagesFromIntent = Telephony.Sms.Intents.getMessagesFromIntent(intent);
I receive an SmsMessage array here, the body message is correct. But i need to test my check sender phone number before i can notify the UI that the SMS is received: But nr is always null here:
private boolean isCorrectSender(#Nullable final SmsMessage message) {
if (message == null) {
return false;
}
final String nr = message.getOriginatingAddress();
Can someone point me whats wrong here ?
PS: SMSConstants and PhoneConstants are all framework classes i took from AOSP to get it running because those APIs are non public
[1] http://twit88.com/home/utility/sms-pdu-encode-decode
So I have this pretty simple app. It sends encrypted SMS messages to the specified phone number. It works swell, but I am having issues finding a way to make the recieved messages automatically show up in the message log. I currectly have a "refresh" button that updates the message log if a new message is available. I don't want to have to use a refresh button, I want the message to simply show up as it is received.
The way the app works is, it takes the message to be sent from the textbox and encrypts it. It then sends the message and when received, it decrypts and stores in a variable and presents in the message log (after I press "refresh").
I have tried many searches on google but can not find something useful because the words are too sensetive. I usually find links to people not being able to receive messages or just links to download messaging apps.
Here is some of my code. This is the receive sms part.
public class SmsReceiver extends BroadcastReceiver
{
public static String decrypted = "";
#Override
public void onReceive(Context context, Intent intent)
{
//---get the SMS message passed in---
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str ="";
String info = "";
if (bundle != null)
{
//---retrieve the SMS message received---
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for (int i=0; i<msgs.length; i++){
msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
info += "SMS from " + msgs[i].getOriginatingAddress();
info += " : ";
str += msgs[i].getMessageBody().toString();
if (i==msgs.length-1 && MainActivity.locked == true){
try {
decrypted = AESHelper.decrypt(MainActivity.seed, str);
} catch (Exception e) {
e.printStackTrace();
}
MainActivity.rand = Math.random();
MainActivity.seed = String.valueOf(MainActivity.rand);
decrypted = info + decrypted;
info = "";
MainActivity.locked = false;
}
}
}
So, in my main activity, I have the refresh button set to check the length of decrypted. If length of decrypted > 0 then I take decrypted's content and display them in the message log.
There are multiple ways to do this. Simple way would be to use TimerTask that runs every second in your MainActivity to check the length of 'decrypted' variable. Timertask does not run on ui thread. But since you are using it only to check the length of a variable you should be fine. If you need help with timertask, use my example below:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new SpecificTask(), 1000, 200);
But you have to define your SpecificTask() class...
private Specific Task extends TimerTask{
#Override
public void run() {
if(decrypted.length()>0){
//do refresh here but make sure you run this code onuithread
//just use runonuithread...
}
}
}
Or you could just use a handler object...
boolean mStopHandler = false;
Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
if (!mStopHandler) {
if(decrypted.length()>0){
//refreshlayout code
}
handler.postDelayed(this, 500);
}
}
};
// start your handler with:
handler.post(runnable);
I want to open incoming sms from notification directly to my application's intent , Please help I tried following code to read sms from inbox
public class SmsReceiver extends BroadcastReceiver
{
public static String BODY = "Test";
public static String ADDRESS = "5556";
#Override
public void onReceive(Context context, Intent intent)
{
//---get the SMS message passed in---
Bundle bundle = intent.getExtras();
SmsMessage[] msgs = null;
String str = "";
if (bundle != null)
{
//---retrieve the SMS message received---
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for (int i=0; i<msgs.length; i++){
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
str += "SMS from " + msgs[i].getOriginatingAddress();
str += " :";
str += msgs[i].getMessageBody().toString();
str += "\n";
ADDRESS=msgs[i].getOriginatingAddress();
BODY=str;
}
//---display the new SMS message---
Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
}
When a new SMS is received by your device, the android creates a intent and broadcasts the SMS_RECEIVED_ACTION. What you are going to do is create an Intent Filter for the activity of your application that handles the SMS that the phone receives.
When the phone gets a new SMS message and the user clicks on the notification, she is presented with a dialog of apps that can handle this action*****. Your app should be there, and when she decides that she wants your app to handle the incoming message then you can use the getMessagesFromIntent method in order to extract the message (you use that method inside your app).
PS: You cannot set your app as the default message app, which you probably need to do. The user has to explicitly choose your app to open the message, and if she wants it to be the default messaging app (by ticking the set as default checkbox).
Note: It looks like you have to create a broadcast receiver that receives the SMS_RECEIVED_ACTION which you can use prior to API 19 as a constant at android.provider.Telephony.SMS_RECEIVED and launch your own notifications in which you direct the user directly to the application of yours. Unfortunately it seems that the default messaging app will still issue notifications.
Credit: #Mike M.