Browse Source

Reworked background services via Android-Job. This finally adds support for newer Android versions (respecting Doze mode et al.) and stops crashing the app on Android 8. Fixes #462 and fixes #464.

pull/471/head
Eric Kok 6 years ago
parent
commit
d689a1f151
  1. 9
      app/build.gradle
  2. 7
      app/src/main/AndroidManifest.xml
  3. 4
      app/src/main/java/org/transdroid/core/app/settings/NotificationSettings.java
  4. 5
      app/src/main/java/org/transdroid/core/app/settings/SystemSettings.java
  5. 10
      app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java
  6. 50
      app/src/main/java/org/transdroid/core/gui/TransdroidApp.java
  7. 16
      app/src/main/java/org/transdroid/core/gui/settings/NotificationSettingsActivity.java
  8. 9
      app/src/main/java/org/transdroid/core/gui/settings/SystemSettingsActivity.java
  9. 50
      app/src/main/java/org/transdroid/core/service/AlarmReceiver.java
  10. 60
      app/src/main/java/org/transdroid/core/service/AppUpdateJob.java
  11. 92
      app/src/main/java/org/transdroid/core/service/AppUpdateJobRunner.java
  12. 91
      app/src/main/java/org/transdroid/core/service/BootReceiver.java
  13. 61
      app/src/main/java/org/transdroid/core/service/RssCheckerJob.java
  14. 70
      app/src/main/java/org/transdroid/core/service/RssCheckerJobRunner.java
  15. 41
      app/src/main/java/org/transdroid/core/service/ScheduledJobCreator.java
  16. 56
      app/src/main/java/org/transdroid/core/service/ServerCheckerJob.java
  17. 85
      app/src/main/java/org/transdroid/core/service/ServerCheckerJobRunner.java
  18. 3
      app/src/main/res/values-bg/strings.xml
  19. 3
      app/src/main/res/values-cs/strings.xml
  20. 3
      app/src/main/res/values-da/strings.xml
  21. 3
      app/src/main/res/values-de/strings.xml
  22. 3
      app/src/main/res/values-es/strings.xml
  23. 3
      app/src/main/res/values-et/strings.xml
  24. 3
      app/src/main/res/values-fa/strings.xml
  25. 3
      app/src/main/res/values-fi/strings.xml
  26. 3
      app/src/main/res/values-fr/strings.xml
  27. 3
      app/src/main/res/values-he/strings.xml
  28. 3
      app/src/main/res/values-hu/strings.xml
  29. 3
      app/src/main/res/values-it/strings.xml
  30. 3
      app/src/main/res/values-ja/strings.xml
  31. 3
      app/src/main/res/values-ko/strings.xml
  32. 3
      app/src/main/res/values-nl/strings.xml
  33. 3
      app/src/main/res/values-pl/strings.xml
  34. 3
      app/src/main/res/values-pt-rBR/strings.xml
  35. 3
      app/src/main/res/values-pt/strings.xml
  36. 3
      app/src/main/res/values-ru/strings.xml
  37. 3
      app/src/main/res/values-sl/strings.xml
  38. 3
      app/src/main/res/values-sv/strings.xml
  39. 3
      app/src/main/res/values-tr/strings.xml
  40. 3
      app/src/main/res/values-uk/strings.xml
  41. 3
      app/src/main/res/values-vi/strings.xml
  42. 3
      app/src/main/res/values-zh-rCN/strings.xml
  43. 3
      app/src/main/res/values-zh-rHK/strings.xml
  44. 6
      app/src/main/res/values/strings.xml
  45. 2
      build.gradle

9
app/build.gradle

