Android receiver ignore NEW_OUTGOING_CALL - android

I have a with Broadcastreceiver with an intent-filter to catch android.intent.action.NEW_OUTGOING_CALL.
I read many tutorials and answer here about handling NEW_OUTGOING_CALL intent, but I was unable to make this thing works.
My goal is to log intent android.intent.action.NEW_OUTGOING_CALL received by my Broadcastreceiver. I'm unable to make this simple thing works.
Here's my code:
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.vannus.broadcasttest">
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".TestReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
</manifest>
This is the code for the Broadcastreceiver (TestReceiver.java)
package net.vannus.broadcasttest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class TestReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Log.w("###TEST###",intent.getAction());
}
}
The project also contains an empty MainActivity with no functionality.
Executing the project the main activity is launch, but no log are written when I try to make or receive calls.
I tested the code in the emulator (Android 7) and on a Motorola G4 phone (Android 6.0), but nothing was logged on logcat.
I'm using Android Studio 2.3
What am I doing wrong?
Thanks
Vannus

From android Oreo the problem is that for "dangerous" type permissions (of which PROCESS_OUTGOING_CALLS" is one), it is not enough to declare then in the manifest. You need to specifically prompt the user to grant this permission. This can be done using the framework as discussed here:
https://developer.android.com/training/permissions/requesting
Specifically you need to basically call "requestPermissions" with an array of the permissions you actually need and it will ask the user to approve them.
Personally I find it quite annoying but I get the rationale behind it.

The solution is very simple.... on the phone go to settings-> apps select application and give phone permission.
The clue came when searching the logcat I found this error
03-05 20:18:57.090 1547-1775/system_process W/BroadcastQueue: Permission Denial: receiving Intent { act=android.intent.action.NEW_OUTGOING_CALL flg=0x10000010 (has extras) } to net.vannus.broadcasttest/.TestReceiver requires android.permission.PROCESS_OUTGOING_CALLS due to sender android (uid 1000).

in my case, app had the permissions already, but for some reason when i declared
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter
after android.intent.action.NEW_OUTGOING_CALL, the receiver started sending out the new outgoing call event.
so the declaration looks like this :
<receiver android:name=".CallReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>

Check for permission run time
#TargetApi(Build.VERSION_CODES.M)
public static boolean hasSelfPermission(Activity activity, String[] permissions) {
// Below Android M all permissions are granted at install time and are already available.
if (!isMNC()) {
return true;
}
// Verify that all required permissions have been granted
for (String permission : permissions) {
if (activity.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
and use this method to check permission
#TargetApi(Build.VERSION_CODES.M)
private boolean isReadStatePermission() {
if (hasSelfPermission((Activity) context, READ_PHONE_STATE)) {
return true;
} else {
if (((Activity) context).shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE)) {
((Activity) context).requestPermissions(READ_PHONE_STATE, REQUEST_WRITE_STORAGE);
} else {
((Activity) context).requestPermissions(READ_PHONE_STATE, REQUEST_WRITE_STORAGE);
}
return false;
}
perform any operation after checking the permission
if (isReadStatePermission()) {
PERFROM YOUR OPERATION
}

Related

BroadcastReceiver not called when WiFi changes

I've implemented a BroadcastReceiver according to https://developer.android.com/guide/components/broadcasts but it does not seem to work.
The receiver part of my Manifest.xml looks like this (I use android.permission.ACCESS_NETWORK_STATE and android.permission.ACCESS_WIFI_STATE):
...
<receiver android:name=".BackgroundTask">
<intent-filter>
<action android:name="android.net.wifi.WIFI_STATE_CHANGED"/>
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
...
and it's declared within my application.
My BroadcastReceiver class looks like this:
public class BackgroundTask extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("Connection changed!");
Toast.makeText(context, "Network state changed", Toast.LENGTH_LONG).show();
}
}
Neither the toast is displayed nor I receive the println-ed output on my logcat.
I also read the note which recommends me to use scheduled jobs instead of receivers, but I could not find an example how to use this for listening to network changes.
The reason I want to use this is because I want my (background)-app only to run while my phone is connected to my WiFi - if you have any different suggestions on how to implement this, I'm also very thankful.
Btw. I'm using Android 8.0.0.
Cheers,
Nikolar
Update:
Somehow it still does not work. Am I forgetting anything?
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="mypackagename">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
<receiver android:name=".BackgroundPoller">
</receiver>
</application>
</manifest>
Just for clearence I renamed my BackgroundTask-Class to BootReceiver:
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("INFO", "BootReceiver started");
Intent newIntent = new Intent(context, BackgroundPoller.class);
context.sendBroadcast(newIntent);
Log.d("INFO", "BackgroundPoller activated");
}
}
When I successfully send my broadcast
adb.exe shell am broadcast -a android.intent.action.ACTION_BOOT_COMPLETED
I still don't get a log output.
To get around Oreo's broadcast receiver restrictions, you have to register your receivers using Context.registerReceiver(). You could do this by subclassing Application and registering receivers in onCreate(). The only downside to doing this is your app would have to be launched to have Application.onCreate() get called. To get around this, you could register an ACTION_BOOT_COMPLETED receiver in your manifest as this action is exempt from the restriction. Your ACTION_BOOT_COMPLETED receiver doesn't have to do anything, but it will force your app to start running on boot and therefore Application.onCreate() will get called. Then the only challenge is keeping your app running because the system will kill it if the user doesn't go into it. There's a couple options to solve this. You could write a foreground service whose only purpose is to keep the app alive. Or perhaps use AlarmManager to schedule some intent that will wake your app back up, which will register your receivers again.

