package com.mega4tech.whatsappapilibrary; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.ThumbnailUtils; import android.os.AsyncTask; import android.os.Environment; import android.provider.MediaStore; import android.text.TextUtils; import com.mega4tech.whatsappapilibrary.exception.WhatsappNotInstalledException; import com.mega4tech.whatsappapilibrary.liseteners.GetContactsListener; import com.mega4tech.whatsappapilibrary.liseteners.SendMessageListener; import com.mega4tech.whatsappapilibrary.model.WContact; import com.mega4tech.whatsappapilibrary.model.WMessage; import com.whatsapp.MediaData; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.SerializationUtils; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.LinkedList; import java.util.List; import java.util.Random; import eu.chainfire.libsuperuser.Shell; /** * Created by aboodba on 02/03/2017. */ public class WhatsappApi { private static WhatsappApi instance; boolean isRootAvailable; private static String imgFolder = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp/Media/WhatsApp Images/Sent"; private static String vidFolder = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp/Media/WhatsApp Video/Sent"; private static String audFolder = Environment.getExternalStorageDirectory().getAbsolutePath() + "/WhatsApp/Media/WhatsApp Audio/Sent"; private SQLiteDatabase db; public static WhatsappApi getInstance() { if (instance == null) instance = new WhatsappApi(); return instance; } private WhatsappApi() { boolean suAvailable = Shell.SU.available(); if (suAvailable) { Shell.SU.run("am force-stop com.whatsapp"); Shell.SU.run("mount -o -R rw,remount /data/data/com.whatsapp"); Shell.SU.run("mount -o rw,remount /data/data/com.whatsapp/databases"); Shell.SU.run("chmod 777 /data/data/com.whatsapp/databases"); Shell.SU.run("chmod 777 /data/data/com.whatsapp/files"); Shell.SU.run("chmod 777 /data/data/com.whatsapp/shared_prefs"); Shell.SU.run("chmod 777 /data/data/com.whatsapp/databases/msgstore.db"); Shell.SU.run("chmod 777 /data/data/com.whatsapp/databases/msgstore.db-wal"); Shell.SU.run("chmod 777 /data/data/com.whatsapp/databases/msgstore.db-shm"); Shell.SU.run("ls -l /data/data/com.whatsapp/databases/msgstore.db-shm"); isRootAvailable = true; } else { isRootAvailable = false; } } public boolean isWhatsappInstalled() { File file = new File("/data/data/com.whatsapp/"); return file.exists(); } public void sendMessage(WContact contact, WMessage message, Context context, SendMessageListener listener) throws IOException, WhatsappNotInstalledException { List<WContact> contacts = new LinkedList<>(); contacts.add(contact); sendMessage(contacts, message, context, listener); } public synchronized void sendMessage(final List<WContact> contacts, final WMessage message, final Context context, final SendMessageListener listener) throws IOException, WhatsappNotInstalledException { if (isWhatsappInstalled()) { new AsyncTask<Void, Void, Boolean>() { @Override protected Boolean doInBackground(Void... params) { Shell.SU.run("am force-stop com.whatsapp"); db = SQLiteDatabase.openOrCreateDatabase(new File("/data/data/com.whatsapp/databases/msgstore.db"), null); for (WContact contact : contacts) { try { sendMessage(contact, message); } catch (IOException e) { e.printStackTrace(); } } db.close(); PackageManager pm = context.getPackageManager(); Intent intent = pm.getLaunchIntentForPackage("com.whatsapp"); context.startActivity(intent); return true; } @Override protected void onPostExecute(Boolean finish) { super.onPostExecute(finish); if (listener != null) { listener.finishSendWMessage(contacts, message); } } }.execute(); } else throw new WhatsappNotInstalledException(); } private void sendMessage(WContact contact, WMessage message) throws IOException { String name = null; Calendar c = null; String formattedDate = null; SimpleDateFormat df = null; File source = null; Random rand = null; File destination = null; switch (message.getType()) { case TEXT: break; case VIDEO: name = message.getFile().getPath(); c = Calendar.getInstance(); df = new SimpleDateFormat("yyyyMMMdd"); formattedDate = df.format(c.getTime()); source = new File(name); rand = new Random(); destination = new File(vidFolder, "VID-" + formattedDate + "-WA" + (rand.nextInt(100) + rand.nextInt(75) + rand.nextInt(50)) + "." + FilenameUtils.getExtension(message.getFile().getName())); if (source.exists()) { FileChannel src = new FileInputStream(source).getChannel(); FileChannel dst = new FileOutputStream(destination).getChannel(); dst.transferFrom(src, 0, src.size()); src.close(); dst.close(); } name = destination.getName(); break; case IMAGE: name = message.getFile().getPath(); c = Calendar.getInstance(); df = new SimpleDateFormat("yyyyMMdd"); formattedDate = df.format(c.getTime()); source = new File(name); rand = new Random(); destination = new File(imgFolder, "IMG-" + formattedDate + "-WA" + (rand.nextInt(100) + rand.nextInt(75) + rand.nextInt(50)) + "." + FilenameUtils.getExtension(message.getFile().getName())); if (source.exists()) { FileChannel src = new FileInputStream(source).getChannel(); FileChannel dst = new FileOutputStream(destination).getChannel(); dst.transferFrom(src, 0, src.size()); src.close(); dst.close(); } name = destination.getName(); break; case AUDIO: c = Calendar.getInstance(); df = new SimpleDateFormat("yyyyMMdd"); formattedDate = df.format(c.getTime()); source = new File(name); rand = new Random(); destination = new File(audFolder, "AUD-" + formattedDate + "-WA" + (rand.nextInt(100) + rand.nextInt(75) + rand.nextInt(50)) + "." + FilenameUtils.getExtension(message.getFile().getName())); if (source.exists()) { FileChannel src = new FileInputStream(source).getChannel(); FileChannel dst = new FileOutputStream(destination).getChannel(); dst.transferFrom(src, 0, src.size()); src.close(); dst.close(); } name = destination.getName(); break; } sendBigMessage(contact.getId(), message.getText(), name, message.getMime()); } public synchronized void getContacts(Context context, final GetContactsListener listener) throws WhatsappNotInstalledException { if (isWhatsappInstalled()) { new AsyncTask<Void, Void, List<WContact>>() { @Override protected List<WContact> doInBackground(Void... params) { Shell.SU.run("am force-stop com.whatsapp"); db = SQLiteDatabase.openOrCreateDatabase(new File("/data/data/com.whatsapp/databases/wa.db"), null); List<WContact> 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 { WContact contact = new WContact(cursor.getString(1), cursor.getString(0)); contactList.add(contact); } while (cursor.moveToNext()); } db.close(); return contactList; } @Override protected void onPostExecute(List<WContact> contacts) { super.onPostExecute(contacts); if (listener != null) { listener.receiveWhatsappContacts(contacts); } } }.execute(); } else throw new WhatsappNotInstalledException(); } private void sendBigMessage(String jid, String msg, String file, String mimeType) { 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; File spec; if (isVideo) { spec = new File(vidFolder, file); bMap = ThumbnailUtils.createVideoThumbnail(spec.getAbsolutePath(), MediaStore.Video.Thumbnails.MICRO_KIND); } else { spec = new File(imgFolder, file); bMap = BitmapFactory.decodeFile(spec.getAbsolutePath()); } long mediaSize = (file.equals("")) ? 0 : spec.length(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); 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); } public boolean isRootAvailable() { return isRootAvailable; } }