WakefulBroadcastReceiver.java revision 9ee2ff6063726f07853980ce717dc55f0636c4f7
15831dcb3eeea951273281349285915243bd5a767Dianne Hackborn/* 25831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Copyright (C) 2013 The Android Open Source Project 35831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * 45831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 55831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * you may not use this file except in compliance with the License. 65831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * You may obtain a copy of the License at 75831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * 85831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 95831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * 105831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 115831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 125831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * See the License for the specific language governing permissions and 145831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * limitations under the License. 155831dcb3eeea951273281349285915243bd5a767Dianne Hackborn */ 165831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 175831dcb3eeea951273281349285915243bd5a767Dianne Hackbornpackage android.support.v4.content; 185831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 195831dcb3eeea951273281349285915243bd5a767Dianne Hackbornimport android.content.BroadcastReceiver; 205831dcb3eeea951273281349285915243bd5a767Dianne Hackbornimport android.content.ComponentName; 215831dcb3eeea951273281349285915243bd5a767Dianne Hackbornimport android.content.Context; 225831dcb3eeea951273281349285915243bd5a767Dianne Hackbornimport android.content.Intent; 235831dcb3eeea951273281349285915243bd5a767Dianne Hackbornimport android.os.PowerManager; 245831dcb3eeea951273281349285915243bd5a767Dianne Hackbornimport android.util.Log; 255831dcb3eeea951273281349285915243bd5a767Dianne Hackbornimport android.util.SparseArray; 265831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 275831dcb3eeea951273281349285915243bd5a767Dianne Hackborn/** 285831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Helper for the common pattern of implementing a {@link BroadcastReceiver} 295831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * that will receiver a device wakeup event, and wants to pass that work 305831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * off to a {@link android.app.Service} while ensuring the device does not 315831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * go back to sleep during the transition. 325831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * 335831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * <p>This class takes care of creating and managing a partial wake lock 345831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * for you; you must request the {@link android.Manifest.permission#WAKE_LOCK} 355831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * permission to use it.</p> 365831dcb3eeea951273281349285915243bd5a767Dianne Hackborn */ 375831dcb3eeea951273281349285915243bd5a767Dianne Hackbornpublic abstract class WakefulBroadcastReceiver extends BroadcastReceiver { 385831dcb3eeea951273281349285915243bd5a767Dianne Hackborn private static final String EXTRA_WAKE_LOCK_ID = "android.support.content.wakelockid"; 395831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 405831dcb3eeea951273281349285915243bd5a767Dianne Hackborn private static final SparseArray<PowerManager.WakeLock> mActiveWakeLocks 415831dcb3eeea951273281349285915243bd5a767Dianne Hackborn = new SparseArray<PowerManager.WakeLock>(); 425831dcb3eeea951273281349285915243bd5a767Dianne Hackborn private static int mNextId = 1; 435831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 445831dcb3eeea951273281349285915243bd5a767Dianne Hackborn /** 455831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Do a {@link android.content.Context#startService(android.content.Intent) 465831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Context.startService}, but holding a wake lock while the service starts. 475831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * This will modify the Intent to hold an extra identifying the wake lock; 485831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * when the service receives it in {@link android.app.Service#onStartCommand 495831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Service.onStartCommand}, it should the Intent it receives there back to 505831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * {@link #completeWakefulIntent(android.content.Intent)} in order to release 515831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * the wake lock. 525831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * 535831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * @param context The Context in which it operate. 545831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * @param intent The Intent with which to start the service, as per 555831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * {@link android.content.Context#startService(android.content.Intent) 565831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Context.startService}. 575831dcb3eeea951273281349285915243bd5a767Dianne Hackborn */ 585831dcb3eeea951273281349285915243bd5a767Dianne Hackborn public static ComponentName startWakefulService(Context context, Intent intent) { 595831dcb3eeea951273281349285915243bd5a767Dianne Hackborn synchronized (mActiveWakeLocks) { 605831dcb3eeea951273281349285915243bd5a767Dianne Hackborn int id = mNextId; 615831dcb3eeea951273281349285915243bd5a767Dianne Hackborn mNextId++; 625831dcb3eeea951273281349285915243bd5a767Dianne Hackborn if (mNextId <= 0) { 635831dcb3eeea951273281349285915243bd5a767Dianne Hackborn mNextId = 1; 645831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 655831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 665831dcb3eeea951273281349285915243bd5a767Dianne Hackborn intent.putExtra(EXTRA_WAKE_LOCK_ID, id); 675831dcb3eeea951273281349285915243bd5a767Dianne Hackborn ComponentName comp = context.startService(intent); 685831dcb3eeea951273281349285915243bd5a767Dianne Hackborn if (comp == null) { 695831dcb3eeea951273281349285915243bd5a767Dianne Hackborn return null; 705831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 715831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 725831dcb3eeea951273281349285915243bd5a767Dianne Hackborn PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 735831dcb3eeea951273281349285915243bd5a767Dianne Hackborn PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 745831dcb3eeea951273281349285915243bd5a767Dianne Hackborn "wake:" + comp.flattenToShortString()); 755831dcb3eeea951273281349285915243bd5a767Dianne Hackborn wl.setReferenceCounted(false); 765831dcb3eeea951273281349285915243bd5a767Dianne Hackborn wl.acquire(60*1000); 775831dcb3eeea951273281349285915243bd5a767Dianne Hackborn mActiveWakeLocks.put(id, wl); 785831dcb3eeea951273281349285915243bd5a767Dianne Hackborn return comp; 795831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 805831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 815831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 825831dcb3eeea951273281349285915243bd5a767Dianne Hackborn /** 835831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Finish the execution from a previous {@link #startWakefulService}. Any wake lock 845831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * that was being held will now be released. 855831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * 865831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * @param intent The Intent as originally generated by {@link #startWakefulService}. 879ee2ff6063726f07853980ce717dc55f0636c4f7Dianne Hackborn * @return Returns true if the intent is associated with a wake lock that is 885831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * now released; returns false if there was no wake lock specified for it. 895831dcb3eeea951273281349285915243bd5a767Dianne Hackborn */ 905831dcb3eeea951273281349285915243bd5a767Dianne Hackborn public static boolean completeWakefulIntent(Intent intent) { 915831dcb3eeea951273281349285915243bd5a767Dianne Hackborn final int id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0); 925831dcb3eeea951273281349285915243bd5a767Dianne Hackborn if (id == 0) { 935831dcb3eeea951273281349285915243bd5a767Dianne Hackborn return false; 945831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 955831dcb3eeea951273281349285915243bd5a767Dianne Hackborn synchronized (mActiveWakeLocks) { 965831dcb3eeea951273281349285915243bd5a767Dianne Hackborn PowerManager.WakeLock wl = mActiveWakeLocks.get(id); 975831dcb3eeea951273281349285915243bd5a767Dianne Hackborn if (wl != null) { 985831dcb3eeea951273281349285915243bd5a767Dianne Hackborn wl.release(); 995831dcb3eeea951273281349285915243bd5a767Dianne Hackborn mActiveWakeLocks.remove(id); 1005831dcb3eeea951273281349285915243bd5a767Dianne Hackborn return true; 1015831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 1025831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // We return true whether or not we actually found the wake lock 1035831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // the return code is defined to indicate whether the Intent contained 1045831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // an identifier for a wake lock that it was supposed to match. 1055831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // We just log a warning here if there is no wake lock found, which could 1065831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // happen for example if this function is called twice on the same 1075831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // intent or the process is killed and restarted before processing the intent. 1085831dcb3eeea951273281349285915243bd5a767Dianne Hackborn Log.w("WakefulBroadcastReceiver", "No active wake lock id #" + id); 1095831dcb3eeea951273281349285915243bd5a767Dianne Hackborn return true; 1105831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 1115831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 1125831dcb3eeea951273281349285915243bd5a767Dianne Hackborn} 113