My app can't receive BOOT_COMPLETED broadcast

I am working on an app which needs receive BOOT_COMPLETED broadcast when the device boots.
According to the documents in Android Developers, I already know that since android 3.1, apps that never run after installing or force killed by user will not receive the boot broadcast when device boots, so with the rules, how can I receive boot broadcast? By the way, I have already tried open my app when boot is finished, but it is still not working.
Here's the code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.guoyonghui.todo"
android:installLocation="auto">
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:name=".BaseApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".tasks.TasksActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".taskdetail.TaskDetailActivity"/>
<activity android:name=".addedittask.AddEditTaskActivity"/>
<activity android:name=".statistics.StatisticsActivity"/>
<receiver android:name=".alarm.AlarmReceiver">
<intent-filter>
<action android:name="com.guoyonghui.todo.alarm.ACTION_TASK_ALARM"/>
</intent-filter>
</receiver>
<receiver
android:name=".alarm.BootReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
</application>
</manifest>
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Toast.makeText(context, action, Toast.LENGTH_SHORT).show();
Log.d("AlarmReceiver", action);
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
TasksRepository tasksRepository = TasksRepository.getInstance(TasksLocalDataSource.getInstance(context));
List<Task> tasks = tasksRepository.loadTasks();
for (Task task : tasks) {
if (task.isActive()) {
AlarmReceiver.setAlarm(context, task);
}
}
}
}
}
You don't want to use the Default category in this case. According to the documentation of this category, it is used for the following purpose:
Set if the activity should be an option for the default action (center press) to perform on a piece of data. Setting this will hide from the user any activities without it set when performing an action on some data. Note that this is normally -not- set in the Intent when initiating an action -- it is for use in intent filters specified in packages. (Emphasis mine)
See the list of categories and what they're for here:
https://developer.android.com/reference/android/content/Intent.html

Android: Boot Complete only works if I launch App Immediately

