Skip to content

Commit

Permalink
Warn when changing to metered network if setting is enabled (#1640)
Browse files Browse the repository at this point in the history
Co-authored-by: ashiagr <[email protected]>
  • Loading branch information
mchowning and ashiagr authored Jan 26, 2024
1 parent 92a1352 commit 54ddbe1
Show file tree
Hide file tree
Showing 17 changed files with 370 additions and 37 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
7.57
-----

* Updates:
* Warn when switching to metered network if warn before using data setting is enabled
([#1640](https://github.com/Automattic/pocket-casts-android/pull/1640))
* Bug Fixes:
* Fixed starring episode from full-screen player does not prevent episode from being archived
([#1735](https://github.com/Automattic/pocket-casts-android/pull/1735))
Expand Down Expand Up @@ -29,6 +33,7 @@
([#1657](https://github.com/Automattic/pocket-casts-android/pull/1662))
* Fixed an issue with incorrect playback speed shown on the media notification
([#1648](https://github.com/Automattic/pocket-casts-android/pull/1666))

7.54
-----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,8 @@ class EpisodeFragment : BaseFragment() {
val shouldClose = if (viewModel.shouldShowStreamingWarning(context)) {
warningsHelper.streamingWarningDialog(onConfirm = {
val shouldCloseAfterWarning = viewModel.playClickedGetShouldClose(
warningsHelper,
warningsHelper = warningsHelper,
showedStreamWarning = true,
force = true,
fromListUuid = fromListUuid,
)
Expand All @@ -362,7 +363,11 @@ class EpisodeFragment : BaseFragment() {
}).show(parentFragmentManager, "stream warning")
false
} else {
viewModel.playClickedGetShouldClose(warningsHelper, fromListUuid = fromListUuid)
viewModel.playClickedGetShouldClose(
warningsHelper = warningsHelper,
showedStreamWarning = false,
fromListUuid = fromListUuid,
)
}

if (shouldClose) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ class EpisodeFragmentViewModel @Inject constructor(

fun playClickedGetShouldClose(
warningsHelper: WarningsHelper,
showedStreamWarning: Boolean,
force: Boolean = false,
fromListUuid: String? = null,
): Boolean {
Expand All @@ -267,7 +268,12 @@ class EpisodeFragmentViewModel @Inject constructor(
FirebaseAnalyticsTracker.podcastEpisodePlayedFromList(it, episode.podcastUuid)
analyticsTracker.track(AnalyticsEvent.DISCOVER_LIST_EPISODE_PLAY, mapOf(LIST_ID_KEY to it, PODCAST_ID_KEY to episode.podcastUuid))
}
playbackManager.playNow(episode, forceStream = force, sourceView = source)
playbackManager.playNow(
episode = episode,
forceStream = force,
showedStreamWarning = showedStreamWarning,
sourceView = source,
)
warningsHelper.showBatteryWarningSnackbarIfAppropriate()
return true
}
Expand Down
1 change: 1 addition & 0 deletions modules/features/shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ dependencies {
implementation(project(":modules:services:preferences"))
implementation(project(":modules:services:repositories"))
implementation(project(":modules:services:utils"))
testImplementation(project(":modules:services:sharedtest"))
}
2 changes: 1 addition & 1 deletion modules/features/shared/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -24,40 +24,44 @@ class AppLifecycleObserver constructor(
@ApplicationContext private val appContext: Context,
private val appLifecycleAnalytics: AppLifecycleAnalytics,
private val appLifecycleOwner: LifecycleOwner = ProcessLifecycleOwner.get(),
private val preferencesFeatureProvider: PreferencesFeatureProvider,
private val applicationScope: CoroutineScope,
private val defaultReleaseFeatureProvider: DefaultReleaseFeatureProvider,
private val firebaseRemoteFeatureProvider: FirebaseRemoteFeatureProvider,
private val networkConnectionWatcher: NetworkConnectionWatcherImpl,
private val packageUtil: PackageUtil,
private val preferencesFeatureProvider: PreferencesFeatureProvider,
private val settings: Settings,
private val applicationScope: CoroutineScope,
) : DefaultLifecycleObserver {

@Inject
constructor(
@ApplicationContext appContext: Context,
@ApplicationScope applicationScope: CoroutineScope,
appLifecycleAnalytics: AppLifecycleAnalytics,
preferencesFeatureProvider: PreferencesFeatureProvider,
defaultReleaseFeatureProvider: DefaultReleaseFeatureProvider,
networkConnectionWatcher: NetworkConnectionWatcherImpl,
firebaseRemoteFeatureProvider: FirebaseRemoteFeatureProvider,
packageUtil: PackageUtil,
preferencesFeatureProvider: PreferencesFeatureProvider,
settings: Settings,
@ApplicationScope applicationScope: CoroutineScope,
) : this(
appContext = appContext,
applicationScope = applicationScope,
appLifecycleAnalytics = appLifecycleAnalytics,
appLifecycleOwner = ProcessLifecycleOwner.get(),
preferencesFeatureProvider = preferencesFeatureProvider,
defaultReleaseFeatureProvider = defaultReleaseFeatureProvider,
firebaseRemoteFeatureProvider = firebaseRemoteFeatureProvider,
networkConnectionWatcher = networkConnectionWatcher,
packageUtil = packageUtil,
preferencesFeatureProvider = preferencesFeatureProvider,
settings = settings,
applicationScope = applicationScope,
)

fun setup() {
appLifecycleOwner.lifecycle.addObserver(this)
handleNewInstallOrUpgrade()
setupFeatureFlags()
networkConnectionWatcher.startWatching()
}

override fun onResume(owner: LifecycleOwner) {
Expand All @@ -73,6 +77,7 @@ class AppLifecycleObserver constructor(

override fun onDestroy(owner: LifecycleOwner) {
applicationScope.cancel("Application onTerminate")
networkConnectionWatcher.stopWatching()
super.onDestroy(owner)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package au.com.shiftyjelly.pocketcasts.shared

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import androidx.annotation.VisibleForTesting
import au.com.shiftyjelly.pocketcasts.repositories.di.ApplicationScope
import au.com.shiftyjelly.pocketcasts.repositories.playback.NetworkConnectionWatcher
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import au.com.shiftyjelly.pocketcasts.utils.Network as PCNetworkUtils

@Singleton
class NetworkConnectionWatcherImpl @Inject constructor(
@ApplicationScope private val applicationScope: CoroutineScope,
@ApplicationContext private val context: Context,
) : NetworkConnectionWatcher {

private val _networkCapabilities = MutableStateFlow<NetworkCapabilities?>(null)
override val networkCapabilities: StateFlow<NetworkCapabilities?> = _networkCapabilities

private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
this@NetworkConnectionWatcherImpl.onCapabilitiesChanged(networkCapabilities)
super.onCapabilitiesChanged(network, networkCapabilities)
}
}

fun startWatching() {
val networkRequest = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.build()

PCNetworkUtils.getConnectivityManager(context)
.registerNetworkCallback(networkRequest, networkCallback)
}

fun stopWatching() {
PCNetworkUtils.getConnectivityManager(context)
.unregisterNetworkCallback(networkCallback)
}

@VisibleForTesting
internal fun onCapabilitiesChanged(networkCapabilities: NetworkCapabilities) {
_networkCapabilities.value = networkCapabilities
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package au.com.shiftyjelly.pocketcasts.shared.di

import au.com.shiftyjelly.pocketcasts.repositories.playback.NetworkConnectionWatcher
import au.com.shiftyjelly.pocketcasts.shared.NetworkConnectionWatcherImpl
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
abstract class SharedModule {

@Binds
@Singleton
abstract fun provideNetworkConnectionWatcher(networkWatcherImpl: NetworkConnectionWatcherImpl): NetworkConnectionWatcher
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class AppLifecycleObserverTest {

@Mock private lateinit var appLifecycle: Lifecycle

@Mock private lateinit var networkConnectionWatcher: NetworkConnectionWatcherImpl

lateinit var appLifecycleObserver: AppLifecycleObserver

@Before
Expand All @@ -74,6 +76,7 @@ class AppLifecycleObserverTest {
firebaseRemoteFeatureProvider = firebaseRemoteFeatureProvider,
packageUtil = packageUtil,
settings = settings,
networkConnectionWatcher = networkConnectionWatcher,
applicationScope = CoroutineScope(Dispatchers.Default),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ enum class SourceView(val analyticsValue: String) {
MULTI_SELECT("multi_select"),
STATS("stats"),
WHATS_NEW("whats_new"),
METERED_NETWORK_CHANGE("metered_network_change"),
;

fun skipTracking() = this in listOf(AUTO_PLAY, AUTO_PAUSE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package au.com.shiftyjelly.pocketcasts.repositories.playback

import android.net.NetworkCapabilities
import kotlinx.coroutines.flow.StateFlow

interface NetworkConnectionWatcher {
val networkCapabilities: StateFlow<NetworkCapabilities?>
}
Loading

0 comments on commit 54ddbe1

Please sign in to comment.