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.
Related
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
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
if (incomingNumber == null || "".equals(incomingNumber)) {
return;
}
break;
}
}
I got same issue below Android sdk27 ever, I start PhoneStateListener in PhoneService ,
public void startPhoneStateListener() {
mTelManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
mTelManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
but I only start Service in RootReceiver, not in MainActivity ,when I start PhoneService in MainActivity ,I fixed it.
<receiver android:name=".receiver.RootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
but this only work below Android sdk 27 , I have no idea about Android 9.0 , by the way, I have written the permission :
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
As per the Behavior Changes for all apps in Android 9.0:
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.
You must request the READ_CALL_LOG permission if you want the incoming phone number.
Note that as per that same page:
To read numbers from onCallStateChanged(), you need the READ_CALL_LOG permission only. You don't need the READ_PHONE_STATE permission.
I once had a broadcast receiver defined in my manifest to receive the Phone State, like this...
<receiver
android:name=".TelephonyManagerReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
I know in Android O I need to remove this and register the receiver in code, so I've done this...
private BroadcastReceiver callReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
callReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Phone","received");
}
};
this.registerReceiver(
callReceiver,
new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED)
); }
I'd expect to see some logging when I receive/make a call, but I do not. Any ideas?
I had the same problem. I added two dynamic permissions: CALL_PHONE, READ_PHONE_STATE and receiver is working well even if it's declared only in Manifest file.
I tested solution on emulator and also on phone - Nexus 5.
(This way it's working when app is open or in background, if you close app it won't work. For this I think you have to use foreground service)
I hope it's not too late.
Did you add the permission in the manifest and also request the permission at runtime?
Manifest:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Runtime:
private static final int REQUEST_PHONE_STATE = 1;
private static String[] PERMISSIONS_PHONE_STATE = {
Manifest.permission.READ_PHONE_STATE
};
public static void verifyPhonePermissions(Activity activity) {
// Check if we have this permission
int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_PHONE_STATE,
REQUEST_PHONE_STATE
);
}
}
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."
I want to receive notification when Mobile network connection is lost or received. Through following code, I can receive notification for Wi-Fi (Data) connection but not for Mobile (Voice) connection.
Manifest :
<uses-permission android:name="android.permission.ACCESS_NETWORK_ST ATE"/>
<application android:icon="#drawable/icon" android:label="#string/app_name">
<receiver android:name=".notifier">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE " />
</intent-filter>
</receiver>
</application>
Java :
public class notifier extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast toast = Toast.makeText(context, "Network Changed !!", Toast.LENGTH_LONG);
toast.show();
}
}
Please tell me, how can I receive notification for Mobile Network (Voice).
Pseudocode!!
PhoneStateListener myListener = new PhoneStateListener() {
#Override
public void onServiceStateChanged (ServiceState serviceState) {
// Handle different service states here.
}
};
((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE))
.listen(myListener, PhoneStateListener.LISTEN_SERVICE_STATE);
http://developer.android.com/reference/android/telephony/TelephonyManager.html#listen(android.telephony.PhoneStateListener, int)
Check the permission in the AndroidManifest.xml, first.
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"></uses-permission>
And try this code below.
ConnectivityManager manager = (ConnectivityManager)appContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mobile = manager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if(mobile.isConnected()) {
//Do Sth.
}
If this is not work, check your phone's brand. If the phone's developer blocked some codes or not implement some code, it doesn't work. What is your phone?