user790995
user790995

Reputation:

Sending a SMS on Android through ADB

I would like to be able to send a SMS from my Android phone while it's connected to my computer using the following ADB commands

adb shell am start -a android.intent.action.SENDTO -d sms:CCXXXXXXXXXX --es sms_body "SMS BODY GOES HERE" --ez exit_on_sent true
adb shell input keyevent 22
adb shell input keyevent 66

I've got this working however on the phone this will pop up a text message to the recipient with the body filled in and then click the send button and return to where you were. Is there any way to do this completely in the background so it would not interfere with anything happening on the phone?

Upvotes: 30

Views: 58741

Answers (9)

Mikhail
Mikhail

Reputation: 1

For Android 13 and Android 14:

adb shell service call isms 5 i32 0 s16 "com.android.mms.service" s16 "null" s16 "+7xxxxxxxxxxx" s16 "null" s16 "'MESSAGE'" s16 "null" s16 "null" i32 0 i64 0

Upvotes: 0

Ako
Ako

Reputation: 995

Android 13 function signature hasn't changed, but adb command fails when trying previous answers here with weird response.

void sendTextForSubscriber(in int subId, String callingPkg, String callingAttributionTag,
            in String destAddr, in String scAddr, in String text, in PendingIntent sentIntent,
            in PendingIntent deliveryIntent, in boolean persistMessageForNonDefaultSmsApp,
            in long messageId);

Unix shell alias in e.g. .bash_profile

alias sms='adb shell service call isms 5 i32 0 s16 "com.android.mms.service" s16 "null" s16 "$1" s16 "null" s16 "$2" s16 "null" s16 "null" i32 0 i64 0'

Usage: sms "+372xxxxxx" "Your message"


Windows CMD alias:

DOSKEY sms=adb shell service call isms 5 i32 0 s16 "com.android.mms.service" s16 "null" s16 "$1" s16 "null" s16 "'$*'" s16 "null" s16 "null" i32 0 i64 0

Add a *.bat/cmd file path to AutoRun value in HKLM\Software\Microsoft\Command Processor

Usage: sms +372xxxxxx Your message

Upvotes: 0

Forrest Holub
Forrest Holub

Reputation: 41

For Android 12 (sdk 31), please find the latest solution:

adb shell service call isms 5 i32 0 s16 "com.android.mms.service" s16 "null" s16 '+0123456789' s16 "null" s16 "text message body here" s16 "null" s16 "null" s16 "null" s16 "null"

This is based on the following function as found in the source code in case you'd like to change the "null" values:

void sendTextForSubscriber(
  in int subId, 
  String callingPkg, 
  String callingAttributionTag, 
  in String destAddr, 
  in String scAddr, 
  in String text, 
  in PendingIntent sentIntent,
  in PendingIntent deliveryIntent, 
  in boolean persistMessageForNonDefaultSmsApp,
  in long messageId);

This was tested successfully using Samsung Galaxy S21 and Motorola (new flagship) on T-Mobile network.

**note previous issue (reason for downvoted) was due to "services" instead of "service" in the package name. Uncertain why GS21 unaffected by these changes.

Upvotes: 3

Ameer Hamza
Ameer Hamza

Reputation: 21

For android version 8, I used this code:

Process process = new Process();
process.StartInfo.FileName = "adb.exe";
process.StartInfo.Arguments = "shell service call isms 7 i32 2  s16 'com.android.mms.service' s16 '" + 03001111111 + "' s16 'null' s16 '" + textBox1.Text + "' i32 0 i32 0";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start(); 

But sometime depend upon mobile phone in I use same code Samsung j5 version 8 but here I use isms 7 i32 8.

For android version 9, I used this code:

Process process = new Process();
process.StartInfo.FileName = "adb.exe";
process.StartInfo.Arguments = "shell service call isms 7 i32 2 s16 'com.android.mms.service' s16 '" + 03001111111 + "' s16 'null' s16 '" + textBox1.Text + "' i32 0 i32 0";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start(); 

For android version 6, I used this code:

Process process = new Process();
process.StartInfo.FileName = "adb.exe";
process.StartInfo.Arguments = "shell service call isms 7 i32 1 s16 'com.android.mms.service' s16 '" + 03001111111 + "' s16 'null' s16 '" + textBox1.Text + "' i32 0 i32 0";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start(); 

But I stuck in android version 11. I used to many conditions but not come to correct place.

Upvotes: 2

Taknok
Taknok

Reputation: 757

Short version :

