Auto Reply to WhatsApp message in background - android

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.

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();

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();
}

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

Related

Start Chrome as Web-App on Android start

i have a quite specific problem. I have realized a Web App on an Android tablet, which will be used on an exhibition (Outform iDisplay). For this reason, the Web App has to start directly after boot. The after-boot thing is no problem (Broadcast with "android.permission.RECEIVE_BOOT_COMPLETED"), but i have a problem to start Chrome as Web-App. For getting the Intent, i have read the Icons in the launcher favorites with this snippet:
//Kitkat, therefore launcher3
url = "content://com.android.launcher3.settings/favorites?Notify=true";
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(Uri.parse(url), null, null, null, null);
if (cursor != null && cursor.moveToFirst())
{
do
{
String ent1 = cursor.getString(0);
String ent2 = cursor.getString(1);
String ent3 = cursor.getString(2); //there is the Intent string
String ent4 = cursor.getString(3);
System.out.println("Test");
String ent5 = cursor.getString(4);
String ent6 = cursor.getString(5);
String ent7 = cursor.getString(6);
String ent8 = cursor.getString(7);
String ent9 = cursor.getString(8);
String ent10 = cursor.getString(9);
String ent11 = cursor.getString(10);
String ent12 = cursor.getString(11);
String ent14 = cursor.getString(13);
String ent15 = cursor.getString(14);
String ent17 = cursor.getString(16);
String ent18 = cursor.getString(17);
String ent19 = cursor.getString(18);
String ent20 = cursor.getString(19);
if(ent2.equals("History Book")) //Get the right intent
{
runAction = ent3;
}
System.out.println(ent3);
} while (cursor.moveToNext());
}
The Intent string contains something like this:
#Intent;action=com.google.android.apps.chrome.webapps.WebappManager.ACTION_START_WEBAPP;package=com.android.chrome;S.org.chromium.chrome.browser.webapp_title=History%20Book;S.org.chromium.chrome.browser.webapp_id=86e362e4-a25d-4142-8a32-c02ffcb176a9;i.org.chromium.content_public.common.orientation=6;S.org.chromium.chrome.browser.webapp_icon=;S.org.chromium.chrome.browser.webapp_mac=3ZaXFbyWnJQaqFFOuUj3OssNz7DrBaaiWfzO2Dd7VIU%3D%0A;S.org.chromium.chrome.browser.webapp_url=http%3A%2F%2F192.168.5.148%2Fstyria%2Fhistorybook%2Findex.html;end
This looks quite good, but how can i start an Intent like this in a small app, which just has the single purpose to start this intent?
Just a small note at the end: I have tried to pack this thing into a webview, but the webview died constantly because of an libc error, so this is no option for me.
Finally i got this thing working. I was on the right way, but some Chrome.apk reverse engineering helped me for the last mile.
I have created a dummy activity with the following code in onCreate:
Search for the right entry on the homescreen, in my case for the AOSP launcher 3:
//Search for the History Book Shortcut on the Homescreen
String url = "";
String runAction="";
final String AUTHORITY = "com.android.launcher3.settings";
final Uri CONTENT_URI = Uri.parse("content://" +
AUTHORITY + "/favorites?notify=true");
final ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(CONTENT_URI,null,null,null,null);
cursor.moveToFirst();
do {
String id = cursor.getString(cursor.getColumnIndex("_id"));
String title = cursor.getString(cursor.getColumnIndex("title"));
String intent = cursor.getString(cursor.getColumnIndex("intent"));
if(title.equals(getResources().getString(R.string.homescreen_link)))
{
runAction = intent;
}
} while (cursor.moveToNext());
At this point, i have hopefully the intent as string. So, parse the string and create a new intent:
Intent intent = new Intent();
intent.setAction("com.google.android.apps.chrome.webapps.WebappManager.ACTION_START_WEBAPP");
intent.setPackage("com.android.chrome");
intent.setClassName("com.android.chrome", "com.google.android.apps.chrome.webapps.WebappManager");
HashMap<String, String> intentVals = getIntentParams(runAction);
intent.putExtra("org.chromium.chrome.browser.webapp_title",intentVals.get("S.org.chromium.chrome.browser.webapp_title"));
intent.putExtra("org.chromium.chrome.browser.webapp_icon",intentVals.get("S.org.chromium.chrome.browser.webapp_icon"));
intent.putExtra("org.chromium.chrome.browser.webapp_id",intentVals.get("S.org.chromium.chrome.browser.webapp_id"));
intent.putExtra("org.chromium.chrome.browser.webapp_url",intentVals.get("S.org.chromium.chrome.browser.webapp_url"));
intent.putExtra("org.chromium.chrome.browser.webapp_mac",intentVals.get("S.org.chromium.chrome.browser.webapp_mac"));
int orientation = 6;
try
{
orientation = Integer.parseInt(intentVals.get("i.org.chromium.content_public.common.orientation"));
}
catch(NumberFormatException _nex)
{
Log.e(TAG, "Wrong format, using default (6)");
}
intent.putExtra("org.chromium.content_public.common.orientation", orientation);
try
{
byte[] abyte0 = Base64.decode(
intentVals.get("S.org.chromium.chrome.browser.webapp_mac"),
0);
System.out.println(new String(abyte0));
}
catch (IllegalArgumentException _iae)
{
Log.e(TAG,
"Wrong webapp_mac: "
+ intentVals
.get("S.org.chromium.chrome.browser.webapp_mac"));
}
startActivity(intent);
finish();
And this function parses the intent parameters out of the intent string:
private HashMap<String, String> getIntentParams(String _runAction)
{
HashMap<String, String> retMap = new HashMap<String, String>();
String[] pairs = _runAction.split(";");
for (int i = 0; i < pairs.length; i++)
{
String[] keyval = pairs[i].split("=");
if(keyval.length==2)
{
String key = keyval[0];
String value = "";
try
{
value = java.net.URLDecoder.decode(keyval[1], "UTF-8");
}
catch (UnsupportedEncodingException _uee)
{
Log.e(TAG, "Unsupported Encoding: " + _uee.getMessage());
}
retMap.put(key, value);
}
}
return retMap;
}
And the strings.xml in res/values:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">WebAppStarter</string>
<string name="homescreen_link">History Book</string>
</resources>
That's it. You can configure the Homescreen link name to search for in strings.xml. When the app finds the string, it parses the intent string and creates a new intent to start Chrome as a Full Screen Activity Web App.

