Rocky
Rocky

Reputation: 3235

Auto Reply to WhatsApp message in background

I just checking out the Application, is doing auto reply to WhatsApp message in background. I also trying to doing so, but can't get success in it. I had tried :

 Intent sendIntent = new Intent();
 sendIntent.setAction(Intent.ACTION_SEND);
 sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
 sendIntent.setType("text/plain");
 sendIntent.setPackage("com.whatsapp");
 startActivity(sendIntent);

But it opening the WhatsApp application :(, not sending the message.

I go through with several links: Question1, Question2 also article on it but not getting satisfactory answer.

The application are accessing the notifications to get the messages, and replying to it, I also tried reading notifications using NotificationListenerService, and got success to read message :), but can't send reply to it, I want to know how they are sending the messages in the background without opening the application.

Upvotes: 7

Views: 5583

Answers (3)

fbiego
fbiego

Reputation: 418

After reading the notification, check if it has a reply action then use RemoteInput to reply on the notification. Check this answer https://stackoverflow.com/a/73017178/13222541

Upvotes: 0

Niza Siwale
Niza Siwale

Reputation: 2405

On a rooted device you can simply insert a message into the database /data/data/com.whatsapp/databases/msgstore.db like this.

Firstly get the contacts from the database. WhatsApp uses its own IDs for contacts(not user numbers) in the jid column, will have to get that and the display name.

 class Contact{
public String jid;
public String displayName;
public Contact(String displayName,String jid){
this.displayName = displayName;
this.jid = jid;
}
}
public List<Contact> getContacts(){
     Shell.SU.run("am force-stop com.whatsapp");
     Shell.SU.run("chmod 777 /data/data/com.whatsapp");
                        db = SQLiteDatabase.openOrCreateDatabase(new File("/data/data/com.whatsapp/databases/wa.db"), null);
                        List<Contact> contactList = new LinkedList<>();
                        String selectQuery = "SELECT  jid, display_name FROM wa_contacts where phone_type is not null and is_whatsapp_user = 1";
                        Cursor cursor = db.rawQuery(selectQuery, null);
                        if (cursor.moveToFirst()) {
                            do {
                                Contact contact = new Contact(cursor.getString(1), cursor.getString(0));
                                contactList.add(contact);
                            } while (cursor.moveToNext());
                        }
                        db.close();
}

Then send the message like so

    private void sendBigMessage(String jid, String msg, String file, String mimeType) {

     Shell.SU.run("am force-stop com.whatsapp");
 db = SQLiteDatabase.openOrCreateDatabase(new File("/data/data/com.whatsapp/databases/msgstore.db"), null);

            long l1;
            long l2;
            int k;
            String query2, query1;

            Random localRandom = new Random(20L);
            l1 = System.currentTimeMillis();
            l2 = l1 / 1000L;
            k = localRandom.nextInt();

            int mediaType = 0;

            if (mimeType == null || mimeType.length() < 2)
                mediaType = 0;
            else
                mediaType = (mimeType.contains("video")) ? 3
                        : (mimeType.contains("image")) ? 1
                        : (mimeType.contains("audio")) ? 2
                        : 0;

            ContentValues initialValues = new ContentValues();
            initialValues.put("key_remote_jid", jid);
            initialValues.put("key_from_me", 1);
            initialValues.put("key_id", l2 + "-" + k);
            initialValues.put("status", 1);
            initialValues.put("needs_push", 0);
            initialValues.put("timestamp", l1);
            initialValues.put("media_wa_type", mediaType);
            initialValues.put("media_name", file);
            initialValues.put("latitude", 0.0);
            initialValues.put("longitude", 0.0);
            initialValues.put("received_timestamp", l1);
            initialValues.put("send_timestamp", -1);
            initialValues.put("receipt_server_timestamp", -1);
            initialValues.put("receipt_device_timestamp", -1);
            initialValues.put("raw_data", -1);
            initialValues.put("recipient_count", 0);
            initialValues.put("media_duration", 0);

            if (!TextUtils.isEmpty(file) && !TextUtils.isEmpty(mimeType)) {
                //boolean isVideo = mimeType.contains("video");
                Bitmap bMap = null;
                File spec;
                if (mediaType == 3) {
                    spec = new File(vidFolder, file);
                    bMap = ThumbnailUtils.createVideoThumbnail(spec.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND);
                } else if(mediaType == 2) {
                    spec = new File(audFolder, file);
                }else{
                    spec = new File(imgFolder, file);
                    bMap = BitmapFactory.decodeFile(spec.getAbsolutePath());
                }
                long mediaSize = (file.equals("")) ? 0 : spec.length();
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                if(mediaType == 1 || mediaType ==3) {
                    bMap = Bitmap.createScaledBitmap(bMap, 100, 59, false);
                    bMap.compress(Bitmap.CompressFormat.JPEG, 60, bos);
                }
                byte[] bArray = bos.toByteArray();

                MediaData md = new MediaData();
                md.fileSize = mediaSize;
                md.file = spec;
                md.autodownloadRetryEnabled = true;
                byte[] arr = SerializationUtils.serialize(md);

                initialValues.put("thumb_image", arr);
                initialValues.put("quoted_row_id", 0);
                //initialValues.put("media_mime_type", mimeType);
                //initialValues.put("media_hash", "9vZ3oZyplgiZ40jJvo/sLNrk3c1fuLOA+hLEhEjL+rg=");
                initialValues.put("raw_data", bArray);
                initialValues.put("media_size", mediaSize);
                initialValues.put("origin", 0);
                initialValues.put("media_caption", msg);
            } else
                initialValues.put("data", msg);

            long idm = db.insert("messages", null, initialValues);

            query1 = " insert into chat_list (key_remote_jid) select '" + jid
                    + "' where not exists (select 1 from chat_list where key_remote_jid='" + jid + "');";

            query2 = " update chat_list set message_table_id = (select max(messages._id) from messages) where chat_list.key_remote_jid='" + jid + "';";


            ContentValues values = new ContentValues();
            values.put("docid", idm);
            values.put("c0content", "null  ");
            db.insert("messages_fts_content", null, values);


            db.execSQL(query1 + query2);
 db.close();
        }

Upvotes: 1

Sunny Kumar Aditya
Sunny Kumar Aditya

Reputation: 2846

I haven't tested this but I think this can be done via Read Notification Bar title, message using Accessibility Service Programmatically

and https://developer.android.com/reference/android/app/RemoteInput

From doc :

 public static final String KEY_QUICK_REPLY_TEXT = "quick_reply";
 Notification.Action action = new Notification.Action.Builder(
         R.drawable.reply, "Reply", actionIntent)
         .addRemoteInput(new RemoteInput.Builder(KEY_QUICK_REPLY_TEXT)
                 .setLabel("Quick reply").build())
         .build();

Upvotes: 3

Related Questions