Android 5 and older (here android 4):

adb shell service call isms 5 s16 "com.android.mms" s16 "+01234567890" s16 "+01SMSCNUMBER" s16 "Hello world !" i32 0 i32 0

Android 5 and later (here android 9):

adb shell service call isms 7 i32 0 s16 "com.android.mms.service" s16 "+1234567890" s16 "null" s16 "Hey\ you\ !" s16 "null" s16 "null"

Isms method number (5 and 7 above) may change with the android version . Read full explanation to understand it.


Full explanation for all android version :

Yes it exists ! but not with this command, because these input events are blocked in sleep mode. This solution depends on your android version, so I'm going to explain you for almost all version ...

1st, check if you have the service isms by running :

adb shell service check isms
Service isms: found

The answer is found, good, keep moving. The service isms have various "options" the syntax is :

service call name_service option args

The service name can be found by typing :

adb shell service list

It will display a lot of services avaible, but the interesting line is :

5       isms: [com.android.internal.telephony.ISms]

You can see com.android.internal.telephony.Isms, so on this link choose your android version (by changing branch), then navigate to : telephony/java/com/android/internal/telephony and open Isms.aidl

For the rest I will take the android Pie (android 9) file (link).

On the line 185 we have :

void sendTextForSubscriberWithSelfPermissions(...)

Note : before android 5 the method is named sendText(...).

It is the 7th declaration in the interface ISMS . So our option to send a sms is the number 7. On the top of the declaration there is the explanation of the arguments. Here a short version:

  • subId : after android 5, the SIM card you want to use 0, 1 or 2 depending of your android version (ex 0-1 for android 9 and 1-2 for android 8)
  • callingPkg : the name of the package that will send your sms (I explain how to find it later)
  • destinationAdress : the phone number of the message recipient
  • scAddress : your smsc is only need in android 5 and lower (explained after)
  • parts : your message !
  • sendIntends and deliveryIntents : you don't care

-> Find your package name : Explore your app file or download Package Name Viewer on google play, find your message application and copy the name (com.android...)

-> Find your smsc : In your application -> settings -> SMSC or Service Center or Message Center etc, copy the number display (DON'T CHANGE IT)

Just before finishing, in services the strings are declared by s16 and integers and PendingIntent with i32.

So for my example we have :

  • subId : 0
  • callingPkg : com.android.mms
  • target number : +01234567890
  • SMSC : +01000000000
  • My text : Hello world !
  • sendIntends and deliveryIntents we don't care so we put 0 to set it to default value.

Finally :

Android 5 and older (here android 4):

adb shell service call isms 5 s16 "com.android.mms" s16 "+01234567890" s16 "+01000000000" s16 "Hello world !" i32 0 i32 0

Android 5 and later (here android 9):

adb shell service call isms 7 i32 0 s16 "com.android.mms.service" s16 "+1234567890" s16 "null" s16 "'Hey you !'" s16 "null" s16 "null"

-> An example in a batch file :

The send.bat for android 4 :

echo off
set num=%1
shift
for /f "tokens=1,* delims= " %%a in ("%*") do set ALL_BUT_FIRST=%%b
echo %ALL_BUT_FIRST%
adb shell service call isms 5 s16 "com.android.mms" s16 "%num%" s16 "+01000000000" s16 "%ALL_BUT_FIRST%" i32 0 i32 0

run with :

send.bat +01234567890 Hey you !

Now tell me if it works with your android version :)

Edit : Corrected with information given by Alex P. Edit 2: Corrected with information given by Neil

Upvotes: 47

Vlatko Šurlan
Vlatko Šurlan

Reputation: 444

I've spent a LOT of time trying to get this right for my HTC Desire with SlimKat. Now I use this script that allows me to send an SMS almost instantly (yad GUI is extremely fast) with my PC keyboard. I just select a cellphone number (let's say 00165826453) and press WinKey+S and this opens up:

SMS app for Linux using yad

This is the BASH script that I developed for this:

#!/usr/bin/env bash

