mirror of
https://gitlab.com/oeffi/oeffi.git
synced 2025-07-06 17:38:48 +00:00
NearestFavoriteStationWidgetService: migrate periodic refresh from JobIntentService to JobScheduler
* Receive MY_PACKAGE_REPLACED and MY_PACKAGE_UNSUSPENDED system broadcasts to schedule our job. * Remove the foreground notification, as it's not necessary any more.
This commit is contained in:
parent
7634c116ae
commit
2034119b71
11 changed files with 81 additions and 93 deletions
|
@ -248,6 +248,12 @@
|
|||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/nearest_favorite_station_widget" />
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z" />
|
||||
</vector>
|
|
@ -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" />
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue