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}
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 *
378fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * <h3>Example</h3>
388fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick *
398fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * <p>A {@link WakefulBroadcastReceiver} uses the method
408fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()}
418fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * to start the service that does the work. This method is comparable to
428fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * {@link android.content.Context#startService startService()}, except that
438fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * the {@link WakefulBroadcastReceiver} is holding a wake lock when the service
448fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * starts. The intent that is passed with
458fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()}
468fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * holds an extra identifying the wake lock.</p>
478fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick *
488fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * {@sample development/samples/Support4Demos/src/com/example/android/supportv4/content/SimpleWakefulReceiver.java complete}
498fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick *
508fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * <p>The service (in this example, an {@link android.app.IntentService}) does
518fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * some work. When it is finished, it releases the wake lock by calling
528fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * {@link WakefulBroadcastReceiver#completeWakefulIntent
538fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * completeWakefulIntent(intent)}. The intent it passes as a parameter
548fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * is the same intent that the {@link WakefulBroadcastReceiver} originally
558fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * passed in.</p>
568fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick *
578fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick * {@sample development/samples/Support4Demos/src/com/example/android/supportv4/content/SimpleWakefulService.java complete}
585831dcb3eeea951273281349285915243bd5a767Dianne Hackborn */
595831dcb3eeea951273281349285915243bd5a767Dianne Hackbornpublic abstract class WakefulBroadcastReceiver extends BroadcastReceiver {
605831dcb3eeea951273281349285915243bd5a767Dianne Hackborn    private static final String EXTRA_WAKE_LOCK_ID = "android.support.content.wakelockid";
615831dcb3eeea951273281349285915243bd5a767Dianne Hackborn
625831dcb3eeea951273281349285915243bd5a767Dianne Hackborn    private static final SparseArray<PowerManager.WakeLock> mActiveWakeLocks
635831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            = new SparseArray<PowerManager.WakeLock>();
645831dcb3eeea951273281349285915243bd5a767Dianne Hackborn    private static int mNextId = 1;
655831dcb3eeea951273281349285915243bd5a767Dianne Hackborn
665831dcb3eeea951273281349285915243bd5a767Dianne Hackborn    /**
675831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * Do a {@link android.content.Context#startService(android.content.Intent)
685831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * Context.startService}, but holding a wake lock while the service starts.
695831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * This will modify the Intent to hold an extra identifying the wake lock;
705831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * when the service receives it in {@link android.app.Service#onStartCommand
718fa60a6aa36ef3385391c6eb0589fe157bb08345kmccormick     * Service.onStartCommand}, it should pass back the Intent it receives there to
725831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * {@link #completeWakefulIntent(android.content.Intent)} in order to release
735831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * the wake lock.
745831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     *
755831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * @param context The Context in which it operate.
765831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * @param intent The Intent with which to start the service, as per
775831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * {@link android.content.Context#startService(android.content.Intent)
785831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * Context.startService}.
795831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     */
805831dcb3eeea951273281349285915243bd5a767Dianne Hackborn    public static ComponentName startWakefulService(Context context, Intent intent) {
815831dcb3eeea951273281349285915243bd5a767Dianne Hackborn        synchronized (mActiveWakeLocks) {
825831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            int id = mNextId;
835831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            mNextId++;
845831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            if (mNextId <= 0) {
855831dcb3eeea951273281349285915243bd5a767Dianne Hackborn                mNextId = 1;
865831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            }
875831dcb3eeea951273281349285915243bd5a767Dianne Hackborn
885831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            intent.putExtra(EXTRA_WAKE_LOCK_ID, id);
895831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            ComponentName comp = context.startService(intent);
905831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            if (comp == null) {
915831dcb3eeea951273281349285915243bd5a767Dianne Hackborn                return null;
925831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            }
935831dcb3eeea951273281349285915243bd5a767Dianne Hackborn
945831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
955831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
965831dcb3eeea951273281349285915243bd5a767Dianne Hackborn                    "wake:" + comp.flattenToShortString());
975831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            wl.setReferenceCounted(false);
985831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            wl.acquire(60*1000);
995831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            mActiveWakeLocks.put(id, wl);
1005831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            return comp;
1015831dcb3eeea951273281349285915243bd5a767Dianne Hackborn        }
1025831dcb3eeea951273281349285915243bd5a767Dianne Hackborn    }
1035831dcb3eeea951273281349285915243bd5a767Dianne Hackborn
1045831dcb3eeea951273281349285915243bd5a767Dianne Hackborn    /**
1055831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * Finish the execution from a previous {@link #startWakefulService}.  Any wake lock
1065831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * that was being held will now be released.
1075831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     *
1085831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * @param intent The Intent as originally generated by {@link #startWakefulService}.
1099ee2ff6063726f07853980ce717dc55f0636c4f7Dianne Hackborn     * @return Returns true if the intent is associated with a wake lock that is
1105831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     * now released; returns false if there was no wake lock specified for it.
1115831dcb3eeea951273281349285915243bd5a767Dianne Hackborn     */
1125831dcb3eeea951273281349285915243bd5a767Dianne Hackborn    public static boolean completeWakefulIntent(Intent intent) {
1135831dcb3eeea951273281349285915243bd5a767Dianne Hackborn        final int id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0);
1145831dcb3eeea951273281349285915243bd5a767Dianne Hackborn        if (id == 0) {
1155831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            return false;
1165831dcb3eeea951273281349285915243bd5a767Dianne Hackborn        }
1175831dcb3eeea951273281349285915243bd5a767Dianne Hackborn        synchronized (mActiveWakeLocks) {
1185831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            PowerManager.WakeLock wl = mActiveWakeLocks.get(id);
1195831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            if (wl != null) {
1205831dcb3eeea951273281349285915243bd5a767Dianne Hackborn                wl.release();
1215831dcb3eeea951273281349285915243bd5a767Dianne Hackborn                mActiveWakeLocks.remove(id);
1225831dcb3eeea951273281349285915243bd5a767Dianne Hackborn                return true;
1235831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            }
1245831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            // We return true whether or not we actually found the wake lock
1255831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            // the return code is defined to indicate whether the Intent contained
1265831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            // an identifier for a wake lock that it was supposed to match.
1275831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            // We just log a warning here if there is no wake lock found, which could
1285831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            // happen for example if this function is called twice on the same
1295831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            // intent or the process is killed and restarted before processing the intent.
1305831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            Log.w("WakefulBroadcastReceiver", "No active wake lock id #" + id);
1315831dcb3eeea951273281349285915243bd5a767Dianne Hackborn            return true;
1325831dcb3eeea951273281349285915243bd5a767Dianne Hackborn        }
1335831dcb3eeea951273281349285915243bd5a767Dianne Hackborn    }
1345831dcb3eeea951273281349285915243bd5a767Dianne Hackborn}
135