diff --git a/oeffi/AndroidManifest.xml b/oeffi/AndroidManifest.xml
index a2e6313..a213549 100644
--- a/oeffi/AndroidManifest.xml
+++ b/oeffi/AndroidManifest.xml
@@ -248,6 +248,12 @@
+
+
+
+
+
+
diff --git a/oeffi/res/drawable-anydpi/ic_stat_notify_sync_24dp.xml b/oeffi/res/drawable-anydpi/ic_stat_notify_sync_24dp.xml
deleted file mode 100644
index 9e6222a..0000000
--- a/oeffi/res/drawable-anydpi/ic_stat_notify_sync_24dp.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/oeffi/res/xml/nearest_favorite_station_widget.xml b/oeffi/res/xml/nearest_favorite_station_widget.xml
index 157e072..98b8c3c 100644
--- a/oeffi/res/xml/nearest_favorite_station_widget.xml
+++ b/oeffi/res/xml/nearest_favorite_station_widget.xml
@@ -6,5 +6,4 @@
android:minResizeHeight="55dp"
android:minWidth="294dp"
android:previewImage="@drawable/nearest_favorite_station_widget_preview"
- android:resizeMode="horizontal|vertical"
- android:updatePeriodMillis="1800000" />
+ android:resizeMode="horizontal|vertical" />
diff --git a/oeffi/src/de/schildbach/oeffi/Application.java b/oeffi/src/de/schildbach/oeffi/Application.java
index a69fcab..9493840 100644
--- a/oeffi/src/de/schildbach/oeffi/Application.java
+++ b/oeffi/src/de/schildbach/oeffi/Application.java
@@ -17,13 +17,9 @@
package de.schildbach.oeffi;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Build;
import android.preference.PreferenceManager;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
@@ -35,7 +31,6 @@ import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
import com.google.common.base.Stopwatch;
import de.schildbach.oeffi.directions.QueryHistoryProvider;
import de.schildbach.oeffi.stations.FavoriteStationsProvider;
-import de.schildbach.oeffi.stations.NearestFavoriteStationWidgetService;
import de.schildbach.oeffi.util.ErrorReporter;
import de.schildbach.pte.NetworkId;
import okhttp3.OkHttpClient;
@@ -121,8 +116,6 @@ public class Application extends android.app.Application {
QueryHistoryProvider.deleteQueryHistory(this, SBB);
log.info("Migrations took {}", watch);
-
- initNotificationManager();
}
private void initLogging() {
@@ -178,20 +171,6 @@ public class Application extends android.app.Application {
config.setUserAgentValue(getPackageName());
}
- private void initNotificationManager() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- final Stopwatch watch = Stopwatch.createStarted();
- final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-
- final NotificationChannel appwidget = new NotificationChannel(
- NearestFavoriteStationWidgetService.NOTIFICATION_CHANNEL_ID_APPWIDGET,
- getString(R.string.notification_channel_appwidget_name), NotificationManager.IMPORTANCE_LOW);
- nm.createNotificationChannel(appwidget);
-
- log.info("created notification channels, took {}", watch);
- }
- }
-
private void migrateSelectedNetwork(final String fromName, final NetworkId to) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
diff --git a/oeffi/src/de/schildbach/oeffi/stations/FavoriteStationsActivity.java b/oeffi/src/de/schildbach/oeffi/stations/FavoriteStationsActivity.java
index 0463554..7151c3d 100644
--- a/oeffi/src/de/schildbach/oeffi/stations/FavoriteStationsActivity.java
+++ b/oeffi/src/de/schildbach/oeffi/stations/FavoriteStationsActivity.java
@@ -121,7 +121,7 @@ public class FavoriteStationsActivity extends OeffiActivity
} else if (menuItemId == R.id.station_context_remove_favorite) {
adapter.removeEntry(adapterPosition);
updateGUI();
- FavoriteUtils.notifyFavoritesChanged(this);
+ NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
return true;
} else {
return false;
diff --git a/oeffi/src/de/schildbach/oeffi/stations/FavoriteUtils.java b/oeffi/src/de/schildbach/oeffi/stations/FavoriteUtils.java
index 489c5f3..4a15681 100644
--- a/oeffi/src/de/schildbach/oeffi/stations/FavoriteUtils.java
+++ b/oeffi/src/de/schildbach/oeffi/stations/FavoriteUtils.java
@@ -17,12 +17,8 @@
package de.schildbach.oeffi.stations;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
import android.content.ContentResolver;
import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import de.schildbach.pte.NetworkId;
@@ -71,17 +67,4 @@ public class FavoriteUtils {
return favorites;
}
- public static void notifyFavoritesChanged(final Context context) {
- // notify widgets
- final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
- for (final AppWidgetProviderInfo providerInfo : appWidgetManager.getInstalledProviders()) {
- // limit to own widgets
- if (providerInfo.provider.getPackageName().equals(context.getPackageName())) {
- final Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
- appWidgetManager.getAppWidgetIds(providerInfo.provider));
- context.sendBroadcast(intent);
- }
- }
- }
}
diff --git a/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationWidgetProvider.java b/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationWidgetProvider.java
index 249370a..9c2ddfa 100644
--- a/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationWidgetProvider.java
+++ b/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationWidgetProvider.java
@@ -17,7 +17,6 @@
package de.schildbach.oeffi.stations;
-import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
@@ -32,15 +31,6 @@ public class NearestFavoriteStationWidgetProvider extends AppWidgetProvider {
public void onReceive(final Context context, final Intent intent) {
final String action = intent.getAction();
log.info("got broadcast: {}", action);
-
- if (Intent.ACTION_BOOT_COMPLETED.equals(action))
- NearestFavoriteStationWidgetService.enqueueWork(context, new Intent());
- else
- super.onReceive(context, intent);
- }
-
- @Override
- public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
- NearestFavoriteStationWidgetService.enqueueWork(context, new Intent());
+ NearestFavoriteStationWidgetService.schedulePeriodic(context);
}
}
diff --git a/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationWidgetService.java b/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationWidgetService.java
index 5db1406..1add583 100644
--- a/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationWidgetService.java
+++ b/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationWidgetService.java
@@ -19,6 +19,10 @@ package de.schildbach.oeffi.stations;
import android.Manifest;
import android.app.PendingIntent;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -38,10 +42,10 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import android.text.format.DateFormat;
+import android.text.format.DateUtils;
import android.view.View;
import android.widget.RemoteViews;
-import androidx.core.app.JobIntentService;
-import androidx.core.app.NotificationCompat;
+import androidx.annotation.WorkerThread;
import androidx.core.content.ContextCompat;
import com.google.common.base.Throwables;
import com.google.common.util.concurrent.SettableFuture;
@@ -68,24 +72,59 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-public class NearestFavoriteStationWidgetService extends JobIntentService {
+public class NearestFavoriteStationWidgetService extends JobService {
private AppWidgetManager appWidgetManager;
private LocationManager locationManager;
private ContentResolver contentResolver;
+ private Executor executor = Executors.newFixedThreadPool(2);
private HandlerThread backgroundThread;
private Handler backgroundHandler;
- private static final int JOB_ID = 1;
- public static final String NOTIFICATION_CHANNEL_ID_APPWIDGET = "appwidget";
- private static final int NOTIFICATION_ID_APPWIDGET_UPDATE = 1;
+ private static final int JOB_ID_PERIODIC = 0;
+ private static final int JOB_ID_IMMEDIATE = 1;
private static final Logger log = LoggerFactory.getLogger(NearestFavoriteStationWidgetService.class);
- public static void enqueueWork(final Context context, final Intent work) {
- enqueueWork(context, NearestFavoriteStationWidgetService.class, JOB_ID, work);
+ public static void schedulePeriodic(final Context context) {
+ final JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ final ComponentName providerName = new ComponentName(context, NearestFavoriteStationWidgetProvider.class);
+ final boolean haveWidgets = AppWidgetManager.getInstance(context).getAppWidgetIds(providerName).length > 0;
+ if (haveWidgets) {
+ final JobInfo.Builder jobInfo = new JobInfo.Builder(JOB_ID_PERIODIC, new ComponentName(context,
+ NearestFavoriteStationWidgetService.class));
+ jobInfo.setPeriodic(DateUtils.MINUTE_IN_MILLIS * 15);
+ jobInfo.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ final JobInfo job = jobInfo.build();
+ jobScheduler.schedule(job);
+ log.info("Scheduled periodic job: {}", job);
+ } else {
+ jobScheduler.cancelAll();
+ }
+ }
+
+ public static void scheduleImmediate(final Context context) {
+ final JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ final ComponentName providerName = new ComponentName(context, NearestFavoriteStationWidgetProvider.class);
+ final boolean haveWidgets = AppWidgetManager.getInstance(context).getAppWidgetIds(providerName).length > 0;
+ if (haveWidgets) {
+ final JobInfo.Builder jobInfo = new JobInfo.Builder(JOB_ID_IMMEDIATE, new ComponentName(context,
+ NearestFavoriteStationWidgetService.class));
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
+ jobInfo.setExpedited(true);
+ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
+ jobInfo.setImportantWhileForeground(true);
+ jobInfo.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ final JobInfo job = jobInfo.build();
+ jobScheduler.schedule(job);
+ log.info("Scheduled immediate job: {}", job);
+ } else {
+ jobScheduler.cancelAll();
+ }
}
@Override
@@ -110,25 +149,28 @@ public class NearestFavoriteStationWidgetService extends JobIntentService {
private RemoteViews views;
@Override
- protected void onHandleWork(final Intent intent) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- final NotificationCompat.Builder notification = new NotificationCompat.Builder(this,
- NOTIFICATION_CHANNEL_ID_APPWIDGET);
- notification.setSmallIcon(R.drawable.ic_stat_notify_sync_24dp);
- notification.setWhen(System.currentTimeMillis());
- notification.setOngoing(true);
- startForeground(NOTIFICATION_ID_APPWIDGET_UPDATE, notification.build());
- }
-
- handleIntent();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
- stopForeground(true);
+ public boolean onStartJob(final JobParameters params) {
+ log.info("Job started: {}", params);
+ executor.execute(() -> {
+ runJob();
+ jobFinished(params, false);
+ log.info("Job finished: {}", params);
+ });
+ return true;
}
- private void handleIntent() {
+ @Override
+ public boolean onStopJob(final JobParameters params) {
+ log.info("Job stopped: {}", params);
+ return false;
+ }
+
+ @WorkerThread
+ private void runJob() {
final ComponentName providerName = new ComponentName(this, NearestFavoriteStationWidgetProvider.class);
final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(providerName);
+ if (appWidgetIds.length == 0)
+ return;
views = new RemoteViews(getPackageName(), R.layout.station_widget_content);
diff --git a/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationsWidgetPermissionActivity.java b/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationsWidgetPermissionActivity.java
index a32d0d6..7bc4648 100644
--- a/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationsWidgetPermissionActivity.java
+++ b/oeffi/src/de/schildbach/oeffi/stations/NearestFavoriteStationsWidgetPermissionActivity.java
@@ -53,7 +53,7 @@ public class NearestFavoriteStationsWidgetPermissionActivity extends Activity {
for (int i = 0; i < permissions.length; i++)
log.info("{}{} granted",
permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED ? "" : " " + "not");
- FavoriteUtils.notifyFavoritesChanged(this);
+ NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
finish();
}
}
diff --git a/oeffi/src/de/schildbach/oeffi/stations/StationDetailsActivity.java b/oeffi/src/de/schildbach/oeffi/stations/StationDetailsActivity.java
index c1d3c76..7bd2bce 100644
--- a/oeffi/src/de/schildbach/oeffi/stations/StationDetailsActivity.java
+++ b/oeffi/src/de/schildbach/oeffi/stations/StationDetailsActivity.java
@@ -157,13 +157,13 @@ public class StationDetailsActivity extends OeffiActivity implements StationsAwa
FavoriteStationsProvider.TYPE_FAVORITE, selectedNetwork, selectedStation);
if (rowUri != null) {
selectedFavState = FavoriteStationsProvider.TYPE_FAVORITE;
- FavoriteUtils.notifyFavoritesChanged(StationDetailsActivity.this);
+ NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
}
} else {
final int numRows = FavoriteUtils.delete(getContentResolver(), selectedNetwork, selectedStation.id);
if (numRows > 0) {
selectedFavState = null;
- FavoriteUtils.notifyFavoritesChanged(StationDetailsActivity.this);
+ NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
}
}
});
diff --git a/oeffi/src/de/schildbach/oeffi/stations/StationsActivity.java b/oeffi/src/de/schildbach/oeffi/stations/StationsActivity.java
index 45f4908..9ffdf9e 100644
--- a/oeffi/src/de/schildbach/oeffi/stations/StationsActivity.java
+++ b/oeffi/src/de/schildbach/oeffi/stations/StationsActivity.java
@@ -696,7 +696,7 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
if (rowUri != null) {
favorites.put(location.id, FavoriteStationsProvider.TYPE_FAVORITE);
postLoadNextVisible(0);
- FavoriteUtils.notifyFavoritesChanged(this);
+ NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
return true;
} else {
return false;
@@ -707,7 +707,7 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
final int numRows = FavoriteUtils.delete(getContentResolver(), network, location.id);
if (numRows > 0) {
favorites.remove(location.id);
- FavoriteUtils.notifyFavoritesChanged(this);
+ NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
return true;
} else {
return false;
@@ -719,7 +719,7 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
network, location);
if (rowUriIgnored != null) {
favorites.put(location.id, FavoriteStationsProvider.TYPE_IGNORE);
- FavoriteUtils.notifyFavoritesChanged(this);
+ NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
return true;
} else {
return false;
@@ -731,7 +731,7 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
if (numRowsIgnored > 0) {
favorites.remove(location.id);
postLoadNextVisible(0);
- FavoriteUtils.notifyFavoritesChanged(this);
+ NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
return true;
} else {
return false;