Skip to content

Commit

Permalink
Make PendingIntent explicitly immutable
Browse files Browse the repository at this point in the history
Fixes crash on Android 12. Closes #68.
  • Loading branch information
red-coracle committed Oct 25, 2021
1 parent 4895233 commit 066b779
Showing 1 changed file with 50 additions and 91 deletions.
141 changes: 50 additions & 91 deletions app/src/main/java/com/redcoracle/episodes/AutoRefreshHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,28 @@
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.preference.PreferenceManager;
import android.util.Log;

import androidx.core.net.ConnectivityManagerCompat;

import com.redcoracle.episodes.db.ShowsProvider;
import com.redcoracle.episodes.db.ShowsTable;
import com.redcoracle.episodes.services.AsyncTask;
import com.redcoracle.episodes.services.RefreshAllShowsTask;

public class AutoRefreshHelper
implements SharedPreferences.OnSharedPreferenceChangeListener
{
public class AutoRefreshHelper implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = AutoRefreshHelper.class.getName();

private static final String KEY_PREF_AUTO_REFRESH_ENABLED =
"pref_auto_refresh_enabled";
private static final String KEY_PREF_AUTO_REFRESH_PERIOD =
"pref_auto_refresh_period";
private static final String KEY_PREF_AUTO_REFRESH_WIFI_ONLY =
"pref_auto_refresh_wifi_only";

private static final String KEY_LAST_AUTO_REFRESH_TIME =
"last_auto_refresh_time";
private static final String KEY_PREF_AUTO_REFRESH_ENABLED = "pref_auto_refresh_enabled";
private static final String KEY_PREF_AUTO_REFRESH_PERIOD = "pref_auto_refresh_period";
private static final String KEY_PREF_AUTO_REFRESH_WIFI_ONLY = "pref_auto_refresh_wifi_only";
private static final String KEY_LAST_AUTO_REFRESH_TIME = "last_auto_refresh_time";

private static AutoRefreshHelper instance;

Expand All @@ -69,14 +59,13 @@ public AutoRefreshHelper(Context context) {

public static synchronized AutoRefreshHelper getInstance(Context context) {
if (instance == null) {
instance = new AutoRefreshHelper(context);
instance = new AutoRefreshHelper(context.getApplicationContext());
}
return instance;
}

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(KEY_PREF_AUTO_REFRESH_ENABLED)) {
onAutoRefreshEnabledChanged();
} else if (key.equals(KEY_PREF_AUTO_REFRESH_PERIOD)) {
Expand All @@ -103,8 +92,7 @@ private boolean getAutoRefreshEnabled() {
}

private long getAutoRefreshPeriod() {
final String hours =
preferences.getString(KEY_PREF_AUTO_REFRESH_PERIOD, "0");
final String hours = preferences.getString(KEY_PREF_AUTO_REFRESH_PERIOD, "0");

// convert hours to milliseconds
return Long.parseLong(hours) * 60 * 60 * 1000;
Expand All @@ -119,62 +107,58 @@ private long getPrevAutoRefreshTime() {
}

private void setPrevAutoRefreshTime(long time) {
final SharedPreferences.Editor editor =
preferences.edit();
final SharedPreferences.Editor editor = preferences.edit();
editor.putLong(KEY_LAST_AUTO_REFRESH_TIME, time);
editor.apply();
}

private boolean checkNetwork() {
final ConnectivityManager connManager =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
final ConnectivityManager connManager = (ConnectivityManager)context.getSystemService(
Context.CONNECTIVITY_SERVICE
);
final NetworkInfo net = connManager.getActiveNetworkInfo();

final boolean connected = net != null && net.isConnected();
final boolean metered =
ConnectivityManagerCompat.isActiveNetworkMetered(connManager);
final boolean metered = ConnectivityManagerCompat.isActiveNetworkMetered(connManager);
final boolean unmeteredOnly = getAutoRefreshWifiOnly();

final boolean okay = connected && !(metered && unmeteredOnly);

Log.i(TAG,
String.format("connected=%b, metered=%b, unmeteredOnly=%b, checkNetwork() %s.",
connected, metered, unmeteredOnly,
okay ? "passes" : "fails"));
Log.i(TAG, String.format("connected=%b, metered=%b, unmeteredOnly=%b, checkNetwork() %s.",
connected, metered, unmeteredOnly, okay ? "passes" : "fails"));

return okay;
}

public void rescheduleAlarm() {
NetworkStateReceiver.disable(context);

final AlarmManager alarmManager =
(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);

final Intent intent =
new Intent(context, AutoRefreshHelper.Service.class);
final PendingIntent pendingIntent =
PendingIntent.getService(context, 0, intent, 0);
final AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
final Intent intent = new Intent(context, AutoRefreshHelper.Service.class);
final int intentFlag;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
intentFlag = PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT;
} else {
intentFlag = PendingIntent.FLAG_UPDATE_CURRENT;
}
final PendingIntent pendingIntent = PendingIntent.getService(
context,
0,
intent,
intentFlag
);

if (getAutoRefreshEnabled() && getAutoRefreshPeriod() != 0) {
final long alarmTime =
getPrevAutoRefreshTime() + getAutoRefreshPeriod();

final long alarmTime = getPrevAutoRefreshTime() + getAutoRefreshPeriod();
Log.i(TAG, String.format("Scheduling auto refresh alarm for %d.", alarmTime));

alarmManager.set(AlarmManager.RTC,
alarmTime,
pendingIntent);
alarmManager.set(AlarmManager.RTC, alarmTime, pendingIntent);
} else {
Log.i(TAG, "Cancelling auto refresh alarm.");

alarmManager.cancel(pendingIntent);
}
}

public static class Service
extends IntentService
{
public static class Service extends IntentService {
private static final String TAG = Service.class.getName();

public Service() {
Expand All @@ -183,68 +167,43 @@ public Service() {

@Override
protected void onHandleIntent(Intent intent) {
final AutoRefreshHelper helper =
AutoRefreshHelper.getInstance(getApplicationContext());
final AutoRefreshHelper helper = AutoRefreshHelper.getInstance(getApplicationContext());

if (helper.checkNetwork()) {
Log.i(TAG, "Refreshing all shows.");
new AsyncTask().executeAsync(new RefreshAllShowsTask());
helper.setPrevAutoRefreshTime(System.currentTimeMillis());
helper.rescheduleAlarm();

} else {
NetworkStateReceiver.enable(this);
}
}

private static Cursor getShowsCursor(ContentResolver contentResolver) {
final String[] projection = {
ShowsTable.COLUMN_ID
};

final Cursor cursor =
contentResolver.query(ShowsProvider.CONTENT_URI_SHOWS,
projection,
null,
null,
null);

return cursor;
}
}

public static class BootReceiver
extends BroadcastReceiver
{
public static class BootReceiver extends BroadcastReceiver {
private static final String TAG = BootReceiver.class.getName();

@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.i(TAG, "Boot received.");

// ensure that the auto-refresh alarm is scheduled.
AutoRefreshHelper.getInstance(context.getApplicationContext())
.rescheduleAlarm();
AutoRefreshHelper.getInstance(context.getApplicationContext()).rescheduleAlarm();
}
}
}

// This receiver is disabled by default in the manifest.
// It should only be enabled when it needed, and should be
// disabled again straight afterwards.
public static class NetworkStateReceiver
extends BroadcastReceiver
{
public static class NetworkStateReceiver extends BroadcastReceiver {
private static final String TAG = NetworkStateReceiver.class.getName();

@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Network state change received.");

final AutoRefreshHelper helper =
AutoRefreshHelper.getInstance(context.getApplicationContext());

final AutoRefreshHelper helper = AutoRefreshHelper.getInstance(context.getApplicationContext());
if (helper.checkNetwork()) {
helper.rescheduleAlarm();
}
Expand All @@ -253,35 +212,35 @@ public void onReceive(Context context, Intent intent) {
public static void enable(Context context) {
final PackageManager packageManager = context.getPackageManager();

final ComponentName receiver =
new ComponentName(context, NetworkStateReceiver.class);
final ComponentName receiver = new ComponentName(context, NetworkStateReceiver.class);

if (packageManager.getComponentEnabledSetting(receiver) !=
PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
Log.i(TAG, "Enabling network state receiver.");
}

packageManager.setComponentEnabledSetting(
receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
);
}

public static void disable(Context context) {
final PackageManager packageManager = context.getPackageManager();

final ComponentName receiver =
new ComponentName(context, NetworkStateReceiver.class);
final ComponentName receiver = new ComponentName(context, NetworkStateReceiver.class);

if (packageManager.getComponentEnabledSetting(receiver) !=
PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
Log.i(TAG, "Disabling network state receiver.");
}

packageManager.setComponentEnabledSetting(
receiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
receiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
);
}
}
}

0 comments on commit 066b779

Please sign in to comment.