Skip to content

Commit

Permalink
Replace LiveData and callbacks with flows (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
fstanis authored Sep 20, 2021
1 parent 4fe078e commit 162266f
Show file tree
Hide file tree
Showing 24 changed files with 713 additions and 396 deletions.
4 changes: 3 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ android {
applicationId "com.devrel.android.minwos"
minSdkVersion 26
targetSdkVersion 30
versionCode 301
versionCode 302
versionName "3.0"

testInstrumentationRunner 'com.devrel.android.minwos.TestRunner'
Expand Down Expand Up @@ -61,6 +61,7 @@ dependencies {
implementation 'androidx.fragment:fragment-ktx:1.3.3'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.3.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0-alpha01'
implementation 'androidx.lifecycle:lifecycle-service:2.3.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
Expand All @@ -74,6 +75,7 @@ dependencies {
testImplementation 'androidx.arch.core:core-testing:2.1.0'
testImplementation 'com.google.truth:truth:1.0.1'
testImplementation 'junit:junit:4.13.2'
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlin_version"
testImplementation 'org.mockito:mockito-core:3.3.3'

androidTestImplementation 'androidx.test:rules:1.3.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,14 @@
package com.devrel.android.minwos.data.networks

import android.net.LinkProperties
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.runBlocking

class FakeConnectivityStatusListener : ConnectivityStatusListener {
var connectivityCallback: ((ConnectivityStatus) -> Unit)? = null
override val flow = MutableSharedFlow<ConnectivityStatus>()

override fun setCallback(callback: (ConnectivityStatus) -> Unit) {
connectivityCallback = callback
}

override fun clearCallback() {
connectivityCallback = null
}

override fun startListening() {}
override fun stopListening() {}
override fun refresh() {
connectivityCallback?.invoke(
override fun refresh() = runBlocking {
flow.emit(
ConnectivityStatus(
null,
listOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,21 @@

package com.devrel.android.minwos.data.phonestate

class FakeTelephonyStatusListener : TelephonyStatusListener {
var telephonyCallback: ((TelephonyStatus) -> Unit)? = null

override fun setCallback(callback: (TelephonyStatus) -> Unit) {
telephonyCallback = callback
}
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.runBlocking

override fun clearCallback() {
telephonyCallback = null
}
class FakeTelephonyStatusListener : TelephonyStatusListener {
override val flow = MutableSharedFlow<TelephonyStatus>()

override fun startListening() {}
override fun stopListening() {}
override fun refresh() {
telephonyCallback?.invoke(
override fun refresh() = runBlocking {
flow.emit(
TelephonyStatus(
listOf(
TelephonyStatus.TelephonyData(SubscriptionInfo(99, 0), SimInfo("", "refresh"))
)
)
)
}

override fun recheckPermissions() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.runBlocking
import org.hamcrest.Matchers.allOf
import org.junit.Before
import org.junit.Rule
Expand All @@ -67,8 +69,8 @@ class NetworksFragmentTest {
@BindValue
val telephonyStatusListener: TelephonyStatusListener = FakeTelephonyStatusListener()

private val connectivityCallback get() =
(connectivityStatusListener as FakeConnectivityStatusListener).connectivityCallback
private val sharedFlow
get() = connectivityStatusListener.flow as MutableSharedFlow<ConnectivityStatus>

@Before
fun setUp() {
Expand All @@ -81,13 +83,13 @@ class NetworksFragmentTest {
}

@Test
fun displaysNetworks() {
fun displaysNetworks() = runBlocking {
val network1 =
NetworkData(0, linkProperties = LinkProperties().apply { interfaceName = "test0" })
val network2 =
NetworkData(1, linkProperties = LinkProperties().apply { interfaceName = "test1" })
onView(withId(R.id.networksRecyclerView)).check(matches(hasChildCount(0)))
connectivityCallback?.invoke(ConnectivityStatus(null, listOf(network1, network2)))
sharedFlow.emit(ConnectivityStatus(null, listOf(network1, network2)))
onView(withId(R.id.networksRecyclerView)).check(
matches(
allOf(
Expand All @@ -97,7 +99,7 @@ class NetworksFragmentTest {
)
)
)
connectivityCallback?.invoke(ConnectivityStatus(network2, listOf(network1, network2)))
sharedFlow.emit(ConnectivityStatus(network2, listOf(network1, network2)))
onView(withId(R.id.networksRecyclerView)).check(
matches(
allOf(
Expand All @@ -107,6 +109,7 @@ class NetworksFragmentTest {
)
)
)
Unit
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.UninstallModules
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.runBlocking
import org.hamcrest.Matchers.allOf
import org.junit.Before
import org.junit.Rule
Expand All @@ -70,8 +72,8 @@ class PhoneStateFragmentTest {
val telephonyStatusListener: TelephonyStatusListener = FakeTelephonyStatusListener()

private val baseTelephonyData = TelephonyData(SubscriptionInfo(1, 0), SimInfo("", ""))
private val telephonyCallback get() =
(telephonyStatusListener as FakeTelephonyStatusListener).telephonyCallback
private val sharedFlow
get() = telephonyStatusListener.flow as MutableSharedFlow<TelephonyStatus>

@Before
fun setUp() {
Expand All @@ -84,11 +86,11 @@ class PhoneStateFragmentTest {
}

@Test
fun displaysPhoneState() {
fun displaysPhoneState() = runBlocking {
val data1 = baseTelephonyData.copy(networkType = TelephonyManager.NETWORK_TYPE_EDGE)
val data2 = baseTelephonyData.copy(networkType = TelephonyManager.NETWORK_TYPE_LTE)
onView(withId(R.id.telephonyRecyclerView)).check(matches(hasChildCount(0)))
telephonyCallback?.invoke(TelephonyStatus(listOf(data1, data2)))
sharedFlow.emit(TelephonyStatus(listOf(data1, data2)))
onView(withId(R.id.telephonyRecyclerView)).check(
matches(
allOf(
Expand All @@ -98,6 +100,7 @@ class PhoneStateFragmentTest {
)
)
)
Unit
}

@Test
Expand Down
5 changes: 4 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
<!-- Required to read TelephonyDisplayInfo -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<!-- Refreshing causes a small tick vibration -->
<uses-permission android:name="android.permission.VIBRATE" />

<!-- Not used, make sure they aren't included -->
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
Expand Down Expand Up @@ -57,4 +60,4 @@
<service android:name=".service.ForegroundStatusService" />
</application>

</manifest>
</manifest>
21 changes: 17 additions & 4 deletions app/src/main/java/com/devrel/android/minwos/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import android.app.Application
import android.app.NotificationManager
import android.content.Context
import android.net.ConnectivityManager
import android.os.Vibrator
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import dagger.Module
Expand All @@ -29,6 +30,10 @@ import dagger.hilt.android.HiltAndroidApp
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob

@HiltAndroidApp
class App : Application()
Expand All @@ -37,22 +42,30 @@ class App : Application()
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
@Singleton
fun provideConnectivityManager(@ApplicationContext context: Context) =
context.getSystemService(ConnectivityManager::class.java)!!

@Provides
@Singleton
fun provideTelephonyManager(@ApplicationContext context: Context) =
context.getSystemService(TelephonyManager::class.java)!!

@Provides
@Singleton
fun provideNotificationManager(@ApplicationContext context: Context) =
context.getSystemService(NotificationManager::class.java)!!

@Provides
@Singleton
fun provideSubscriptionManager(@ApplicationContext context: Context) =
context.getSystemService(SubscriptionManager::class.java)!!

@Provides
fun provideVibrator(@ApplicationContext context: Context) =
context.getSystemService(Vibrator::class.java)!!

@Provides
fun provideDispatcher() = Dispatchers.Default

@Provides
@Singleton
fun provideCoroutineScope(coroutineDispatcher: CoroutineDispatcher): CoroutineScope =
CoroutineScope(SupervisorJob() + coroutineDispatcher)
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ data class ConnectivityStatus(
// ensure default network is first, if set
val networks = defaultNetwork?.let { listOf(it).union(allNetworks).toList() } ?: allNetworks

companion object {
val EMPTY = ConnectivityStatus(null, listOf())
}

data class NetworkData(
val id: Int,
val networkCapabilities: NetworkCapabilities? = null,
Expand Down
Loading

0 comments on commit 162266f

Please sign in to comment.