if [ $# -eq 1 ]; then
    phoneNumber=${1//[^0-9\+]/}
else
    phoneNumber=`xsel | sed 's/[^0-9\+]//g'`
fi

if [ -z "$phoneNumber" ]; then
    yadText=`yad --form --field="Phone number" --field="Multiline text:TXT" --width=400 --height=320 --title="Send SMS" --focus-field=1 --button="Send SMS:0"`
else
    yadText=`yad --form --field="Phone number" "$phoneNumber" --field="SMS text:TXT" --width=400 --height=320 --title="Send SMS" --focus-field=2 --button="Send SMS:0"`
fi

phoneNumber=${yadText//\|*/}
smsText=${yadText#*|}
smsText=${smsText%|*}

ssh root@noa "su shell service call isms 5 s16 \"com.android.mms\" s16 \"$phoneNumber\" s16 \"null\" s16 \"$smsText\" s16 \"null\" s16 \"null\""

It is phonomenaly useful and quick. The only drawback for me is that the sent SMS messages do not appear in the default SMS app on my SlimKat.

In order for this to work on your Debian derivative you have to:

aptDistro> sudo apt install yad bash

or the equivalent for your distro.

This works on my machine because I have setup an SSH server on my SlimKat install with key authentication. You could slightly modify it to work via ADB wirelessly.

Upvotes: 4

uphillbattle
uphillbattle

Reputation: 21

Thank you, Taknok, for a great answer.

I'm using a Samsung Galaxy S5 with Android version 6.0.1. On my phone, the SIM card subId is actually 3 (not 0, 1 or 2 as suggested in your answer). Took me I while to figure out, so I'm posting here in case others wonder about the same. This command worked:

adb shell service call isms 7 i32 3 s16 "com.android.mms" s16 "+123456789" s16 "+100000000" s16 "'Hello world'" i32 0 i32 0

Upvotes: 2

Maxime Pelletier
Maxime Pelletier

Reputation: 21

The answer below worked great for me ! In Android 5.02 the option is 12 and I figured out you could send null as the SMSC to use the default, so sending a SMS worked with :

adb shell service call isms 12 s16 "com.android.mms" s16 "+01234567890" s16 "null" s16 "Hello world" i32 0 i32 0

Upvotes: 2

Kerem Kusmezer
Kerem Kusmezer

Reputation: 500

Instead of this , write your own intentservice like the following. Create a entry for the following IntentService in your manifest.

String targetPhoneNumber = "XX-XXXXXXX-XXXXXX-XXXX";
SmsToSend targetSms = new SmsToSend();
String urlText = url;
targetSms.setPhoneNumbers(new String[]{targetPhoneNumber});
targetSms.setSmsBody("Help me");
Intent smsIntent = targetSms.convertToIntent(context);
        startService(smsIntent);


        import java.util.ArrayList;
        import android.app.IntentService;
        import android.app.PendingIntent;
        import android.content.Intent;

        public class SendStreamMessage extends IntentService {

        public SendStreamMessage() {
            super("Sms Sender Intent Service");
        }

        @Override
        protected void onHandleIntent(Intent intent) {
            sendSms(intent);
        }

        private void sendSms(Intent intent) {
            try {
                SmsToSend smsSend = (SmsToSend) intent
                        .getParcelableExtra("SMSMessage");
                Intent sentIntent = new Intent(SmsDeliveryHandlers.SENT_SMS_ACTION);

                PendingIntent sentPI = PendingIntent.getBroadcast(
                        SendStreamMessage.this, 0, sentIntent, 0);
                Intent deliveryIntent = new Intent(
                        SmsDeliveryHandlers.DELIVERED_SMS_ACTION);
                PendingIntent deliverPI = PendingIntent.getBroadcast(
                        SendStreamMessage.this, 0, deliveryIntent, 0);
                android.telephony.SmsManager smsManager = android.telephony.SmsManager
                        .getDefault();

                ArrayList<String> messages = smsManager.divideMessage(smsSend
                        .getSmsBody());

                int smsSize = messages.size();

                ArrayList<PendingIntent> sentPiList = new ArrayList<PendingIntent>(
                        smsSize);
                ArrayList<PendingIntent> deliverPiList = new ArrayList<PendingIntent>(
                        smsSize);

                for (int i = 0; i < smsSize; i++) {
                    sentPiList.add(sentPI);
                    deliverPiList.add(deliverPI);
                }

                if (smsSize > 1) {
                    for (int i = 0; i < smsSend.getPhoneNumbers().length; i++) {
                        String targetPhoneNumber = smsSend.getPhoneNumbers()[i];
                        SmsDeliveryHandlers handler = new SmsDeliveryHandlers(
                                targetPhoneNumber, smsSend.getSmsBody());
                        try {
                            smsManager.sendMultipartTextMessage(targetPhoneNumber,
                                    null, messages, sentPiList, deliverPiList);
                        } catch (Exception ex) {
                            handler.cleanReceiver();
                        }
                    }
                } else {
                    SmsDeliveryHandlers handler;
                    for (int i = 0; i < smsSend.getPhoneNumbers().length; i++) {
                        String targetPhoneNumber = smsSend.getPhoneNumbers()[i];
                        handler = new SmsDeliveryHandlers(targetPhoneNumber,
                                smsSend.getSmsBody());
                        try {
                            smsManager.sendTextMessage(targetPhoneNumber, null,
                                    smsSend.getSmsBody(), sentPI, deliverPI);
                        } catch (Exception ex) {
                            handler.cleanReceiver();
                        }
                    }
                }
            } finally {
            }
        }
    }

    import android.app.Activity;
    import android.content.BroadcastReceiver;
    import android.content.ContentResolver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.net.Uri;

    public final class SmsDeliveryHandlers extends BroadcastReceiver {
        public static final String SENT_SMS_ACTION = "SENT_SMS_ACTION";
        public static final String DELIVERED_SMS_ACTION = "DELIVERED_SMS_ACTION";
        private SmsToSend send;
        private Context context;
        private Uri sendboxUri;

        public SmsDeliveryHandlers(String phoneNumber, String message) {
            this(new SmsToSend(message, phoneNumber));
        }

        public SmsDeliveryHandlers(SmsToSend send) {
            this.send = send;
            IntentFilter targetFilter = new IntentFilter();
            targetFilter.addAction(SENT_SMS_ACTION);
            targetFilter.addAction(DELIVERED_SMS_ACTION); 
            context = MmsLiveApplication.getInstance().getTargetContext();
            context.registerReceiver(this, targetFilter);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            if (SENT_SMS_ACTION.equals(intent.getAction())) {
                handleSend();
            } else if (DELIVERED_SMS_ACTION.equals(intent.getAction())) {
                handleDelivery();
            }
        }
        private synchronized void handleSend() {
            String address = send.getPhoneNumbers()[0];
            ContentResolver contentResolver = context.getContentResolver();
            int resultCode = getResultCode();
            if(resultCode != Activity.RESULT_OK)
            {           
                cleanReceiver();
            }
        }

        public void cleanReceiver() {
            context.unregisterReceiver(this); 
        }

        private void handleDelivery() {
            switch (getResultCode()) {
            case Activity.RESULT_OK:
                // HACK This is a hack to insert the send sms result to the real
                // message send table ;)
                break;
            case Activity.RESULT_CANCELED:
                break;
            }
            cleanReceiver();
        }
    }

package com.ttech.mmslive.contacts;


import android.content.Context;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;

public class SmsToSend implements Parcelable{
    public static final Parcelable.Creator<SmsToSend> CREATOR = new Parcelable.Creator<SmsToSend>() {
        public SmsToSend createFromParcel(Parcel in) {
            return new SmsToSend(in);
        }
        public SmsToSend[] newArray(int size) {
            return new SmsToSend[size];
        }
    };
    public SmsToSend()
    {       
    }
    public SmsToSend(Parcel in) {
        readFromParcel(in);
    }   
    public SmsToSend(String smsBody,String phoneNumber)
    {
        this.smsBody = smsBody;
        phoneNumbers = new String[]{phoneNumber};
    }   
    public Intent convertToIntent(Context targetContext)
    {
        Intent targetIntent = new Intent(targetContext,SendStreamMessage.class);
        targetIntent.putExtra("SMSMessage", this);
        return targetIntent;
    }
    @Override
    public int describeContents() {
        return 0;
    }
    private String[] phoneNumbers; 
    private String smsBody;
    public String[] getPhoneNumbers() {
        return phoneNumbers;
    }
    public String getSmsBody() {
        return smsBody;
    }
    public void readFromParcel(Parcel in) {
        smsBody = in.readString();
        int length = in.readInt();
        if(length > 0)
        {
            phoneNumbers = new String[length];
            in.readStringArray(phoneNumbers);
        }
    }
    public void setPhoneNumbers(String[] phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }
    public void setSmsBody(String smsBody) {
        this.smsBody = smsBody;
    }
    @Override
    public void writeToParcel(Parcel parcel, int params) {
        parcel.writeString(smsBody);
        if(phoneNumbers != null && phoneNumbers.length > 0)
        {
            parcel.writeInt(phoneNumbers.length);
            parcel.writeStringArray(phoneNumbers);
        }
        else{
            parcel.writeInt(0);
        }
    }
}

Upvotes: 6

Related Questions