Dock and screen off broadcast service - android

First,I have searched for the question and found about 2-3 stackoverflow links but I dont get a definite answer.Basically,my app needs to start a activity when the phone is docked (any type of dock) or when screen is off.I registered a broadcast receiver in manifest:
<receiver android:name=".BootReciever">
<intent-filter >
<action android:name="android.intent.action.ACTION_DOCK_EVENT"/>
<action android:name="android.intent.action.SCREEN_OFF"/>
</intent-filter>
</receiver>
And in my class:
public class BootReciever extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(Intent.ACTION_DOCK_EVENT)){
//work for dock
}
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
//work for screen off
}
}
}
But both doesnt work.My work is not done is both the cases.I read about I have to do it in services but since I have never worked with my own service and I fell android.developers.com is a bit of pro friendly,I have difficulty getting it to work.Can somebody say me how to I achieve the above?And my app has to listen for it as long service.So even when my app isnt in foreground.Thanks for your help.

The SCREEN_OFF has definitely to be registered programatically (see this link for instance, it'a a protected intent):
public class MainActivity extends Activity {
BroadcastReceiver receiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("TAG", "on or off");
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
Log.d("TAG", "Register receiver");
registerReceiver(receiver, filter);
} catch (Exception e) {
Log.d("TAG", "Caught: " + e.getStackTrace());
}
}
#Override
public void onDestroy() {
super.onDestroy();
try {
Log.d("TAG", "Unregister receiver");
unregisterReceiver(receiver);
} catch (Exception e) {
Log.d("TAG", "Caught: " + e.getStackTrace());
}
}
}
For the ACTION_DOCK_EVENT I would assume something else being wrong. May be it doesn't work due to the combination with ACTION_SCREEN_OFF, may be it's due to a naming issue (I wouldn't expect a relative path for .BootReciever, for instance; check, if a full qualified class name works).
Hope this helps .... Cheers!

Receivers for these kinds of intents need to be registered dynamically in the code.
this.receiver = new BootReceiver();
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_DOCK_EVENT);
this.registerReceiver(receiver, filter);
You could do this in any activity (register in onStart(), un-register in onStop(), see visible lifetime section) or in you application object.
The problem with dynamic registration though is your application has to be started before BootReceiver can receive intents.

Related

Sending data from `BraodcastReceiver` to `Activity`

I have a MainActivity and a MyBroadcastReceiver. The BroadcastReceiver waits for incoming SMSes and reads the sms and senderId, it should send this data to MainActivity in real time. I have tried to implement the BroadcastReceiver in the Activity itself but it launches the activity again.
Public class MainActivity extends AppCompatActivity{
public static String BROADCAST_ACTION = "SMSCOMING";
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final Bundle bundle = intent.getExtras();
try {
//Getting the data d
triggerFunc(d);
}
}
} catch (Exception e) {
Log.e(TAG, "Exception: " + e.getMessage());
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter();
filter.addAction(BROADCAST_ACTION);
this.registerReceiver(this.broadcastReceiver, filter);
}
void triggerFunc(data d){
//Do some stuff
}
}
Please note that we have two kind of broadcast receivers in Android:
Standalone broadcast receivers (one of four main Android building blocks). This type of receivers must be registered in Android manifest file. These receivers will be run whenever their matching intents are received, no matter app's UI is running or not.
In-Activity broadcast receivers. This kind of receivers don't need to be registered in Manifest file, you should instead register them at runtime. These receivers are only run when their enclosing activity is active and running.
So, if you would like your app to be able to catch all SMS messages, regardless of its UI status, you would need the former option. However if you would need your app to catch SMS message while its activity is shown, you would need the latter option.
When the BroadcastReceiver receives an SMS notification, it cannot know if the Activity is running or not. If you want to launch the Activity, you need to create an appropriate Intent and call Context.startActivity().
You should create a class which extends BroadcastReceiver rather than simply an instance of an anonymous inner class. Also, you should register your BroadcastReceiver using the <receiver> tag in AndroidManifest.xml.
whatever code you have added in question as per that your Receiver only called when you Activity is running. instead of that create broadcast separately(remove from activity & create new class in your package) and register in AndroidManifest file and call your activity from Receiver.
just like below.
create BroadcastReceiver Class in your package.
public class BinarySMSReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
final Bundle bundle = intent.getExtras();
try {
//Getting the data d
Intent intent = new Intent();
intent.setClassName(context, "activity.class");
intent.putExtras(bundle);
context.startActivity(intent);
} catch (Exception e) {
Log.e(TAG, "Exception: " + e.getMessage());
}
}
};
in AndroidManifest
<receiver android:name="com.company.application.SMSBroadcastReceiver" >
<intent-filter android:priority="500">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>

