From 3617700351662e2c890d2903a5b7bd7f83cfc0bd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 14 Aug 2015 19:49:17 +1200 Subject: [PATCH] Add wake lock to receiver --- .../v4/content/WakefulBroadcastReceiver.java | 134 ++++++++++++++++++ .../org/traccar/client/AutostartReceiver.java | 4 +- .../org/traccar/client/TrackingService.java | 7 + 3 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java diff --git a/app/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java b/app/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java new file mode 100644 index 0000000..137e5fa --- /dev/null +++ b/app/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.support.v4.content; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.PowerManager; +import android.util.Log; +import android.util.SparseArray; + +/** + * Helper for the common pattern of implementing a {@link BroadcastReceiver} + * that receives a device wakeup event and then passes the work off + * to a {@link android.app.Service}, while ensuring that the + * device does not go back to sleep during the transition. + * + *

This class takes care of creating and managing a partial wake lock + * for you; you must request the {@link android.Manifest.permission#WAKE_LOCK} + * permission to use it.

+ * + *

Example

+ * + *

A {@link WakefulBroadcastReceiver} uses the method + * {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()} + * to start the service that does the work. This method is comparable to + * {@link android.content.Context#startService startService()}, except that + * the {@link WakefulBroadcastReceiver} is holding a wake lock when the service + * starts. The intent that is passed with + * {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()} + * holds an extra identifying the wake lock.

+ * + * {@sample development/samples/Support4Demos/src/com/example/android/supportv4/content/SimpleWakefulReceiver.java complete} + * + *

The service (in this example, an {@link android.app.IntentService}) does + * some work. When it is finished, it releases the wake lock by calling + * {@link WakefulBroadcastReceiver#completeWakefulIntent + * completeWakefulIntent(intent)}. The intent it passes as a parameter + * is the same intent that the {@link WakefulBroadcastReceiver} originally + * passed in.

+ * + * {@sample development/samples/Support4Demos/src/com/example/android/supportv4/content/SimpleWakefulService.java complete} + */ +public abstract class WakefulBroadcastReceiver extends BroadcastReceiver { + private static final String EXTRA_WAKE_LOCK_ID = "android.support.content.wakelockid"; + + private static final SparseArray mActiveWakeLocks + = new SparseArray(); + private static int mNextId = 1; + + /** + * Do a {@link android.content.Context#startService(android.content.Intent) + * Context.startService}, but holding a wake lock while the service starts. + * This will modify the Intent to hold an extra identifying the wake lock; + * when the service receives it in {@link android.app.Service#onStartCommand + * Service.onStartCommand}, it should pass back the Intent it receives there to + * {@link #completeWakefulIntent(android.content.Intent)} in order to release + * the wake lock. + * + * @param context The Context in which it operate. + * @param intent The Intent with which to start the service, as per + * {@link android.content.Context#startService(android.content.Intent) + * Context.startService}. + */ + public static ComponentName startWakefulService(Context context, Intent intent) { + synchronized (mActiveWakeLocks) { + int id = mNextId; + mNextId++; + if (mNextId <= 0) { + mNextId = 1; + } + + intent.putExtra(EXTRA_WAKE_LOCK_ID, id); + ComponentName comp = context.startService(intent); + if (comp == null) { + return null; + } + + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + "wake:" + comp.flattenToShortString()); + wl.setReferenceCounted(false); + wl.acquire(60*1000); + mActiveWakeLocks.put(id, wl); + return comp; + } + } + + /** + * Finish the execution from a previous {@link #startWakefulService}. Any wake lock + * that was being held will now be released. + * + * @param intent The Intent as originally generated by {@link #startWakefulService}. + * @return Returns true if the intent is associated with a wake lock that is + * now released; returns false if there was no wake lock specified for it. + */ + public static boolean completeWakefulIntent(Intent intent) { + final int id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0); + if (id == 0) { + return false; + } + synchronized (mActiveWakeLocks) { + PowerManager.WakeLock wl = mActiveWakeLocks.get(id); + if (wl != null) { + wl.release(); + mActiveWakeLocks.remove(id); + return true; + } + // We return true whether or not we actually found the wake lock + // the return code is defined to indicate whether the Intent contained + // an identifier for a wake lock that it was supposed to match. + // We just log a warning here if there is no wake lock found, which could + // happen for example if this function is called twice on the same + // intent or the process is killed and restarted before processing the intent. + Log.w("WakefulBroadcastReceive", "No active wake lock id #" + id); + return true; + } + } +} diff --git a/app/src/main/java/org/traccar/client/AutostartReceiver.java b/app/src/main/java/org/traccar/client/AutostartReceiver.java index b3308c7..e61d230 100644 --- a/app/src/main/java/org/traccar/client/AutostartReceiver.java +++ b/app/src/main/java/org/traccar/client/AutostartReceiver.java @@ -15,13 +15,13 @@ */ package org.traccar.client; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.preference.PreferenceManager; +import android.support.v4.content.WakefulBroadcastReceiver; -public class AutostartReceiver extends BroadcastReceiver { +public class AutostartReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { diff --git a/app/src/main/java/org/traccar/client/TrackingService.java b/app/src/main/java/org/traccar/client/TrackingService.java index 46d56b9..4926baf 100644 --- a/app/src/main/java/org/traccar/client/TrackingService.java +++ b/app/src/main/java/org/traccar/client/TrackingService.java @@ -51,9 +51,16 @@ public class TrackingService extends Service { return null; } + @SuppressWarnings("deprecation") + @Override + public void onStart(Intent intent, int startId) { + AutostartReceiver.completeWakefulIntent(intent); + } + @TargetApi(Build.VERSION_CODES.ECLAIR) @Override public int onStartCommand(Intent intent, int flags, int startId) { + onStart(intent, startId); return START_STICKY; }