7

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.

Rocky
  • 2,903
  • 1
  • 22
  • 26
  • You need a number to send message. You've to send to a specific number. – AA Shakil Jun 18 '18 at 10:31
  • @AAShakil did you check the application, which i mention above in application, it didn't take any user input, it directly reply to WhatsApp message. – Rocky Jun 19 '18 at 02:15
  • honestly I think they did a workaround to [click to chat](https://blog.cloudrail.com/whatsapp-api-how-to-use-the-whatsapp-chat-api/). You can try like opening this in a custom webview and clicking the button by code. But not sure – Pier Giorgio Misley Jun 19 '18 at 07:53
  • https://stackoverflow.com/questions/28980078/read-notification-bar-title-message-using-accessibility-service-programmaticall – Sunny Kumar Aditya Jun 20 '18 at 09:54
  • @Rocky have you got the solution for this ! – bhanu kaushik Jul 23 '19 at 09:45

3 Answers3

3

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();
Sunny Kumar Aditya
  • 2,806
  • 4
  • 26
  • 38
1

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();
        }
Niza Siwale
  • 2,390
  • 1
  • 18
  • 20
  • I wanted to know to do this on non-rooted device. – Rocky Jun 21 '18 at 12:41
  • On non rooted devices, there is probably a Broadcast Receiver that Google now and WhatsApp use to communicate. Unfortunately it is not public – Niza Siwale Jun 21 '18 at 12:43
  • actually this is not working. On my app I have privilege to read and write to external memory, Whatsapp is correctly terminated with the su command, but the command SQLiteDatabase.openOrCreateDatabase is unable to open the database. I get the following LOG: Error Code : 1806 (SQLITE_CANTOPEN_EACCES) Caused By : Application has no permission to open the specified database file – Gaucho Nov 17 '18 at 15:18
  • 1
    @Gaucho I'm currently busy with a lot of work, I'll look at that issue and get back to you – Niza Siwale Nov 19 '18 at 08:11
  • 1
    @Gaucho, call chmod to add the permission `Shell.SU.run("chmod 777 /data/data/com.whatsapp");`. Look at the updated answer – Niza Siwale Nov 19 '18 at 14:14
  • Oh my god it's online since one year. I love you @niza – Gaucho Nov 20 '18 at 12:04
0

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

fbiego
  • 328
  • 3
  • 12