Remove floating button from WindowManager when power key pressed

My app has a service that add a floating button to WindowManager.
I want to remove my floating button from WindowManager When user press the power key and turn screen off. So when user turn screen on my floating button does not conceal (mask) android pattern screen lock.
I add following code to my Service but it doesn't work !
Should I add any permission or my service must run in background?!
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
{
try{
// Remove Floating Button from Window Manager
MyWindowManager.removeView(floating_btn);
// Stop Service
stopSelf();
}
catch (Exception e)
{
//Log Error
}
}
}
}
Normally you would declare a receiver in your manifest. Something like this
<receiver android:name="com.whatever.client.Receiver"
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF" />
</intent-filter>
</receiver>
For some reason (not sure why), you don't seem to be able to do this for SCREEN_OFF or SCREEN_ON. So you have to register it programmatically.
As a test, I made a simple app.
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
startService(new Intent(context, MyService.class));
}
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(receiver, filter);
}
}
With a simple service.
public class MyService extends IntentService {
public MyService() {
super("MyService");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.e("MyService", "Screen was turned off!");
}
}
I've got the same problem and I'm working on it now. In your case it didn't work because 1) your "stopSelf()" have to in class extended by Service, not by BroadcastReceiver. 2) if you want to remove a view from window manager you have to somehow pass(the information of view) that view from that method where you'd declared it to method where you want to remove that view

Unable to catch SMS received with android.provider.Telephony.SMS_RECEIVED

I am not able to catch the intent when a SMS is received. Below is my code of the service. I am able to catch the "Intent.ACTION_SCREEN_ON" and "Intent.ACTION_SCREEN_OFF" but I am NOT able to catch the SMS_RECEIVED intent "android.provider.Telephony.SMS_RECEIVED".
Sincerely appreciate any hints on what I am doing wrong here?
public class SmsCatcher extends Service{
BroadcastReceiver myBroadcast = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("myBroadcast SmsCatcher", "Entered onReceive method");
if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Log.i("myBroadcast SmsCatcher", "Caught SCREEN_OFF");
}
if(intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Log.i("myBroadcast SmsCatcher", "Caught SCREEN_ON");
}
if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
Log.i("myBroadcast SmsCatcher", "SMS_RECEIVED");
}
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.i("neil SmsCatcher", "Entered onCreate() in 'SmsCatcher extends Service'");
Toast.makeText(this, "Entered onCreate() in 'SmsCatcher extends Service'", Toast.LENGTH_LONG).show();
registerReceiver(myBroadcast, new IntentFilter(Intent.ACTION_SCREEN_ON));
registerReceiver(myBroadcast, new IntentFilter(Intent.ACTION_SCREEN_OFF));
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i("neil SmsCatcher", "Entered onDestroy() in 'SmsCatcher extends Service'");
Toast.makeText(this, "Entered onDestroy() in 'SmsCatcher extends Service'", Toast.LENGTH_LONG).show();
}
}
UPDATE 1: Adding some more information from my ongoing debug:
I used the App Internal Broadcasts Monitor to see there is a broadcast when there is a text message received and I dont see anything, very strange. What could be the reason?
I have other SMS apps installed (Hangout, AT&T Messages) - these cant suppress the broadcast can they?
UPDATE 2: FOUND PROBLEM BUT DONT KNOW HOW TO SOLVE
I uninstalled the Google Hangouts (replaces Talk) app and it WORKS!!!
Any solution around this? (should i be opening a separate thread as per stackoverflow rules?)
UPDATE 3: FOUND ROOTCAUSE (with help below of course, thank you)
It turns out that because of the new Google Hangouts App, I needed to setPriority(int). I found the solution at Enabling SMS support in Hangouts 2.0 breaks the BroadcastReceiver of SMS_RECEIVED in my app
You need to register the android.provider.Telephony.SMS_RECEIVED intent filter,only if you have registered it you can able to check the intent in the onRecive like
IntentFilter filter = new IntentFilter(android.provider.Telephony.SMS_RECEIVED);
this.registerReceiver(myBroadcastReceiver, filter);
Update From the question:
It turns out Google Hangouts App aborts the sms broadcast as soon as it receives it,So disabling SMS support in Hangouts 2.0 may fix the issue.
You did not register the intent-filter:
#Override
public void onCreate() {
// ..
registerReceiver(myBroadcast, new IntentFilter(Intent.ACTION_SCREEN_ON));
registerReceiver(myBroadcast, new IntentFilter(Intent.ACTION_SCREEN_OFF));
registerReceiver(myBroadcast, new IntentFilter("android.provider.Telephony.SMS_RECEIVED")); // missing in your code
}
And please check your permissions for android.permission.RECEIVE_SMS in AndroidManifest.xml.

