1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/background/BackgroundService.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,114 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.background; 1.9 + 1.10 +import java.lang.reflect.InvocationTargetException; 1.11 +import java.lang.reflect.Method; 1.12 + 1.13 +import org.mozilla.gecko.background.common.log.Logger; 1.14 + 1.15 +import android.app.AlarmManager; 1.16 +import android.app.IntentService; 1.17 +import android.app.PendingIntent; 1.18 +import android.content.Context; 1.19 +import android.content.Intent; 1.20 +import android.net.ConnectivityManager; 1.21 +import android.net.NetworkInfo; 1.22 +import android.os.Build; 1.23 + 1.24 +public abstract class BackgroundService extends IntentService { 1.25 + private static final String LOG_TAG = BackgroundService.class.getSimpleName(); 1.26 + 1.27 + protected BackgroundService() { 1.28 + super(LOG_TAG); 1.29 + } 1.30 + 1.31 + protected BackgroundService(String threadName) { 1.32 + super(threadName); 1.33 + } 1.34 + 1.35 + public static void runIntentInService(Context context, Intent intent, Class<? extends BackgroundService> serviceClass) { 1.36 + Intent service = new Intent(context, serviceClass); 1.37 + service.setAction(intent.getAction()); 1.38 + service.putExtras(intent); 1.39 + context.startService(service); 1.40 + } 1.41 + 1.42 + /** 1.43 + * Returns true if the OS will allow us to perform background 1.44 + * data operations. This logic varies by OS version. 1.45 + */ 1.46 + @SuppressWarnings("deprecation") 1.47 + protected boolean backgroundDataIsEnabled() { 1.48 + ConnectivityManager connectivity = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE); 1.49 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 1.50 + return connectivity.getBackgroundDataSetting(); 1.51 + } 1.52 + NetworkInfo networkInfo = connectivity.getActiveNetworkInfo(); 1.53 + if (networkInfo == null) { 1.54 + return false; 1.55 + } 1.56 + return networkInfo.isAvailable(); 1.57 + } 1.58 + 1.59 + protected AlarmManager getAlarmManager() { 1.60 + return getAlarmManager(this.getApplicationContext()); 1.61 + } 1.62 + 1.63 + protected static AlarmManager getAlarmManager(Context context) { 1.64 + return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 1.65 + } 1.66 + 1.67 + protected void scheduleAlarm(long pollInterval, PendingIntent pendingIntent) { 1.68 + Logger.info(LOG_TAG, "Setting inexact repeating alarm for interval " + pollInterval); 1.69 + if (pollInterval <= 0) { 1.70 + throw new IllegalArgumentException("pollInterval " + pollInterval + " must be positive"); 1.71 + } 1.72 + final AlarmManager alarm = getAlarmManager(); 1.73 + final long firstEvent = System.currentTimeMillis(); 1.74 + alarm.setInexactRepeating(AlarmManager.RTC, firstEvent, pollInterval, pendingIntent); 1.75 + } 1.76 + 1.77 + protected void cancelAlarm(PendingIntent pendingIntent) { 1.78 + final AlarmManager alarm = getAlarmManager(); 1.79 + alarm.cancel(pendingIntent); 1.80 + // For testing - allows us to see if the intent, and thus the alarm, has been cancelled. 1.81 + pendingIntent.cancel(); 1.82 + } 1.83 + 1.84 + /** 1.85 + * To avoid tight coupling to Fennec, we use reflection to find 1.86 + * <code>GeckoPreferences</code>, invoking the same code path that 1.87 + * <code>GeckoApp</code> uses on startup to send the <i>other</i> 1.88 + * notification to which we listen. 1.89 + * 1.90 + * Invoke this to handle one of the system intents to which we listen to 1.91 + * launch our service without the browser being opened. 1.92 + * 1.93 + * All of this is neatly wrapped in <code>try…catch</code>, so this code 1.94 + * will run safely without a Firefox build installed. 1.95 + */ 1.96 + protected static void reflectContextToFennec(Context context, String className, String methodName) { 1.97 + // Ask the browser to tell us the current state of the preference. 1.98 + try { 1.99 + Class<?> geckoPreferences = Class.forName(className); 1.100 + Method broadcastSnippetsPref = geckoPreferences.getMethod(methodName, Context.class); 1.101 + broadcastSnippetsPref.invoke(null, context); 1.102 + return; 1.103 + } catch (ClassNotFoundException e) { 1.104 + Logger.error(LOG_TAG, "Class " + className + " not found!"); 1.105 + return; 1.106 + } catch (NoSuchMethodException e) { 1.107 + Logger.error(LOG_TAG, "Method " + className + "/" + methodName + " not found!"); 1.108 + return; 1.109 + } catch (IllegalArgumentException e) { 1.110 + Logger.error(LOG_TAG, "Got exception invoking " + methodName + "."); 1.111 + } catch (IllegalAccessException e) { 1.112 + Logger.error(LOG_TAG, "Got exception invoking " + methodName + "."); 1.113 + } catch (InvocationTargetException e) { 1.114 + Logger.error(LOG_TAG, "Got exception invoking " + methodName + "."); 1.115 + } 1.116 + } 1.117 +}