How to add custom header while making a pjsip makecall()?

I need to add one custom header for before making a sip call. please help me.
Thanks in advance.
Finally i got the answer for my question. You should change your make makeSipCall() method.
private boolean makeSipCall(String phoneNumber)
{
if(!created)
return false;
Log.i("MtaAPIImpl", (new StringBuilder("makecall : ")).append(phoneNumber).toString());
phoneNumber = (new StringBuilder("<sip:")).append(phoneNumber).append("#").append(sipServer).append(">").toString();
byte userData[] = new byte[1];
int callId[] = new int[1];
pjsua_call_setting cs = new pjsua_call_setting();
pjsua.call_setting_default(cs);
cs.setVid_cnt(0L);
cs.setAud_cnt(1L);
cs.setFlag(0L);
pjsua_msg_data msgData = new pjsua_msg_data();
pjsua.msg_data_init(msgData);
pj_pool_t pool = pjsua.pool_create("call_tmp", 512L, 512L);
pjsua.csipsimple_init_acc_msg_data(pool, 1, msgData);
pj_str_t uri = pjsua.pj_str_copy(phoneNumber);
//Here adding headers adding through bundel.
Bundle extra_header = new Bundle();
final Bundle b = new Bundle();
extra_header.putString("header-Name", "Header-Value");
b.putBundle(SipCallSession.OPT_CALL_EXTRA_HEADERS, extra_header);
Bundle extraHeaders = b.getBundle(SipCallSession.OPT_CALL_EXTRA_HEADERS);
for (String key : extraHeaders.keySet()) {
try {
String value = extraHeaders.getString(key.toString());
if (!TextUtils.isEmpty(value)) {
int res = pjsua.csipsimple_msg_data_add_string_hdr(pool, msgData,pjsua.pj_str_copy(key), pjsua.pj_str_copy(value));
if (res == pjsuaConstants.PJ_SUCCESS) {
Log.e(THIS_FILE, "Failed to add Xtra hdr (" + key + " : "+ value + ") probably not X- header");
}
}
} catch (Exception e) {
Log.e(THIS_FILE, "Invalid header value for key : " + key);
}
}
int status = pjsua.call_make_call(1, uri, cs, userData, msgData, callId);
pjsua.pj_pool_release(pool);
return status == pjsuaConstants.PJ_SUCCESS;
}

How to get Metadata of an object retrieved from amazon S3 in android?

