Android : WakefulIntentService does not release wake lock - android

Here is the code that I use in BroadCastReceiver:
public class SMSBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// SMSReceivedService is my custom service, extends from Service class
Intent myIntent = new Intent(context, SMSReceivedService.class);
myIntent.putExtras(intent);
WakefulIntentService.sendWakefulWork(context, myIntent);
}
}
public class SMSReceivedService extends extends WakefulIntentService {
public SMSReceivedService(String name) {
super(name);
}
#Override
protected void doWakefulWork(Intent intent) {
// main code here
}
}
Here is the piece of code that's inside WakefulIntentService
synchronized private static PowerManager.WakeLock getLock(Context context) {
if (lockStatic == null) {
PowerManager mgr =
(PowerManager)context.getSystemService(Context.POWER_SERVICE);
lockStatic=mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NAME);
lockStatic.setReferenceCounted(true);
}
return(lockStatic);
}
public static void sendWakefulWork(Context ctxt, Intent i) {
getLock(ctxt.getApplicationContext()).acquire();
ctxt.startService(i);
}
As who has used WakefullIntentService will know that, just call sendWakefulWork and WakefullIntentService will do all stuff in the background. But in code above, WakefullIntentService just hold wake lock, but after finish, I don't see any code that release this lock. Is it true ? So it will affect the Android User. Please give me ideas.

Either you are using my WakefulIntentService, or you invented your own with the same name. If you are using my WakefulIntentService, the lock is released in onHandleIntent(), as you can tell by reading the source code.

Related

How to test broadcast receiver is executed in unit test?

I need to invoke a method on main thread, for that purpose i am using #UiThreadTest and calling the method inside my test.
That method is responsible to send broadcast receiver.
So i am registering the receiver and setting a boolean value to test if broadcast has been sent or not.
In logs i am able to see the broadcast is executed.
But getting assertion failure error inside test.
Is this some threading issue?
//broadcase receiver
private class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, final Intent intent) {
if (mUiUpdateReceiver != null && intent.getAction().equals(MessageCenter.INTENT_UI_REFRESH)) {
mbroadcastFlag = true;
}
}
}
//test
#UiThreadTest
public void test_broadcast () throws Exception{
mUiUpdateReceiver = new Receiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(SampleClass.INTENT_REFRESH);
LocalBroadcastManager.getInstance(mAppContext).registerReceiver(mUiUpdateReceiver, intentFilter);
mbroadcastFlag = false;
sampleClass.method();
Thread.sleep(2000);
assertTrue(mbroadcastFlag);
LocalBroadcastManager.getInstance(mAppContext).unregisterReceiver(mUiUpdateReceiver);
}
Konstantin Loginov's answear is ok, but it uses JUnit3 (because he extends ApplicationTestCase; if you extend any TestCase class Android framework will run your tests with JUnit3 runner by default).
If you want to use newer JUnit 4 You can use something like this:
public class MyReceiver extends BroadcastReceiver {
boolean flag;
#Override
public void onReceive(Context context, Intent intent) {
Uri packageName = intent.getData();
if(packageName.toString().equals("package:" + context.getPackageName())){
flag = true;
}
}
}
And the Test itself:
public class MyReceiverTest {
Context context;
#Before
public void init() {
context = new RenamingDelegatingContext(InstrumentationRegistry.getInstrumentation().getTargetContext(), "test_");
}
#Test
public void myReceiverTest() throws InterruptedException {
MyReceiver receiver = new MyReceiver();
//remeber to change Intent.ACTION_PACKAGE_REPLACED
//with your action name from your mainfest file
LocalBroadcastManager.getInstance(context).registerReceiver(receiver, new IntentFilter(Intent.ACTION_PACKAGE_REPLACED));
String pn = context.getPackageName();
Intent i = new Intent(Intent.ACTION_PACKAGE_REPLACED);
i.setData(Uri.parse("package:" + context.getPackageName()));
LocalBroadcastManager.getInstance(context).sendBroadcast(i);
Thread.sleep(2000);
boolean b = receiver.flag;
assertTrue(b);
LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver);
assertTrue(true);
}
I wrote for you a small hello-world with broadcast receiver and unit test for it.
Here's my broadcast receiver:
public class UiRefreshReceiver extends BroadcastReceiver {
boolean broadcastFlag;
public UiRefreshReceiver() {}
#Override
public void onReceive(Context context, Intent intent) {
broadcastFlag = true;
}
}
And test class for it:
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
#UiThreadTest
public void test_broadcast () throws Exception{
UiRefreshReceiver mUiUpdateReceiver = new UiRefreshReceiver();
LocalBroadcastManager.getInstance(getContext()).registerReceiver(mUiUpdateReceiver, new IntentFilter("my-event"));
assertFalse(mUiUpdateReceiver.broadcastFlag);
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(new Intent("my-event"));
Thread.sleep(2000);
assertTrue(mUiUpdateReceiver.broadcastFlag);
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mUiUpdateReceiver);
}
}
I hope, it'd help.
Though, in my humble opinion - it's enough to simply unit-test onReceive() code.

