After Width: | Height: | Size: 942 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 578 B |
After Width: | Height: | Size: 632 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.4 KiB |
@ -0,0 +1,34 @@ |
|||||||
|
package org.transdroid.core.service; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.EReceiver; |
||||||
|
|
||||||
|
import android.content.BroadcastReceiver; |
||||||
|
import android.content.Context; |
||||||
|
import android.content.Intent; |
||||||
|
|
||||||
|
/** |
||||||
|
* Acts simply as an intermediary to start the appropriate background service when an alarm goes off. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EReceiver |
||||||
|
public class AlarmReceiver extends BroadcastReceiver { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onReceive(Context context, Intent intent) { |
||||||
|
switch (intent.getIntExtra("service", -1)) { |
||||||
|
case BootReceiver.ALARM_SERVERCHECKER: |
||||||
|
context.startService(new Intent(context, ServerCheckerService_.class)); |
||||||
|
break; |
||||||
|
case BootReceiver.ALARM_RSSCHECKER: |
||||||
|
context.startService(new Intent(context, RssCheckerService_.class)); |
||||||
|
break; |
||||||
|
case BootReceiver.ALARM_APPUPDATES: |
||||||
|
context.startService(new Intent(context, AppUpdateService_.class)); |
||||||
|
break; |
||||||
|
default: |
||||||
|
// No valid service start ID
|
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,136 @@ |
|||||||
|
package org.transdroid.core.service; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.util.Random; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.Bean; |
||||||
|
import org.androidannotations.annotations.EService; |
||||||
|
import org.androidannotations.annotations.SystemService; |
||||||
|
import org.apache.http.HttpResponse; |
||||||
|
import org.apache.http.client.ClientProtocolException; |
||||||
|
import org.apache.http.client.methods.HttpGet; |
||||||
|
import org.apache.http.impl.client.AbstractHttpClient; |
||||||
|
import org.apache.http.impl.client.DefaultHttpClient; |
||||||
|
import org.transdroid.core.R; |
||||||
|
import org.transdroid.core.app.settings.NotificationSettings; |
||||||
|
import org.transdroid.core.app.settings.SystemSettings; |
||||||
|
import org.transdroid.core.gui.log.Log; |
||||||
|
import org.transdroid.daemon.util.HttpHelper; |
||||||
|
|
||||||
|
import android.app.IntentService; |
||||||
|
import android.app.NotificationManager; |
||||||
|
import android.app.PendingIntent; |
||||||
|
import android.content.Intent; |
||||||
|
import android.content.pm.PackageInfo; |
||||||
|
import android.content.pm.PackageManager.NameNotFoundException; |
||||||
|
import android.net.Uri; |
||||||
|
import android.support.v4.app.NotificationCompat; |
||||||
|
import android.support.v4.app.NotificationCompat.Builder; |
||||||
|
|
||||||
|
@EService |
||||||
|
public class AppUpdateService extends IntentService { |
||||||
|
|
||||||
|
private static final String LATEST_URL_APP = "http://www.transdroid.org/update/latest-app.php"; |
||||||
|
private static final String LATEST_URL_SEARCH = "http://www.transdroid.org/update/latest-search.php"; |
||||||
|
private static final String DOWNLOAD_URL_APP = "http://www.transdroid.org/latest"; |
||||||
|
private static final String DOWNLOAD_URL_SEARCH = "http://www.transdroid.org/latest-search"; |
||||||
|
|
||||||
|
@Bean |
||||||
|
protected ConnectivityHelper connectivityHelper; |
||||||
|
@Bean |
||||||
|
protected SystemSettings systemSettings; |
||||||
|
@Bean |
||||||
|
protected NotificationSettings notificationSettings; |
||||||
|
@SystemService |
||||||
|
protected NotificationManager notificationManager; |
||||||
|
|
||||||
|
public AppUpdateService() { |
||||||
|
super("AppUpdateService"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onHandleIntent(Intent intent) { |
||||||
|
|
||||||
|
if (!connectivityHelper.shouldPerformActions() || !systemSettings.checkForUpdates()) { |
||||||
|
Log.d(this, |
||||||
|
"Skip the app update service, as background data is disabled, the service is disabled or we are not connected."); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
DefaultHttpClient httpclient = new DefaultHttpClient(); |
||||||
|
Random random = new Random(); |
||||||
|
|
||||||
|
try { |
||||||
|
|
||||||
|
// Retrieve what is the latest released app and search module versions
|
||||||
|
String[] app = retrieveLatestVersion(httpclient, LATEST_URL_APP); |
||||||
|
String[] search = retrieveLatestVersion(httpclient, LATEST_URL_SEARCH); |
||||||
|
int appVersion = Integer.parseInt(app[0].trim()); |
||||||
|
int searchVersion = Integer.parseInt(search[0].trim()); |
||||||
|
|
||||||
|
// New version of the app?
|
||||||
|
try { |
||||||
|
PackageInfo appPackage = getPackageManager().getPackageInfo(getPackageName(), 0); |
||||||
|
if (appPackage.versionCode < appVersion) { |
||||||
|
// New version available! Notify the user.
|
||||||
|
newNotification(getString(R.string.update_app_newversion), |
||||||
|
getString(R.string.update_app_newversion), |
||||||
|
getString(R.string.update_updateto, app[1].trim()), |
||||||
|
DOWNLOAD_URL_APP + "?" + Integer.toString(random.nextInt()), 90000); |
||||||
|
} |
||||||
|
} catch (NameNotFoundException e) { |
||||||
|
// Not installed... this can never happen since this Service is part of the app itself
|
||||||
|
} |
||||||
|
|
||||||
|
// New version of the search module?
|
||||||
|
try { |
||||||
|
PackageInfo searchPackage = getPackageManager().getPackageInfo("org.transdroid.search", 0); |
||||||
|
if (searchPackage.versionCode < searchVersion) { |
||||||
|
// New version available! Notify the user.
|
||||||
|
newNotification(getString(R.string.update_search_newversion), |
||||||
|
getString(R.string.update_search_newversion), |
||||||
|
getString(R.string.update_updateto, search[1].trim()), |
||||||
|
DOWNLOAD_URL_SEARCH + "?" + Integer.toString(random.nextInt()), 90001); |
||||||
|
} |
||||||
|
} catch (NameNotFoundException e) { |
||||||
|
// The search module isn't installed yet at all; ignore and wait for the user to manually
|
||||||
|
// install it (when the first search is initiated)
|
||||||
|
} |
||||||
|
|
||||||
|
} catch (Exception e) { |
||||||
|
// Cannot check right now for some reason; log and ignore
|
||||||
|
Log.d(this, "Cannot retrieve latest app or search module version code from the site: " + e.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the latest version number of the app or search module by checking an online text file that looks like |
||||||
|
* '160|1.1.15' for version code 160 and version name 1.1.15. |
||||||
|
* @param httpclient An already instantiated HTTP client |
||||||
|
* @param url The URL of the the text file that contains the current latest version code and name |
||||||
|
* @return A string array with two elements: the version code and the version number |
||||||
|
* @throws ClientProtocolException Thrown when the provided URL is invalid |
||||||
|
* @throws IOException Thrown when the last version information could not be retrieved |
||||||
|
*/ |
||||||
|
private String[] retrieveLatestVersion(AbstractHttpClient httpclient, String url) throws ClientProtocolException, |
||||||
|
IOException { |
||||||
|
HttpResponse request = httpclient.execute(new HttpGet(url)); |
||||||
|
InputStream stream = request.getEntity().getContent(); |
||||||
|
String appVersion[] = HttpHelper.convertStreamToString(stream).split("\\|"); |
||||||
|
stream.close(); |
||||||
|
return appVersion; |
||||||
|
} |
||||||
|
|
||||||
|
private void newNotification(String ticker, String title, String text, String downloadUrl, int notifyID) { |
||||||
|
PendingIntent pi = PendingIntent.getActivity(this, notifyID, |
||||||
|
new Intent(Intent.ACTION_VIEW, Uri.parse(downloadUrl)), Intent.FLAG_ACTIVITY_NEW_TASK); |
||||||
|
Builder builder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_stat_notification) |
||||||
|
.setTicker(ticker).setContentTitle(title).setContentText(text) |
||||||
|
.setLights(notificationSettings.getDesiredLedColour(), 600, 1000) |
||||||
|
.setSound(notificationSettings.getSound()).setAutoCancel(true).setContentIntent(pi); |
||||||
|
notificationManager.notify(notifyID, builder.build()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
package org.transdroid.core.service; |
||||||
|
|
||||||
|
import org.transdroid.core.app.settings.NotificationSettings; |
||||||
|
import org.transdroid.core.app.settings.NotificationSettings_; |
||||||
|
import org.transdroid.core.app.settings.SystemSettings; |
||||||
|
import org.transdroid.core.app.settings.SystemSettings_; |
||||||
|
import org.transdroid.core.gui.log.Log; |
||||||
|
|
||||||
|
import android.app.AlarmManager; |
||||||
|
import android.app.PendingIntent; |
||||||
|
import android.content.BroadcastReceiver; |
||||||
|
import android.content.Context; |
||||||
|
import android.content.Intent; |
||||||
|
import android.os.SystemClock; |
||||||
|
|
||||||
|
/** |
||||||
|
* Receives the intent that the device has been started in order to set up proper alarms for all background services. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
public class BootReceiver extends BroadcastReceiver { |
||||||
|
|
||||||
|
public static final int ALARM_SERVERCHECKER = 0; |
||||||
|
public static final int ALARM_RSSCHECKER = 1; |
||||||
|
public static final int ALARM_APPUPDATES = 2; |
||||||
|
|
||||||
|
public static PendingIntent piServerChecker = null, piRssChecker = null, piAppUpdates = null; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onReceive(Context context, Intent intent) { |
||||||
|
startBackgroundServices(context, false); |
||||||
|
startAppUpdatesService(context); |
||||||
|
} |
||||||
|
|
||||||
|
public static void startBackgroundServices(Context context, boolean forceReload) { |
||||||
|
NotificationSettings notificationSettings = NotificationSettings_.getInstance_(context); |
||||||
|
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); |
||||||
|
if (notificationSettings.isEnabled() && (forceReload || (piServerChecker == null && piRssChecker == null))) { |
||||||
|
|
||||||
|
Log.d(context, "Boot signal received, starting server and rss checker background services"); |
||||||
|
// Schedule repeating alarms, with the first being (somewhat) in 1 second from now
|
||||||
|
piServerChecker = PendingIntent.getBroadcast(context, ALARM_SERVERCHECKER, new Intent(context, |
||||||
|
AlarmReceiver_.class).putExtra("service", ALARM_SERVERCHECKER), 0); |
||||||
|
piRssChecker = PendingIntent.getBroadcast(context, ALARM_RSSCHECKER, new Intent(context, |
||||||
|
AlarmReceiver_.class).putExtra("service", ALARM_RSSCHECKER), 0); |
||||||
|
alarms.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, |
||||||
|
notificationSettings.getInvervalInMilliseconds(), piServerChecker); |
||||||
|
alarms.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, |
||||||
|
notificationSettings.getInvervalInMilliseconds(), piRssChecker); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void startAppUpdatesService(Context context) { |
||||||
|
SystemSettings systemSettings = SystemSettings_.getInstance_(context); |
||||||
|
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); |
||||||
|
if (systemSettings.checkForUpdates() && piAppUpdates == null) { |
||||||
|
|
||||||
|
Log.d(context, "Boot signal received, starting app update checker service"); |
||||||
|
// Schedule a daily, with the first being (somewhat) in 1 second from now
|
||||||
|
piAppUpdates = PendingIntent.getBroadcast(context, ALARM_APPUPDATES, new Intent(context, |
||||||
|
AlarmReceiver_.class).putExtra("service", ALARM_APPUPDATES), 0); |
||||||
|
alarms.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, |
||||||
|
AlarmManager.INTERVAL_DAY, piAppUpdates); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void cancelBackgroundServices(Context context) { |
||||||
|
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); |
||||||
|
if (piServerChecker != null) { |
||||||
|
alarms.cancel(piServerChecker); |
||||||
|
piServerChecker = null; |
||||||
|
} |
||||||
|
if (piRssChecker != null) { |
||||||
|
alarms.cancel(piRssChecker); |
||||||
|
piRssChecker = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void cancelAppUpdates(Context context) { |
||||||
|
if (piAppUpdates != null) { |
||||||
|
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); |
||||||
|
alarms.cancel(piAppUpdates); |
||||||
|
piAppUpdates = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package org.transdroid.core.service; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.EBean; |
||||||
|
import org.androidannotations.annotations.SystemService; |
||||||
|
import org.androidannotations.annotations.EBean.Scope; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.net.ConnectivityManager; |
||||||
|
|
||||||
|
@EBean(scope = Scope.Singleton) |
||||||
|
public class ConnectivityHelper { |
||||||
|
|
||||||
|
@SystemService |
||||||
|
protected ConnectivityManager connectivityManager; |
||||||
|
|
||||||
|
public ConnectivityHelper(Context context) { |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") |
||||||
|
public boolean shouldPerformActions() { |
||||||
|
// First check the old background data setting (this will always be true for ICS+)
|
||||||
|
if (!connectivityManager.getBackgroundDataSetting()) |
||||||
|
return false; |
||||||
|
|
||||||
|
// Still good? Check the current active network instead
|
||||||
|
return connectivityManager.getActiveNetworkInfo().isConnected(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
package org.transdroid.core.service; |
||||||
|
|
||||||
|
import java.util.LinkedHashSet; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.Bean; |
||||||
|
import org.androidannotations.annotations.EService; |
||||||
|
import org.androidannotations.annotations.SystemService; |
||||||
|
import org.transdroid.core.R; |
||||||
|
import org.transdroid.core.app.settings.ApplicationSettings; |
||||||
|
import org.transdroid.core.app.settings.NotificationSettings; |
||||||
|
import org.transdroid.core.app.settings.RssfeedSetting; |
||||||
|
import org.transdroid.core.gui.log.Log; |
||||||
|
import org.transdroid.core.gui.rss.RssfeedsActivity_; |
||||||
|
import org.transdroid.core.rssparser.Item; |
||||||
|
import org.transdroid.core.rssparser.RssParser; |
||||||
|
import org.transdroid.daemon.util.Collections2; |
||||||
|
|
||||||
|
import android.app.IntentService; |
||||||
|
import android.app.NotificationManager; |
||||||
|
import android.app.PendingIntent; |
||||||
|
import android.content.Intent; |
||||||
|
import android.support.v4.app.NotificationCompat; |
||||||
|
import android.support.v4.app.NotificationCompat.Builder; |
||||||
|
|
||||||
|
/** |
||||||
|
* A background service that checks all user-configured RSS feeds for new items. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EService |
||||||
|
public class RssCheckerService extends IntentService { |
||||||
|
|
||||||
|
@Bean |
||||||
|
protected ConnectivityHelper connectivityHelper; |
||||||
|
@Bean |
||||||
|
protected NotificationSettings notificationSettings; |
||||||
|
@Bean |
||||||
|
protected ApplicationSettings applicationSettings; |
||||||
|
@SystemService |
||||||
|
protected NotificationManager notificationManager; |
||||||
|
|
||||||
|
public RssCheckerService() { |
||||||
|
super("RssCheckerService"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onHandleIntent(Intent intent) { |
||||||
|
|
||||||
|
if (!connectivityHelper.shouldPerformActions() || !notificationSettings.isEnabled()) { |
||||||
|
Log.d(this, |
||||||
|
"Skip the RSS checker service, as background data is disabled, the service is disabled or we are not connected."); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Check every RSS feed for new items
|
||||||
|
int unread = 0; |
||||||
|
Set<String> hasUnread = new LinkedHashSet<String>(); |
||||||
|
for (RssfeedSetting feed : applicationSettings.getRssfeedSettings()) { |
||||||
|
try { |
||||||
|
|
||||||
|
Log.d(this, "Try to parse " + feed.getName() + " (" + feed.getUrl() + ")"); |
||||||
|
RssParser parser = new RssParser(feed.getUrl()); |
||||||
|
parser.parse(); |
||||||
|
if (parser.getChannel() == null) |
||||||
|
continue; |
||||||
|
|
||||||
|
// Find the last item that is newer than the last viewed date
|
||||||
|
for (Item item : parser.getChannel().getItems()) { |
||||||
|
if (item.getPubdate() != null && item.getPubdate().before(feed.getLastViewed())) { |
||||||
|
break; |
||||||
|
} else { |
||||||
|
unread++; |
||||||
|
if (!hasUnread.contains(feed.getName())) |
||||||
|
hasUnread.add(feed.getName()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Log.d(this, feed.getName() + " has " + (hasUnread.contains(feed.getName()) ? "" : "no ") |
||||||
|
+ "unread items"); |
||||||
|
|
||||||
|
} catch (Exception e) { |
||||||
|
// Ignore RSS feeds that could not be retrieved or parsed
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (unread == 0) { |
||||||
|
// No new items; just exit
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// Provide a notification, since there are new RSS items
|
||||||
|
PendingIntent pi = PendingIntent.getActivity(this, 80000, new Intent(this, RssfeedsActivity_.class), |
||||||
|
Intent.FLAG_ACTIVITY_NEW_TASK); |
||||||
|
String title = getResources().getQuantityString(R.plurals.rss_service_new, unread, Integer.toString(unread)); |
||||||
|
String forString = Collections2.joinString(hasUnread, ", "); |
||||||
|
Builder builder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_stat_notification) |
||||||
|
.setTicker(title).setContentTitle(title) |
||||||
|
.setContentText(getString(R.string.rss_service_newfor, forString)).setNumber(unread) |
||||||
|
.setLights(notificationSettings.getDesiredLedColour(), 600, 1000) |
||||||
|
.setSound(notificationSettings.getSound()).setAutoCancel(true).setContentIntent(pi); |
||||||
|
if (notificationSettings.shouldVibrate()) |
||||||
|
builder.setVibrate(notificationSettings.getDefaultVibratePattern()); |
||||||
|
notificationManager.notify(80001, builder.build()); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,183 @@ |
|||||||
|
package org.transdroid.core.service; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.androidannotations.annotations.Bean; |
||||||
|
import org.androidannotations.annotations.EService; |
||||||
|
import org.androidannotations.annotations.SystemService; |
||||||
|
import org.json.JSONArray; |
||||||
|
import org.json.JSONException; |
||||||
|
import org.json.JSONObject; |
||||||
|
import org.transdroid.core.R; |
||||||
|
import org.transdroid.core.app.settings.ApplicationSettings; |
||||||
|
import org.transdroid.core.app.settings.NotificationSettings; |
||||||
|
import org.transdroid.core.app.settings.ServerSetting; |
||||||
|
import org.transdroid.core.gui.TorrentsActivity_; |
||||||
|
import org.transdroid.core.gui.log.Log; |
||||||
|
import org.transdroid.daemon.IDaemonAdapter; |
||||||
|
import org.transdroid.daemon.Torrent; |
||||||
|
import org.transdroid.daemon.task.DaemonTaskResult; |
||||||
|
import org.transdroid.daemon.task.RetrieveTask; |
||||||
|
import org.transdroid.daemon.task.RetrieveTaskSuccessResult; |
||||||
|
import org.transdroid.daemon.util.Collections2; |
||||||
|
|
||||||
|
import android.app.IntentService; |
||||||
|
import android.app.NotificationManager; |
||||||
|
import android.app.PendingIntent; |
||||||
|
import android.content.Intent; |
||||||
|
import android.support.v4.app.NotificationCompat; |
||||||
|
import android.support.v4.app.NotificationCompat.Builder; |
||||||
|
import android.support.v4.app.NotificationCompat.InboxStyle; |
||||||
|
|
||||||
|
/** |
||||||
|
* A background service that checks all user-configured servers (if so desired) for new and finished torrents. |
||||||
|
* @author Eric Kok |
||||||
|
*/ |
||||||
|
@EService |
||||||
|
public class ServerCheckerService extends IntentService { |
||||||
|
|
||||||
|
@Bean |
||||||
|
protected ConnectivityHelper connectivityHelper; |
||||||
|
@Bean |
||||||
|
protected NotificationSettings notificationSettings; |
||||||
|
@Bean |
||||||
|
protected ApplicationSettings applicationSettings; |
||||||
|
@SystemService |
||||||
|
protected NotificationManager notificationManager; |
||||||
|
|
||||||
|
public ServerCheckerService() { |
||||||
|
super("ServerCheckerService"); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void onHandleIntent(Intent intent) { |
||||||
|
|
||||||
|
if (!connectivityHelper.shouldPerformActions() || !notificationSettings.isEnabled()) { |
||||||
|
Log.d(this, |
||||||
|
"Skip the server checker service, as background data is disabled, the service is disabled or we are not connected."); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
int notifyBase = 10000; |
||||||
|
for (ServerSetting server : applicationSettings.getServerSettings()) { |
||||||
|
|
||||||
|
// No need to check if the server is not properly configured or none of the two types of notifications are
|
||||||
|
// enabled by the user for this specific server
|
||||||
|
if (server.getType() == null || server.getAddress() == null || server.getAddress().equals("") |
||||||
|
|| !(server.shouldAlarmOnFinishedDownload() || server.shouldAlarmOnNewTorrent())) |
||||||
|
return; |
||||||
|
|
||||||
|
// Get the statistics for the last time we checked this server
|
||||||
|
JSONArray lastStats = applicationSettings.getServerLastStats(server); |
||||||
|
|
||||||
|
// Synchronously retrieve torrents listing
|
||||||
|
IDaemonAdapter adapter = server.createServerAdapter(); |
||||||
|
DaemonTaskResult result = RetrieveTask.create(adapter).execute(); |
||||||
|
if (!(result instanceof RetrieveTaskSuccessResult)) { |
||||||
|
// Cannot retrieve torrents at this time
|
||||||
|
return; |
||||||
|
} |
||||||
|
List<Torrent> retrieved = ((RetrieveTaskSuccessResult) result).getTorrents(); |
||||||
|
Log.d(this, server.getName() + ": Retrieved torrent listing"); |
||||||
|
|
||||||
|
// Check for differences between the last and the current stats
|
||||||
|
JSONArray currentStats = new JSONArray(); |
||||||
|
List<Torrent> newTorrents = new ArrayList<Torrent>(); |
||||||
|
List<Torrent> doneTorrents = new ArrayList<Torrent>(); |
||||||
|
for (Torrent torrent : retrieved) { |
||||||
|
|
||||||
|
// Remember this torrent for the next time
|
||||||
|
try { |
||||||
|
currentStats.put(new JSONObject().put("id", torrent.getUniqueID()).put("done", |
||||||
|
torrent.getPartDone() == 1F)); |
||||||
|
} catch (JSONException e) { |
||||||
|
// Can't build the JSON object; this should not happen and we can safely ignore it
|
||||||
|
} |
||||||
|
|
||||||
|
// See if this torrent was done the last time we checked
|
||||||
|
if (lastStats != null) { |
||||||
|
Boolean wasDone = findLastDoneStat(lastStats, torrent); |
||||||
|
if (server.shouldAlarmOnNewTorrent() && wasDone == null) { |
||||||
|
// This torrent wasn't present earlier
|
||||||
|
newTorrents.add(torrent); |
||||||
|
continue; |
||||||
|
} |
||||||
|
if (server.shouldAlarmOnFinishedDownload() && torrent.getPartDone() == 1F && !wasDone) |
||||||
|
// This torrent is now done, but wasn't before
|
||||||
|
doneTorrents.add(torrent); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// Store the now-current statistics on torrents for the next time we check this server
|
||||||
|
applicationSettings.setServerLastStats(server, currentStats); |
||||||
|
|
||||||
|
// Notify on new and now-done torrents for this server
|
||||||
|
Log.d(this, server.getName() + ": " + newTorrents.size() + " new torrents, " + doneTorrents.size() |
||||||
|
+ " newly finished torrents."); |
||||||
|
Intent i = new Intent(this, TorrentsActivity_.class); |
||||||
|
i.putExtra("org.transdroid.START_SERVER", server.getOrder()); |
||||||
|
// Should start the main activity directly into this server
|
||||||
|
PendingIntent pi = PendingIntent.getActivity(this, notifyBase + server.getOrder(), i, |
||||||
|
Intent.FLAG_ACTIVITY_NEW_TASK); |
||||||
|
ArrayList<Torrent> affectedTorrents = new ArrayList<Torrent>(newTorrents.size() + doneTorrents.size()); |
||||||
|
affectedTorrents.addAll(newTorrents); |
||||||
|
affectedTorrents.addAll(doneTorrents); |
||||||
|
String title, forString = Collections2.joinString(affectedTorrents, ", "); |
||||||
|
if (newTorrents.size() > 0 && doneTorrents.size() > 0) { |
||||||
|
// Note: use the 'one' plural iif 1 new torrent was added and 1 was newly finished
|
||||||
|
title = getResources().getQuantityString(R.plurals.status_service_finished, |
||||||
|
newTorrents.size() + doneTorrents.size() == 2 ? 1 : 2, Integer.toString(newTorrents.size()), |
||||||
|
Integer.toString(doneTorrents.size())); |
||||||
|
} else if (newTorrents.size() > 0) { |
||||||
|
title = getResources().getQuantityString(R.plurals.status_service_added, newTorrents.size(), |
||||||
|
Integer.toString(newTorrents.size())); |
||||||
|
} else if (doneTorrents.size() > 0) { |
||||||
|
title = getResources().getQuantityString(R.plurals.status_service_finished, doneTorrents.size(), |
||||||
|
Integer.toString(doneTorrents.size())); |
||||||
|
} else { |
||||||
|
// No notification to show
|
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// Build the basic notification
|
||||||
|
Builder builder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_stat_notification) |
||||||
|
.setTicker(title).setContentTitle(title).setContentText(forString) |
||||||
|
.setNumber(affectedTorrents.size()) |
||||||
|
.setLights(notificationSettings.getDesiredLedColour(), 600, 1000) |
||||||
|
.setSound(notificationSettings.getSound()).setAutoCancel(true).setContentIntent(pi); |
||||||
|
if (notificationSettings.shouldVibrate()) |
||||||
|
builder.setVibrate(notificationSettings.getDefaultVibratePattern()); |
||||||
|
|
||||||
|
// Add at most 5 lines with the affected torrents
|
||||||
|
InboxStyle inbox = new NotificationCompat.InboxStyle(builder); |
||||||
|
if (affectedTorrents.size() < 6) { |
||||||
|
for (Torrent affectedTorrent : affectedTorrents) { |
||||||
|
inbox.addLine(affectedTorrent.getName()); |
||||||
|
} |
||||||
|
} else { |
||||||
|
for (int j = 0; j < 4; j++) { |
||||||
|
inbox.addLine(affectedTorrents.get(j).getName()); |
||||||
|
} |
||||||
|
inbox.addLine(getString(R.string.status_service_andothers, affectedTorrents.get(5).getName())); |
||||||
|
} |
||||||
|
notificationManager.notify(notifyBase + server.getOrder(), inbox.build()); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private Boolean findLastDoneStat(JSONArray lastStats, Torrent torrent) { |
||||||
|
for (int i = 0; i < lastStats.length(); i++) { |
||||||
|
try { |
||||||
|
if (lastStats.getJSONObject(i).getString("id").equals(torrent.getUniqueID())) |
||||||
|
return lastStats.getJSONObject(i).getBoolean("done"); |
||||||
|
} catch (JSONException e) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
} |