diff -r 000000000000 -r 6474c204b198 mobile/android/base/background/BackgroundService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mobile/android/base/background/BackgroundService.java Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,114 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.background; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.mozilla.gecko.background.common.log.Logger; + +import android.app.AlarmManager; +import android.app.IntentService; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; + +public abstract class BackgroundService extends IntentService { + private static final String LOG_TAG = BackgroundService.class.getSimpleName(); + + protected BackgroundService() { + super(LOG_TAG); + } + + protected BackgroundService(String threadName) { + super(threadName); + } + + public static void runIntentInService(Context context, Intent intent, Class serviceClass) { + Intent service = new Intent(context, serviceClass); + service.setAction(intent.getAction()); + service.putExtras(intent); + context.startService(service); + } + + /** + * Returns true if the OS will allow us to perform background + * data operations. This logic varies by OS version. + */ + @SuppressWarnings("deprecation") + protected boolean backgroundDataIsEnabled() { + ConnectivityManager connectivity = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return connectivity.getBackgroundDataSetting(); + } + NetworkInfo networkInfo = connectivity.getActiveNetworkInfo(); + if (networkInfo == null) { + return false; + } + return networkInfo.isAvailable(); + } + + protected AlarmManager getAlarmManager() { + return getAlarmManager(this.getApplicationContext()); + } + + protected static AlarmManager getAlarmManager(Context context) { + return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + } + + protected void scheduleAlarm(long pollInterval, PendingIntent pendingIntent) { + Logger.info(LOG_TAG, "Setting inexact repeating alarm for interval " + pollInterval); + if (pollInterval <= 0) { + throw new IllegalArgumentException("pollInterval " + pollInterval + " must be positive"); + } + final AlarmManager alarm = getAlarmManager(); + final long firstEvent = System.currentTimeMillis(); + alarm.setInexactRepeating(AlarmManager.RTC, firstEvent, pollInterval, pendingIntent); + } + + protected void cancelAlarm(PendingIntent pendingIntent) { + final AlarmManager alarm = getAlarmManager(); + alarm.cancel(pendingIntent); + // For testing - allows us to see if the intent, and thus the alarm, has been cancelled. + pendingIntent.cancel(); + } + + /** + * To avoid tight coupling to Fennec, we use reflection to find + * GeckoPreferences, invoking the same code path that + * GeckoApp uses on startup to send the other + * notification to which we listen. + * + * Invoke this to handle one of the system intents to which we listen to + * launch our service without the browser being opened. + * + * All of this is neatly wrapped in try…catch, so this code + * will run safely without a Firefox build installed. + */ + protected static void reflectContextToFennec(Context context, String className, String methodName) { + // Ask the browser to tell us the current state of the preference. + try { + Class geckoPreferences = Class.forName(className); + Method broadcastSnippetsPref = geckoPreferences.getMethod(methodName, Context.class); + broadcastSnippetsPref.invoke(null, context); + return; + } catch (ClassNotFoundException e) { + Logger.error(LOG_TAG, "Class " + className + " not found!"); + return; + } catch (NoSuchMethodException e) { + Logger.error(LOG_TAG, "Method " + className + "/" + methodName + " not found!"); + return; + } catch (IllegalArgumentException e) { + Logger.error(LOG_TAG, "Got exception invoking " + methodName + "."); + } catch (IllegalAccessException e) { + Logger.error(LOG_TAG, "Got exception invoking " + methodName + "."); + } catch (InvocationTargetException e) { + Logger.error(LOG_TAG, "Got exception invoking " + methodName + "."); + } + } +}