I'm trying to reset alarms in my app and using a receiver to get onBootCompleted. To see if the intent was received, I'm using a toast. The toast only appears if I immediately open the app. Otherwise, the toast does not appear. I looked at previous questions but almost all of them involve services, which I am not using. I am not sure if that is a part of the problem.
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="internalOnly"
package="package.name" >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:configChanges="orientation|screenSize|keyboardHidden"
android:name=".MainActivity"
android:label="#string/app_name"
android:launchMode="singleTop" >
<meta-data android:name="android.app.searchable"
android:resource="#xml/searchable" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
</activity>
<receiver android:name=".AlarmReceiver" >
<intent-filter>
<action android:name="android.intent.action.ALARM_SERVICE" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmReset"android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
Receiver Class
public class AlarmReset extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Hello! Got message",
Toast.LENGTH_LONG).show();
//reset alarms etc. No service set.
}
I also tried writing the manifest receiver as
<receiver android:name=".AlarmReset" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Key points I found online were to include permissions (which I did) and to watch out for logging.
What I do not understand is why it works if I immediately (within a few seconds, otherwise the toast does not appear) start my activity but is unsuccessful otherwise. I am considering testing a few possibilities like launching the activity itself through code or using a service like most others have. I am currently testing on Android 4.4 on an actual phone.
When an app is installed, it is in a stopped state. None of its components will be activated (such as your BOOT_COMPLETED receiver) until the app is moved out of this state by being launched by the user. This is why your app doesn't work unless you launch it once.
Note that force stopping the app from Settings also moves it into this stopped state.
See this page for more details (search the page for "launch controls").
Starting with Android 3.1 all applications, upon installation, are placed in a "stopped" state.(This is the same state that the application ends up in after the user force-stops the app from the Settings application.)
While in "stopped" state, the application will not run for any reason, except by a manual launch of an activity. (Meaning no BroadcastReceviers(ACTION_PACKAGE_INSTALLED, BOOT_COMPLETED etc.) will be invoked, regardless of the event for which they have registered, until the user runs the app manually.)
But you can start a serivice for ex-
1) In your element:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
2) In your element (be sure to use a fully-qualified [or relative] class name for your BroadcastReceiver):
<receiver android:name="com.example.MyBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
In MyBroadcastReceiver.java:
package com.example;
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent startServiceIntent = new Intent(context, MyService.class);
context.startService(startServiceIntent);
}
}
I feel the need to clarify the issue and solution, since the question was not clear (due to confidentiality issues).
The Basic Solution to my problem was just starting a service.
The Problem: I was trying to make the alarm in my class, AlarmReset, through AlarmManager. That in itself may have been an issue, but in addition, I tried to access objects that were instantiated in the MainActivity, furthering my dilemma. The reason why it worked when I opened MainActivity quickly enough, I suspect, is because I was able to instantiate the objects and set up the prerequisites for the class to directly access. I think the toast not appearing is similar to the issue.
The Solution: I set up a service class which I directed AlarmReset to. This is what I changed the AlarmReset class to:
public class AlarmReset extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Hello! Got message",
Toast.LENGTH_LONG).show();
//Pretty sure the Toast doesn't appear still.
Intent service = new Intent(context, Service.class);
context.startService(service);
}
Then my service class
public class Service extends IntentService {
private DataBaseManager database;
public Service()
{
super("Service");
}
#Override
protected void onHandleIntent(Intent intent)
{
database = new DataBaseManager(this);
Toast.makeText(this, "Hi",
Toast.LENGTH_LONG).show();
Toast.makeText(this, "Hello! Got message",
Toast.LENGTH_LONG).show();
//rest of code
}
Similarly, the text does not appear except if I am on the app immediately (I suspect it has to do with the threads).
Here, I made sure to instantiate my objects before using them (or did so after crashing).
A few possible problems that others may encounter (as I have read) are the following:
Installing in internal storage
android:installLocation="internalOnly"
and receiving permission for booting
<uses-permission
android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Some problems that people had suggested and were not very important were:
Using android:enabled and android:exported. Default values are fine
Writing the full receiver name. For me it wasn't necessary
<action android:name="android.intent.action.QUICKBOOT_POWERON" /> did not seem to do much.

Start an Activity on Phone Boot in Android

I want to start my application automatically when the phone boots.
I declared a BroadcastReceiver in the manifest file.
<receiver android:name=".Autostart">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
I made a java file for the receiver.
Autostart.java
public class Autostart extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent pushIntent = new Intent(context, MushTouchActivity.class);
pushIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(pushIntent);
}
}
}
But, the application does not launch when I switch my phone on. Can anyone tell me what I am missing here ?
try your if statement like this:
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
Intent i = new Intent(context, MushTouchActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
In case you are on Android 3.1 or newer:
Make sure that you started your application at least once manually (e.g. by opening it from the app drawer). Otherwise your app is marked as stopped by the system:
Applications are in a stopped state when they are first installed but are not yet launched
Stopped apps do not receive any broadcast intents, including BOOT_COMPLETED.
See Android 3.1. Platform - Launch controls on stopped applications for more information.
The best answer would be to show a Notification and ask the user to launch the app from that notification and use a pending intent for that activity in the notification.
Tested on Android 10
1. Create A Broadcast Listener
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() == "android.intent.action.ACTION_SHUTDOWN") {
// Your tasks for shut down
} else {
// Your tasks for Boot up
}
}
}
2. Config Manifest
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:theme="#style/AppTheme">
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.ACTION_BOOT_COMPLETED" />
<action android:name="android.intent.action.REBOOT" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
</intent-filter>
</receiver>
</application>
If you search for a sample application code for working with services in background and control actions on screen off/on then visit this repo:
https://github.com/varunon9/DynamicWallpaper
you can update this repo source code with step 1 and 2 for control boot and shutdown events in addition to screen on/off.

Intercepting outgoing call - what am I missing?

I'm trying to write a simple app to capture the ACTION_NEW_OUTGOING_CALL intent and write some debugging information.
Here is my manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.apis"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="#drawable/icon" android:label="#string/app_name">
<receiver android:name="DialerReceiver" android:exported="false" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"></uses-permission>
</manifest>
And here is the code for DialerReceiver:
package com.example.android.apis;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class DialerReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
debugOut("arg0: " + arg0.toString());
debugOut("arg1: " + arg1.toString());
debugOut("isOrderedBroadcast = " + isOrderedBroadcast());
}
private static void debugOut(String str) {
Log.i("DialerReceiver", str);
}
}
For reasons that I do not understand, when I install this and initiate an outgoing call, I get the following error:
WARN/ActivityManager(59): Permission Denial:
broadcasting Intent { act=android.intent.action.NEW_OUTGOING_CALL (has extras) }
from com.android.phone (pid=123, uid=1001) requires null
due to receiver com.example.android.apis/com.example.android.apis.DialerReceiver
What gives? It seems like PROCESS_OUTGOING_CALLS should be sufficient.
FWIW, if I change to a notification without permissions (TIMEZONE_CHANGED, for example), this works like a charm.
Thanks in advance.
Answering my own question.
After reviewing my manifest, it seemed like android:exported="false" was incorrect, since Android itself would need to invoke DialerReceiver.
When I changed this to android:export="true", everything worked just fine.
FWIW, I did this against the emulator (API version 8 and version 10 devices).
I am also intercepting outgoing calls to take an action. I also only have the added permission, PROCESS_OUTGOING_FILES, but I did notice that in my DialerReceiver declaration I am setting a priority:
<receiver
android:name="DialerReceiver"
android:enabled="true">
<intent-filter android:priority="2147483647">
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
This setup works fine for me. I can post some code from the DialerReceiver class if you need it. Are you testing this against an emulator or a phone? I have only tested against an actual phone. I am not using an emulator.
Hope this helps.

Categories

Resources