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 extends BackgroundService> 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: }