Skip to content

Commit

Permalink
Encapsulate network connectivity observing for different API versions.
Browse files Browse the repository at this point in the history
+ New: Using ConnectivityManager#registerDefaultNetworkCallback for
  Android Nougat and newer.
+ NetworkInfo#isConnectedOrConnecting and ConnectivityManager#CONNECTIVITY_ACTION
  have been deprecated in API level 28.
+ Related commit: 49a2bbf.
+ Relates to issue tuxmobil#138.
  • Loading branch information
johnjohndoe committed Jul 29, 2019
1 parent 218e491 commit f3c8651
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@
import nerd.tuxmobil.fahrplan.congress.MyApp.TASKS;
import nerd.tuxmobil.fahrplan.congress.R;
import nerd.tuxmobil.fahrplan.congress.models.Lecture;
import nerd.tuxmobil.fahrplan.congress.net.ConnectivityObserver;
import nerd.tuxmobil.fahrplan.congress.net.FetchScheduleResult;
import nerd.tuxmobil.fahrplan.congress.net.HttpStatus;
import nerd.tuxmobil.fahrplan.congress.notifications.NotificationHelper;
import nerd.tuxmobil.fahrplan.congress.repositories.AppRepository;
import nerd.tuxmobil.fahrplan.congress.schedule.MainActivity;
import nerd.tuxmobil.fahrplan.congress.utils.FahrplanMisc;

import static nerd.tuxmobil.fahrplan.congress.net.Connectivity.networkIsAvailable;

public class UpdateService extends JobIntentService {

private static final int JOB_ID = 2119;
Expand Down Expand Up @@ -114,12 +113,19 @@ private void fetchFahrplan() {

@Override
protected void onHandleWork(@NonNull Intent intent) {
if (!networkIsAvailable(this)) {
ConnectivityObserver connectivityObserver = new ConnectivityObserver(this, () -> {
MyApp.LogDebug(LOG_TAG, "Network is available");
fetchSchedule();
return null;
}, () -> {
MyApp.LogDebug(LOG_TAG, "Network is not available");
stopSelf();
return;
}
return null;
}, true);
connectivityObserver.start();
}

private void fetchSchedule() {
AppRepository appRepository = AppRepository.Companion.getInstance(getApplicationContext());
MyApp.meta = appRepository.readMeta(); // to load eTag
MyApp.LogDebug(LOG_TAG, "Fetching schedule ...");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
package nerd.tuxmobil.fahrplan.congress.base;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.WindowManager;

import nerd.tuxmobil.fahrplan.congress.net.ConnectivityStateReceiver;
import nerd.tuxmobil.fahrplan.congress.R;
import nerd.tuxmobil.fahrplan.congress.autoupdate.UpdateService;
import nerd.tuxmobil.fahrplan.congress.net.ConnectivityObserver;
import nerd.tuxmobil.fahrplan.congress.utils.ActivityHelper;

public abstract class BaseActivity extends AppCompatActivity {

private ConnectivityStateReceiver connectivityStateReceiver;
private ConnectivityObserver connectivityObserver;

@Override
public void onAttachedToWindow() {
Expand All @@ -26,14 +31,18 @@ public void onAttachedToWindow() {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
connectivityStateReceiver = new ConnectivityStateReceiver();
registerReceiver(connectivityStateReceiver, ConnectivityStateReceiver.getIntentFilter());
connectivityObserver = new ConnectivityObserver(this, () -> {
Log.d(getClass().getName(), "Network is available.");
startUpdateService();
return null;
});
connectivityObserver.start();
}

@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(connectivityStateReceiver);
connectivityObserver.stop();
}

@Override
Expand All @@ -46,6 +55,15 @@ public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}

private void startUpdateService() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean defaultValue = getResources().getBoolean(R.bool.preferences_auto_update_enabled_default_value);
boolean doAutoUpdates = preferences.getBoolean("auto_update", defaultValue);
if (doAutoUpdates) {
UpdateService.start(this);
}
}

protected void addFragment(@IdRes int containerViewId,
@NonNull Fragment fragment,
@NonNull String fragmentTag) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@ import android.app.NotificationManager
import android.content.Context
import android.content.Context.*
import android.content.Intent
import android.net.ConnectivityManager
import android.view.LayoutInflater

fun Context.getAlarmManager() = getSystemService(ALARM_SERVICE) as AlarmManager

fun Context.getConnectivityManager() = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager

fun Context.getLayoutInflater() = getSystemService(LAYOUT_INFLATER_SERVICE) as LayoutInflater

fun Context.getNotificationManager() = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
@file:JvmName("ConnectivityObserver")

package nerd.tuxmobil.fahrplan.congress.net

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.Network
import android.os.Build

/**
* Observes network connectivity by consulting the [ConnectivityManager].
* Observing can run infinitely or automatically be stopped after the first response is received.
*/
class ConnectivityObserver @JvmOverloads constructor(

val context: Context,
val onConnectionAvailable: () -> Unit,
val onConnectionLost: () -> Unit = {},
val shouldStopAfterFirstResponse: Boolean = false

) {

private val connectivityManager
get() = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

@Suppress("DEPRECATION")
private val intentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)

private val broadCastReceiver = object : BroadcastReceiver() {

@Suppress("DEPRECATION")
override fun onReceive(context: Context?, intent: Intent?) {
if (ConnectivityManager.CONNECTIVITY_ACTION != intent?.action) {
return
}
val networkInfo = connectivityManager.activeNetworkInfo
if (networkInfo != null && networkInfo.isConnectedOrConnecting) {
onConnectionAvailable.invoke()
} else {
onConnectionLost.invoke()
}
if (shouldStopAfterFirstResponse) {
stop()
}
}

}

private lateinit var networkCallback: ConnectivityManager.NetworkCallback

init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
networkCallback = object : ConnectivityManager.NetworkCallback() {

override fun onAvailable(network: Network) {
super.onAvailable(network)
onConnectionAvailable.invoke()
if (shouldStopAfterFirstResponse) {
stop()
}
}

override fun onLost(network: Network?) {
super.onLost(network)
onConnectionLost.invoke()
if (shouldStopAfterFirstResponse) {
stop()
}
}
}
}
}

fun start() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
// Decouple from component lifecycle, use application context.
// See: https://developer.android.com/reference/android/content/Context.html#getApplicationContext()
context.applicationContext.registerReceiver(broadCastReceiver, intentFilter)
} else {
connectivityManager.registerDefaultNetworkCallback(networkCallback)
}
}

fun stop() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
context.applicationContext.unregisterReceiver(broadCastReceiver)
} else {
connectivityManager.unregisterNetworkCallback(networkCallback)
}
}

}

This file was deleted.

0 comments on commit f3c8651

Please sign in to comment.