I'm trying to create an external broadcast service which sends a number. A client (external application) trying to send a request to my service and the service sends back a number. I registered my service and broadcast resiever in AndroidManifest.xml:
<service android:exported="true" android:enabled="true" android:name=".MyService"/>
<receiver android:exported="true" android:enabled="true" android:name=".MyStartServiceReceiver">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
my broadcast class:
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent intent1 = new Intent(context, MyService.class);
context.startService(intent1);
}
}
in MyService class I'm trying to put extra data
public void onStart(Intent intent, int startId) {
Log.i(TAG, "service started");
intent.setClass(getApplicationContext(), MyService.class);
intent.setAction(Intent.ACTION_SEND);
intent.putExtra("result", 10);
sendBroadcast(intent);
}
and send it back, but I keep getting zero. To check my service I use adb shell:
adb shell am broadcast -a android.intent.action.SEND
Broadcasting: Intent { act=android.intent.action.SEND }
Broadcast completed: result=0
Does anybody know what's wrong in my service?
You can see here:
http://developer.android.com/reference/android/content/Intent.html
that ACTION_SEND is activity action, it cannot be used with receiver.
So you must switch from receiver to activity, you can make it a hidden activity using Theme.NoDisplay
[edit]
some more explanation: BroadcastReceiver with intent-filter for them?
Try something like this.
Method to send broadcast, used within the MyService
public static void sendSomeBroadcast(Context context, String topic) {
Intent actionIntent = new Intent();
// I would use Constants for these Action/Extra values
actionIntent.setAction(ConstantClass.SEND_SOME_BROADCAST);
actionIntent.putExtra(ConstantClas.BROADCAST_RESULT, 10);
LocalBroadcastManager.getInstance(context).sendBroadcast(actionIntent);
}
In action
public void onStart(Intent intent, int startId) {
sendSomeBroadcast();
}
BroadcastReceiver
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// do what you want with the intent, for example intent.getExtras()..
Intent intent1 = new Intent(context, MyService.class);
context.startService(intent1);
}
}
Binding the receiver and listening for specific Action
private void bindStartServiceReceiver() {
MyStartServiceReceiver startServiceReceiver = new MyStartServiceReceiver();
//This may need to be changed to fit your application
LocalBroadcastManager.getInstance(this).registerReceiver(subscribeTopicReceiver,
new IntentFilter(ConstantClass.SEND_SOME_BROADCAST));
}
Related
MyReceiver.java
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Log.i("MyReceiver", "MyAction received!");
}
}
In AndroidManifest.xml (under the application tag)
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="MyAction" />
</intent-filter>
</receiver>
MainActivity.Java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sendBroadcast(new Intent("MyAction"));
}
}
MyReceiver.onReceive method is never triggered.
Did I miss something?
I use Android 8.
Then you have to use an explicit Intent, one that identifies the receiver, such as:
sendBroadcast(new Intent(this, MyReceiver.class).setAction("MyAction"));
See Broacast limitations in Android 8 release docs.
In Android 8 onwords
We need to provide the explicite class for handling i.e setcomponent param along with action
Example :
private void triggerBroadCast(String firstFavApp, String secondFavApp) {
Intent intent = new Intent("FavAppsUpdated");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.putExtra("FIRST_FAV_APP", firstFavApp);
intent.putExtra("SECOND_FAV_APP", secondFavApp);
intent.setComponent(new
ComponentName("com.android.systemui",
"com.android.systemui.statusbar.phone.FavAppsChanged"));
Log.i(TAG, "Trigger Fav Apps" + firstFavApp + " " + secondFavApp);
favouriteContract.getAppContext().sendBroadcast(intent);
}
Below Android 8
Only action is enough for receiving Broadcast
void broadCastParkingStates(Context context) {
Intent intent = new Intent("ReverseCameraStates");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.putExtra("PARKING_GUIDE", ReverseCameraPreference.getParkingGuide(context));
intent.putExtra("PARKING_SENSOR", ReverseCameraPreference.getParkingSensor(context));
intent.putExtra("TRAJECTORY", ReverseCameraPreference.getTrajectory(context));
Log.i("BootCompletedReceiver", "Sending Reverse Camera settings states BaordCast");
Log.i("BootCompletedReceiver", "States Parking:Sensor:Trajectory="
+ intent.getExtras().getBoolean("PARKING_GUIDE")
+ ":" + intent.getExtras().getBoolean("PARKING_SENSOR")
+ ":" + intent.getExtras().getBoolean("TRAJECTORY")
);
context.sendBroadcast(intent);
}
If you have multiple receivers, you can send broadcast to all the receivers using only custom action defined in manifest for that you need to add the following flag while sending broadcast
Note: I have used adb to test it on Android 10, you can add it in application
FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000
adb shell am broadcast -a MyAction -f 0x01000000
In Kotlin:
val intent = Intent(this, MyBroadCastReceiver::class.java)
intent.addCategory(Intent.CATEGORY_DEFAULT)
intent.action = "my.custom.broadcast"
sendBroadcast(intent)
Change the MainActivity's code as follows:
Intent intent = new Intent(this, MyReceiver.class);
intent.setAction("MyAction");
sendBroadcast(intent);
The string itself does not matter, just need to be the same in all places and unique, I use fully qualified name of the constant.
<receiver android:name="com.mypackage.receivers.MyBroadcastReceiver">
<intent-filter>
<action android:name="com.mypackage.receivers.MyBroadcastReceiver.ACTION_CUSTOM"/>
</intent-filter>
</receiver>
The receiver:
package com.mypackage.receivers;
public class MyBroadcastReceiver extends BroadcastReceiver {
public static final String ACTION_CUSTOM = "com.mypackage.receivers.MyBroadcastReceiver.ACTION_CUSTOM";
#Override
public void onReceive(Context context, Intent intent) {
if (ACTION_CUSTOM.equals(intent.getAction())) {
// do custom action
}
}
}
To broadcast the intent:
sendBroadcast(new Intent(MyBroadcastReceiver.ACTION_CUSTOM));
I have App A and App B. In App A I want to send broadcast to App B.
This is the code for App A:
final Intent intent = new Intent();
intent.setAction("com.pkg.perform.Ruby");
intent.putExtra("KeyName", "code1id");
intent.setComponent(new ComponentName("com.pkg.AppB", "com.pkg.AppB.MainActivity"));
sendBroadcast(intent);
And in App B - In MainActivity, I have MyBroadCastReceiver Class.
public class MainActivity extends Activity {
private MyBroadcastReceiver MyReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Receive broadcast from External App
IntentFilter intentFilter = new IntentFilter("com.pkg.perform.Ruby");
MyReceiver = new MyBroadcastReceiver();
if(intentFilter != null)
{
registerReceiver(MyReceiver, intentFilter);
}
}
public class MyBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(MainActivity.this, "Data Received from External App", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
if(MyReceiver != null)
unregisterReceiver(MyReceiver);
}
}
I am getting the error - Receiver is not registered.
First thing first declare the receiver in app B in the manifest file like this:
<receiver android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.pkg.perform.Ruby" />
</intent-filter>
</receiver>
when sending the broadcast add FLAG_INCLUDE_STOPPED_PACKAGES flag to the intent [src] because when you broadcast from app A to app B , app B might not be running, this flag insures that the broadcast reachs out even apps not running:
FLAG_INCLUDE_STOPPED_PACKAGES flag is added to the intent before it
is sent to indicate that the intent is to be allowed to start a
component of a stopped application.
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
In your case it will be like this:
final Intent intent=new Intent();
intent.setAction("com.pkg.perform.Ruby");
intent.putExtra("KeyName","code1id");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setComponent(
new ComponentName("com.pkg.AppB","com.pkg.AppB.MyBroadcastReceiver"));
sendBroadcast(intent);
In App A: Send the broadcast here.
final Intent i= new Intent();
i.putExtra("data", "Some data");
i.setAction("com.pkg.perform.Ruby");
i.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
getApplicationContext().sendBroadcast(i);
In App B manifest
<receiver android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.pkg.perform.Ruby" />
</intent-filter>
</receiver>
In App B MainActivity: register the receiver oncreate(), and unregister onDestroy()
public class MainActivity extends AppCompatActivity
{
private MyBroadcastReceiver MyReceiver;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyReceiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter("com.pkg.perform.Ruby");
if(intentFilter != null)
{
registerReceiver(MyReceiver, intentFilter);
}
}
#Override
protected void onDestroy()
{
super.onDestroy();
if(MyReceiver != null)
unregisterReceiver(MyReceiver);
}
}
In App B BroadcastReceiver
public class MyBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
String data = intent.getStringExtra("data");
Log.i("BR" ,"Data received: " + data);
}
}
There may be two cases :
Your appB is not running, hence the activity is not instantiated, and so the receiver is not registered.
Your activity is destroyed, means that you have unregistered your receiver that you registered via registerReceiver() in onCreate()
Solution :
Register your broadcast receiver in manifest.
Inside manifest of appB :
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="com.pkg.perform.Ruby" />
</intent-filter>
</receiver>
And comment out the line in appA
intent.setComponent(new ComponentName("com.pkg.AppB","com.pkg.AppB.MainActivity"));
Write the logic in MyBroadcastReceiver to display relevant data/launch new activity
MyReceiver is class not object. Create
myReceiver = new MyReceiver();
and put...........
registerReceiver(myReceiver,intentFilter);
If this helps some one and it works for me
In App A in activity or in a content provider-
Intent intent = new Intent("Updated");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setComponent (new
ComponentName "com.exam.appA",
"com.exam.appA.DbaseChanged"));
getContext().sendBroadcast(intent);
In App B in the manifest
<receiver
android:name=".DbaseChanged"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="Updated" />
</intent-filter>
</receiver>
In App B Broadcast receiver class-
public class DbaseChanged extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent
intent) {
String act = intent.getAction();
if(act != null && act.equals("Updated") )
{
Toast.makeText(context, act ,
Toast.LENGTH_SHORT).show();
}
}
}
I needed to call setPackage("package_name") to ensure explicitness when I registered the broadcast receiver in the Manifest. I was then able to receive the data even if the app was closed completely.
// sending app sends broadcast
Intent intent = new Intent(ACTION_RECOMMEND);
intent.putExtra(LISTEN_RECOMMENDATION, "Triggered - Jhene Aiko");
intent.putExtra(WATCH_RECOMMENDATION, "Goblin - Kim Go-eun");
intent.setPackage("com.example.package.receiverapp");
sendBroadcast(intent);
//receiving app manifest registers receiver
<receiver
android:name=".ManifestRegisteredBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.random.action.RECOMMEND" />
</intent-filter>
</receiver>
I didn't need to add intent.setPackage(package_name) when registering the receiver via an activity, but this also meant that I couldn't get the data if the activity was destroyed (app closed, app in background for long period)
I have an alarm manager whose receiver I had registered in my code. The whole point of having an alarm manager in case of Timer is that it should run in background when in Pause state. Now, do I unregister it in onPause() or in OnDestroy() and will it still run in background and wake up and the receiver would receive it?
EDIT:
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MyClass.class);
i.putExtra("fromReciever", true);
startActivity(i);
}
I would suggest that you register it in your AndroidManifest.xml file. Example:
<receiver android:name="com.example.android.MyReceiver" >
<intent-filter>
<action android:name="com.example.android.USER_ACTION" />
</intent-filter>
</receiver>
This will keep your receiver registered as long as the application is installed on your device. All you have to do is implement it:
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Intent Detected.", Toast.LENGTH_LONG).show();
}
}
And you are set.
Additionally, you can check out this tutorial for more information.
Added
If you want to resume your Activity you can add this code in your Receiver onReceive method.
Intent intent = new Intent(this, YourActivity.class);
intent.putExtra("fromOnReceive", true);
context.startActivity(intent);
Then, in your Activity onCreate method, you check if it was called from your Receiver
#Override
protected void onCreate(Bundle savedInstanceState) {
if(getIntent().hasExtras()){
boolean fromReceiver = getIntent().getExtras().getBoolean("fromOnReceive");
if(fromReceiver)
//Do work
}
}
I have an intent i, when I broadcast that intent via sendOrderedBroadcast(i, null); Random receivers were being invoked ( i know it is completely normal). I used queryBroadcastReceivers (Intent intent, int flags) and found multiple Broadcastreceivers registered. I would like to send my intent to a particular receiver.
Could anyone kindly let me know how to do it.
Thanks in advance.
BroadcastReceiver:
public class OutgoingReceiver extends BroadcastReceiver {
public static final String CUSTOM_INTENT = "jason.wei.custom.intent.action.TEST";
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("HIT OUTGOING");
Intent i = new Intent();
i.setAction(CUSTOM_INTENT);
context.sendBroadcast(i);
}
}
add this code into manifest
<receiver android:name=".IncomingReceiver" android:enabled="true">
<intent-filter>
<action android:name="jason.wei.custom.intent.action.TEST"></action>
</intent-filter>
</receiver>
I am new to android, I have created intent's like this -
<receiver android:name=".IncommigCallListener" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<receiver android:name=".OutgoingCallReciever" >
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
Now i created a service like this -
<service
android:name=".CallLogger"
android:exported="false"/>
Class CallLogger
public class CallLogger extends IntentService {
public CallLogger(String name) {
super(name);
// TODO Auto-generated constructor stub
}
#Override
protected void onHandleIntent(Intent arg0) {
// TODO Auto-generated method stub
System.out.println("service started");
}
}
I don't want to have any activity in my application, i just want to start the service so that it can work in background and receive PHONE_STATE and NEW_OUTGOING_CALL intent.
When i start this application, it doesn't log anything on PHONE_STATE or NEW_OUTGOING_CALL intent.
How can start service in background without using any activity ?
Edit :
public class OutgoingCallReciever extends BroadcastReceiver {
#Override
public void onReceive(Context ctx, Intent intent) {
String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
}
}
and
public class IncommigCallListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
String incommingCallNumber = incomingNumber;
System.out.println("incomming call : " + incomingNumber);
break;
}
}
}
Just start service in your BroadcastReceiver's onReceive method. As you are registering BroadcastReceiver in AndroidManifist, It will always listen for Broadcasts even if application is not running (OS will run it for you).
Example
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, MyService.class);
context.startService(service);
}
}
EDIT
To start a service on Boot completed you can do something like this.
1) Add permission to your Manifist :
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
2) Register your Broadcast Receiver with BOOT COMPLETE action.
<receiver android:name="com.example.BootBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
3) In BootBroadcastReceiver.java:
public class BootBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, MyService.class);
context.startService(serviceIntent );
}
}
You should be able to do something like this in your receiver.
public class OutgoingCallReciever extends BroadcastReceiver {
#Override
public void onReceive(Context ctx, Intent intent) {
String number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Intent service = new Intent(context, CallLogger.class);
context.startService(service);
}
}
You need to create an intent and call startService() on it to "launch" the service.
Also for what it's worth you should get out of the habbit of System.out.println use Log.d(tag,msg) to print debugging information to the logcat. You can switch the d to other letters if you want to print in different channels.
Why nothing gets printed is only due to the problem that System.out.println does not work in Android! Where do you think the background process will "print" this thing?
You need to change that to Log.d(tag, msg) and then check your logcat to see the output! Otherwise I guess your code might be running properly.