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