سؤال

I've an app that has a background service running every minute. I want the service to wake the device up if it's asleep. I am using a PowerManager but the device doesn't wake up. Any ideas why? Thanks in advance.

@Override
protected void onHandleIntent(Intent intent) {
    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK,
            "My Tag");
    wl.acquire();
    // do work as device is awake
    wl.release();
}

[edit1]

This is how i start the service from an Activity.

// get a Calendar object with current time
Calendar cal = Calendar.getInstance();
// add 5 minutes to the calendar object
cal.add(Calendar.MINUTE, 1);
Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
intent.putExtra("alarm_message", "sending outstanding transactions");
// In reality, you would want to have a static variable for the
// request code instead of 192837
PendingIntent sender = PendingIntent.getBroadcast(
        getApplicationContext(), 192837, intent,
        PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
// am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
// 86400000 = 24 hours
// 43200000 = 12 hours
// 3600000 = 1hr
// 1800000 = 30 mins
// 300000 = 5 mins
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),60000,sender);

AlarmReceiver class

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import android.os.Bundle;

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        try {

            Bundle bundle = intent.getExtras();
            String message = bundle.getString("alarm_message");
            // Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
            Intent myIntent = new Intent(context,
                    SendOutstandingTransactions.class);
            myIntent.setAction("com.carefreegroup.startatboot.MyService");
            context.startService(myIntent);
        } catch (Exception e) {
            Toast.makeText(
                    context,
                    "There was an error somewhere, but we still received an alarm",
                    Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }
}

The following class calls the Activity which I want to start when the device is asleep.

SendOutstandingTransactions IntentService.

protected void onHandleIntent(Intent intent) {
    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK,
            "My Tag");
    wl.acquire();
    if (hasMessageDisplayed == false) {
        Intent i = new Intent(this, DisplayMessageActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(i);
    }
    wl.release();
}

[edit2]

@Override
public void onDestroy() {
    super.onDestroy();
    PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wl = pm.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK, "com.something.alarm");
    // Acquire the lock
    if (wl.isHeld()) wl.release();
}
هل كانت مفيدة؟

المحلول

Either use Commonsware's WakefulIntentService or do this :

class YourService extends IntentService {

    private static final String LOCK_NAME = YourService.class.getName()
            + ".Lock";
    private static volatile WakeLock lockStatic = null; // notice static

    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,
                    LOCK_NAME);
            lockStatic.setReferenceCounted(true);
        }
        return (lockStatic);
    }

    public static void startYourService(Context ctxt, Intent i) { // STATIC 
        getLock(ctxt.getApplicationContext()).acquire();
        ctxt.startService(i);
    }

    public YourService(String name) {
        super(name);
        setIntentRedelivery(true);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        PowerManager.WakeLock lock = getLock(this.getApplicationContext());
        if (!lock.isHeld() || (flags & START_FLAG_REDELIVERY) != 0) {
            lock.acquire();
        }
        super.onStartCommand(intent, flags, startId);
        return (START_REDELIVER_INTENT);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        try {
            // do your thing
        } finally {
            PowerManager.WakeLock lock = getLock(this.getApplicationContext());
            if (lock.isHeld()) lock.release();
        }
    }
}

and in your receiver :

Bundle bundle = intent.getExtras();
String message = bundle.getString("alarm_message");
// Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
Intent myIntent = new Intent(context, SendOutstandingTransactions.class);
myIntent.setAction("com.carefreegroup.startatboot.MyService");
YourService.startYourService(context, myIntent)

which is actually the core from @CommonsWare WakefulIntentService (not sure about the START_FLAG_REDELIVERY, I should ask one of these days)

نصائح أخرى

You need to use an AlarmManager to get the wakelock, fire your service at a given time and let the service release the wakelock. The service itself ,even if running in background, could not be called because the CPU is already sleeping and won't execute your code.

Put this inside the onReceive of your AlarmManager:

         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "com.something.alarm");
         //Acquire the lock
         System.out.println("+++ Acquiring Lock +++");

         if(!wl.isHeld())
            wl.acquire();

          // Fire your service

Then release the wakelock at the end of the execution of your service. This means that you have to call wl.release() inside your service, before it ends.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top