android recognize if call has been answered

I'm trying to add to my broadcast receiver an if, so I will start a different activity if a call has been answered, to the regular activity I start usually, if the screen has just been turned on.
Now as you can see down here I have the class screenJump starting when the user wakes up phone.
I would like to start a phoneActivity I wrote when the user wakes up phone, but only when a call has been answered.
This is my service now.
public class MyService extends Service {
BroadcastReceiver bd;
public MyService() {
}
class ScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent startupIntent = new Intent(context, ScreenJump.class);
startupIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startupIntent);
}
public ScreenReceiver()
{
}
}
#Override
public void onCreate()
{
super.onCreate();
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT);
bd = new ScreenReceiver();
registerReceiver(bd, filter);
}
}

BroadcastReceiver to start a service when device is turned on?

I can get the BroadcastReceiver to work but I'm not sure why the code for the intent to start the service has an error.
public class BroadCastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Intent backGround = new Intent(this,BackGround.class);
startService(backGround);
}
}
The error's are with the new intent(this,BackGround.class) and startService(); now I think I need to implement the service class for the startService method and (this) needs to be something else but I'm not sure what to do here.
This should do it!
public class BroadCastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, BackGround.class));
}
}
and don't forget to include service in manifest as well.

Communication between C2DM BroadcastReceiver and multiple activities

I have an Android application which uses C2DM services (aka push).
I have a separate class which implements the registration process and which receives the data (and extends BroadcastReceiver).
I want to communicate this data to the activity which currently is in the foreground. The activity currently in the foreground may differ depending on user action.
What's the best way to communicate in between the receiver and the current activity?
Thanks.
I solved this problem by sending out a new broadcast from the C2DMReceiver class, which looked something like this.
The C2DMReceiver class:
public class C2DMReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
handleRegistration(context, intent);
} else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
handleMessage(context, intent);
}
}
private void handleRegistration(Context context, Intent intent) {
// handle registration
}
private void handleMessage(Context context, Intent intent) {
Intent i = new Intent("push");
i.putExtras(intent);
// context.sendOrderedBroadcast(i, null);
context.sendBroadcast(i);
}
}
Another class I called PushReceiver. This is the class that will extend BroadcastReceiver and receive the broadcast sent by C2DMReceiver.
public class PushReceiver extends BroadcastReceiver {
public PushReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
// do stuff
abortBroadcast();
}
public static class PushFilter extends IntentFilter {
private static final int DEFAULT_PUSH_PRIORITY = 1;
public PushFilter() {
this(DEFAULT_PUSH_PRIORITY);
}
public PushFilter(int priority) {
super("push");
setPriority(priority);
}
}
}
And the activity class, in this case called MyActivity. This should work well if you are using a base activity class that all other activities extend. That way every activity registers the receiver. By doing the register/unregister in onResume/onPause, you should be able to guarantee that only the current activity receives the broadcast. If not, you can send an ordered broadcast from C2DMReceiver and use priority in the PushFilter.
public class MyActivity extends Activity {
private PushReceiver pushReceiver;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// your onCreate method
pushReceiver = new PushReceiver();
}
public void onResume() {
super.onResume();
// your onResume method
registerReceiver(pushReceiver, new PushReceiver.PushFilter());
}
public void onPause() {
super.onPause();
// your onPause method
unregisterReceiver(pushReceiver);
}
}
In my case, I wrote the PushReceiver constructor to take a View and then "did stuff" with the view in the onReceive method. Without knowing more about what your trying to do, I can't elaborate on this, but hopefully this can provide a decent template to work from.

Is it possible to call a non activity class from a BroadcastReceiver, If yes how we can do?

I have one BroadcastReceiver,it notify when phone state is changed, at that time i wan't to get a data from CallLog.Calls(this reside in my non activity class) and save it to my SQLite database.But now i facing a problem when calling a class.
Since i am new to android, any help or idea will be appreciated.
Thanks in advance
You could start an IntentService from your BroadcastReceiver and from there do whatever you want.
public class UpdateReceiver extends BroadcastReceiver {
private static Context mContext;
#Override
public void onReceive(Context context, Intent intent) {
mContext = context;
context.startService(new Intent(context, UpdateService.class));
}
public static class UpdateService extends IntentService {
public UpdateService() {
super("UpdateService");
}
#Override
protected void onHandleIntent(Intent intent) {
// Do whatever you want from here
Logic.doSomething(mContext);
}
}
}
Add the service to your manifest.
<service android:name="com.example.UpdateReceiver$UpdateService" />

Categories

Resources