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