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