I'm developing an application in which i can send specific messages to specific number.
the messages are already pre-defined for example "SYSSTAT", and number is also pre-define when user start application he/she enter receiver device number.
But i'm getting error as SMSManager returns RESULT_ERROR_GENERIC_FAILURE, i had tested on various OS like start from Marshmallow to Pie but i'm getting error only on Marshmallow devices.
I had already give each permission manually too, but unfortunately not work on marshmallow devices only i had checked on Redmi 4A, Note 7 pro, Note 7, Nokia 6.1, etc...
Kindly help me.
It's due to simInfo.subscriptionId
here is sample code hwo i manage it.
val activeList = subscriptionManager.activeSubscriptionInfoList
if (activeList != null && activeList.isNotEmpty()) {
isMultipleSubscriptions = activeList.size > 1
val simInfo1 = activeList[0] as SubscriptionInfo
val simInfo2 = activeList[1] as SubscriptionInfo
if (simInfo1.displayName != null && simInfo1.displayName != "") {
companies.add(simInfo1.displayName.toString())
companySubscriptionId.add(simInfo1.subscriptionId)
}
if (simInfo2.displayName != null && simInfo2.displayName != "") {
companies.add(simInfo2.displayName.toString())
companySubscriptionId.add(simInfo2.subscriptionId)
}
}
And send SMS using selected subscription id
SmsManager.getSmsManagerForSubscriptionId(aSubscriptionId)
.sendTextMessage(
phoneNumber,
null,
aMsg,
sentPI,
deliveredPI
)
Related
I'm facing a weird crash in the Samsung device only.
See the stacktrace below,
Fatal Exception: com.pilabs.musicplayer.tageditor.TagEditFailedException: Tag edit failed : Changing volume from /storage/3964-3431/Music/Bujji-MassTamilan.io.mp3 to /storage/emulated/0/Music/.pending-1608532169-Bujji-MassTamilan.io.mp3 not allowed
at com.pilabs.musicplayer.tageditor.PiTagEditor.handleException(PiTagEditor.java:643)
at com.pilabs.musicplayer.tageditor.PiTagEditor.editTrackTagInfoImpl(PiTagEditor.java:217)
at com.pilabs.musicplayer.tageditor.PiTagEditor.access$setUiCallback$p(PiTagEditor.java:37)
at com.pilabs.musicplayer.tageditor.PiTagEditor$editTrackTagInfo$1.invokeSuspend(PiTagEditor.java:79)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(BaseContinuationImpl.java:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.java:238)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.java:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$createdWorkers(CoroutineScheduler.java:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.java:742)
Where TagEditFailedException is my own Written Exception. Actual exception being,
java.lang.IllegalArgumentException: Changing volume from /storage/3964-3431/Music/Bujji-MassTamilan.io.mp3 to /storage/emulated/0/Music/.pending-1608532169-Bujji-MassTamilan.io.mp3 not allowed
More than anything, look for
Changing volume from /storage/3964-3431/Music/Bujji-MassTamilan.io.mp3 to /storage/emulated/0/Music/.pending-1608532169-Bujji-MassTamilan.io.mp3 not allowed
I debugged the code and found that the app is crashing when updating IS_PENDING before updating other metadata.
private fun updateNameChangesInAndroidDb(application: Application, editTrackTagInfo: EditTrackTagInfo) {
val uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
editTrackTagInfo.trackId.toLong())
val contentValues = ContentValues()
if (hasQ()) {
contentValues.put(MediaStore.Audio.Media.IS_PENDING, 1)
application.contentResolver.update(uri, contentValues, null, null)
}
contentValues.clear()
if (hasQ())
contentValues.put(MediaStore.Audio.Media.IS_PENDING, 0)
with(editTrackTagInfo) {
title?.let { it -> contentValues.put(MediaStore.Audio.Media.TITLE, it) }
album?.let { it -> contentValues.put(MediaStore.Audio.Media.ALBUM, it) }
artist?.let { it -> contentValues.put(MediaStore.Audio.Media.ARTIST, it) }
}
val rowsUpdated = application.contentResolver.update(uri, contentValues,
null, null)
app crashes at
application.contentResolver.update(uri, contentValues, null, null)
while updating IS_PENDING to 1 in
if (hasQ()) {
contentValues.put(MediaStore.Audio.Media.IS_PENDING, 1)
application.contentResolver.update(uri, contentValues, null, null)
}
I don't understand why updating is_pending would change the volume from SD_Card to internal storage (/storage/emulated/0...).
App crashes only on Android 11 devices. That too on Samsung device only. That too when the track I'm trying to edit is from SD-CARD.
I have tried with Android 11 pixel devices and it works fine.
The track which I'm trying to edit is in SdCard at location
/storage/3964-3431/Music/Bujji-MassTamilan.mp3
I don't understand why while updating IS_PENDING to 1 in samsung android 11 device, root location of media is changing to internal storage
/storage/emulated/0/Music/...
Summary - App crashes only in Android 11 Samsung device when media-file is from SD-Card.
As you know, Xiaomi devices have their own system of permissions. I'm testing my application on the device xiaomi redmi 3, api 22, android 5.1.1. I want to check if there is permission to access the camera and audio. But the standard way does not work:
ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), "android.permission.CAMERA");
returns 0, although this is not true.
I found another way, but it also does not work correctly:
boolean b = hasSelfPermissionForXiaomi(getActivity(),"android.permission.CAMERA");
private boolean hasSelfPermissionForXiaomi(Context context,String permission){
String permissionTop = AppOpsManagerCompat.permissionToOp(permission);
if(permissionTop == null){
// not dangerous
return true;
}
int noteOp = AppOpsManagerCompat.noteOp(context,permissionTop, Process.myUid(),context.getPackageName());
return noteOp == AppOpsManagerCompat.MODE_ALLOWED && checkSelfPermission(context,permission) == PackageManager.PERMISSION_GRANTED;
}
b = true, although this is not true.
Guys, did any of you understand how to check permissions on xiaomi devices ???
I would know one thing about SMS...
I know that is possible read SMS in Android, but I don't know how I can read "Unread SMS", and in particular how to accede to each field like "sender", "SMS", "date", "time", "text".
What that i must do is: when a sms is received, an application "reads" the message and stores all the information in a data structure.
IMPORTANT:
Another question: is it possible read "Unread SMS" in WhatsApp or other IM application (for example facebook messenger) ?
And in this case how I can accede to each field ?
Regards
Reading Phone SMS
Check this out How can I read SMS messages from the device programmatically in Android?
Reading Facebook messages
For facebook you need to implement their API. See this Read Messages in Facebook
Reading Whatsapp messages
Option 1
Whatsapp did not publish any official APIs.
There's this open source API for communicating with whatsapp, it's not official and might stop working if Whatsapp update their protocols.
https://github.com/venomous0x/WhatsAPI
Regarding the legality of using this or other non-official API, it depends on the service agreement that you agreed to with Whatsapp. Read it and see if they frown upon using their communication protocols with clients other than theirs. My guess would be they do not allow it.
Option 2
WhatsApp makes a chat backup everyday at 4 AM on your SD Card. This is a single database encrypted with an AES key. Since it is on the external storage, your app can read it if you have access to the external storage.
You can easily decrypt this database (there is a paper available on this online).
However, this will only give you updated chats once every 24 hours.
If you want more realtime updates, your device has to be rooted, and you will need a completely new parser, as on the internal storage the chats are stored in more than one database.
Option 3
Read this SO question Get all messages from Whatsapp
NOTE: I am not sure about the Whatsapp stuff. It's just a compilation of various posts together.
The easiest function
To read the sms I wrote a function that returns a Conversation object:
class Conversation(val number: String, val message: List<Message>)
class Message(val number: String, val body: String, val date: Date)
fun getSmsConversation(context: Context, number: String? = null, completion: (conversations: List<Conversation>?) -> Unit) {
val cursor = context.contentResolver.query(Telephony.Sms.CONTENT_URI, null, null, null, null)
val numbers = ArrayList<String>()
val messages = ArrayList<Message>()
var results = ArrayList<Conversation>()
while (cursor != null && cursor.moveToNext()) {
val smsDate = cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Sms.DATE))
val number = cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Sms.ADDRESS))
val body = cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Sms.BODY))
numbers.add(number)
messages.add(Message(number, body, Date(smsDate.toLong())))
}
cursor?.close()
numbers.forEach { number ->
if (results.find { it.number == number } == null) {
val msg = messages.filter { it.number == number }
results.add(Conversation(number = number, message = msg))
}
}
if (number != null) {
results = results.filter { it.number == number } as ArrayList<Conversation>
}
completion(results)
}
Using:
getSmsConversation(this){ conversations ->
conversations.forEach { conversation ->
println("Number: ${conversation.number}")
println("Message One: ${conversation.message[0].body}")
println("Message Two: ${conversation.message[1].body}")
}
}
Or get only conversation of specific number:
getSmsConversation(this, "+33666494128"){ conversations ->
conversations.forEach { conversation ->
println("Number: ${conversation.number}")
println("Message One: ${conversation.message[0].body}")
println("Message Two: ${conversation.message[1].body}")
}
}
I have been searching for this from past few days and I came to know that:
"Dual SIM is not supported in Android out of the box. It is a custom modification by manufacturers, and there is no public API to control it."
There is a solution provided in the below link but its not working on my phone Samsung Galaxy S4 Mini.
Call from second sim
I also found this link, which I found very informative.
http://www.devlper.com/2010/06/using-android-telephonymanager/
Now I know that using the following code, I might have a chance to get lucky to make it working:
Intent callIntent = new Intent(Intent.ACTION_CALL)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
callIntent.setData(Uri.parse("tel:" + phone));
context.startActivity(callIntent);
callIntent.putExtra("com.android.phone.extra.slot", 0); //For sim 1
and
callIntent.putExtra("com.android.phone.extra.slot", 1); //For sim 2
I am not sure about this, but I have a question.
In Settings under the SIM Card Manager section, when I have to choose a preferred SIM card for Voice Call, I get four options:
Current Network
Ask Always
SIM 1
SIM 2
When I choose Ask Always option then before making a call I am always asked for choosing a SIM Card, displayed in a Dialog Box, to make the call. My question is can I exploit this thing in my App where I press a button to make a call but it always asks me the same way it does when I chose Ask Always option.
I am sorry, I made this question lengthy, but I think it required it. Please help and big thanks in advance.
EDIT:
How can I achieve this, everytime I press any button (Kind of similar to Ask Always option in Settings) :
Code:
private final static String simSlotName[] = {
"extra_asus_dial_use_dualsim",
"com.android.phone.extra.slot",
"slot",
"simslot",
"sim_slot",
"subscription",
"Subscription",
"phone",
"com.android.phone.DialingMode",
"simSlot",
"slot_id",
"simId",
"simnum",
"phone_type",
"slotId",
"slotIdx"
};
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + "any number"));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("com.android.phone.force.slot", true);
intent.putExtra("Cdma_Supp", true);
//Add all slots here, according to device.. (different device require different key so put all together)
for (String s : simSlotName)
intent.putExtra(s, 0); //0 or 1 according to sim.......
//works only for API >= 21
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
intent.putExtra("android.telecom.extra.PHONE_ACCOUNT_HANDLE", (Parcelable) " here You have to get phone account handle list by using telecom manger for both sims:- using this method getCallCapablePhoneAccounts()");
context.startActivity(intent);
TelecomManager telecomManager = (TelecomManager) this.getSystemService(Context.TELECOM_SERVICE);
List<PhoneAccountHandle> phoneAccountHandleList = telecomManager.getCallCapablePhoneAccounts();
Intent intent = new Intent(Intent.ACTION_CALL).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse("tel:" + number));
intent.putExtra("com.android.phone.force.slot", true);
intent.putExtra("Cdma_Supp", true);
if (simselected== 0) { //0 for sim1
for (String s : simSlotName)
intent.putExtra(s, 0); //0 or 1 according to sim.......
if (phoneAccountHandleList != null && phoneAccountHandleList.size() > 0)
intent.putExtra("android.telecom.extra.PHONE_ACCOUNT_HANDLE", phoneAccountHandleList.get(0));
} else { 1 for sim2
for (String s : simSlotName)
intent.putExtra(s, 1); //0 or 1 according to sim.......
if (phoneAccountHandleList != null && phoneAccountHandleList.size() > 1)
intent.putExtra("android.telecom.extra.PHONE_ACCOUNT_HANDLE", phoneAccountHandleList.get(1));
}
startActivity(intent);
I have an answer for this problem as I was looking for this option. Here are the steps:
first you need xposed framework and;
install miui application and;
add preferred sim option in contact
my application tries to retrieve proxy information from app using android.net.Proxy and than set the information on my restemplate .
It works fine on nexus one but in other phones like Samsung Galaxy it retrives the value -1 for the port , the host works fine.
I've looked everywhere and i cant find out why is returning this value even after i set the proxy port value on the phone , i also read that this method android.net.Proxy.getHost() and
android.net.Proxy.getPort() are deprecated , so my question is :
How can i retrieve proxy information from phone ?
Thanks.
Try the following:
String port = System.getProperty("http.proxyPort");
String hostName = System.getProperty("http.proxyHost");
Much more detailed answer here: Getting WiFi proxy settings in Android
I'm currently doing the following:
private static final boolean IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
...
String proxyAddress;
int proxyPort;
if( IS_ICS_OR_LATER )
{
proxyAddress = System.getProperty( "http.proxyHost" );
String portStr = System.getProperty( "http.proxyPort" );
proxyPort = Integer.parseInt( ( portStr != null ? portStr : "-1" ) );
}
else
{
proxyAddress = android.net.Proxy.getHost( context );
proxyPort = android.net.Proxy.getPort( context );
}
However this only works for System Wide Proxy Settings on pre-3.1 devices, as WiFi AP specific Proxy Settings were not implemented yet. And the System Wide Proxy can not easily be set through the standard Android UI.