package com.whatscloud.logic.sync.integration; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Base64; import android.util.Log; import com.whatscloud.config.db.SQLite3; import com.whatscloud.config.debug.Logging; import com.whatscloud.config.functionality.Sync; import com.whatscloud.config.integration.WhatsAppInterface; import com.whatscloud.logic.sync.db.SQLite; import com.whatscloud.logic.root.RootCommand; import com.whatscloud.model.Chat; import com.whatscloud.model.ChatMessage; import com.whatscloud.utils.strings.StringUtils; import java.io.ByteArrayOutputStream; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Random; public class WhatsApp { SQLite mSQLite; Context mContext; public WhatsApp(Context context) { //-------------------------------- // Save context instance //-------------------------------- this.mContext = context; //-------------------------------- // Create database connector //-------------------------------- this.mSQLite = new SQLite( context ); } private void resetUnreadCount(ChatMessage message) throws Exception { //-------------------------------- // Initialize contact hash map //-------------------------------- HashMap<String, String> contact = new HashMap<String, String>(); //-------------------------------- // Reset unseen msg count //-------------------------------- contact.put("unseen_msg_count", "0"); //-------------------------------- // Execute SQL query //-------------------------------- mSQLite.update("wa_contacts", contact, "jid = '" + message.jid + "'", WhatsAppInterface.CONTACTS_DB); } public void resetTotalUnreadCount() throws Exception { //-------------------------------- // Initialize contact hash map //-------------------------------- HashMap<String, String> contact = new HashMap<String, String>(); //-------------------------------- // Reset unseen msg count //-------------------------------- contact.put("unseen_msg_count", "0"); //-------------------------------- // Execute SQL query //-------------------------------- mSQLite.update("wa_contacts", contact, "1 = 1", WhatsAppInterface.CONTACTS_DB); //-------------------------------- // Restart WhatsApp! //-------------------------------- restartWhatsApp(); } private int getLastChatMessageIDByJID(String jid) throws Exception { //-------------------------------- // Get back last id for this chat //-------------------------------- String[] columns = new String[] { "_id" }; //-------------------------------- // Execute SQL query //-------------------------------- List<HashMap<String, String>> rows = mSQLite.select(columns, "messages", "key_remote_jid = '" + jid + "' ORDER BY _id DESC LIMIT 0, 1", WhatsAppInterface.MESSAGE_DB); //-------------------------------- // No rows? //-------------------------------- if ( rows.size() == 0 ) { return 0; } //-------------------------------- // Get last id //-------------------------------- int id = 0; try { id = Integer.parseInt(rows.get(0).get("_id")); } catch( Exception exc ) { //-------------------------------- // Log it //-------------------------------- Log.e(Logging.TAG_NAME, "parseInt() failed in getLastChatMessageIDByJID(): " + rows.get(0).get("_id")); } //-------------------------------- // Return id //-------------------------------- return id; } public int getTotalUnreadCount() throws Exception { //-------------------------------- // Get back last id for this chat //-------------------------------- String[] columns = new String[] { "sum(unseen_msg_count)" }; //-------------------------------- // Execute SQL query //-------------------------------- List<HashMap<String, String>> rows = mSQLite.select(columns, "wa_contacts", "1 = 1", WhatsAppInterface.CONTACTS_DB); //-------------------------------- // No rows? //-------------------------------- if ( rows.size() == 0 ) { return 0; } //-------------------------------- // Get unread count //-------------------------------- int unread = 0; try { unread = Integer.parseInt(rows.get(0).get("sum(unseen_msg_count)")); } catch( Exception exc ) { //-------------------------------- // Log it //-------------------------------- Log.e(Logging.TAG_NAME, "parseInt() failed in getTotalUnreadCount(): " + rows.get(0).get("_id")); } //-------------------------------- // Return count //-------------------------------- return unread; } public int getLastChatID() throws Exception { //-------------------------------- // Get back sum //-------------------------------- String[] columns = new String[] { "_id" }; //-------------------------------- // Execute SQL query //-------------------------------- List<HashMap<String, String>> rows = mSQLite.select(columns, "wa_contacts", "1 = 1 ORDER BY _id DESC LIMIT 0, 1", WhatsAppInterface.CONTACTS_DB); //-------------------------------- // No rows? //-------------------------------- if ( rows.size() == 0 ) { return 0; } //-------------------------------- // Get count //-------------------------------- int count = 0; try { count = Integer.parseInt(rows.get(0).get("_id")); } catch( Exception exc ) { //-------------------------------- // Log it //-------------------------------- Log.e(Logging.TAG_NAME, "parseInt() failed in getLastChatID(): " + rows.get(0).get("_id")); } //-------------------------------- // Return count //-------------------------------- return count; } private void updateChatLastMessageID(ChatMessage message) throws Exception { //-------------------------------- // Get last id //-------------------------------- int lastID = getLastChatMessageIDByJID(message.jid); //-------------------------------- // Initialize contact hash map //-------------------------------- HashMap<String, String> chat = new HashMap<String, String>(); //-------------------------------- // Reset unseen msg count //-------------------------------- chat.put("message_table_id", lastID + ""); //-------------------------------- // Update sort timestamp // to sort WhatsApp chat list // according to last sent message //-------------------------------- chat.put("sort_timestamp", message.timeStamp + ""); //-------------------------------- // Execute SQL query //-------------------------------- mSQLite.update("chat_list", chat, "key_remote_jid = '" + message.jid + "'", WhatsAppInterface.MESSAGE_DB); } private void insertMessageDB(ChatMessage message) throws Exception { //-------------------------------- // Initialize row hash map //-------------------------------- HashMap<String, String> row = new HashMap<String, String>(); //-------------------------------- // Add message-specific fields //-------------------------------- row.put("data", message.data); row.put("key_remote_jid", message.jid); row.put("timestamp", message.timeStamp); row.put("key_from_me", message.fromMe + ""); row.put("received_timestamp", message.timeStamp); //-------------------------------- // Add default fields //-------------------------------- row.put("key_id", getKeyID(message)); row.put("status", "0"); row.put("needs_push", "0"); row.put("media_size", "0"); row.put("origin", "0"); row.put("recipient_count", ""); row.put("media_wa_type", "0"); row.put("media_duration", "0"); row.put("send_timestamp", "-1"); row.put("latitude", "0.0"); row.put("longitude", "0.0"); row.put("receipt_server_timestamp", "-1"); row.put("receipt_device_timestamp", "-1"); //-------------------------------- // Execute SQL query //-------------------------------- mSQLite.insert(row, "messages", WhatsAppInterface.MESSAGE_DB); } private void doSendMessage(ChatMessage message) throws Exception { //-------------------------------- // Execute SQL query //-------------------------------- insertMessageDB(message); //-------------------------------- // Reset chat unread counter //-------------------------------- resetUnreadCount(message); //-------------------------------- // Create chat item in case // we never contacted this JID // before now //-------------------------------- createChatIfMissing(message); //-------------------------------- // Update last id (to display // the last-inserted message) //-------------------------------- updateChatLastMessageID(message); } private void createChatIfMissing(ChatMessage message) throws Exception { //-------------------------------- // Select _id for testing //-------------------------------- String[] columns = new String[] { "_id" }; //-------------------------------- // Get chats by JID //-------------------------------- List<HashMap<String, String>> chats = mSQLite.select(columns, "chat_list", "key_remote_jid = '" + message.jid + "' LIMIT 0, 1", WhatsAppInterface.MESSAGE_DB); //-------------------------------- // Chat exists? //-------------------------------- if ( chats.size() > 0 ) { return; } //-------------------------------- // Initialize row hash map //-------------------------------- HashMap<String, String> row = new HashMap<String, String>(); //-------------------------------- // Add message-specific fields //-------------------------------- row.put("key_remote_jid", message.jid); //-------------------------------- // Execute SQL query //-------------------------------- mSQLite.insert(row, "chat_list", WhatsAppInterface.MESSAGE_DB); } public void sendMessages(List<ChatMessage> messages) throws Exception { //-------------------------------- // Sort by id ascending //-------------------------------- Collections.sort(messages); //-------------------------------- // Iterate over chat messages //-------------------------------- for ( ChatMessage message : messages ) { //-------------------------------- // This function takes care of // everything! //-------------------------------- doSendMessage(message); } //-------------------------------- // Log insertion //-------------------------------- Log.d(Logging.TAG_NAME, "Inserted messages into database"); //-------------------------------- // Restart WhatsApp! //-------------------------------- restartWhatsApp(); } void restartWhatsApp() throws Exception { //-------------------------------- // Stop WhatsApp! //-------------------------------- RootCommand.execute(WhatsAppInterface.STOP_WHATSAPP_COMMAND); //-------------------------------- // Wait 200ms //-------------------------------- Thread.sleep(200); //-------------------------------- // Start Messaging Service //-------------------------------- RootCommand.execute(WhatsAppInterface.START_MESSAGING_SERVICE_COMMAND); //-------------------------------- // Log restart //-------------------------------- Log.d(Logging.TAG_NAME, "Restarted " + WhatsAppInterface.PACKAGE); } String getKeyID(ChatMessage message) { //-------------------------------- // Get a solid id //-------------------------------- return message.timeStamp + "-" + ( new Random().nextInt(10) + 1); } public List<ChatMessage> getMessages(int minMessageID, String jid, int limit) throws Exception { //-------------------------------- // Query WhatsApp's DB //-------------------------------- List<ChatMessage> messages = new ArrayList<ChatMessage>(); //-------------------------------- // Get new messages //-------------------------------- String[] columns = new String[] { "_id", "data", "status", "media_url", "timestamp", "key_from_me", "media_caption", "media_wa_type", "remote_resource", "key_remote_jid" }; //-------------------------------- // Execute SQL query //-------------------------------- List<HashMap<String, String>> rows = mSQLite.select(columns, "messages", "_id > " + minMessageID + " AND media_wa_type != 4 AND status != -1" + ((jid != null) ? " AND key_remote_jid = '" + jid + "'" : "") + " ORDER BY timestamp " + ((jid != null) ? "DESC" : "ASC") + ((limit > 0) ? " LIMIT 0, " + limit : ""), WhatsAppInterface.MESSAGE_DB); //-------------------------------- // Loop over returned rows //-------------------------------- for ( HashMap<String, String> row : rows ) { //-------------------------------- // Create new generic message //-------------------------------- ChatMessage message = new ChatMessage(); //-------------------------------- // Extract integers from row //-------------------------------- try { message.id = Integer.parseInt(row.get("_id")); message.type = Integer.parseInt(row.get("media_wa_type")); message.fromMe = Integer.parseInt( row.get("key_from_me") ); } catch( Exception exc ) { //-------------------------------- // Log it //-------------------------------- Log.e(Logging.TAG_NAME, "parseInt() failed in getMessages(): " + row.get("_id") + ", " + row.get("media_wa_type") + ", " + row.get("key_from_me")); //-------------------------------- // Just skip for now //-------------------------------- continue; } //-------------------------------- // Extract strings from row //-------------------------------- message.data = row.get("data"); message.status = row.get("status"); message.jid = row.get("key_remote_jid"); message.mediaURL = row.get("media_url"); message.timeStamp = row.get("timestamp"); message.sender = row.get("remote_resource"); //-------------------------------- // Convert line break back //-------------------------------- message.data = message.data.replace( SQLite3.LINE_BREAK_CHAR, "\n" ); //-------------------------------- // Sync media caption //-------------------------------- if (! StringUtils.stringIsNullOrEmpty( message.mediaURL ) ) { message.data = row.get("media_caption"); } //-------------------------------- // Add to list of messages //-------------------------------- messages.add(message); } //-------------------------------- // Return messages //-------------------------------- return messages; } public List<Chat> getChats(int lastChatID) throws Exception { //-------------------------------- // Query WhatsApp's DB //-------------------------------- List<Chat> chats = new ArrayList<Chat>(); //-------------------------------- // Get new messages //-------------------------------- String[] columns = new String[] { "_id", "is_whatsapp_user", "jid", "display_name", "number", "status" }; //-------------------------------- // Execute SQL query //-------------------------------- List<HashMap<String, String>> rows = mSQLite.select(columns, "wa_contacts", "_id > " + lastChatID + " ORDER BY _id ASC LIMIT 0, " + Sync.MAX_CHATS_PER_SYNC, WhatsAppInterface.CONTACTS_DB); //-------------------------------- // Loop over returned rows //-------------------------------- for ( HashMap<String, String> row : rows ) { //-------------------------------- // Create new generic chat //-------------------------------- Chat chat = new Chat(); //-------------------------------- // Extract integers from row //-------------------------------- try { chat.id = Integer.parseInt(row.get("_id")); chat.whatsAppUser = Integer.parseInt(row.get("is_whatsapp_user")); } catch( Exception exc ) { //-------------------------------- // Log it //-------------------------------- Log.e(Logging.TAG_NAME, "parseInt() failed in getChats(): " + row.get("_id") + ", " + row.get("is_whatsapp_user")); //-------------------------------- // Just skip for now //-------------------------------- continue; } //-------------------------------- // Extract strings from row //-------------------------------- chat.jid = row.get("jid"); chat.name = row.get("display_name"); chat.number = row.get("number"); chat.status = row.get("status"); //-------------------------------- // Attempt to retrieve chat pic //-------------------------------- //chat.picture = getChatPicture(chat); //-------------------------------- // Add to list of chats //-------------------------------- chats.add(chat); } //-------------------------------- // Return chats //-------------------------------- return chats; } private String getChatPicture(Chat chat) { //-------------------------------- // No JID, no go //-------------------------------- if ( StringUtils.stringIsNullOrEmpty(chat.jid)) { return ""; } //-------------------------------- // Proceed with caution //-------------------------------- try { //-------------------------------- // Create Avatars folder //-------------------------------- RootCommand.execute(WhatsAppInterface.PATH_TO_BUSYBOX_BINARY + " mkdir " + WhatsAppInterface.WHATSAPP_PICTURES_DESTINATION_FOLDER); //-------------------------------- // Copy from internal data to // /sdcard/ so we can access it //-------------------------------- RootCommand.execute(WhatsAppInterface.PATH_TO_BUSYBOX_BINARY + " cp " + WhatsAppInterface.WHATSAPP_PICTURES_SOURCE_FOLDER + "/" + chat.jid + ".j " + WhatsAppInterface.WHATSAPP_PICTURES_DESTINATION_FOLDER + "/" + chat.jid + ".jpg"); } catch( Exception exc ) { //-------------------------------- // Log the exception //-------------------------------- Log.d(Logging.TAG_NAME, exc.getMessage()); //-------------------------------- // This may fail in case // there is no image //-------------------------------- return ""; } //-------------------------------- // Create path to file //-------------------------------- File jpg = new File( WhatsAppInterface.WHATSAPP_PICTURES_DESTINATION_FOLDER + "/" + chat.jid + ".jpg"); //-------------------------------- // File does not exist? //-------------------------------- if ( ! jpg.exists() ) { return ""; } //-------------------------------- // Read the file as bytes //-------------------------------- Bitmap bitmap = BitmapFactory.decodeFile(jpg.getAbsolutePath()); //-------------------------------- // Read failed? //-------------------------------- if ( bitmap == null ) { return ""; } //-------------------------------- // Resize it (it's pretty big) //-------------------------------- bitmap = Bitmap.createScaledBitmap(bitmap, Sync.PICTURE_DIMENSIONS, Sync.PICTURE_DIMENSIONS, false); //-------------------------------- // Create a stream //-------------------------------- ByteArrayOutputStream stream = new ByteArrayOutputStream(); //-------------------------------- // Compress into output stream //-------------------------------- bitmap.compress(Bitmap.CompressFormat.JPEG, Sync.PICTURE_QUALITY, stream); //-------------------------------- // Convert to byte array //-------------------------------- byte[] bytes = stream.toByteArray(); //-------------------------------- // Encode as Base64 string //-------------------------------- return Base64.encodeToString(bytes, Base64.NO_WRAP); } public List<Chat> getChatList() throws Exception { //-------------------------------- // Query WhatsApp's DB //-------------------------------- List<Chat> chats = new ArrayList<Chat>(); //-------------------------------- // Define columns //-------------------------------- String[] columns = new String[] { "_id", "key_remote_jid", }; //-------------------------------- // Execute SQL query //-------------------------------- List<HashMap<String, String>> rows = mSQLite.select(columns, "chat_list", "1 = 1 ORDER BY message_table_id DESC", WhatsAppInterface.MESSAGE_DB); //-------------------------------- // Loop over returned rows //-------------------------------- for ( HashMap<String, String> row : rows ) { //-------------------------------- // Create new generic chat //-------------------------------- Chat chat = new Chat(); //-------------------------------- // Extract integers from row //-------------------------------- try { chat.id = Integer.parseInt(row.get("_id")); } catch( Exception exc ) { //-------------------------------- // Log it //-------------------------------- Log.e(Logging.TAG_NAME, "parseInt() failed in getChatList(): " + row.get("_id")); //-------------------------------- // Just skip for now //-------------------------------- continue; } //-------------------------------- // Extract strings from row //-------------------------------- chat.jid = row.get("key_remote_jid"); //-------------------------------- // Add to list of chats //-------------------------------- chats.add(chat); } //-------------------------------- // Return chats //-------------------------------- return chats; } }