|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko.background; |
|
6 |
|
7 import java.lang.reflect.InvocationTargetException; |
|
8 import java.lang.reflect.Method; |
|
9 |
|
10 import org.mozilla.gecko.background.common.log.Logger; |
|
11 |
|
12 import android.app.AlarmManager; |
|
13 import android.app.IntentService; |
|
14 import android.app.PendingIntent; |
|
15 import android.content.Context; |
|
16 import android.content.Intent; |
|
17 import android.net.ConnectivityManager; |
|
18 import android.net.NetworkInfo; |
|
19 import android.os.Build; |
|
20 |
|
21 public abstract class BackgroundService extends IntentService { |
|
22 private static final String LOG_TAG = BackgroundService.class.getSimpleName(); |
|
23 |
|
24 protected BackgroundService() { |
|
25 super(LOG_TAG); |
|
26 } |
|
27 |
|
28 protected BackgroundService(String threadName) { |
|
29 super(threadName); |
|
30 } |
|
31 |
|
32 public static void runIntentInService(Context context, Intent intent, Class<? extends BackgroundService> serviceClass) { |
|
33 Intent service = new Intent(context, serviceClass); |
|
34 service.setAction(intent.getAction()); |
|
35 service.putExtras(intent); |
|
36 context.startService(service); |
|
37 } |
|
38 |
|
39 /** |
|
40 * Returns true if the OS will allow us to perform background |
|
41 * data operations. This logic varies by OS version. |
|
42 */ |
|
43 @SuppressWarnings("deprecation") |
|
44 protected boolean backgroundDataIsEnabled() { |
|
45 ConnectivityManager connectivity = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE); |
|
46 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { |
|
47 return connectivity.getBackgroundDataSetting(); |
|
48 } |
|
49 NetworkInfo networkInfo = connectivity.getActiveNetworkInfo(); |
|
50 if (networkInfo == null) { |
|
51 return false; |
|
52 } |
|
53 return networkInfo.isAvailable(); |
|
54 } |
|
55 |
|
56 protected AlarmManager getAlarmManager() { |
|
57 return getAlarmManager(this.getApplicationContext()); |
|
58 } |
|
59 |
|
60 protected static AlarmManager getAlarmManager(Context context) { |
|
61 return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); |
|
62 } |
|
63 |
|
64 protected void scheduleAlarm(long pollInterval, PendingIntent pendingIntent) { |
|
65 Logger.info(LOG_TAG, "Setting inexact repeating alarm for interval " + pollInterval); |
|
66 if (pollInterval <= 0) { |
|
67 throw new IllegalArgumentException("pollInterval " + pollInterval + " must be positive"); |
|
68 } |
|
69 final AlarmManager alarm = getAlarmManager(); |
|
70 final long firstEvent = System.currentTimeMillis(); |
|
71 alarm.setInexactRepeating(AlarmManager.RTC, firstEvent, pollInterval, pendingIntent); |
|
72 } |
|
73 |
|
74 protected void cancelAlarm(PendingIntent pendingIntent) { |
|
75 final AlarmManager alarm = getAlarmManager(); |
|
76 alarm.cancel(pendingIntent); |
|
77 // For testing - allows us to see if the intent, and thus the alarm, has been cancelled. |
|
78 pendingIntent.cancel(); |
|
79 } |
|
80 |
|
81 /** |
|
82 * To avoid tight coupling to Fennec, we use reflection to find |
|
83 * <code>GeckoPreferences</code>, invoking the same code path that |
|
84 * <code>GeckoApp</code> uses on startup to send the <i>other</i> |
|
85 * notification to which we listen. |
|
86 * |
|
87 * Invoke this to handle one of the system intents to which we listen to |
|
88 * launch our service without the browser being opened. |
|
89 * |
|
90 * All of this is neatly wrapped in <code>try…catch</code>, so this code |
|
91 * will run safely without a Firefox build installed. |
|
92 */ |
|
93 protected static void reflectContextToFennec(Context context, String className, String methodName) { |
|
94 // Ask the browser to tell us the current state of the preference. |
|
95 try { |
|
96 Class<?> geckoPreferences = Class.forName(className); |
|
97 Method broadcastSnippetsPref = geckoPreferences.getMethod(methodName, Context.class); |
|
98 broadcastSnippetsPref.invoke(null, context); |
|
99 return; |
|
100 } catch (ClassNotFoundException e) { |
|
101 Logger.error(LOG_TAG, "Class " + className + " not found!"); |
|
102 return; |
|
103 } catch (NoSuchMethodException e) { |
|
104 Logger.error(LOG_TAG, "Method " + className + "/" + methodName + " not found!"); |
|
105 return; |
|
106 } catch (IllegalArgumentException e) { |
|
107 Logger.error(LOG_TAG, "Got exception invoking " + methodName + "."); |
|
108 } catch (IllegalAccessException e) { |
|
109 Logger.error(LOG_TAG, "Got exception invoking " + methodName + "."); |
|
110 } catch (InvocationTargetException e) { |
|
111 Logger.error(LOG_TAG, "Got exception invoking " + methodName + "."); |
|
112 } |
|
113 } |
|
114 } |