I am retrieving an object from amazon s3.How to get metadata of retrieved object in android? From the metadata, i want to find out whether that object is image or Non-image (like pdf, csv, ...)
Thanks for any help.
I am using the following code for getting list of names under a folder.
AmazonS3Client s3Client;
s3Client = new AmazonS3Client(new BasicAWSCredentials(
Constants.ACCESS_KEY_ID, Constants.SECRET_KEY));
ObjectListing objListOfPath = s3Client.listObjects(
Constants.getPictureBucket(), path);
List<S3ObjectSummary> keyListOfObjectSummaries = objListOfPath
.getObjectSummaries();
ObjectListing next = s3Client.listNextBatchOfObjects(objListOfPath);
keyListOfObjectSummaries.addAll(next.getObjectSummaries());
System.out.println("keyListOfObjectSummaries size() "
+ keyListOfObjectSummaries.size());
ArrayList<String> arrListImageName = new ArrayList<String>();
if (keyListOfObjectSummaries.size() > 0) {
for (int i = 0; i < keyListOfObjectSummaries.size(); i++) {
String imagePath = keyListOfObjectSummaries.get(i).getKey();
arrListImageName.add(strImageName);
}
for (int i = 0; i < arrListImageName.size(); i++) {
System.out.println("Index " + i + " image Name "
+ arrListImageName.get(i));
String strReceiptImageName = arrListImageName.get(i);
String strReceiptNameExtension = extractReceiptNameExtension(arrListImageName.get(i));
S3Object objectReceiptFromAmazonS3 = s3Client.getObject(
Constants.PICTURE_BUCKET, keyListOfObjectSummaries
.get(i).getKey());
InputStream inputStreamReceiptObject = objectReceiptFromAmazonS3
.getObjectContent();
SOLUTION:
System.out.println("CONTENT TYPE " +objectReceiptFromAmazonS3.getObjectMetadata().getContentType());
Thanks to Harshit and sanket !
This has worked for me to download a file hosted in S3 from a simple servlet.
private static final int BYTES_DOWNLOAD = 1024;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String key = request.getParameter("key");
HttpSession session = request.getSession();
String bucketname = (String) session.getAttribute("BUCKETNAME");
AmazonS3 s3 = new AmazonS3Client(Constants.credentials);
Region usWest2 = Region.getRegion(Regions.US_WEST_2);
s3.setRegion(usWest2);
S3Object object = s3.getObject(new GetObjectRequest(bucketname, key));
response.setContentType(object.getObjectMetadata().getContentType());
response.setHeader("Content-Disposition","attachment;filename="+object.getKey());
InputStream is = object.getObjectContent();int read=0;
byte[] bytes = new byte[BYTES_DOWNLOAD];
OutputStream os = response.getOutputStream();
while((read = is.read(bytes))!= -1){
os.write(bytes, 0, read);
}
os.flush();
os.close();
}
use this couple of lines :
ObjectMetadata metaData = new ObjectMetadata();
metaData.addUserMetadata("key", key of your file);
System.out.println("Content type is========"+metaData.getContentType());
this might be help you..

Updating a column in database of the selected user ID IN ANDROID

Can somebody help me about this matter? I have a listview with checkbox, every time the user tick the checkbox, all the selected user ID was inserted into a arraylist. Then if the button Export was clicked, all the column "Mark" in the database should be updated from "Not send" to "sent". I know that by this code the database will be updated:
public void updateEmailmark(String consumerId)
{
SQLiteDatabase db = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(Constants.CONSUMER_EMAILMARK, "Sent");
db.update(Constants.DATABASE_TABLE_CONSUMER, contentValues, Constants.CONSUMER_ID + "=?",new String[]{consumerId});
db.close();
}
but my problem is I don't know how to update that column when the user selected many UserID to export. I only knew that I need to use a for loop but I don't know how. Thank for anyone who will help me. Here's my other code.
btn_Export.setOnClickListener(new OnClickListener()
{
public void onClick(View v){
arraylistSelectedConsumerIds = simpleAdapterConsumerData.getArrayListConsumerId();
arraylistSelectedConsumer = simpleAdapterConsumerData.getArrayListConsumer();
if (!arraylistSelectedConsumerIds.toString().equals("[]") && !arraylistSelectedConsumer.toString().equals("[]"))
{
boolean hasSDCard = false;
boolean sdCardIsWriteable = true;
String sdCardState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(sdCardState))
hasSDCard = true;
else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(sdCardState))
sdCardIsWriteable = true;
if (hasSDCard == true && sdCardIsWriteable == true){
new AsyncCreateBackup().execute();
String date = String.valueOf(calendar.get(Calendar.MONTH)+1)+"-"+String.valueOf(calendar.get(Calendar.DATE))+"-"+String.valueOf(calendar.get(Calendar.YEAR));
int fileCounter = 1;
File sdcard = Environment.getExternalStorageDirectory();
File dir = new File (sdcard.getAbsolutePath() + "/CompanyCares/export/");
if (dir.exists()){
File[]dirs = dir.listFiles();
try{
for(File fileFolder: dirs){
if(fileFolder.isDirectory() && fileFolder.getName().contains("export_"+date)){
fileCounter++;
}
}
} catch (Exception e){
e.printStackTrace();
}
}
consumerData = new StringBuilder();
File personFile;
time = String.valueOf(calendar.get(Calendar.HOUR_OF_DAY))+String.valueOf(calendar.get(Calendar.MINUTE))+String.valueOf(calendar.get(Calendar.SECOND));
personFile = createCSV("Person_Table_"+date+"_"+time, Constants.COLUMN_STRING_PERSON_TABLE, getConsumersDetails(arraylistSelectedConsumerIds), fileCounter, false);
createEmailWithAttachments(personFile);
arrayListExportedConsumerId.addAll(arraylistSelectedConsumerIds);
arrayListExportedConsumer.addAll(arraylistSelectedConsumer);
exportedConsumerId = new HashSet<String>();
exportedConsumer = new HashSet<String>();
exportedConsumerId.addAll(arrayListExportedConsumerId);
exportedConsumer.addAll(arrayListExportedConsumer);
sharedPreferencesEditor.putStringSet(Constants.SHARED_PREFERENCES_EXPORTED_CONSUMER_ID, exportedConsumerId);
sharedPreferencesEditor.putStringSet(Constants.SHARED_PREFERENCES_EXPORTED_CONSUMER, exportedConsumer);
sharedPreferencesEditor.commit();
}else{
Toast.makeText(AdminActivity.this, getString(R.string.error_sdcard), Toast.LENGTH_SHORT).show();
}
}else{
Toast.makeText(AdminActivity.this, getString(R.string.error_select), Toast.LENGTH_LONG).show();
}
}
});

