15831dcb3eeea951273281349285915243bd5a767Dianne Hackborn/* 2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 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 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.legacy.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/** 2824baf5ec619d91776c3bd4d265bc4b1d940aad58Dianne Hackborn * This helper is for an old pattern of implementing a {@link BroadcastReceiver} 298fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * that receives a device wakeup event and then passes the work off 308fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * to a {@link android.app.Service}, while ensuring that the 318fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * device does not 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> 368fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * 37d5c17f0019d5a66247b083355add28ab3730a9b2Olivier Gaillard * <p>Wakelocks held by this class are reported to tools as 38d5c17f0019d5a66247b083355add28ab3730a9b2Olivier Gaillard * {@code "androidx.core:wake:<component-name>"}.</p> 39d5c17f0019d5a66247b083355add28ab3730a9b2Olivier Gaillard * 408fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * <h3>Example</h3> 418fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * 428fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * <p>A {@link WakefulBroadcastReceiver} uses the method 438fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()} 448fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * to start the service that does the work. This method is comparable to 458fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * {@link android.content.Context#startService startService()}, except that 468fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * the {@link WakefulBroadcastReceiver} is holding a wake lock when the service 478fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * starts. The intent that is passed with 488fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()} 498fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * holds an extra identifying the wake lock.</p> 508fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * 513328f87260d3b7be4fcf0c22cdc2dda5d60ab77cAurimas Liutikas * {@sample frameworks/support/samples/Support4Demos/src/main/java/com/example/android/supportv4/content/SimpleWakefulReceiver.java 52a3274ee2c60634908ab5bd93bbafc51c9567016bAlan Viverette * complete} 538fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * 548fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * <p>The service (in this example, an {@link android.app.IntentService}) does 558fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * some work. When it is finished, it releases the wake lock by calling 568fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * {@link WakefulBroadcastReceiver#completeWakefulIntent 578fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * completeWakefulIntent(intent)}. The intent it passes as a parameter 588fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * is the same intent that the {@link WakefulBroadcastReceiver} originally 598fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * passed in.</p> 608fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * 613328f87260d3b7be4fcf0c22cdc2dda5d60ab77cAurimas Liutikas * {@sample frameworks/support/samples/Support4Demos/src/main/java/com/example/android/supportv4/content/SimpleWakefulService.java 62a3274ee2c60634908ab5bd93bbafc51c9567016bAlan Viverette * complete} 6324baf5ec619d91776c3bd4d265bc4b1d940aad58Dianne Hackborn * 6424baf5ec619d91776c3bd4d265bc4b1d940aad58Dianne Hackborn * @deprecated As of {@link android.os.Build.VERSION_CODES#O Android O}, background check 6524baf5ec619d91776c3bd4d265bc4b1d940aad58Dianne Hackborn * restrictions make this class no longer generally useful. (It is generally not safe to 6624baf5ec619d91776c3bd4d265bc4b1d940aad58Dianne Hackborn * start a service from the receipt of a broadcast, because you don't have any guarantees 6724baf5ec619d91776c3bd4d265bc4b1d940aad58Dianne Hackborn * that your app is in the foreground at this point and thus allowed to do so.) Instead, 6824baf5ec619d91776c3bd4d265bc4b1d940aad58Dianne Hackborn * developers should use android.app.job.JobScheduler to schedule a job, and this 6924baf5ec619d91776c3bd4d265bc4b1d940aad58Dianne Hackborn * does not require that the app hold a wake lock while doing so (the system will take 7024baf5ec619d91776c3bd4d265bc4b1d940aad58Dianne Hackborn * care of holding a wake lock for the job). 715831dcb3eeea951273281349285915243bd5a767Dianne Hackborn */ 7224baf5ec619d91776c3bd4d265bc4b1d940aad58Dianne Hackborn@Deprecated 735831dcb3eeea951273281349285915243bd5a767Dianne Hackbornpublic abstract class WakefulBroadcastReceiver extends BroadcastReceiver { 74ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas private static final String EXTRA_WAKE_LOCK_ID = "androidx.contentpager.content.wakelockid"; 755831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 76ce92ed7b666861a8a2ee3cfc1abd9b7fafa2eb6cAurimas Liutikas private static final SparseArray<PowerManager.WakeLock> sActiveWakeLocks = new SparseArray<>(); 775831dcb3eeea951273281349285915243bd5a767Dianne Hackborn private static int mNextId = 1; 785831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 795831dcb3eeea951273281349285915243bd5a767Dianne Hackborn /** 805831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Do a {@link android.content.Context#startService(android.content.Intent) 815831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Context.startService}, but holding a wake lock while the service starts. 825831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * This will modify the Intent to hold an extra identifying the wake lock; 835831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * when the service receives it in {@link android.app.Service#onStartCommand 848fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * Service.onStartCommand}, it should pass back the Intent it receives there to 855831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * {@link #completeWakefulIntent(android.content.Intent)} in order to release 865831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * the wake lock. 875831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * 885831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * @param context The Context in which it operate. 895831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * @param intent The Intent with which to start the service, as per 905831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * {@link android.content.Context#startService(android.content.Intent) 915831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Context.startService}. 925831dcb3eeea951273281349285915243bd5a767Dianne Hackborn */ 935831dcb3eeea951273281349285915243bd5a767Dianne Hackborn public static ComponentName startWakefulService(Context context, Intent intent) { 94ce92ed7b666861a8a2ee3cfc1abd9b7fafa2eb6cAurimas Liutikas synchronized (sActiveWakeLocks) { 955831dcb3eeea951273281349285915243bd5a767Dianne Hackborn int id = mNextId; 965831dcb3eeea951273281349285915243bd5a767Dianne Hackborn mNextId++; 975831dcb3eeea951273281349285915243bd5a767Dianne Hackborn if (mNextId <= 0) { 985831dcb3eeea951273281349285915243bd5a767Dianne Hackborn mNextId = 1; 995831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 1005831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 1015831dcb3eeea951273281349285915243bd5a767Dianne Hackborn intent.putExtra(EXTRA_WAKE_LOCK_ID, id); 1025831dcb3eeea951273281349285915243bd5a767Dianne Hackborn ComponentName comp = context.startService(intent); 1035831dcb3eeea951273281349285915243bd5a767Dianne Hackborn if (comp == null) { 1045831dcb3eeea951273281349285915243bd5a767Dianne Hackborn return null; 1055831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 1065831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 1075831dcb3eeea951273281349285915243bd5a767Dianne Hackborn PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 1085831dcb3eeea951273281349285915243bd5a767Dianne Hackborn PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 109d5c17f0019d5a66247b083355add28ab3730a9b2Olivier Gaillard "androidx.core:wake:" + comp.flattenToShortString()); 1105831dcb3eeea951273281349285915243bd5a767Dianne Hackborn wl.setReferenceCounted(false); 111ce92ed7b666861a8a2ee3cfc1abd9b7fafa2eb6cAurimas Liutikas wl.acquire(60 * 1000); 112ce92ed7b666861a8a2ee3cfc1abd9b7fafa2eb6cAurimas Liutikas sActiveWakeLocks.put(id, wl); 1135831dcb3eeea951273281349285915243bd5a767Dianne Hackborn return comp; 1145831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 1155831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 1165831dcb3eeea951273281349285915243bd5a767Dianne Hackborn 1175831dcb3eeea951273281349285915243bd5a767Dianne Hackborn /** 1185831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * Finish the execution from a previous {@link #startWakefulService}. Any wake lock 1195831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * that was being held will now be released. 1205831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * 1215831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * @param intent The Intent as originally generated by {@link #startWakefulService}. 1229ee2ff6063726f07853980ce717dc55f0636c4f7Dianne Hackborn * @return Returns true if the intent is associated with a wake lock that is 1235831dcb3eeea951273281349285915243bd5a767Dianne Hackborn * now released; returns false if there was no wake lock specified for it. 1245831dcb3eeea951273281349285915243bd5a767Dianne Hackborn */ 1255831dcb3eeea951273281349285915243bd5a767Dianne Hackborn public static boolean completeWakefulIntent(Intent intent) { 1265831dcb3eeea951273281349285915243bd5a767Dianne Hackborn final int id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0); 1275831dcb3eeea951273281349285915243bd5a767Dianne Hackborn if (id == 0) { 1285831dcb3eeea951273281349285915243bd5a767Dianne Hackborn return false; 1295831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 130ce92ed7b666861a8a2ee3cfc1abd9b7fafa2eb6cAurimas Liutikas synchronized (sActiveWakeLocks) { 131ce92ed7b666861a8a2ee3cfc1abd9b7fafa2eb6cAurimas Liutikas PowerManager.WakeLock wl = sActiveWakeLocks.get(id); 1325831dcb3eeea951273281349285915243bd5a767Dianne Hackborn if (wl != null) { 1335831dcb3eeea951273281349285915243bd5a767Dianne Hackborn wl.release(); 134ce92ed7b666861a8a2ee3cfc1abd9b7fafa2eb6cAurimas Liutikas sActiveWakeLocks.remove(id); 1355831dcb3eeea951273281349285915243bd5a767Dianne Hackborn return true; 1365831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 1375831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // We return true whether or not we actually found the wake lock 1385831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // the return code is defined to indicate whether the Intent contained 1395831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // an identifier for a wake lock that it was supposed to match. 1405831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // We just log a warning here if there is no wake lock found, which could 1415831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // happen for example if this function is called twice on the same 1425831dcb3eeea951273281349285915243bd5a767Dianne Hackborn // intent or the process is killed and restarted before processing the intent. 143ce92ed7b666861a8a2ee3cfc1abd9b7fafa2eb6cAurimas Liutikas Log.w("WakefulBroadcastReceiv.", "No active wake lock id #" + id); 1445831dcb3eeea951273281349285915243bd5a767Dianne Hackborn return true; 1455831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 1465831dcb3eeea951273281349285915243bd5a767Dianne Hackborn } 1475831dcb3eeea951273281349285915243bd5a767Dianne Hackborn} 148