How do I register in manifest an *inner* MEDIA_BUTTON BroadcastReceiver?

I managed to get my headset buttons get recognized by my app when pressed, but one of the buttons needs to call a method that's in MyCustomActivity. The problem is onReceive's 1st parameter is a Context that cannot be cast to Activity and so I am forced to implement my BroadcastReceiver as an inner class inside MyCustomActivity.
So far so good but how do I register this inner MediaButtonEventReceiver in the manifest?
For the independent class, this was simple:
<receiver android:name=".RemoteControlReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
What is the trick/syntax to do the same for MyCustomActivity's mReceiver?
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context ctx, Intent intent) {
// ...
}
}
You don't, if it's meant to be part of the Activity, you register it dynamically:
BroadcastReceiver receiver;
#Override
protected void onCreate (Bundle b)
{
super.onCreate (b);
IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
filter.setPriority(10000);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context ctx, Intent intent) {
// ...
}
};
registerReceiver (receiver, filter);
}
Then don't forget to unregister in onPause() (to avoid leaking).
#Override
protected void onPause()
{
try{
unregisterReceiver (receiver);
}
catch (IllegalStateException e)
{
e.printStackTrace();
}
super.onPause();
}
This dynamic registration does mean however, that if your Activity isn't in the foreground, the button won't work. You can try unregistering in onDestroy() instead, but the surest way to avoid leaking is onPause().
Alternatively, to make the button respond no matter what, consider making a Service, and having that register your receiver.
So far so good but how do I register this inner MediaButtonEventReceiver in the manifest?
You can't. You can register it dynamically by calling registerReceiver() on the activity, though.

Programmatically register a broadcast receiver