reading sms records from database android

I have over 3000 sms on my device. I'm trying to read all messages in the database. I am using this query:
Cursor cur1 = c.getContentResolver().query(Uri.parse("content://sms/"), null, null, null, null);
cur1.getCount() returns all 3000 sms, but when I parse it through a loop it only runs through 400 to 500.
Cursor cur1 = c.getContentResolver().query(Uri.parse("content://sms/"), null, null, null, null);
int size = cur1.getCount();
if(size > 0)
{
sms = new SMS[size];
//int i = 0;
for(int i = 0 ; i < size ; i++)
{
cur1.moveToNext();
ContactInfo p = new ContactInfo();
String content = cur1.getString(cur1.getColumnIndex("body"));
String number = cur1.getString(cur1.getColumnIndex("address"));
long date = cur1.getLong(cur1.getColumnIndex("date"));
String person = cur1.getString(cur1.getColumnIndex("person"));
String protocol = cur1.getString(cur1.getColumnIndex("protocol"));
String name = p.getName(number, c);
String type = null;
Calendar cal=Calendar.getInstance();
cal.clear();
cal.setTimeInMillis(date);
String date_time=String.format("%1$te %1$tB %1$tY,%1$tI:%1$tM:%1$tS %1$Tp",cal);
Log.i("INFO", content+" "+i);
sms[i] = new SMS(type , name , number , date_time , content );
}
}
After 400-500 iterations logcat prints
09-19 20:28:31.148: E/liblog(3153): failed to call dumpstate
09-19 20:28:31.179: I/ActivityManager(3153): Process com.arslan (pid 1766) has died.
Many other processes are running on device and due to this long process of reading 3000 messages it takes a lot of continuous CPU time that's why process killed. When I tried to read it through thread it works fine.
final Cursor cur1 = c.getContentResolver().query(Uri.parse("content://sms/"), null, null, null, "date ASC");
final int size = cur1.getCount();
final int sleeptimer = size;
final SMS [] sms = new SMS[size];
Thread myThread = new Thread()
{
public void run()
{
try
{
int currentwait = 0;
int j=0;
while(currentwait < sleeptimer)
{
sleep(200);
currentwait+=200;
for(int i = 0 ; i < 200 ; i++)
{
if(!cur1.moveToNext())
{
break;
}
ContactInfo p = new ContactInfo();
String content = cur1.getString(cur1.getColumnIndex("body"));
String number = cur1.getString(cur1.getColumnIndex("address"));
long date = cur1.getLong(cur1.getColumnIndex("date"));
String protocol = cur1.getString(cur1.getColumnIndex("protocol"));
String name = p.getName(number, c);
String type = null;
Calendar cal=Calendar.getInstance();
cal.clear();
cal.setTimeInMillis(date);
String date_time=String.format("%1$te %1$tB %1$tY,%1$tI:%1$tM:%1$tS %1$Tp",cal);
Log.i("INFO", content+" "+j);
sms[j] = new SMS(type , name , number , date_time , content );
j++;
}
}
}
catch(Exception e)
{
}
finally{
}
}
};
myThread.start();

Categories

Resources