Skip to main content

Android SMS/MMS in background using AsyncTask




Currently in android  from KITKAT sending SMS/MMS can be sent only by default SMS app. You have to make your app as default SMS app before sending sms/mms from your app (later we will discuss about this).
Newly from 5.x android has removed “Enable/Disable” of mobile data programmatically, so in this case you have to manually enable your mobile data from settings.
Here i am gonna use a library called “Android SMS/MMS/Google Voice Sending Library” which is created by Jacob Klinker.

To check whether app is default sms app or not add this in:
AndroidManifest.xml.
<!-- Activity that allows the user to send new SMS/MMS messages -->
        <activity android:name=".ComposeSmsActivity" >
            <intent-filter>
                <action android:name="android.intent.action.SEND" />                
                <action android:name="android.intent.action.SENDTO" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="sms" />
                <data android:scheme="smsto" />
                <data android:scheme="mms" />
                <data android:scheme="mmsto" />
            </intent-filter>
        </activity>
//add permission
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.provider.Telephony.SMS_RECEIVED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
 
Create a activity called ComposeSmsActivity to make your app default sms app: 
public class ComposeSmsActivity extends Activity {
    @Override
    protected void onResume() {
        super.onResume();

        final String myPackageName = getPackageName();
        if (!Telephony.Sms.getDefaultSmsPackage(this).equals(myPackageName)) {
            // App is not default.
            // Show the "not currently set as the default SMS app" interface
            View viewGroup = findViewById(R.id.not_default_app);
            viewGroup.setVisibility(View.VISIBLE);

            // Set up a button that allows the user to change the default SMS app
            Button button = (Button) findViewById(R.id.change_default_app);
            button.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    Intent intent =
                            new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
                    intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, 
                            myPackageName);
                    startActivity(intent);
                }
            });
        } else {
            // App is the default.
            // Hide the "not currently set as the default SMS app" interface
            View viewGroup = findViewById(R.id.not_default_app);
            viewGroup.setVisibility(View.GONE);
        }
    }
}

Create a AsyncTask for sending sms/mms in background. 

AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called onPreExecute, doInBackground, onProgressUpdate and onPostExecute.
AsyncTask must be subclassed to be used. The subclass will override at least one method (doInBackground(Params...)), and most often will override a second one (onPostExecute(Result).)

SMS/MMS AsyncTask.java:
 
public class SMSMMS_AsyncTask extends AsyncTask<String, Integer, String>
 {
    private Settings settings;
    Context mContext;
    public static String filePath;
    String TYPE = "";
    private static final int EOF = -1;
    String[] SendTo={"mobilenumber1","mobilenumber2"};
    String text = "";

    public SMSMMS_AsyncTask(Context context, String file_path, 
                              String Type, String text) {
        this.mContext = context;
        this.filePath=file_path;
        this.TYPE = Type;
        this.text = text;

        if (PreferenceManager.getDefaultSharedPreferences(mContext)
                .getBoolean("request_permissions", true) &&
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mContext.startActivity(new Intent(mContext, PermissionActivity.class));
            Log.e("SMSMMS_AsyncTask", "error starting permission intent");
            return;
        }
        initSettings();
    }

//onPreExecute() check setting to send the sms/mms:
@Override
    protected void onPreExecute() {
        super.onPreExecute();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !android.provider.Settings.System.canWrite(mContext)) {
            Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_WRITE_SETTINGS);
            intent.setData(Uri.parse("packagemContext.getPackageName()));
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            try {
                mContext.startActivity(intent);
            } catch (Exception e) {
                Log.e("SMSMMS_AsyncTask", "error starting permission intent", e);
            }
        }
    }

//In doInBackground() send the sms/mms:

    @Override
    protected String doInBackground(String... params) {
       com.klinker.android.send_message.Settings sendSettings = new com.klinker.android.send_message.Settings();
       sendSettings.setMmsc(settings.getMmsc());
       sendSettings.setProxy(settings.getMmsProxy());
       sendSettings.setPort(settings.getMmsPort());
 
       Transaction transaction = new Transaction(mContext, sendSettings);
       Message message = new Message("MMS message", SendTo);

       if (MMSTYPE.equals("IMAGE")) {
           message.setType(Message.TYPE_SMSMMS);
           BitmapFactory.Options bmOptions = new BitmapFactory.Options();
           message.setImage(BitmapFactory.decodeFile(filePath, bmOptions));
       } else if (MMSTYPE.equals("AUDIO")) {
           message.setType(Message.TYPE_VOICE);
           byte[] data = null;
           InputStream is = null;
           File file = new File(filePath);
           try {
               is = openInputStream(file);
               data = toByteArray(is, file.length());
           } catch (IOException e) {
               e.printStackTrace();
           }
           message.addAudio(data);
       } else if (MMSTYPE.equals("TEXT")) {
           message.setType(Message.TYPE_SMSMMS);
           message.setText(text);
       } 

       transaction.sendNewMessage(message, Transaction.NO_THREAD_ID);

      return null;
   }

   @Override
   protected void onPostExecute(String s) {
     super.onPostExecute(s);
   }
 
//Init the Apns setting:

 private void initSettings() {
    settings = Settings.get(mContext);
    if (TextUtils.isEmpty(settings.getMmsc())) {
       initApns();
    }
 }

 private void initApns() {
    ApnUtils.initDefaultApns(mContext, new ApnUtils.OnApnFinishedListener() {
    @Override
    public void onFinished() {
        settings = Settings.get(mContext, true); 
    }
   });
 }
Methods for converting audio file to ByteArray[] format:
public static FileInputStream openInputStream(File file) throws IOException {
   if (file.exists()) {
     if (file.isDirectory()) {
        throw new IOException("File '" + file + "' exists but is a directory");
     }
     if (file.canRead() == false) {
        throw new IOException("File '" + file + "' cannot be read");
     }
   } else {
      throw new FileNotFoundException("File '" + file + "' does not exist");
   }
  return new FileInputStream(file);
 }

 public static byte[] toByteArray(InputStream input, int size) throws IOException {
   if (size < 0) {
       throw new IllegalArgumentException("Size must be equal or greater than zero: " + size);
   }
   if (size == 0) {
       return new byte[0];
   }
   byte[] data = new byte[size];
   int offset = 0;
   int readed;
   while (offset < size && (readed = input.read(data, offset, size - offset)) != EOF) {
         offset += readed;
   }
   if (offset != size) {
       throw new IOException("Unexpected readed size. current: " + offset + ", excepted: " + size);
   }
  return data;
 }

 public static byte[] toByteArray(InputStream input, long size) throws IOException {
   if (size > Integer.MAX_VALUE) {
       throw new IllegalArgumentException("Size cannot be greater than Integer max value: " + size);
    }
    return toByteArray(input, (int) size);
 }

}
For more clarification try android sms/mms library sample.