I'd like to know what is the best practice/way of programmatically register a broadcast receiver. I want to register specific receivers according to user choice.
As the registration is done through the manifest file, I'm wondering if there's a proper way to achieve this in code.
In your onCreate method you can register a receiver like this:
private BroadcastReceiver receiver;
#Override
public void onCreate(Bundle savedInstanceState){
// your oncreate code should be
IntentFilter filter = new IntentFilter();
filter.addAction("SOME_ACTION");
filter.addAction("SOME_OTHER_ACTION");
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//do something based on the intent's action
}
};
registerReceiver(receiver, filter);
}
Remember to run this in the onDestroy method:
#Override
protected void onDestroy() {
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
super.onDestroy();
}
One important point that people forget to mention is the life time of the Broadcast Receiver. The difference of programmatically registering it from registering in AndroidManifest.xml is that. In the manifest file, it doesn't depend on application life time. While when programmatically registering it it does depend on the application life time. This means that if you register in AndroidManifest.xml, you can catch the broadcasted intents even when your application is not running.
Edit: The mentioned note is no longer true as of Android 3.1, the Android system excludes all receiver from receiving intents by default if the corresponding application has never been started by the user or if the user explicitly stopped the application via the Android menu (in Manage → Application). https://developer.android.com/about/versions/android-3.1.html
This is an additional security feature as the user can be sure that only the applications he started will receive broadcast intents.
So it can be understood as receivers programmatically registered in Application's onCreate() would have same effect with ones declared in AndroidManifest.xml from Android 3.1 above.
It sounds like you want to control whether components published in your manifest are active, not dynamically register a receiver (via Context.registerReceiver()) while running.
If so, you can use PackageManager.setComponentEnabledSetting() to control whether these components are active:
http://developer.android.com/reference/android/content/pm/PackageManager.html#setComponentEnabledSetting(android.content.ComponentName, int, int)
Note if you are only interested in receiving a broadcast while you are running, it is better to use registerReceiver(). A receiver component is primarily useful for when you need to make sure your app is launched every time the broadcast is sent.
Define a broadcast receiver anywhere in Activity/Fragment like this:
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG," onRecieve"); //do something with intent
}
};
Define IntentFilter in onCreate()
mIntentFilter=new IntentFilter("action_name");
Now register the BroadcastReciever in onResume() and Unregister it in onPause() [because there is no use of broadcast if the activity is paused].
#Override
protected void onResume() {
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
}
#Override
protected void onPause() {
if(mReceiver != null) {
unregisterReceiver(mReceiver);
mReceiver = null;
}
super.onPause();
}
For detail tutorial, have a look at broadcast receiver-two ways to implement.
package com.example.broadcastreceiver;
import android.app.Activity;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
UserDefinedBroadcastReceiver broadCastReceiver = new UserDefinedBroadcastReceiver();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/**
* This method enables the Broadcast receiver for
* "android.intent.action.TIME_TICK" intent. This intent get
* broadcasted every minute.
*
* #param view
*/
public void registerBroadcastReceiver(View view) {
this.registerReceiver(broadCastReceiver, new IntentFilter(
"android.intent.action.TIME_TICK"));
Toast.makeText(this, "Registered broadcast receiver", Toast.LENGTH_SHORT)
.show();
}
/**
* This method disables the Broadcast receiver
*
* #param view
*/
public void unregisterBroadcastReceiver(View view) {
this.unregisterReceiver(broadCastReceiver);
Toast.makeText(this, "unregistered broadcst receiver", Toast.LENGTH_SHORT)
.show();
}
}
Two choices
1) If you want to read Broadcast only when the Activity is visible
then,
registerReceiver(...) in onStart() and unregisterReceiver(...) in onStop()
2) If you want to read Broadcast even if Activity is in Background
then,
registerReceiver(...) in onCreate(...) and unregisterReceiver(...) in onDestroy()
Bonus:
If you are lazy
If you don't want to write boilerplate code for registering and unregistering a BroadcastReceiver again and again in each Activity then,
Create an abstract Activity
Write boilerplate code in Activity
Leave the implementation as abstract methods
Here is the code snippet:
Abstract Activity
public abstract class BasicActivity extends AppCompatActivity {
private BroadcastReceiver broadcastReceiver;
private IntentFilter filter;
private static final String TAG = "BasicActivity";
/**********************************************************************
* Boilerplate code
**********************************************************************/
#Override
public void onCreate(Bundle sis){
super.onCreate(sis);
broadcastReceiver = getBroadcastReceiver();
filter = getFilter();
}
#Override
public void onStart(){
super.onStart();
register();
}
#Override
public void onStop(){
super.onStop();
unregister();
}
private void register(){
registerReceiver(broadcastReceiver,filter);
}
private void unregister(){
unregisterReceiver(broadcastReceiver);
}
/**********************************************************************
* Abstract methods
**********************************************************************/
public abstract BroadcastReceiver getBroadcastReceiver();
public abstract IntentFilter getFilter();
}
Using this approach you can write more boilerplate code such as
writing common animations, binding to a service, etc.
See full code:
HERE
According to Listening For and Broadcasting Global Messages, and Setting Alarms in Common Tasks and How to Do Them in Android:
If the receiving class is not
registered using in its
manifest, you can dynamically
instantiate and register a receiver by
calling Context.registerReceiver().
Take a look at registerReceiver (BroadcastReceiver receiver, IntentFilter filter) for more info.
It is best practice to always supply the permission when registering the receiver, otherwise you will receive for any application that sends a matching intent. This can allow malicious apps to broadcast to your receiver.
for LocalBroadcastManager
Intent intent = new Intent("any.action.string");
LocalBroadcastManager.getInstance(context).
sendBroadcast(intent);
and register in onResume
LocalBroadcastManager.getInstance(
ActivityName.this).registerReceiver(chatCountBroadcastReceiver, filter);
and Unregister it onStop
LocalBroadcastManager.getInstance(
ActivityName.this).unregisterReceiver(chatCountBroadcastReceiver);
and recieve it ..
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("mBroadcastReceiver", "onReceive");
}
};
where IntentFilter is
new IntentFilter("any.action.string")
Create a broadcast receiver
[BroadcastReceiver(Enabled = true, Exported = false)]
public class BCReceiver : BroadcastReceiver
{
BCReceiver receiver;
public override void OnReceive(Context context, Intent intent)
{
//Do something here
}
}
From your activity add this code:
LocalBroadcastManager.getInstance(ApplicationContext)
.registerReceiver(receiver, filter);

Categories

Resources