@ -53,8 +53,8 @@ android {
} }
dependencies { dependencies {
implementation 'org.androidannotations:androidannotations-api:4.4.0' implementation 'org.androidannotations:androidannotations-api:4.5.2'
implementation 'org.androidannotations:ormlite-api:4.4.0' implementation 'org.androidannotations:ormlite-api:4.5.2'
implementation 'com.j256.ormlite:ormlite-core:4.48' implementation 'com.j256.ormlite:ormlite-core:4.48'
implementation 'com.j256.ormlite:ormlite-android:4.48' implementation 'com.j256.ormlite:ormlite-android:4.48'
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
@ -66,7 +66,8 @@ dependencies {
implementation('com.github.afollestad.material-dialogs:core:0.9.6.0@aar') { implementation('com.github.afollestad.material-dialogs:core:0.9.6.0@aar') {
transitive = true transitive = true
} }
annotationProcessor 'org.androidannotations:androidannotations:4.4.0' implementation 'com.evernote:android-job:1.2.6'
annotationProcessor 'org.androidannotations:ormlite:4.4.0' annotationProcessor 'org.androidannotations:androidannotations:4.5.2'
annotationProcessor 'org.androidannotations:ormlite:4.5.2'
} }

7
app/src/main/AndroidManifest.xml

@ -44,6 +44,7 @@
android:required="false" /> android:required="false" />
<application <application
android:name=".core.gui.TransdroidApp_"
android:allowBackup="true" android:allowBackup="true"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
@ -254,12 +255,6 @@
android:label="Remote RSS feeds" android:label="Remote RSS feeds"
android:theme="@style/TransdroidTheme" /> android:theme="@style/TransdroidTheme" />
<!-- Background services -->
<service android:name="org.transdroid.core.service.ServerCheckerService_" />
<service android:name="org.transdroid.core.service.RssCheckerService_" />
<service android:name="org.transdroid.core.service.AppUpdateService_" />
<receiver android:name="org.transdroid.core.service.AlarmReceiver_" />
<receiver android:name="org.transdroid.core.service.BootReceiver_" > <receiver android:name="org.transdroid.core.service.BootReceiver_" >
<intent-filter> <intent-filter>
<action <action

4
app/src/main/java/org/transdroid/core/app/settings/NotificationSettings.java

@ -34,6 +34,8 @@ import android.provider.Settings;
@EBean(scope = Scope.Singleton) @EBean(scope = Scope.Singleton)
public class NotificationSettings { public class NotificationSettings {
private static final long MINIMUM_BACKGROUND_INTERVAL = 900_000; // 15 minutes
@RootContext @RootContext
protected Context context; protected Context context;
private SharedPreferences prefs; private SharedPreferences prefs;
@ -67,7 +69,7 @@ public class NotificationSettings {
* @return The interval, in milliseconds * @return The interval, in milliseconds
*/ */
public Long getInvervalInMilliseconds() { public Long getInvervalInMilliseconds() {
return Long.parseLong(getRawInverval()) * 1000L; return Math.max(Long.parseLong(getRawInverval()) * 1000L, MINIMUM_BACKGROUND_INTERVAL);
} }
private String getRawSound() { private String getRawSound() {

5
app/src/main/java/org/transdroid/core/app/settings/SystemSettings.java

@ -21,7 +21,6 @@ import java.util.Date;
import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext; import org.androidannotations.annotations.RootContext;
import org.androidannotations.annotations.EBean.Scope; import org.androidannotations.annotations.EBean.Scope;
import org.transdroid.core.service.AppUpdateService;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -70,7 +69,7 @@ public class SystemSettings {
/** /**
* Returns the date when we last checked transdroid.org for the latest app version. * Returns the date when we last checked transdroid.org for the latest app version.
* @return The date/time when the {@link AppUpdateService} checked on the server for updates * @return The date/time when the {@link org.transdroid.core.service.AppUpdateJob} checked on the server for updates
*/ */
public Date getLastCheckedForAppUpdates() { public Date getLastCheckedForAppUpdates() {
long lastChecked = prefs.getLong("system_lastappupdatecheck", -1L); long lastChecked = prefs.getLong("system_lastappupdatecheck", -1L);
@ -79,7 +78,7 @@ public class SystemSettings {
/** /**
* Stores the date at which was last successfully, fully checked for new updates to the app. * Stores the date at which was last successfully, fully checked for new updates to the app.
* @param lastChecked The date/time at which the {@link AppUpdateService} last checked the server for updates * @param lastChecked The date/time at which the {@link org.transdroid.core.service.AppUpdateJob} last checked the server for updates
*/ */
public void setLastCheckedForAppUpdates(Date lastChecked) { public void setLastCheckedForAppUpdates(Date lastChecked) {
prefs.edit().putLong("system_lastappupdatecheck", lastChecked == null ? -1L : lastChecked.getTime()).apply(); prefs.edit().putLong("system_lastappupdatecheck", lastChecked == null ? -1L : lastChecked.getTime()).apply();

10
app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java

@ -87,8 +87,7 @@ import org.transdroid.core.gui.rss.RssfeedsActivity_;
import org.transdroid.core.gui.search.FilePickerHelper; import org.transdroid.core.gui.search.FilePickerHelper;
import org.transdroid.core.gui.search.UrlEntryDialog; import org.transdroid.core.gui.search.UrlEntryDialog;
import org.transdroid.core.gui.settings.MainSettingsActivity_; import org.transdroid.core.gui.settings.MainSettingsActivity_;
import org.transdroid.core.service.BootReceiver; import org.transdroid.core.service.*;
import org.transdroid.core.service.ConnectivityHelper;
import org.transdroid.core.widget.ListWidgetProvider; import org.transdroid.core.widget.ListWidgetProvider;
import org.transdroid.daemon.Daemon; import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonException; import org.transdroid.daemon.DaemonException;
@ -320,9 +319,10 @@ public class TorrentsActivity extends AppCompatActivity implements TorrentTasksE
} }
firstStart = false; firstStart = false;
// Start the alarms for the background services, if needed // Start the jobs for the background services, if needed
BootReceiver.startBackgroundServices(getApplicationContext(), false); ServerCheckerJob.schedule(getApplicationContext());
BootReceiver.startAppUpdatesService(getApplicationContext()); RssCheckerJob.schedule(getApplicationContext());
AppUpdateJob.schedule(getApplicationContext());
} }

50
app/src/main/java/org/transdroid/core/gui/TransdroidApp.java

@ -0,0 +1,50 @@
/*
* Copyright 2010-2013 Eric Kok et al.
*
* Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/
package org.transdroid.core.gui;
import android.app.Application;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.evernote.android.job.JobConfig;
import com.evernote.android.job.JobManager;
import com.evernote.android.job.util.JobLogger;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EApplication;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.service.ScheduledJobCreator;
@EApplication
public class TransdroidApp extends Application {
@Bean
protected Log log;
@Override
public void onCreate() {
super.onCreate();
// Configure Android-Job
JobConfig.addLogger(new JobLogger() {
@Override
public void log(int priority, @NonNull String tag, @NonNull String message, @Nullable Throwable t) {
log.d(tag, message);
}
});
JobManager.create(this).addJobCreator(new ScheduledJobCreator());
}
}

16
app/src/main/java/org/transdroid/core/gui/settings/NotificationSettingsActivity.java

@ -29,6 +29,8 @@ import org.androidannotations.annotations.OptionsItem;
import org.transdroid.R; import org.transdroid.R;
import org.transdroid.core.app.settings.NotificationSettings; import org.transdroid.core.app.settings.NotificationSettings;
import org.transdroid.core.service.BootReceiver; import org.transdroid.core.service.BootReceiver;
import org.transdroid.core.service.RssCheckerJob;
import org.transdroid.core.service.ServerCheckerJob;
@EActivity @EActivity
public class NotificationSettingsActivity extends PreferenceCompatActivity implements OnSharedPreferenceChangeListener { public class NotificationSettingsActivity extends PreferenceCompatActivity implements OnSharedPreferenceChangeListener {
@ -73,18 +75,8 @@ public class NotificationSettingsActivity extends PreferenceCompatActivity imple
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
ServerCheckerJob.schedule(getApplicationContext());
boolean disabled = !notificationSettings.isEnabledForRss() && !notificationSettings.isEnabledForTorrents(); RssCheckerJob.schedule(getApplicationContext());
updatePrefsEnabled(disabled);
if (disabled) {
// Disabled all background notifications; disable the alarms that start the service
BootReceiver.cancelBackgroundServices(getApplicationContext());
}
// (Re-)enable the alarms for the background services
// Note that this still respects the user preference
BootReceiver.startBackgroundServices(getApplicationContext(), true);
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")

9
app/src/main/java/org/transdroid/core/gui/settings/SystemSettingsActivity.java

@ -25,7 +25,6 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener; import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
@ -47,7 +46,7 @@ import org.transdroid.core.gui.log.ErrorLogSender;
import org.transdroid.core.gui.navigation.NavigationHelper; import org.transdroid.core.gui.navigation.NavigationHelper;
import org.transdroid.core.gui.search.BarcodeHelper; import org.transdroid.core.gui.search.BarcodeHelper;
import org.transdroid.core.gui.search.SearchHistoryProvider; import org.transdroid.core.gui.search.SearchHistoryProvider;
import org.transdroid.core.service.BootReceiver; import org.transdroid.core.service.AppUpdateJob;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
@ -85,11 +84,7 @@ public class SystemSettingsActivity extends PreferenceCompatActivity {
private OnPreferenceClickListener onCheckUpdatesClick = new OnPreferenceClickListener() { private OnPreferenceClickListener onCheckUpdatesClick = new OnPreferenceClickListener() {
@Override @Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
if (((CheckBoxPreference) preference).isChecked()) { AppUpdateJob.schedule(getApplicationContext());
BootReceiver.startAppUpdatesService(getApplicationContext());
} else {
BootReceiver.cancelAppUpdates(getApplicationContext());
}
return true; return true;
} }
}; };

50
app/src/main/java/org/transdroid/core/service/AlarmReceiver.java

@ -1,50 +0,0 @@
/*
* Copyright 2010-2013 Eric Kok et al.
*
* Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/
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;
}
}
}

60
app/src/main/java/org/transdroid/core/service/AppUpdateJob.java

@ -0,0 +1,60 @@
/*
* Copyright 2010-2013 Eric Kok et al.
*
* Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/
package org.transdroid.core.service;
import android.content.Context;
import android.support.annotation.NonNull;
import com.evernote.android.job.Job;
import com.evernote.android.job.JobManager;
import com.evernote.android.job.JobRequest;
import org.transdroid.core.app.settings.SystemSettings;
import org.transdroid.core.app.settings.SystemSettings_;
import org.transdroid.core.gui.log.Log_;
import org.transdroid.core.gui.navigation.NavigationHelper_;
import java.util.concurrent.TimeUnit;
public class AppUpdateJob extends Job {
static final String TAG = "app_update_checker";
private static Integer scheduledJobId;
public static void schedule(Context context) {
SystemSettings systemSettings = SystemSettings_.getInstance_(context);
NavigationHelper_ navigationHelper = NavigationHelper_.getInstance_(context);
if (systemSettings.checkForUpdates() && navigationHelper.enableUpdateChecker()) {
Log_.getInstance_(context).d(TAG, "Schedule app update checker job");
scheduledJobId = new JobRequest.Builder(AppUpdateJob.TAG)
.setPeriodic(TimeUnit.DAYS.toMillis(1))
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setUpdateCurrent(true)
.build()
.schedule();
} else if (scheduledJobId != null) {
Log_.getInstance_(context).d(TAG, "Cancel rss checker job");
JobManager.instance().cancel(scheduledJobId);
}
}
@NonNull
@Override
protected Result onRunJob(@NonNull Params params) {
return AppUpdateJobRunner_.getInstance_(getContext()).run();
}
}

92
app/src/main/java/org/transdroid/core/service/AppUpdateService.java → app/src/main/java/org/transdroid/core/service/AppUpdateJobRunner.java

@ -1,29 +1,33 @@
/* /*
* Copyright 2010-2013 Eric Kok et al. * Copyright 2010-2013 Eric Kok et al.
* *
* Transdroid is free software: you can redistribute it and/or modify * Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Transdroid is distributed in the hope that it will be useful, * Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>. * along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.transdroid.core.service; package org.transdroid.core.service;
import java.io.IOException; import android.app.Notification;
import java.io.InputStream; import android.app.NotificationManager;
import java.util.Calendar; import android.app.PendingIntent;
import java.util.Date; import android.content.Context;
import java.util.Random; import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import com.evernote.android.job.Job;
import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EService; import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.androidannotations.annotations.SystemService; import org.androidannotations.annotations.SystemService;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ClientProtocolException;
@ -37,24 +41,22 @@ import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.navigation.NavigationHelper; import org.transdroid.core.gui.navigation.NavigationHelper;
import org.transdroid.daemon.util.HttpHelper; import org.transdroid.daemon.util.HttpHelper;
import android.app.IntentService; import java.io.IOException;
import android.app.Notification; import java.io.InputStream;
import android.app.Notification.Builder; import java.util.Calendar;
import android.app.NotificationManager; import java.util.Date;
import android.app.PendingIntent; import java.util.Random;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
@EService @EBean
public class AppUpdateService extends IntentService { public class AppUpdateJobRunner {
private static final String LATEST_URL_APP = "https://raw.githubusercontent.com/erickok/transdroid/master/latest-app.html"; private static final String LATEST_URL_APP = "https://raw.githubusercontent.com/erickok/transdroid/master/latest-app.html";
private static final String LATEST_URL_SEARCH = "https://raw.githubusercontent.com/erickok/transdroid/master/latest-search.html"; private static final String LATEST_URL_SEARCH = "https://raw.githubusercontent.com/erickok/transdroid/master/latest-search.html";
private static final String DOWNLOAD_URL_APP = "http://www.transdroid.org/latest"; 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"; private static final String DOWNLOAD_URL_SEARCH = "http://www.transdroid.org/latest-search";
@RootContext
protected Context context;
@Bean @Bean
protected Log log; protected Log log;
@Bean @Bean
@ -68,21 +70,16 @@ public class AppUpdateService extends IntentService {
@SystemService @SystemService
protected NotificationManager notificationManager; protected NotificationManager notificationManager;
public AppUpdateService() { Job.Result run() {
super("AppUpdateService");
}
@Override
protected void onHandleIntent(Intent intent) {
// Only run this service if app updates are handled via transdroid.org at all // Only run this service if app updates are handled via transdroid.org at all
if (!navigationHelper.enableUpdateChecker()) if (!navigationHelper.enableUpdateChecker())
return; return Job.Result.FAILURE;
if (!connectivityHelper.shouldPerformBackgroundActions() || !systemSettings.checkForUpdates()) { if (!connectivityHelper.shouldPerformBackgroundActions() || !systemSettings.checkForUpdates()) {
log.d(this, "Skip the app update service, as background data is disabled, the service is explicitly " + log.d(this, "Skip the app update service, as background data is disabled, the service is explicitly " +
"disabled or we are not connected."); "disabled or we are not connected.");
return; return Job.Result.RESCHEDULE;
} }
Date lastChecked = systemSettings.getLastCheckedForAppUpdates(); Date lastChecked = systemSettings.getLastCheckedForAppUpdates();
@ -91,7 +88,7 @@ public class AppUpdateService extends IntentService {
if (lastChecked != null && lastChecked.after(lastDay.getTime())) { if (lastChecked != null && lastChecked.after(lastDay.getTime())) {
log.d(this, "Skip the update service, as we already checked the last 24 hours (or to be exact at " log.d(this, "Skip the update service, as we already checked the last 24 hours (or to be exact at "
+ lastChecked.toString() + ")."); + lastChecked.toString() + ").");
return; return Job.Result.RESCHEDULE;
} }
DefaultHttpClient httpclient = new DefaultHttpClient(); DefaultHttpClient httpclient = new DefaultHttpClient();
@ -107,33 +104,33 @@ public class AppUpdateService extends IntentService {
// New version of the app? // New version of the app?
try { try {
PackageInfo appPackage = getPackageManager().getPackageInfo(getPackageName(), 0); PackageInfo appPackage = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
log.d(this, "Local Transdroid is at " + appPackage.versionCode + " and the reported latest version is " log.d(this, "Local Transdroid is at " + appPackage.versionCode + " and the reported latest version is "
+ appVersion); + appVersion);
if (appPackage.versionCode < appVersion) { if (appPackage.versionCode < appVersion) {
// New version available! Notify the user. // New version available! Notify the user.
newNotification(getString(R.string.update_app_newversion), newNotification(context.getString(R.string.update_app_newversion),
getString(R.string.update_app_newversion), context.getString(R.string.update_app_newversion),
getString(R.string.update_updateto, app[1].trim()), context.getString(R.string.update_updateto, app[1].trim()),
DOWNLOAD_URL_APP + "?" + Integer.toString(random.nextInt()), 90000); DOWNLOAD_URL_APP + "?" + Integer.toString(random.nextInt()), 90000);
} }
} catch (NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
// Not installed... this can never happen since this Service is part of the app itself // Not installed... this can never happen since this Service is part of the app itself
} }
// New version of the search module? // New version of the search module?
try { try {
PackageInfo searchPackage = getPackageManager().getPackageInfo("org.transdroid.search", 0); PackageInfo searchPackage = context.getPackageManager().getPackageInfo("org.transdroid.search", 0);
log.d(this, "Local Transdroid Seach is at " + searchPackage.versionCode log.d(this, "Local Transdroid Seach is at " + searchPackage.versionCode
+ " and the reported latest version is " + searchVersion); + " and the reported latest version is " + searchVersion);
if (searchPackage.versionCode < searchVersion) { if (searchPackage.versionCode < searchVersion) {
// New version available! Notify the user. // New version available! Notify the user.
newNotification(getString(R.string.update_search_newversion), newNotification(context.getString(R.string.update_search_newversion),
getString(R.string.update_search_newversion), context.getString(R.string.update_search_newversion),
getString(R.string.update_updateto, search[1].trim()), context.getString(R.string.update_updateto, search[1].trim()),
DOWNLOAD_URL_SEARCH + "?" + Integer.toString(random.nextInt()), 90001); DOWNLOAD_URL_SEARCH + "?" + Integer.toString(random.nextInt()), 90001);
} }
} catch (NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
// The search module isn't installed yet at all; ignore and wait for the user to manually // 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) // install it (when the first search is initiated)
} }
@ -145,18 +142,21 @@ public class AppUpdateService extends IntentService {
} catch (Exception e) { } catch (Exception e) {
// Cannot check right now for some reason; log and ignore // 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()); log.d(this, "Cannot retrieve latest app or search module version code from the site: " + e.toString());
return Job.Result.FAILURE;
} }
return Job.Result.SUCCESS;
} }
/** /**
* Retrieves the latest version number of the app or search module by checking an online text file that looks like * 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. * '160|1.1.15' for version code 160 and version name 1.1.15.
*
* @param httpclient An already instantiated HTTP client * @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 * @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 * @return A string array with two elements: the version code and the version number
* @throws ClientProtocolException Thrown when the provided URL is invalid * @throws ClientProtocolException Thrown when the provided URL is invalid
* @throws IOException Thrown when the last version information could not be retrieved * @throws IOException Thrown when the last version information could not be retrieved
*/ */
private String[] retrieveLatestVersion(AbstractHttpClient httpclient, String url) throws IOException { private String[] retrieveLatestVersion(AbstractHttpClient httpclient, String url) throws IOException {
HttpResponse request = httpclient.execute(new HttpGet(url)); HttpResponse request = httpclient.execute(new HttpGet(url));
@ -168,9 +168,9 @@ public class AppUpdateService extends IntentService {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void newNotification(String ticker, String title, String text, String downloadUrl, int notifyID) { private void newNotification(String ticker, String title, String text, String downloadUrl, int notifyID) {
PendingIntent pi = PendingIntent.getActivity(this, notifyID, PendingIntent pi = PendingIntent.getActivity(context, notifyID,
new Intent(Intent.ACTION_VIEW, Uri.parse(downloadUrl)), PendingIntent.FLAG_UPDATE_CURRENT); new Intent(Intent.ACTION_VIEW, Uri.parse(downloadUrl)), PendingIntent.FLAG_UPDATE_CURRENT);
Builder builder = new Notification.Builder(this).setSmallIcon(R.drawable.ic_stat_notification) Notification.Builder builder = new Notification.Builder(context).setSmallIcon(R.drawable.ic_stat_notification)
.setTicker(ticker).setContentTitle(title).setContentText(text) .setTicker(ticker).setContentTitle(title).setContentText(text)
.setLights(notificationSettings.getDesiredLedColour(), 600, 1000) .setLights(notificationSettings.getDesiredLedColour(), 600, 1000)
.setSound(notificationSettings.getSound()).setAutoCancel(true).setContentIntent(pi); .setSound(notificationSettings.getSound()).setAutoCancel(true).setContentIntent(pi);

91
app/src/main/java/org/transdroid/core/service/BootReceiver.java

@ -1,113 +1,40 @@
/* /*
* Copyright 2010-2013 Eric Kok et al. * Copyright 2010-2013 Eric Kok et al.
* *
* Transdroid is free software: you can redistribute it and/or modify * Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Transdroid is distributed in the hope that it will be useful, * Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>. * along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.transdroid.core.service; package org.transdroid.core.service;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.SystemClock;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EReceiver; import org.androidannotations.annotations.EReceiver;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.gui.log.*;
import org.transdroid.core.gui.navigation.*;
/** /**
* Receives the intent that the device has been started in order to set up proper alarms for all background services. * Receives the intent that the device has been started in order to set up proper alarms for all background services.
*
* @author Eric Kok * @author Eric Kok
*/ */
@EReceiver @EReceiver
public class BootReceiver extends BroadcastReceiver { 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;
@Bean
protected Log log;
public static void startBackgroundServices(Context context, boolean forceReload) {
NotificationSettings notificationSettings = NotificationSettings_.getInstance_(context);
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// Start the alarms if one of the notifications are enabled and we do not yet have the alarms running
// (or should reload it forcefully)
if ((notificationSettings.isEnabledForRss() || notificationSettings.isEnabledForTorrents()) &&
(forceReload || (piServerChecker == null && piRssChecker == null))) {
Log_.getInstance_(context)
.d("BootReceiver", "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 (NavigationHelper_.getInstance_(context).enableUpdateChecker() && systemSettings.checkForUpdates() &&
piAppUpdates == null) {
Log_.getInstance_(context).d("BootReceiver", "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;
}
}
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
startBackgroundServices(context, false); // Ensure user-requested background jobs are scheduled
startAppUpdatesService(context); ServerCheckerJob.schedule(context);
RssCheckerJob.schedule(context);
AppUpdateJob.schedule(context);
} }
} }

61
app/src/main/java/org/transdroid/core/service/RssCheckerJob.java

@ -0,0 +1,61 @@
/*
* Copyright 2010-2013 Eric Kok et al.
*
* Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/
package org.transdroid.core.service;
import android.content.Context;
import android.support.annotation.NonNull;
import com.evernote.android.job.Job;
import com.evernote.android.job.JobManager;
import com.evernote.android.job.JobRequest;
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 org.transdroid.core.gui.navigation.NavigationHelper_;
import java.util.concurrent.TimeUnit;
public class RssCheckerJob extends Job {
static final String TAG = "rss_checker";
private static Integer scheduledJobId;
public static void schedule(Context context) {
NotificationSettings notificationSettings = NotificationSettings_.getInstance_(context);
if (notificationSettings.isEnabledForRss()) {
Log_.getInstance_(context).d(TAG, "Schedule rss checker job");
scheduledJobId = new JobRequest.Builder(RssCheckerJob.TAG)
.setPeriodic(notificationSettings.getInvervalInMilliseconds())
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setUpdateCurrent(true)
.build()
.schedule();
} else if (scheduledJobId != null) {
Log_.getInstance_(context).d(TAG, "Cancel rss checker job");
JobManager.instance().cancel(scheduledJobId);
}
}
@NonNull
@Override
protected Result onRunJob(@NonNull Params params) {
return RssCheckerJobRunner_.getInstance_(getContext()).run();
}
}

70
app/src/main/java/org/transdroid/core/service/RssCheckerService.java → app/src/main/java/org/transdroid/core/service/RssCheckerJobRunner.java

@ -1,51 +1,50 @@
/* /*
* Copyright 2010-2013 Eric Kok et al. * Copyright 2010-2013 Eric Kok et al.
* *
* Transdroid is free software: you can redistribute it and/or modify * Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Transdroid is distributed in the hope that it will be useful, * Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>. * along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.transdroid.core.service; package org.transdroid.core.service;
import android.app.IntentService;
import android.app.Notification; import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import com.evernote.android.job.Job;
import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EService; import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.androidannotations.annotations.SystemService; import org.androidannotations.annotations.SystemService;
import org.transdroid.R; import org.transdroid.R;
import org.transdroid.core.app.settings.ApplicationSettings; import org.transdroid.core.app.settings.ApplicationSettings;
import org.transdroid.core.app.settings.NotificationSettings; import org.transdroid.core.app.settings.NotificationSettings;
import org.transdroid.core.app.settings.RssfeedSetting; import org.transdroid.core.app.settings.RssfeedSetting;
import org.transdroid.core.gui.log.Log; import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.rss.*; import org.transdroid.core.gui.rss.RssfeedsActivity_;
import org.transdroid.core.rssparser.Item; import org.transdroid.core.rssparser.Item;
import org.transdroid.core.rssparser.RssParser; import org.transdroid.core.rssparser.RssParser;
import org.transdroid.daemon.util.Collections2; import org.transdroid.daemon.util.Collections2;
import java.util.Date;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
/** @EBean
* A background service that checks all user-configured RSS feeds for new items. public class RssCheckerJobRunner {
* @author Eric Kok
*/
@EService
public class RssCheckerService extends IntentService {
@RootContext
protected Context context;
@Bean @Bean
protected Log log; protected Log log;
@Bean @Bean
@ -57,23 +56,17 @@ public class RssCheckerService extends IntentService {
@SystemService @SystemService
protected NotificationManager notificationManager; protected NotificationManager notificationManager;
public RssCheckerService() { Job.Result run() {
super("RssCheckerService");
}
@SuppressWarnings("deprecation")
@Override
protected void onHandleIntent(Intent intent) {
if (!connectivityHelper.shouldPerformBackgroundActions() || !notificationSettings.isEnabledForRss()) { if (!connectivityHelper.shouldPerformBackgroundActions() || !notificationSettings.isEnabledForRss()) {
log.d(this, log.d(this,
"Skip the RSS checker service, as background data is disabled, the service is disabled or we are not connected."); "Skip the RSS checker service, as background data is disabled, the service is disabled or we are not connected.");
return; return Job.Result.RESCHEDULE;
} }
// Check every RSS feed for new items // Check every RSS feed for new items
int unread = 0; int unread = 0;
Set<String> hasUnread = new LinkedHashSet<String>(); Set<String> hasUnread = new LinkedHashSet<>();
for (RssfeedSetting feed : applicationSettings.getRssfeedSettings()) { for (RssfeedSetting feed : applicationSettings.getRssfeedSettings()) {
try { try {
@ -90,14 +83,24 @@ public class RssCheckerService extends IntentService {
} }
// Find the last item that is newer than the last viewed date // Find the last item that is newer than the last viewed date
boolean usePublishDate = false;
if (parser.getChannel().getItems().size() > 0) {
Date pubDate = parser.getChannel().getItems().get(0).getPubdate();
usePublishDate = pubDate != null && pubDate.getTime() > 0;
}
for (Item item : parser.getChannel().getItems()) { for (Item item : parser.getChannel().getItems()) {
if (item.getPubdate() != null && item.getPubdate().before(feed.getLastViewed())) { if (usePublishDate
&& item.getPubdate() != null
&& item.getPubdate().before(feed.getLastViewed())) {
break;
} else if (!usePublishDate
&& item.getTheLink() != null
&& feed.getLastViewedItemUrl() != null
&& item.getTheLink().equals(feed.getLastViewedItemUrl())) {
break; break;
} else { } else {
unread++; unread++;
if (!hasUnread.contains(feed.getName())) { hasUnread.add(feed.getName());
hasUnread.add(feed.getName());
}
} }
} }
@ -111,16 +114,16 @@ public class RssCheckerService extends IntentService {
if (unread == 0) { if (unread == 0) {
// No new items; just exit // No new items; just exit
return; return Job.Result.SUCCESS;
} }
// Provide a notification, since there are new RSS items // Provide a notification, since there are new RSS items
PendingIntent pi = PendingIntent PendingIntent pi = PendingIntent
.getActivity(this, 80000, new Intent(this, RssfeedsActivity_.class), PendingIntent.FLAG_UPDATE_CURRENT); .getActivity(context, 80000, new Intent(context, RssfeedsActivity_.class), PendingIntent.FLAG_UPDATE_CURRENT);
String title = getResources().getQuantityString(R.plurals.rss_service_new, unread, Integer.toString(unread)); String title = context.getResources().getQuantityString(R.plurals.rss_service_new, unread, Integer.toString(unread));
String forString = Collections2.joinString(hasUnread, ", "); String forString = Collections2.joinString(hasUnread, ", ");
Builder builder = new Notification.Builder(this).setSmallIcon(R.drawable.ic_stat_notification).setTicker(title) Notification.Builder builder = new Notification.Builder(context).setSmallIcon(R.drawable.ic_stat_notification).setTicker(title)
.setContentTitle(title).setContentText(getString(R.string.rss_service_newfor, forString)) .setContentTitle(title).setContentText(context.getString(R.string.rss_service_newfor, forString))
.setNumber(unread).setLights(notificationSettings.getDesiredLedColour(), 600, 1000) .setNumber(unread).setLights(notificationSettings.getDesiredLedColour(), 600, 1000)
.setSound(notificationSettings.getSound()).setAutoCancel(true).setContentIntent(pi); .setSound(notificationSettings.getSound()).setAutoCancel(true).setContentIntent(pi);
if (notificationSettings.shouldVibrate()) { if (notificationSettings.shouldVibrate()) {
@ -128,6 +131,7 @@ public class RssCheckerService extends IntentService {
} }
notificationManager.notify(80001, builder.getNotification()); notificationManager.notify(80001, builder.getNotification());
return Job.Result.SUCCESS;
} }
} }

41
app/src/main/java/org/transdroid/core/service/ScheduledJobCreator.java

@ -0,0 +1,41 @@
/*
* Copyright 2010-2013 Eric Kok et al.
*
* Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/
package org.transdroid.core.service;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.evernote.android.job.Job;
import com.evernote.android.job.JobCreator;
public class ScheduledJobCreator implements JobCreator {
@Nullable
@Override
public Job create(@NonNull String tag) {
switch (tag) {
case AppUpdateJob.TAG:
return new AppUpdateJob();
case RssCheckerJob.TAG:
return new RssCheckerJob();
case ServerCheckerJob.TAG:
return new ServerCheckerJob();
default:
return null;
}
}
}

56
app/src/main/java/org/transdroid/core/service/ServerCheckerJob.java

@ -0,0 +1,56 @@
/*
* Copyright 2010-2013 Eric Kok et al.
*
* Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/
package org.transdroid.core.service;
import android.content.Context;
import android.support.annotation.NonNull;
import com.evernote.android.job.Job;
import com.evernote.android.job.JobManager;
import com.evernote.android.job.JobRequest;
import org.transdroid.core.app.settings.NotificationSettings;
import org.transdroid.core.app.settings.NotificationSettings_;
import org.transdroid.core.gui.log.Log_;
public class ServerCheckerJob extends Job {
static final String TAG = "server_checker";
private static Integer scheduledJobId;
public static void schedule(Context context) {
NotificationSettings notificationSettings = NotificationSettings_.getInstance_(context);
if (notificationSettings.isEnabledForTorrents()) {
Log_.getInstance_(context).d(TAG, "Schedule server checker job");
scheduledJobId = new JobRequest.Builder(ServerCheckerJob.TAG)
.setPeriodic(notificationSettings.getInvervalInMilliseconds())
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setUpdateCurrent(true)
.build()
.schedule();
} else if (scheduledJobId != null) {
Log_.getInstance_(context).d(TAG, "Cancel server checker job");
JobManager.instance().cancel(scheduledJobId);
}
}
@NonNull
@Override
protected Result onRunJob(@NonNull Params params) {
return ServerCheckerJobRunner_.getInstance_(getContext()).run();
}
}

85
app/src/main/java/org/transdroid/core/service/ServerCheckerService.java → app/src/main/java/org/transdroid/core/service/ServerCheckerJobRunner.java

@ -1,26 +1,31 @@
/* /*
* Copyright 2010-2013 Eric Kok et al. * Copyright 2010-2013 Eric Kok et al.
* *
* Transdroid is free software: you can redistribute it and/or modify * Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Transdroid is distributed in the hope that it will be useful, * Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>. * along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.transdroid.core.service; package org.transdroid.core.service;
import java.util.ArrayList; import android.app.Notification;
import java.util.List; import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import com.evernote.android.job.Job;
import org.androidannotations.annotations.Bean; import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EService; import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.androidannotations.annotations.SystemService; import org.androidannotations.annotations.SystemService;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -29,7 +34,7 @@ import org.transdroid.R;
import org.transdroid.core.app.settings.ApplicationSettings; import org.transdroid.core.app.settings.ApplicationSettings;
import org.transdroid.core.app.settings.NotificationSettings; import org.transdroid.core.app.settings.NotificationSettings;
import org.transdroid.core.app.settings.ServerSetting; import org.transdroid.core.app.settings.ServerSetting;
import org.transdroid.core.gui.*; import org.transdroid.core.gui.TorrentsActivity_;
import org.transdroid.core.gui.log.Log; import org.transdroid.core.gui.log.Log;
import org.transdroid.daemon.IDaemonAdapter; import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.Torrent; import org.transdroid.daemon.Torrent;
@ -37,24 +42,14 @@ import org.transdroid.daemon.task.DaemonTaskResult;
import org.transdroid.daemon.task.RetrieveTask; import org.transdroid.daemon.task.RetrieveTask;
import org.transdroid.daemon.task.RetrieveTaskSuccessResult; import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
import android.annotation.TargetApi; import java.util.ArrayList;
import android.app.IntentService; import java.util.List;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.Notification.InboxStyle;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Build;
import android.text.TextUtils;
/** @EBean
* A background service that checks all user-configured servers (if so desired) for new and finished torrents. public class ServerCheckerJobRunner {
* @author Eric Kok
*/
@EService
public class ServerCheckerService extends IntentService {
@RootContext
protected Context context;
@Bean @Bean
protected Log log; protected Log log;
@Bean @Bean
@ -66,19 +61,12 @@ public class ServerCheckerService extends IntentService {
@SystemService @SystemService
protected NotificationManager notificationManager; protected NotificationManager notificationManager;
public ServerCheckerService() { Job.Result run() {
super("ServerCheckerService");
}
@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
protected void onHandleIntent(Intent intent) {
if (!connectivityHelper.shouldPerformBackgroundActions() || !notificationSettings.isEnabledForTorrents()) { if (!connectivityHelper.shouldPerformBackgroundActions() || !notificationSettings.isEnabledForTorrents()) {
log.d(this, log.d(this,
"Skip the server checker service, as background data is disabled, the service is disabled or we are not connected."); "Skip the server checker service, as background data is disabled, the service is disabled or we are not connected.");
return; return Job.Result.RESCHEDULE;
} }
int notifyBase = 10000; int notifyBase = 10000;
@ -94,7 +82,7 @@ public class ServerCheckerService extends IntentService {
JSONArray lastStats = applicationSettings.getServerLastStats(server); JSONArray lastStats = applicationSettings.getServerLastStats(server);
// Synchronously retrieve torrents listing // Synchronously retrieve torrents listing
IDaemonAdapter adapter = server.createServerAdapter(connectivityHelper.getConnectedNetworkName(), this); IDaemonAdapter adapter = server.createServerAdapter(connectivityHelper.getConnectedNetworkName(), context);
DaemonTaskResult result = RetrieveTask.create(adapter).execute(log); DaemonTaskResult result = RetrieveTask.create(adapter).execute(log);
if (!(result instanceof RetrieveTaskSuccessResult)) { if (!(result instanceof RetrieveTaskSuccessResult)) {
// Cannot retrieve torrents at this time // Cannot retrieve torrents at this time
@ -132,7 +120,7 @@ public class ServerCheckerService extends IntentService {
} catch (JSONException e) { } catch (JSONException e) {
// Can't build the JSON object; this should not happen and we can safely ignore it // 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 // See if this torrent was done the last time we checked
if (lastStats != null) { if (lastStats != null) {
Boolean wasDone = findLastDoneStat(lastStats, torrent); Boolean wasDone = findLastDoneStat(lastStats, torrent);
@ -146,7 +134,7 @@ public class ServerCheckerService extends IntentService {
// This torrent is now done, but wasn't before // This torrent is now done, but wasn't before
doneTorrents.add(torrent); doneTorrents.add(torrent);
} }
} }
// Store the now-current statistics on torrents for the next time we check this server // Store the now-current statistics on torrents for the next time we check this server
@ -155,26 +143,26 @@ public class ServerCheckerService extends IntentService {
// Notify on new and now-done torrents for this server // Notify on new and now-done torrents for this server
log.d(this, server.getName() + ": " + newTorrents.size() + " new torrents, " + doneTorrents.size() log.d(this, server.getName() + ": " + newTorrents.size() + " new torrents, " + doneTorrents.size()
+ " newly finished torrents."); + " newly finished torrents.");
Intent i = new Intent(this, TorrentsActivity_.class); Intent i = new Intent(context, TorrentsActivity_.class);
i.putExtra("org.transdroid.START_SERVER", server.getOrder()); i.putExtra("org.transdroid.START_SERVER", server.getOrder());
// Should start the main activity directly into this server // Should start the main activity directly into this server
PendingIntent pi = PendingIntent.getActivity(this, notifyBase + server.getOrder(), i, PendingIntent pi = PendingIntent.getActivity(context, notifyBase + server.getOrder(), i,
Intent.FLAG_ACTIVITY_NEW_TASK); PendingIntent.FLAG_CANCEL_CURRENT);
ArrayList<Torrent> affectedTorrents = new ArrayList<>(newTorrents.size() + doneTorrents.size()); ArrayList<Torrent> affectedTorrents = new ArrayList<>(newTorrents.size() + doneTorrents.size());
affectedTorrents.addAll(newTorrents); affectedTorrents.addAll(newTorrents);
affectedTorrents.addAll(doneTorrents); affectedTorrents.addAll(doneTorrents);
String title; String title;
if (newTorrents.size() > 0 && doneTorrents.size() > 0) { if (newTorrents.size() > 0 && doneTorrents.size() > 0) {
// Note: use the 'one' plural iif 1 new torrent was added and 1 was newly finished // Note: use the 'one' plural iif 1 new torrent was added and 1 was newly finished
title = getResources().getQuantityString(R.plurals.status_service_finished, title = context.getResources().getQuantityString(R.plurals.status_service_finished,
newTorrents.size() + doneTorrents.size() == 2 ? 1 : 2, Integer.toString(newTorrents.size()), newTorrents.size() + doneTorrents.size() == 2 ? 1 : 2, Integer.toString(newTorrents.size()),
Integer.toString(doneTorrents.size())); Integer.toString(doneTorrents.size()));
} else if (newTorrents.size() > 0) { } else if (newTorrents.size() > 0) {
title = getResources().getQuantityString(R.plurals.status_service_added, newTorrents.size(), title = context.getResources().getQuantityString(R.plurals.status_service_added, newTorrents.size(),
Integer.toString(newTorrents.size())); Integer.toString(newTorrents.size()));
} else if (doneTorrents.size() > 0) { } else if (doneTorrents.size() > 0) {
title = getResources().getQuantityString(R.plurals.status_service_finished, doneTorrents.size(), title = context.getResources().getQuantityString(R.plurals.status_service_finished, doneTorrents.size(),
Integer.toString(doneTorrents.size())); Integer.toString(doneTorrents.size()));
} else { } else {
// No notification to show // No notification to show
@ -185,9 +173,9 @@ public class ServerCheckerService extends IntentService {
forString += affected.getName() + ", "; forString += affected.getName() + ", ";
} }
forString = forString.substring(0, forString.length() - 2); forString = forString.substring(0, forString.length() - 2);
// Build the basic notification // Build the basic notification
Builder builder = new Notification.Builder(this).setSmallIcon(R.drawable.ic_stat_notification) Notification.Builder builder = new Notification.Builder(context).setSmallIcon(R.drawable.ic_stat_notification)
.setTicker(title).setContentTitle(title).setContentText(forString) .setTicker(title).setContentTitle(title).setContentText(forString)
.setNumber(affectedTorrents.size()) .setNumber(affectedTorrents.size())
.setLights(notificationSettings.getDesiredLedColour(), 600, 1000) .setLights(notificationSettings.getDesiredLedColour(), 600, 1000)
@ -198,7 +186,7 @@ public class ServerCheckerService extends IntentService {
// Add at most 5 lines with the affected torrents // Add at most 5 lines with the affected torrents
Notification notification; Notification notification;
if (android.os.Build.VERSION.SDK_INT >= 16) { if (android.os.Build.VERSION.SDK_INT >= 16) {
InboxStyle inbox = new Notification.InboxStyle(builder); Notification.InboxStyle inbox = new Notification.InboxStyle(builder);
if (affectedTorrents.size() < 6) { if (affectedTorrents.size() < 6) {
for (Torrent affectedTorrent : affectedTorrents) { for (Torrent affectedTorrent : affectedTorrents) {
inbox.addLine(affectedTorrent.getName()); inbox.addLine(affectedTorrent.getName());
@ -207,7 +195,7 @@ public class ServerCheckerService extends IntentService {
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
inbox.addLine(affectedTorrents.get(j).getName()); inbox.addLine(affectedTorrents.get(j).getName());
} }
inbox.addLine(getString(R.string.status_service_andothers, affectedTorrents.get(5).getName())); inbox.addLine(context.getString(R.string.status_service_andothers, affectedTorrents.get(5).getName()));
} }
notification = inbox.build(); notification = inbox.build();
} else { } else {
@ -217,6 +205,7 @@ public class ServerCheckerService extends IntentService {
} }
return Job.Result.SUCCESS;
} }
private Boolean findLastDoneStat(JSONArray lastStats, Torrent torrent) { private Boolean findLastDoneStat(JSONArray lastStats, Torrent torrent) {

3
app/src/main/res/values-bg/strings.xml

@ -223,8 +223,7 @@
<string name="pref_seedbox_xirvikhint3">Като desharedgbit001.xirvik.com</string> <string name="pref_seedbox_xirvikhint3">Като desharedgbit001.xirvik.com</string>
<string name="pref_seedbox_seedstuffhint">Като 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Като 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 минута</item> <item>15 минути</item>
<item>10 минути</item>
<item>30 минути</item> <item>30 минути</item>
<item>1 час</item> <item>1 час</item>
<item>3 часа</item> <item>3 часа</item>

3
app/src/main/res/values-cs/strings.xml

@ -287,8 +287,7 @@
<string name="pref_seedbox_xirviknofolder">Nelze načíst nastavení složky Xirvik SCGI; opakujte akci později nebo zkontrolujte nastavení adresy vašeho serveru</string> <string name="pref_seedbox_xirviknofolder">Nelze načíst nastavení složky Xirvik SCGI; opakujte akci později nebo zkontrolujte nastavení adresy vašeho serveru</string>
<string name="pref_seedbox_seedstuffhint">Např.: Like 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Např.: Like 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minuta</item> <item>15 minut</item>
<item>10 minut</item>
<item>30 minut</item> <item>30 minut</item>
<item>1 hodina</item> <item>1 hodina</item>
<item>3 hodiny</item> <item>3 hodiny</item>

3
app/src/main/res/values-da/strings.xml

@ -303,8 +303,7 @@
<string name="pref_seedbox_xirviknofolder">Kan ikke hente indstillingen for Xirvik SCGI; Prøv igen senere, eller ret din server adresseindstilling</string> <string name="pref_seedbox_xirviknofolder">Kan ikke hente indstillingen for Xirvik SCGI; Prøv igen senere, eller ret din server adresseindstilling</string>
<string name="pref_seedbox_seedstuffhint">Eks. 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Eks. 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minut</item> <item>15 minutter</item>
<item>10 minutter</item>
<item>30 minutter</item> <item>30 minutter</item>
<item>1 time</item> <item>1 time</item>
<item>3 timer</item> <item>3 timer</item>

3
app/src/main/res/values-de/strings.xml

@ -319,8 +319,7 @@
<string name="pref_seedbox_xirviknofolder">Die Xirvik SCGI-Ordner-Einstellung kann nicht abgerufen werden; Bitte versuchen Sie es später erneut, oder korrigieren Sie ihre Serveradresse</string> <string name="pref_seedbox_xirviknofolder">Die Xirvik SCGI-Ordner-Einstellung kann nicht abgerufen werden; Bitte versuchen Sie es später erneut, oder korrigieren Sie ihre Serveradresse</string>
<string name="pref_seedbox_seedstuffhint">Like 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Like 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 Minute</item> <item>15 Minuten</item>
<item>10 Minuten</item>
<item>30 Minuten</item> <item>30 Minuten</item>
<item>1 Stunde</item> <item>1 Stunde</item>
<item>3 Stunden</item> <item>3 Stunden</item>

3
app/src/main/res/values-es/strings.xml

@ -258,8 +258,7 @@
<string name="pref_seedbox_client_info">Cliente a conectarse</string> <string name="pref_seedbox_client_info">Cliente a conectarse</string>
<string name="pref_seedbox_server">Dirección del servidor</string> <string name="pref_seedbox_server">Dirección del servidor</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minuto</item> <item>15 minutos</item>
<item>10 minutos</item>
<item>30 minutos</item> <item>30 minutos</item>
<item>1 hora</item> <item>1 hora</item>
<item>3 horas</item> <item>3 horas</item>

3
app/src/main/res/values-et/strings.xml

@ -186,8 +186,7 @@
<string name="pref_seedbox_xirvikhint3">Nagu desharedgbit001.xirvik.com</string> <string name="pref_seedbox_xirvikhint3">Nagu desharedgbit001.xirvik.com</string>
<string name="pref_seedbox_seedstuffhint">Nagu 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Nagu 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minut</item> <item>15 minutit</item>
<item>10 minutit</item>
<item>30 minutit</item> <item>30 minutit</item>
<item>1 tund</item> <item>1 tund</item>
<item>3 tundi</item> <item>3 tundi</item>

3
app/src/main/res/values-fa/strings.xml

@ -308,8 +308,7 @@
<string name="pref_seedbox_xirviknofolder">نمیتوان تنظیمات پوشهی SCGIی Xirvik را دریافت کرد؛ لطفا ً بعدا ً دوباره امتحان کنید یا تنظیمات نشانی کارگزار را درست کنید</string> <string name="pref_seedbox_xirviknofolder">نمیتوان تنظیمات پوشهی SCGIی Xirvik را دریافت کرد؛ لطفا ً بعدا ً دوباره امتحان کنید یا تنظیمات نشانی کارگزار را درست کنید</string>
<string name="pref_seedbox_seedstuffhint">مانند 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">مانند 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 دقیقه </item> <item> 15 دقیقه </item>
<item> 10 دقیقه </item>
<item> 30 دقیقه </item> <item> 30 دقیقه </item>
<item> 1 ساعت </item> <item> 1 ساعت </item>
<item> 3 ساعت </item> <item> 3 ساعت </item>

3
app/src/main/res/values-fi/strings.xml

@ -144,8 +144,7 @@
<string name="pref_seedbox_xirvikhint3">Kuten desharedgbit001.xirvik.com</string> <string name="pref_seedbox_xirvikhint3">Kuten desharedgbit001.xirvik.com</string>
<string name="pref_seedbox_seedstuffhint">Kuten 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Kuten 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minuutti</item> <item>15 minuuttia</item>
<item>10 minuuttia</item>
<item>30 minuuttia</item> <item>30 minuuttia</item>
<item>1 tunti</item> <item>1 tunti</item>
<item>3 tuntia</item> <item>3 tuntia</item>

3
app/src/main/res/values-fr/strings.xml

@ -303,8 +303,7 @@
<string name="pref_seedbox_xirviknofolder">Impossible de récupérer le paramètre dossier de Xirvik SCGI ; Veuillez réessayer ultérieurement ou corriger le réglage d\'adresse de votre serveur</string> <string name="pref_seedbox_xirviknofolder">Impossible de récupérer le paramètre dossier de Xirvik SCGI ; Veuillez réessayer ultérieurement ou corriger le réglage d\'adresse de votre serveur</string>
<string name="pref_seedbox_seedstuffhint">Comme 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Comme 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minute</item> <item>15 minutes</item>
<item>10 minutes</item>
<item>30 minutes</item> <item>30 minutes</item>
<item>1 heure</item> <item>1 heure</item>
<item>3 heures</item> <item>3 heures</item>

3
app/src/main/res/values-he/strings.xml

@ -257,8 +257,7 @@
<string name="pref_seedbox_xirvikhint3">לדוגמא: desharedgbit001.xirvik.com</string> <string name="pref_seedbox_xirvikhint3">לדוגמא: desharedgbit001.xirvik.com</string>
<string name="pref_seedbox_seedstuffhint">לדוגמא: 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">לדוגמא: 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>דקה</item> <item>15 דקות</item>
<item>10 דקות</item>
<item>חצי שעה</item> <item>חצי שעה</item>
<item>שעה</item> <item>שעה</item>
<item>3 שעות</item> <item>3 שעות</item>

3
app/src/main/res/values-hu/strings.xml

@ -319,8 +319,7 @@
<string name="pref_seedbox_xirviknofolder">Nem lehet letölteni a Xirvik SCGI mappa beállításait; próbálja meg újra később, vagy javítsa ki a szerver címének beállításait</string> <string name="pref_seedbox_xirviknofolder">Nem lehet letölteni a Xirvik SCGI mappa beállításait; próbálja meg újra később, vagy javítsa ki a szerver címének beállításait</string>
<string name="pref_seedbox_seedstuffhint">Például 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Például 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 perc</item> <item>15 perc</item>
<item>10 perc</item>
<item>30 perc</item> <item>30 perc</item>
<item>1 óra</item> <item>1 óra</item>
<item>3 óra</item> <item>3 óra</item>

3
app/src/main/res/values-it/strings.xml

@ -319,8 +319,7 @@
<string name="pref_seedbox_xirviknofolder">Impossibile recuperare la cartella Xirvik SCGI; riprovare più tardi o correggere l\'indirizzo del server</string> <string name="pref_seedbox_xirviknofolder">Impossibile recuperare la cartella Xirvik SCGI; riprovare più tardi o correggere l\'indirizzo del server</string>
<string name="pref_seedbox_seedstuffhint">Esempio: 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Esempio: 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minuto</item> <item>15 minuto</item>
<item>10 minuto</item>
<item>30 minuto</item> <item>30 minuto</item>
<item>1 ora</item> <item>1 ora</item>
<item>3 ore</item> <item>3 ore</item>

3
app/src/main/res/values-ja/strings.xml

@ -311,8 +311,7 @@
<string name="pref_seedbox_xirviknofolder">Xirvik SCGI フォルダー設定を読み取りできません。後で再度実行するか、サーバー・アドレス設定を確認してください</string> <string name="pref_seedbox_xirviknofolder">Xirvik SCGI フォルダー設定を読み取りできません。後で再度実行するか、サーバー・アドレス設定を確認してください</string>
<string name="pref_seedbox_seedstuffhint">001.seedstuff.ca のように</string> <string name="pref_seedbox_seedstuffhint">001.seedstuff.ca のように</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 分</item> <item>15 分</item>
<item>10 分</item>
<item>30 分</item> <item>30 分</item>
<item>1 時間</item> <item>1 時間</item>
<item>3 時間</item> <item>3 時間</item>

3
app/src/main/res/values-ko/strings.xml

@ -311,8 +311,7 @@
<string name="pref_seedbox_xirviknofolder">Xirvik SCGI 폴더 설정을 받아오지 못했습니다; 다음에 다시 시도해 보시거나 서버 주소 설정을 고쳐보세요</string> <string name="pref_seedbox_xirviknofolder">Xirvik SCGI 폴더 설정을 받아오지 못했습니다; 다음에 다시 시도해 보시거나 서버 주소 설정을 고쳐보세요</string>
<string name="pref_seedbox_seedstuffhint">예) 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">예) 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1분</item> <item>15분</item>
<item>10분</item>
<item>30분</item> <item>30분</item>
<item>1시간</item> <item>1시간</item>
<item>3시간</item> <item>3시간</item>

3
app/src/main/res/values-nl/strings.xml

@ -315,8 +315,7 @@
<string name="pref_seedbox_xirviknofolder">Kan de Xirvik SCGI mount instelling niet laden; probeer later nog eens en controleer je serveradres</string> <string name="pref_seedbox_xirviknofolder">Kan de Xirvik SCGI mount instelling niet laden; probeer later nog eens en controleer je serveradres</string>
<string name="pref_seedbox_seedstuffhint">Zoals 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Zoals 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minuut</item> <item>15 minuten</item>
<item>10 minuten</item>
<item>30 minuten</item> <item>30 minuten</item>
<item>1 uur</item> <item>1 uur</item>
<item>3 uur</item> <item>3 uur</item>

3
app/src/main/res/values-pl/strings.xml

@ -284,8 +284,7 @@
<string name="pref_seedbox_xirvikhint3">Jak desharedgbit001.xirvik.com</string> <string name="pref_seedbox_xirvikhint3">Jak desharedgbit001.xirvik.com</string>
<string name="pref_seedbox_seedstuffhint">Jak 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Jak 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minuta</item> <item>15 minut</item>
<item>10 minut</item>
<item>30 minut</item> <item>30 minut</item>
<item>1 godzina</item> <item>1 godzina</item>
<item>3 godziny</item> <item>3 godziny</item>

3
app/src/main/res/values-pt-rBR/strings.xml

@ -319,8 +319,7 @@
<string name="pref_seedbox_xirviknofolder">Não foi possível recuperar a pasta de configuração do Xirvik SCGI; por favor, tente novamente mais tarde ou corrija a configuração de endereço do servidor</string> <string name="pref_seedbox_xirviknofolder">Não foi possível recuperar a pasta de configuração do Xirvik SCGI; por favor, tente novamente mais tarde ou corrija a configuração de endereço do servidor</string>
<string name="pref_seedbox_seedstuffhint">Como 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Como 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minuto</item> <item>15 minutos</item>
<item>10 minutos</item>
<item>30 minutos</item> <item>30 minutos</item>
<item>1 hora</item> <item>1 hora</item>
<item>3 horas</item> <item>3 horas</item>

3
app/src/main/res/values-pt/strings.xml

@ -319,8 +319,7 @@
<string name="pref_seedbox_xirviknofolder">Não é possível obter a configuração de pasta Xirvik SCGI; por favor, tente novamente mais tarde ou corrija a sua configuração de endereço do servidor</string> <string name="pref_seedbox_xirviknofolder">Não é possível obter a configuração de pasta Xirvik SCGI; por favor, tente novamente mais tarde ou corrija a sua configuração de endereço do servidor</string>
<string name="pref_seedbox_seedstuffhint">Por ex. 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Por ex. 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minuto</item> <item>15 minutos</item>
<item>10 minutos</item>
<item>30 minutos</item> <item>30 minutos</item>
<item>1 hora</item> <item>1 hora</item>
<item>3 horas</item> <item>3 horas</item>

3
app/src/main/res/values-ru/strings.xml

@ -327,8 +327,7 @@
<string name="pref_seedbox_xirviknofolder">Не удается получить настройки папок Xirvik SCGI. Пожалуйста, повторите попытку позже или измените адрес сервера.</string> <string name="pref_seedbox_xirviknofolder">Не удается получить настройки папок Xirvik SCGI. Пожалуйста, повторите попытку позже или измените адрес сервера.</string>
<string name="pref_seedbox_seedstuffhint">Как 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Как 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 минута</item> <item>15 минут</item>
<item>10 минут</item>
<item>30 минут</item> <item>30 минут</item>
<item>1 час</item> <item>1 час</item>
<item>3 часа</item> <item>3 часа</item>

3
app/src/main/res/values-sl/strings.xml

@ -335,8 +335,7 @@
<string name="pref_seedbox_xirviknofolder">Ne morem pridobiti Xirvik SCGI nastavitev map; poskusite pozneje ali popravite naslov strežnika</string> <string name="pref_seedbox_xirviknofolder">Ne morem pridobiti Xirvik SCGI nastavitev map; poskusite pozneje ali popravite naslov strežnika</string>
<string name="pref_seedbox_seedstuffhint">Npr. 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Npr. 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minuta</item> <item>15 minut</item>
<item>10 minut</item>
<item>30 minut</item> <item>30 minut</item>
<item>1 ura</item> <item>1 ura</item>
<item>3 ure</item> <item>3 ure</item>

3
app/src/main/res/values-sv/strings.xml

@ -319,8 +319,7 @@
<string name="pref_seedbox_xirviknofolder">Går inte att hämta Xirvik SCGI mappinställningen. Försök igen senare eller korrigera din serveradress</string> <string name="pref_seedbox_xirviknofolder">Går inte att hämta Xirvik SCGI mappinställningen. Försök igen senare eller korrigera din serveradress</string>
<string name="pref_seedbox_seedstuffhint">Som 001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">Som 001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minut</item> <item>15 minuter</item>
<item>10 minuter</item>
<item>30 minuter</item> <item>30 minuter</item>
<item>1 timme</item> <item>1 timme</item>
<item>3 timmar</item> <item>3 timmar</item>

3
app/src/main/res/values-tr/strings.xml

@ -318,8 +318,7 @@
<string name="pref_seedbox_xirviknofolder">Xirvik SCGI klasör ayarı alınamıyor; Lütfen daha sonra yeniden deneyin veya sunucu adresi ayarını doğrulayın</string> <string name="pref_seedbox_xirviknofolder">Xirvik SCGI klasör ayarı alınamıyor; Lütfen daha sonra yeniden deneyin veya sunucu adresi ayarını doğrulayın</string>
<string name="pref_seedbox_seedstuffhint">001.seedstuff.CA gibi</string> <string name="pref_seedbox_seedstuffhint">001.seedstuff.CA gibi</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 dakika</item> <item>15 dakika</item>
<item>10 dakika</item>
<item>30 dakika</item> <item>30 dakika</item>
<item>1 saat</item> <item>1 saat</item>
<item>3 saat</item> <item>3 saat</item>

3
app/src/main/res/values-uk/strings.xml

@ -158,8 +158,7 @@
<string name="pref_export">Експортувати налаштування</string> <string name="pref_export">Експортувати налаштування</string>
<string name="pref_export_success">Налаштування вдало експортовано</string> <string name="pref_export_success">Налаштування вдало експортовано</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minute</item> <item>15 minutes</item>
<item>10 minutes</item>
<item>30 minutes</item> <item>30 minutes</item>
<item>1 hour</item> <item>1 hour</item>
<item>3 hours</item> <item>3 hours</item>

3
app/src/main/res/values-vi/strings.xml

@ -247,8 +247,7 @@
<string name="pref_seedbox_client">Trình điều khiển torrent</string> <string name="pref_seedbox_client">Trình điều khiển torrent</string>
<string name="pref_seedbox_server">Địa chỉ máy chủ</string> <string name="pref_seedbox_server">Địa chỉ máy chủ</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 phút</item> <item>15 phút</item>
<item>10 phút</item>
<item>30 phút</item> <item>30 phút</item>
<item>1 giờ</item> <item>1 giờ</item>
<item>3 giờ</item> <item>3 giờ</item>

3
app/src/main/res/values-zh-rCN/strings.xml

@ -295,8 +295,7 @@
<string name="pref_seedbox_xirviknofolder">无法检索Xirvik SCGI的文件夹设置,请稍后再试或更正您的服务器地址</string> <string name="pref_seedbox_xirviknofolder">无法检索Xirvik SCGI的文件夹设置,请稍后再试或更正您的服务器地址</string>
<string name="pref_seedbox_seedstuffhint">例如:001.seedstuff.ca</string> <string name="pref_seedbox_seedstuffhint">例如:001.seedstuff.ca</string>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>每分钟</item> <item>每15分钟</item>
<item>每10分钟</item>
<item>每30分钟</item> <item>每30分钟</item>
<item>每小时</item> <item>每小时</item>
<item>每3小时</item> <item>每3小时</item>

3
app/src/main/res/values-zh-rHK/strings.xml

@ -153,8 +153,7 @@
<item>30 秒</item> <item>30 秒</item>
</string-array> </string-array>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 分鐘</item> <item>15 分鐘</item>
<item>10 分鐘</item>
<item>30 分鐘</item> <item>30 分鐘</item>
<item>1 小時</item> <item>1 小時</item>
<item>3 小時</item> <item>3 小時</item>

6
app/src/main/res/values/strings.xml

@ -428,8 +428,7 @@
<item>type_linux</item> <item>type_linux</item>
</string-array> </string-array>
<string-array name="pref_notifyinterval_types"> <string-array name="pref_notifyinterval_types">
<item>1 minute</item> <item>15 minutes</item>
<item>10 minutes</item>
<item>30 minutes</item> <item>30 minutes</item>
<item>1 hour</item> <item>1 hour</item>
<item>3 hours</item> <item>3 hours</item>
@ -437,8 +436,7 @@
<item>1 day</item> <item>1 day</item>
</string-array> </string-array>
<string-array name="pref_notifyinterval_values" translatable="false"> <string-array name="pref_notifyinterval_values" translatable="false">
<item>60</item> <item>900</item>
<item>600</item>
<item>1800</item> <item>1800</item>
<item>3600</item> <item>3600</item>
<item>10800</item> <item>10800</item>

2
build.gradle

@ -4,7 +4,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.0' classpath 'com.android.tools.build:gradle:3.2.1'
} }
} }

Loading…
Cancel
Save