Comments

Popular posts from this blog

Vertical AutoScrolling TextView in Android

In android by default we can scroll the text in horizontal using marquee in layout, but if we want to scroll the text in vertical its not possible by default. So here we will learn to create a custom TextView which will auto-scroll in vertical direction. Source Code:  VerticalScrollingTextView-Android Create a AutoScrollingTextView.class which extends TextView: @SuppressLint ( "AppCompatCustomView" ) public class AutoScrollingTextView extends TextView { private static final float DEFAULT_SPEED = 65.0f ; public Scroller scroller ; public float speed = DEFAULT_SPEED ; public boolean continuousScrolling = true; public AutoScrollingTextView (Context context) { super (context) ; init( null, 0 ) ; scrollerInstance(context) ; } public AutoScrollingTextView (Context context , AttributeSet attrs) { super (context , attrs) ; init(attrs , 0 ) ; scr

Flexbox inside the RecyclerView as a LayoutManager (FlexboxLayoutManager).

Currently google has release the Flexbox which can be used for building flexible layouts using FlexboxLayout, it can be interpreted as an advanced LinearLayout because both layouts align their child views sequentially. For more detail on this flexbox-layout But here we are gonna work on Flexbox with RecyclerView. Flexbox with a large number of items in a scrollable container! Let's first see what are the Supported attributes / features comparison Due to some characteristics of the RecyclerView, some Flexbox attributes are not available/not implemented to the FlexboxLayoutManager. Here is a quick overview of the attributes/features comparison between the two containers. Attribute / Feature FlexboxLayout                FlexboxLayoutManager (RecyclerView) flexDirection flexWrap (except wrap_reverse ) justifyContent alignItems alignContent - layout_order - layout_flexGrow layout_flexShrink layout_alignSelf layout_fl

Android RecyclerView and StaggeredGridLayoutManager with Picasso/Glide

This project is there in GitHub https://github.com/yuvaraj119/Picasso-RecyclerView-StaggeredGridLayoutManager You can download and start customizing it for your project also. How to use with Picasso Picasso + RecyclerView + StaggeredGridLayoutManager Its the enhanced version of this project https://github.com/pohh/slotmachinepicasso were there was a problem with Picasso + RecyclerView + StaggeredGridLayoutManager shuffles resizable recycler views infinitely issue posted on github https://github.com/square/picasso/issues/918 I have made some changes now it works with Picasso and Glide without any shuffles and position change Currently this project is done with Picasso If you want to use it with Glide How to use with Glide Glide + RecyclerView + StaggeredGridLayoutManager Add dependencies for Glide https://github.com/bumptech/glide Remove Picasso library from dependency and remove all the codes of Picasso from MyGridAdapter.java and also from other p