I need to read text from incoming SMS and, as from title, I'm facing a strange behaviour: filter is correctly invoked when testing in android emulator and, on real phone, when using an SMS web service but not if SMS comes from another phone; below my code.
MANIFEST
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
Of course permission is granted for all of them.
BROADCAST RECEIVER
public class SmsNotificationReceiver extends BroadcastReceiver {
private static final String TAG = "[SmsNotificationReceiver]";
public SmsNotificationReceiver() {}
#Override
public void onReceive(Context context, #NonNull Intent intent) {
String action = intent.getAction();
if (TextUtils.isEmpty(action)) { return; }
Log.i(TAG, "Action: " + action);
}
}
RECEIVER REGISTRATION
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
BroadcastReceiver smsReceiver = new SmsNotificationReceiver();
registerReceiver(smsReceiver, filter);
Anything wrong I'm doing here? Does anyone met similar behaviour and solved it? If so please kindly address me to recognize what's wrong?
Thanks
Related
I'm developing an app where the app has OTP phone call for setting the user pin. So what i'm going to is to set automaticly the phone number i got from phone call to textview. The problem is PhoneStateReceiver class which extend BroadcastReceiver not working on Pie but working on Oreo.
It's work perfectly fine on my Oreo phone but not with Pie phone, there is no error i got, except on Pie the onReceive at PhoneStateReceiver is not called.
public class PhoneStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if((state.equals(TelephonyManager.EXTRA_STATE_RINGING))){
Toast.makeText(context,"Received State",Toast.LENGTH_SHORT).show();
}
if ((state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))){
Intent local = new Intent();
local.setAction("service.to.activity.transfer");
local.setAction("android.intent.action.PHONE_STATE");
local.setAction("android.intent.action.NEW_OUTGOING_CALL");
local.putExtra("number", incomingNumber);
context.sendBroadcast(local);
}
if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)){
Intent local = new Intent();
local.setAction("service.to.activity.transfer");
local.setAction("android.intent.action.PHONE_STATE");
local.setAction("android.intent.action.NEW_OUTGOING_CALL");
local.putExtra("number", incomingNumber);
context.sendBroadcast(local);
}
}
}
}
This is my Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.jpx.qur">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
<application
android:name=".modules.App"
android:allowBackup="false"
android:icon="#mipmap/ic_launcher_square"
android:label="#string/app_name"
android:networkSecurityConfig="#xml/network_security_config"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:replace="android:allowBackup">
<receiver android:name=".utils.phoneutil.PhoneStateReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
</manifest>
This is how i handle the register receiver on my Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_otp);
getNumberPhone();
}
public void getNumberPhone(){
IntentFilter filter = new IntentFilter();
filter.addAction("service.to.activity.transfer");
BroadcastReceiver updateUIReciver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//UI update here
if (intent != null){
String message = intent.getStringExtra("number");
if(message != null){
if(message.length() == DIGITLENGTH){
String asubstring = message.substring(1, message.length());
pin1.setText(""+asubstring.charAt(0));
pin2.setText(""+asubstring.charAt(1));
pin3.setText(""+asubstring.charAt(2));
pin4.setText(""+asubstring.charAt(3));
}
}
}
}
};
registerReceiver(updateUIReciver, filter);
}
It's work perfectly fine on my Oreo phone but not with Pie phone, there is no error i got, except on Pie the onReceive at PhoneStateReceiver is not called. Please help me to fix this
Add READ_CALL_LOG permission in manifest as below and also take runtime permission:
<uses-permission android:name="android.permission.READ_CALL_LOG" />
As per Android doc:
Restricted access to call logs
Android 9 introduces the CALL_LOG permission group and moves the
READ_CALL_LOG, WRITE_CALL_LOG, and PROCESS_OUTGOING_CALLS permissions
into this group. In previous versions of Android, these permissions
were located in the PHONE permission group.
Restricted access to phone numbers Apps running on Android 9 cannot
read phone numbers or phone state without first acquiring the
READ_CALL_LOG permission, in addition to the other permissions that
your app's use cases require.
Phone numbers associated with incoming and outgoing calls are visible
in the phone state broadcast, such as for incoming and outgoing calls
and are accessible from the PhoneStateListener class. Without the
READ_CALL_LOG permission, however, the phone number field that's
provided in PHONE_STATE_CHANGED broadcasts and through
PhoneStateListener is empty.
To read phone numbers from phone state, update your app to request the
necessary permissions based on your use case:
To read numbers from the PHONE_STATE intent action, you need both the
READ_CALL_LOG permission and the READ_PHONE_STATE permission. To read
numbers from onCallStateChanged(), you need the READ_CALL_LOG
permission only. You don't need the READ_PHONE_STATE permission.
Check full documentation here.
I have a service that is running in the foreground, inside this service i have a broadcast receiver, that listen to the SMS_RECEIVED action.
When the user is inside the application (both the application and the service are in the foreground) everything works well, and i am receiving the intent.
But when the user exists the application (only the service with the broadcast is in the foreground), the service stops when sms is received.
When the service is stopped no error reports are found anywhere (not in the logcat and no crash dialog pops up).
My service with the broadcast:
public class myService extends IntentService {
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(myService.this, intent.getAction(), Toast.LENGTH_SHORT).show();
}
};
#Override
public void onCreate() {
super.onCreate();
IntentFilter i= new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
i.setPriority(999);
registerReceiver(mReceiver, receiverFilter);
startForeground(...);
}
public void onDestroy() {
super.onDestroy();
stopForeground(true);
}
}
And i also have the following permission in my manifest:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
myService is declared like this in the manifest:
<service
android:name=".Services.myService"
android:enabled="true"
android:exported="false" />
I had the same problem and I solved it removing <uses-permission android:name="android.permission.RECEIVE_SMS" />. But removing this permission I can't detect incoming SMS, so I created a class like these Catching Outgoing SMS using ContentObserver and used MESSAGE_TYPE_RECEIVED = 1 instead MESSAGE_TYPE_SENT = 2. You need to add this permission <uses-permission android:name="android.permission.READ_SMS" />.
I am writing an app which receives SMS data message, encrypt its content and save it to database. To realize it I've created a service with a local BroadcastReceiver as follow:
public class SMMReceiverService extends Service {
private class SMMreceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Bundle extras = intent.getExtras();
//call a method from service
}
}
private SMMreceiver smmReceiver;
private IntentFilter intentFilter;
#Override
public void onCreate(){
super.onCreate();
android.os.Debug.waitForDebugger();
smmReceiver = new SMMreceiver();
intentFilter = new IntentFilter();
intentFilter.addAction("android.provider.Telephony.DATA_SMS_RECEIVED");
intentFilter.addDataScheme("sms");
intentFilter.addDataAuthority("localhost","8901");
registerReceiver(smmReceiver, intentFilter);
}
}
Service is starting normally but onReceive method of SMMreceiver is never called. In manifest I've declared only my service as follow:
<service
android:name=".Services.SMMReceiverService"
android:enabled="true"
android:exported="true" >
</service>
There are also all required permissions:
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
How to solve my problem in correct way? I will be grateful for your help!
Well, it seems like you kind of answered your own question.
"Service is starting normally but onReceive method of SMMreceiver is never called. In manifest I've declared only my service as follow:"
you have to also declare your receiver in your manifest, did you do that?
I am learning from "Learning Android" - Oreilly - Marko Gargenta.
I am at chapter 11 (Broadcast Receivers)
I followed the book and everything work OK. But I have a question about how custom permissions are used to restrict sending and receiving the broadcasts within a single app.
The book is clear about this topic. but I feel there is something missing.
How do the receiver and the sender tell each other about different permissions?
In AndroidManifest.xml file:
<permission
android:name="saleh.yamba.SEND_TIMELINE_NOTIFICATIONS"
android:description="#string/send_timeline_notifications_permission_description"
android:label="#string/send_timeline_notifications_permission_label"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="normal" />
<permission
android:name="saleh.yamba.RECEIVE_TIMELINE_NOTIFICATIONS"
android:description="#string/receive_timeline_notifications_permission_description"
android:label="#string/receive_timeline_notifications_permission_label"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="normal" />
<uses-permission android:name="saleh.yamba.SEND_TIMELINE_NOTIFICATIONS" />
<uses-permission android:name="saleh.yamba.RECEIVE_TIMELINE_NOTIFICATIONS" />
In the Service that send broadcasts:
Intent intent = new Intent("saleh.yamba.NEW_STATUS");
updaterService.sendBroadcast(intent, "saleh.yamba.RECEIVE_TIMELINE_NOTIFICATIONS");
Here, sender sends intent with saleh.yamba.RECEIVE_TIMELINE_NOTIFICATIONS permission, Ok, How does the receiver know about this permission?
In the Activity that receives the broadcast via BroadcastReceiver:
TimelineReceiver receiver;
IntentFilter filter;
protected void onCreate(Bundle savedInstanceState)
{
receiver = new TimelineReceiver();
filter = new IntentFilter("saleh.yamba.NEW_STATUS");
}
protected void onResume()
{
this.registerReceiver(receiver, filter, "saleh.yamba.SEND_TIMELINE_NOTIFICATIONS", null);
}
protected void onPause()
{
this.unregisterReceiver(receiver);
}
private class TimelineReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
//do something.
}
}
Here receiver receives it with another permission. OK,
How does the receiver know about saleh.yamba.RECEIVE_TIMELINE_NOTIFICATIONS.
There is nothing in the code of the receiver part that tells that the BroadcastReceiver will be invoked only if the receiver has saleh.yamba.RECEIVE_TIMELINE_NOTIFICATIONSpermission.
There is nothing in the code of the receiver part that tells that the BroadcastReceiver will be invoked only if the sender has saleh.yamba.RECEIVE_TIMELINE_NOTIFICATIONSpermission.
Yes, there is. You passed in saleh.yamba.RECEIVE_TIMELINE_NOTIFICATIONS to registerReceiver().
Specifically, you are using the four-parameter version of registerReceiver(), where the third parameter is a "String naming a permissions that a broadcaster must hold in order to send an Intent to you. If null, no permission is required."
Is there any way to listen to incoming calls by extending BroadcastReceiver to listen to OS's broadcast,without using PhoneStateIntentReceiver or PhoneStateListener.
Also please tell me what will be action and permissions in manifest.
I've tried with as follows but it is not working for incoming calls but working for outgoing
The only one .java file of app is as follows(the app only one .java file and one manifest file)
package com.crsardar.media.audio;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class IncommingCallReceiverCRS extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Log.e("Chitta : ", "Its working");
}
}
manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.crsardar.media.audio"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="#drawable/icon" android:label="#string/app_name">
<receiver android:name="IncommingCallReceiverCRS" android:enabled="true">
<intent-filter>
<!--action android:name="android.intent.action.NEW_OUTGOING_CALL"/-->
<action android:name="android.intent.action.ANSWER" >
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
</manifest>
The action you have defined in your manifest is incorrect. this is an Action Intent that can be used to answer a call and not monitor incoming calls.
You can use two broadcast receivers that listen to ACTION_PHONE_STATE_CHANGED and NEW_OUTGOING_CALL broadcast intents.
The ACTION_PHONE_STATE_CHANGED will be received when there is a new incoming call, call answered or hangup (See the documentation for the EXTRAs received with this Intent).
The NEW_OUTGOING_CALL will be received when there is a new outgoing call placed on your device.
As for permissions, I think you got it about right in your manifest (I assume the RECORD_AUDIO permission is used for something else in your application)
Here is My demo for android unit test. You can refer to it.
public interface ICallVerify {
void onOutgoing(Context context, Intent intent);
void onCallStateChange(Context context, Intent intent);
}
protected void setUpCallVerify(final ICallVerify callVerify) { //listen ingoing and outgoing
final CountDownLatch latch = new CountDownLatch(1);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) { //state change
Log.i(TAG, "outgoing call...");
callVerify.onOutgoing(context, intent);
} else if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)){ // state changed
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (state.equals("RINGING")) {
state += " number:" + intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
}
Log.i(TAG, "call state changed.... " + state);
callVerify.onCallStateChange(context, intent);
}
}
};
IntentFilter filter = new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
ContextUtils.getTargetContext().registerReceiver(receiver, filter);
try {
latch.await(5, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Dont forget to add permissions
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"></uses-permission>