Skip to content

Commit

Permalink
Track network connectivity and resolve in with Resolution Strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
AAverin committed Jun 26, 2016
1 parent 2fe7f0b commit a4b327f
Show file tree
Hide file tree
Showing 10 changed files with 370 additions and 2 deletions.
6 changes: 6 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
</intent-filter>
</activity>

<receiver android:name=".ui.common.broadcasts.ConnectivityBroadcastReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>

<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyDGcw8mbOf8j38aQwkYzBweBAWdhNPN7uU"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package pro.averin.anton.clean.android.cookbook.data.common.connection

import android.net.ConnectivityManager
import javax.inject.Inject
import javax.inject.Singleton


@Singleton
class ConnectionChecker @Inject constructor() {

@Inject lateinit var connectivityManager: ConnectivityManager

fun getNetworkStatus(): Int {
val networkInfo = connectivityManager.activeNetworkInfo
if (networkInfo != null && networkInfo.isConnectedOrConnecting) {
when (networkInfo.type) {
ConnectivityManager.TYPE_WIFI -> return WIFI
ConnectivityManager.TYPE_MOBILE -> return MOBILE
else -> return OFFLINE
}
}

return OFFLINE;
}

fun isOnline(): Boolean {
val activeNetwork = connectivityManager.activeNetworkInfo

return activeNetwork != null && activeNetwork.isConnectedOrConnecting
}


companion object NetworkStatus {
val OFFLINE = 1
val MOBILE = 2
val WIFI = 3
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package pro.averin.anton.clean.android.cookbook.di

import android.net.ConnectivityManager
import com.tbruyelle.rxpermissions.RxPermissions
import dagger.Component
import pro.averin.anton.clean.android.cookbook.BaseContext
import pro.averin.anton.clean.android.cookbook.data.common.connection.ConnectionChecker
import pro.averin.anton.clean.android.cookbook.data.common.rx.Schedulers
import pro.averin.anton.clean.android.cookbook.data.common.rx.bus.GlobalBusSubscriber
import pro.averin.anton.clean.android.cookbook.data.flickr.FlickrRepo
import pro.averin.anton.clean.android.cookbook.ui.common.broadcasts.ConnectivityBroadcastReceiver
import pro.averin.anton.clean.android.cookbook.ui.common.map.MapUtils
import javax.inject.Singleton

Expand All @@ -27,4 +30,8 @@ interface AppComponent {
fun globalBusSubscriber(): GlobalBusSubscriber

fun mapUtils(): MapUtils

fun connectionChecker(): ConnectionChecker
fun connectivityManager(): ConnectivityManager
fun injectTo(connectivityBroadcastReceiver: ConnectivityBroadcastReceiver)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package pro.averin.anton.clean.android.cookbook.di
import android.content.Context
import android.content.SharedPreferences
import android.location.LocationManager
import android.net.ConnectivityManager
import android.preference.PreferenceManager
import dagger.Module
import dagger.Provides
Expand All @@ -12,6 +13,12 @@ import javax.inject.Singleton
@Module
class SystemServicesModule(private val baseContext: BaseContext) {

@Provides
@Singleton
fun connectivityManager(): ConnectivityManager {
return baseContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}

@Provides
@Singleton
fun locationManager(): LocationManager {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package pro.averin.anton.clean.android.cookbook.ui.common

import pro.averin.anton.clean.android.cookbook.data.common.connection.ConnectionChecker
import pro.averin.anton.clean.android.cookbook.data.common.rx.bus.GlobalBusSubscriber
import pro.averin.anton.clean.android.cookbook.data.common.rx.bus.events.ConnectivityAvailableGlobalEvent
import pro.averin.anton.clean.android.cookbook.data.common.rx.bus.events.ConnectivityUnavailableGlobalEvent
import pro.averin.anton.clean.android.cookbook.di.ActivityScope
import pro.averin.anton.clean.android.cookbook.ui.common.resolution.Resolution
import javax.inject.Inject

@ActivityScope
class ConnectionEventsHandler @Inject constructor(
private val globalBusSubscriber: GlobalBusSubscriber,
private val connectionChecker: ConnectionChecker
) {

fun start(resolution: Resolution) {
globalBusSubscriber.subscribe(ConnectivityAvailableGlobalEvent::class) {
resolution.onConnectivityAvailable()
}
globalBusSubscriber.subscribe(ConnectivityUnavailableGlobalEvent::class) {
resolution.onConnectivityUnavailable()
}

if (!connectionChecker.isOnline()) {
resolution.onConnectivityUnavailable()
} else {
resolution.onConnectivityAvailable()
}

}

fun stop() {
globalBusSubscriber.unsubscribe()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package pro.averin.anton.clean.android.cookbook.ui.common.broadcasts

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import pro.averin.anton.clean.android.cookbook.BaseContext
import pro.averin.anton.clean.android.cookbook.data.common.connection.ConnectionChecker
import pro.averin.anton.clean.android.cookbook.data.common.rx.bus.GlobalBus
import pro.averin.anton.clean.android.cookbook.data.common.rx.bus.events.ConnectivityAvailableGlobalEvent
import pro.averin.anton.clean.android.cookbook.data.common.rx.bus.events.ConnectivityUnavailableGlobalEvent
import javax.inject.Inject

class ConnectivityBroadcastReceiver : BroadcastReceiver() {

@Inject lateinit var connectionChecker: ConnectionChecker
@Inject lateinit var globalBus: GlobalBus

override fun onReceive(context: Context?, intent: Intent?) {
val baseContext = context?.applicationContext as BaseContext
baseContext.appComponent.injectTo(this)

if (connectionChecker.isOnline()) {
globalBus.post(ConnectivityAvailableGlobalEvent())
} else {
globalBus.post(ConnectivityUnavailableGlobalEvent())
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package pro.averin.anton.clean.android.cookbook.ui.main.presenter

import android.os.Bundle
import pro.averin.anton.clean.android.cookbook.di.ActivityScope
import pro.averin.anton.clean.android.cookbook.ui.common.ConnectionEventsHandler
import pro.averin.anton.clean.android.cookbook.ui.common.ExtraLifecycleDelegate
import pro.averin.anton.clean.android.cookbook.ui.common.UINavigator
import pro.averin.anton.clean.android.cookbook.ui.common.presenter.BasePresenter
Expand All @@ -11,12 +13,23 @@ import javax.inject.Inject

@ActivityScope
class MainPresenter @Inject constructor(
private val connectionEventsHandler: ConnectionEventsHandler
) : BasePresenter<MainScreenContract>(), ExtraLifecycleDelegate, NavigationDrawerViewExtensionDelegate {

@Inject lateinit var uiNavigator: UINavigator

lateinit var navigationDrawerViewExtension: NavigationDrawerViewExtensionContract

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
connectionEventsHandler.start(view?.getResolution()!!)
}

override fun onDestroy() {
super.onDestroy()
connectionEventsHandler.stop()
}

override fun showInitialScreen() {
uiNavigator.showGoogleMapsScreen()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ import android.support.v7.widget.Toolbar
import pro.averin.anton.clean.android.cookbook.R
import pro.averin.anton.clean.android.cookbook.databinding.ActivityMainBinding
import pro.averin.anton.clean.android.cookbook.di.ActivityComponent
import pro.averin.anton.clean.android.cookbook.ui.common.resolution.Resolution
import pro.averin.anton.clean.android.cookbook.ui.common.resolution.UIResolution
import pro.averin.anton.clean.android.cookbook.ui.common.view.BaseActivity
import pro.averin.anton.clean.android.cookbook.ui.common.view.ScreenContract
import pro.averin.anton.clean.android.cookbook.ui.common.view.ResolvedScreenContract
import pro.averin.anton.clean.android.cookbook.ui.main.presenter.MainPresenter
import javax.inject.Inject

interface MainScreenContract : ScreenContract
interface MainScreenContract : ResolvedScreenContract

class MainActivity : BaseActivity(), MainScreenContract {

@Inject lateinit var presenter: MainPresenter
@Inject lateinit var uiResolution: UIResolution
@Inject lateinit var navigationDrawerViewExtension: NavigationDrawerViewExtension

override fun doInjections(activityComponent: ActivityComponent) {
Expand All @@ -41,4 +44,7 @@ class MainActivity : BaseActivity(), MainScreenContract {
}
}

override fun getResolution(): Resolution? {
return uiResolution
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package pro.averin.anton.clean.android.cookbook.data.common.connection

import android.net.ConnectivityManager
import android.net.NetworkInfo
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.powermock.modules.junit4.PowerMockRunner
import pro.averin.anton.clean.android.cookbook.kotlin.test.assertThat
import pro.averin.anton.clean.android.cookbook.kotlin.test.given
import pro.averin.anton.clean.android.cookbook.kotlin.test.isEqualTo

@RunWith(PowerMockRunner::class)
class ConnectionCheckerTest {

@Mock lateinit var connectivityManager: ConnectivityManager
@Mock lateinit var activeNetworkInfo: NetworkInfo

@InjectMocks lateinit var classToTest: ConnectionChecker

@Test
fun networkStatusOfflineWhenNoNetworksConnected() {
// given
given(connectivityManager.activeNetworkInfo).willReturn(null)

// when
val status = classToTest.getNetworkStatus()

// then
assertThat(status, isEqualTo(ConnectionChecker.OFFLINE))
}

@Test
fun networkStatusOfflineWhenNotWifiOrMobileNetworkConnected() {
// given
given(connectivityManager.activeNetworkInfo).willReturn(activeNetworkInfo)
given(activeNetworkInfo.isConnectedOrConnecting).willReturn(true)
given(activeNetworkInfo.type).willReturn(ConnectivityManager.TYPE_DUMMY)

// when
val status = classToTest.getNetworkStatus()

// then
assertThat(status, isEqualTo(ConnectionChecker.OFFLINE))
}

@Test
fun networkStatusWifiWhenWifiConnected() {
// given
given(connectivityManager.activeNetworkInfo).willReturn(activeNetworkInfo)
given(activeNetworkInfo.type).willReturn(ConnectivityManager.TYPE_WIFI)
given(activeNetworkInfo.isConnectedOrConnecting).willReturn(true)

// when
val status = classToTest.getNetworkStatus()

// then
assertThat(status, isEqualTo(ConnectionChecker.WIFI))
}

@Test
fun offlineWhenActiveNetworkNotConnected() {
// given
given(connectivityManager.activeNetworkInfo).willReturn(activeNetworkInfo)
given(activeNetworkInfo.isConnectedOrConnecting).willReturn(false)

// when
val result = classToTest.isOnline()

// then
assertThat(result, isEqualTo(false))
}


@Test
fun onlineWhenActiveNetworkConnected() {
// given
given(connectivityManager.activeNetworkInfo).willReturn(activeNetworkInfo)
given(activeNetworkInfo.isConnectedOrConnecting).willReturn(true)

// when
val result = classToTest.isOnline()

// then
assertThat(result, isEqualTo(true))
}

@Test
fun networkStatusMobileWhenMobileConnected() {
// given
given(connectivityManager.activeNetworkInfo).willReturn(activeNetworkInfo)
given(activeNetworkInfo.type).willReturn(ConnectivityManager.TYPE_MOBILE)
given(activeNetworkInfo.isConnectedOrConnecting).willReturn(true)

// when
val status = classToTest.getNetworkStatus()

// then
assertThat(status, isEqualTo(ConnectionChecker.MOBILE))
}
}
Loading

0 comments on commit a4b327f

Please sign in to comment.