WakefulBroadcastReceiver.java revision 5831dcb3eeea951273281349285915243bd5a767
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v4.content; 18 19import android.content.BroadcastReceiver; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.Intent; 23import android.os.PowerManager; 24import android.util.Log; 25import android.util.SparseArray; 26 27/** 28 * Helper for the common pattern of implementing a {@link BroadcastReceiver} 29 * that will receiver a device wakeup event, and wants to pass that work 30 * off to a {@link android.app.Service} while ensuring the device does not 31 * go back to sleep during the transition. 32 * 33 * <p>This class takes care of creating and managing a partial wake lock 34 * for you; you must request the {@link android.Manifest.permission#WAKE_LOCK} 35 * permission to use it.</p> 36 */ 37public abstract class WakefulBroadcastReceiver extends BroadcastReceiver { 38 private static final String EXTRA_WAKE_LOCK_ID = "android.support.content.wakelockid"; 39 40 private static final SparseArray<PowerManager.WakeLock> mActiveWakeLocks 41 = new SparseArray<PowerManager.WakeLock>(); 42 private static int mNextId = 1; 43 44 /** 45 * Do a {@link android.content.Context#startService(android.content.Intent) 46 * Context.startService}, but holding a wake lock while the service starts. 47 * This will modify the Intent to hold an extra identifying the wake lock; 48 * when the service receives it in {@link android.app.Service#onStartCommand 49 * Service.onStartCommand}, it should the Intent it receives there back to 50 * {@link #completeWakefulIntent(android.content.Intent)} in order to release 51 * the wake lock. 52 * 53 * @param context The Context in which it operate. 54 * @param intent The Intent with which to start the service, as per 55 * {@link android.content.Context#startService(android.content.Intent) 56 * Context.startService}. 57 */ 58 public static ComponentName startWakefulService(Context context, Intent intent) { 59 synchronized (mActiveWakeLocks) { 60 int id = mNextId; 61 mNextId++; 62 if (mNextId <= 0) { 63 mNextId = 1; 64 } 65 66 intent.putExtra(EXTRA_WAKE_LOCK_ID, id); 67 ComponentName comp = context.startService(intent); 68 if (comp == null) { 69 return null; 70 } 71 72 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 73 PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 74 "wake:" + comp.flattenToShortString()); 75 wl.setReferenceCounted(false); 76 wl.acquire(60*1000); 77 mActiveWakeLocks.put(id, wl); 78 return comp; 79 } 80 } 81 82 /** 83 * Finish the execution from a previous {@link #startWakefulService}. Any wake lock 84 * that was being held will now be released. 85 * 86 * @param intent The Intent as originally generated by {@link #startWakefulService}. 87 * @retun Returns true if the intent is associated with a wake lock that is 88 * now released; returns false if there was no wake lock specified for it. 89 */ 90 public static boolean completeWakefulIntent(Intent intent) { 91 final int id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0); 92 if (id == 0) { 93 return false; 94 } 95 synchronized (mActiveWakeLocks) { 96 PowerManager.WakeLock wl = mActiveWakeLocks.get(id); 97 if (wl != null) { 98 wl.release(); 99 mActiveWakeLocks.remove(id); 100 return true; 101 } 102 // We return true whether or not we actually found the wake lock 103 // the return code is defined to indicate whether the Intent contained 104 // an identifier for a wake lock that it was supposed to match. 105 // We just log a warning here if there is no wake lock found, which could 106 // happen for example if this function is called twice on the same 107 // intent or the process is killed and restarted before processing the intent. 108 Log.w("WakefulBroadcastReceiver", "No active wake lock id #" + id); 109 return true; 110 } 111 } 112} 113